diff --git a/App.config b/App.config
new file mode 100644
index 0000000000000000000000000000000000000000..8324aa6ff159e0630b9811cf7d53f09b4b8adf91
--- /dev/null
+++ b/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ClassDiagram1.cd b/ClassDiagram1.cd
new file mode 100644
index 0000000000000000000000000000000000000000..7b894197b9d8d79b2ad4afafc2c11c60f33c4b42
--- /dev/null
+++ b/ClassDiagram1.cd
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Program.cs b/Program.cs
new file mode 100644
index 0000000000000000000000000000000000000000..94e9cf3bfbe559bedf080d010c8dcec46f07cc41
--- /dev/null
+++ b/Program.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace SignatureVerifier
+{
+ static class Program
+ {
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ static void Main()
+ {
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+ Application.Run(new frmMain());
+ }
+ }
+}
diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..96d1a979f75e5f133f1c3d716ad0a47543c8b8ea
--- /dev/null
+++ b/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ufr-signer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ufr-signer")]
+[assembly: AssemblyCopyright("Copyright © 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("0d346cc0-83c5-4117-b2e6-2a33686b3fc0")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("0.0.0.1")]
+[assembly: AssemblyFileVersion("0.0.0.1")]
diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a048735d37e2371ca7622af9e46890ac2c9dfe1b
--- /dev/null
+++ b/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace SignatureVerifier.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("EcdsaTest.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/Properties/Resources.resx b/Properties/Resources.resx
new file mode 100644
index 0000000000000000000000000000000000000000..af7dbebbacef595e3089c01c05671016c21a8304
--- /dev/null
+++ b/Properties/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..82e72d3e5b06d6b7e161fb0248512521cb5e42b3
--- /dev/null
+++ b/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace SignatureVerifier.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/Properties/Settings.settings b/Properties/Settings.settings
new file mode 100644
index 0000000000000000000000000000000000000000..39645652af62950ebf3b28ec3a5400dcec30b1c4
--- /dev/null
+++ b/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/bc-sharp-crypto/bzip2/src/BZip2Constants.cs b/bc-sharp-crypto/bzip2/src/BZip2Constants.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4a5442d8b3bd6a81b002fdada4e1b803dd60e44e
--- /dev/null
+++ b/bc-sharp-crypto/bzip2/src/BZip2Constants.cs
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*
+ * This package is based on the work done by Keiron Liddle, Aftex Software
+ * to whom the Ant project is very grateful for his
+ * great code.
+ */
+
+using System;
+
+namespace Org.BouncyCastle.Apache.Bzip2
+{
+ /**
+ * Base class for both the compress and decompress classes.
+ * Holds common arrays, and static data.
+ *
+ * @author Keiron Liddle
+ */
+ public class BZip2Constants {
+
+ public const int baseBlockSize = 100000;
+ public const int MAX_ALPHA_SIZE = 258;
+ public const int MAX_CODE_LEN = 23;
+ public const int RUNA = 0;
+ public const int RUNB = 1;
+ public const int N_GROUPS = 6;
+ public const int G_SIZE = 50;
+ public const int N_ITERS = 4;
+ public const int MAX_SELECTORS = (2 + (900000 / G_SIZE));
+ public const int NUM_OVERSHOOT_BYTES = 20;
+
+ public static readonly int[] rNums = {
+ 619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
+ 985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
+ 733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
+ 419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
+ 878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
+ 862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
+ 150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
+ 170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
+ 73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
+ 909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
+ 641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
+ 161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
+ 382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
+ 98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
+ 227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
+ 469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
+ 184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
+ 715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
+ 951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
+ 652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
+ 645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
+ 609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
+ 653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
+ 411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
+ 170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
+ 857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
+ 669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
+ 944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
+ 344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
+ 897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
+ 433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
+ 686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
+ 946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
+ 978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
+ 680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
+ 707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
+ 297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
+ 134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
+ 343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
+ 140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
+ 170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
+ 369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
+ 804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
+ 896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
+ 661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
+ 768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
+ 61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
+ 372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
+ 780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
+ 920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
+ 645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
+ 936, 638
+ };
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/bzip2/src/CBZip2InputStream.cs b/bc-sharp-crypto/bzip2/src/CBZip2InputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..82ff83e4218319b45bc1f6fba26e73cb9b48d648
--- /dev/null
+++ b/bc-sharp-crypto/bzip2/src/CBZip2InputStream.cs
@@ -0,0 +1,921 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*
+ * This package is based on the work done by Keiron Liddle, Aftex Software
+ * to whom the Ant project is very grateful for his
+ * great code.
+ */
+
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Apache.Bzip2
+{
+ /**
+ * An input stream that decompresses from the BZip2 format (with the file
+ * header chars) to be read as any other stream.
+ *
+ * @author Keiron Liddle
+ *
+ * NB: note this class has been modified to read the leading BZ from the
+ * start of the BZIP2 stream to make it compatible with other PGP programs.
+ */
+ public class CBZip2InputStream : Stream
+ {
+ private static void Cadvise() {
+ //System.out.Println("CRC Error");
+ //throw new CCoruptionError();
+ }
+
+// private static void BadBGLengths() {
+// Cadvise();
+// }
+//
+// private static void BitStreamEOF() {
+// Cadvise();
+// }
+
+ private static void CompressedStreamEOF() {
+ Cadvise();
+ }
+
+ private void MakeMaps() {
+ int i;
+ nInUse = 0;
+ for (i = 0; i < 256; i++) {
+ if (inUse[i]) {
+ seqToUnseq[nInUse] = (char) i;
+ unseqToSeq[i] = (char) nInUse;
+ nInUse++;
+ }
+ }
+ }
+
+ /*
+ index of the last char in the block, so
+ the block size == last + 1.
+ */
+ private int last;
+
+ /*
+ index in zptr[] of original string after sorting.
+ */
+ private int origPtr;
+
+ /*
+ always: in the range 0 .. 9.
+ The current block size is 100000 * this number.
+ */
+ private int blockSize100k;
+
+ private bool blockRandomised;
+
+ private int bsBuff;
+ private int bsLive;
+ private CRC mCrc = new CRC();
+
+ private bool[] inUse = new bool[256];
+ private int nInUse;
+
+ private char[] seqToUnseq = new char[256];
+ private char[] unseqToSeq = new char[256];
+
+ private char[] selector = new char[BZip2Constants.MAX_SELECTORS];
+ private char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS];
+
+ private int[] tt;
+ private char[] ll8;
+
+ /*
+ freq table collected to save a pass over the data
+ during decompression.
+ */
+ private int[] unzftab = new int[256];
+
+ private int[][] limit = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+ private int[][] basev = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+ private int[][] perm = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+ private int[] minLens = new int[BZip2Constants.N_GROUPS];
+
+ private Stream bsStream;
+
+ private bool streamEnd = false;
+
+ private int currentChar = -1;
+
+ private const int START_BLOCK_STATE = 1;
+ private const int RAND_PART_A_STATE = 2;
+ private const int RAND_PART_B_STATE = 3;
+ private const int RAND_PART_C_STATE = 4;
+ private const int NO_RAND_PART_A_STATE = 5;
+ private const int NO_RAND_PART_B_STATE = 6;
+ private const int NO_RAND_PART_C_STATE = 7;
+
+ private int currentState = START_BLOCK_STATE;
+
+ private int storedBlockCRC, storedCombinedCRC;
+ private int computedBlockCRC, computedCombinedCRC;
+
+ int i2, count, chPrev, ch2;
+ int i, tPos;
+ int rNToGo = 0;
+ int rTPos = 0;
+ int j2;
+ char z;
+
+ public CBZip2InputStream(Stream zStream) {
+ ll8 = null;
+ tt = null;
+ BsSetStream(zStream);
+ Initialize();
+ InitBlock();
+ SetupBlock();
+ }
+
+ internal static int[][] InitIntArray(int n1, int n2) {
+ int[][] a = new int[n1][];
+ for (int k = 0; k < n1; ++k) {
+ a[k] = new int[n2];
+ }
+ return a;
+ }
+
+ internal static char[][] InitCharArray(int n1, int n2) {
+ char[][] a = new char[n1][];
+ for (int k = 0; k < n1; ++k) {
+ a[k] = new char[n2];
+ }
+ return a;
+ }
+
+ public override int ReadByte() {
+ if (streamEnd) {
+ return -1;
+ } else {
+ int retChar = currentChar;
+ switch (currentState) {
+ case START_BLOCK_STATE:
+ break;
+ case RAND_PART_A_STATE:
+ break;
+ case RAND_PART_B_STATE:
+ SetupRandPartB();
+ break;
+ case RAND_PART_C_STATE:
+ SetupRandPartC();
+ break;
+ case NO_RAND_PART_A_STATE:
+ break;
+ case NO_RAND_PART_B_STATE:
+ SetupNoRandPartB();
+ break;
+ case NO_RAND_PART_C_STATE:
+ SetupNoRandPartC();
+ break;
+ default:
+ break;
+ }
+ return retChar;
+ }
+ }
+
+ private void Initialize() {
+ char magic3, magic4;
+ magic3 = BsGetUChar();
+ magic4 = BsGetUChar();
+ if (magic3 != 'B' && magic4 != 'Z')
+ {
+ throw new IOException("Not a BZIP2 marked stream");
+ }
+ magic3 = BsGetUChar();
+ magic4 = BsGetUChar();
+ if (magic3 != 'h' || magic4 < '1' || magic4 > '9') {
+ BsFinishedWithStream();
+ streamEnd = true;
+ return;
+ }
+
+ SetDecompressStructureSizes(magic4 - '0');
+ computedCombinedCRC = 0;
+ }
+
+ private void InitBlock() {
+ char magic1, magic2, magic3, magic4;
+ char magic5, magic6;
+ magic1 = BsGetUChar();
+ magic2 = BsGetUChar();
+ magic3 = BsGetUChar();
+ magic4 = BsGetUChar();
+ magic5 = BsGetUChar();
+ magic6 = BsGetUChar();
+ if (magic1 == 0x17 && magic2 == 0x72 && magic3 == 0x45
+ && magic4 == 0x38 && magic5 == 0x50 && magic6 == 0x90) {
+ Complete();
+ return;
+ }
+
+ if (magic1 != 0x31 || magic2 != 0x41 || magic3 != 0x59
+ || magic4 != 0x26 || magic5 != 0x53 || magic6 != 0x59) {
+ BadBlockHeader();
+ streamEnd = true;
+ return;
+ }
+
+ storedBlockCRC = BsGetInt32();
+
+ if (BsR(1) == 1) {
+ blockRandomised = true;
+ } else {
+ blockRandomised = false;
+ }
+
+ // currBlockNo++;
+ GetAndMoveToFrontDecode();
+
+ mCrc.InitialiseCRC();
+ currentState = START_BLOCK_STATE;
+ }
+
+ private void EndBlock() {
+ computedBlockCRC = mCrc.GetFinalCRC();
+ /* A bad CRC is considered a fatal error. */
+ if (storedBlockCRC != computedBlockCRC) {
+ CrcError();
+ }
+
+ computedCombinedCRC = (computedCombinedCRC << 1)
+ | (int)(((uint)computedCombinedCRC) >> 31);
+ computedCombinedCRC ^= computedBlockCRC;
+ }
+
+ private void Complete() {
+ storedCombinedCRC = BsGetInt32();
+ if (storedCombinedCRC != computedCombinedCRC) {
+ CrcError();
+ }
+
+ BsFinishedWithStream();
+ streamEnd = true;
+ }
+
+ private static void BlockOverrun() {
+ Cadvise();
+ }
+
+ private static void BadBlockHeader() {
+ Cadvise();
+ }
+
+ private static void CrcError() {
+ Cadvise();
+ }
+
+ private void BsFinishedWithStream() {
+ try {
+ if (this.bsStream != null) {
+ Platform.Dispose(this.bsStream);
+ this.bsStream = null;
+ }
+ } catch {
+ //ignore
+ }
+ }
+
+ private void BsSetStream(Stream f) {
+ bsStream = f;
+ bsLive = 0;
+ bsBuff = 0;
+ }
+
+ private int BsR(int n) {
+ int v;
+ while (bsLive < n) {
+ int zzi;
+ char thech = '\0';
+ try {
+ thech = (char) bsStream.ReadByte();
+ } catch (IOException) {
+ CompressedStreamEOF();
+ }
+ if (thech == '\uffff') {
+ CompressedStreamEOF();
+ }
+ zzi = thech;
+ bsBuff = (bsBuff << 8) | (zzi & 0xff);
+ bsLive += 8;
+ }
+
+ v = (bsBuff >> (bsLive - n)) & ((1 << n) - 1);
+ bsLive -= n;
+ return v;
+ }
+
+ private char BsGetUChar() {
+ return (char) BsR(8);
+ }
+
+ private int BsGetint() {
+ int u = 0;
+ u = (u << 8) | BsR(8);
+ u = (u << 8) | BsR(8);
+ u = (u << 8) | BsR(8);
+ u = (u << 8) | BsR(8);
+ return u;
+ }
+
+ private int BsGetIntVS(int numBits) {
+ return (int) BsR(numBits);
+ }
+
+ private int BsGetInt32() {
+ return (int) BsGetint();
+ }
+
+ private void HbCreateDecodeTables(int[] limit, int[] basev,
+ int[] perm, char[] length,
+ int minLen, int maxLen, int alphaSize) {
+ int pp, i, j, vec;
+
+ pp = 0;
+ for (i = minLen; i <= maxLen; i++) {
+ for (j = 0; j < alphaSize; j++) {
+ if (length[j] == i) {
+ perm[pp] = j;
+ pp++;
+ }
+ }
+ }
+
+ for (i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) {
+ basev[i] = 0;
+ }
+ for (i = 0; i < alphaSize; i++) {
+ basev[length[i] + 1]++;
+ }
+
+ for (i = 1; i < BZip2Constants.MAX_CODE_LEN; i++) {
+ basev[i] += basev[i - 1];
+ }
+
+ for (i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) {
+ limit[i] = 0;
+ }
+ vec = 0;
+
+ for (i = minLen; i <= maxLen; i++) {
+ vec += (basev[i + 1] - basev[i]);
+ limit[i] = vec - 1;
+ vec <<= 1;
+ }
+ for (i = minLen + 1; i <= maxLen; i++) {
+ basev[i] = ((limit[i - 1] + 1) << 1) - basev[i];
+ }
+ }
+
+ private void RecvDecodingTables() {
+ char[][] len = InitCharArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+ int i, j, t, nGroups, nSelectors, alphaSize;
+ int minLen, maxLen;
+ bool[] inUse16 = new bool[16];
+
+ /* Receive the mapping table */
+ for (i = 0; i < 16; i++) {
+ if (BsR(1) == 1) {
+ inUse16[i] = true;
+ } else {
+ inUse16[i] = false;
+ }
+ }
+
+ for (i = 0; i < 256; i++) {
+ inUse[i] = false;
+ }
+
+ for (i = 0; i < 16; i++) {
+ if (inUse16[i]) {
+ for (j = 0; j < 16; j++) {
+ if (BsR(1) == 1) {
+ inUse[i * 16 + j] = true;
+ }
+ }
+ }
+ }
+
+ MakeMaps();
+ alphaSize = nInUse + 2;
+
+ /* Now the selectors */
+ nGroups = BsR(3);
+ nSelectors = BsR(15);
+ for (i = 0; i < nSelectors; i++) {
+ j = 0;
+ while (BsR(1) == 1) {
+ j++;
+ }
+ selectorMtf[i] = (char) j;
+ }
+
+ /* Undo the MTF values for the selectors. */
+ {
+ char[] pos = new char[BZip2Constants.N_GROUPS];
+ char tmp, v;
+ for (v = '\0'; v < nGroups; v++) {
+ pos[v] = v;
+ }
+
+ for (i = 0; i < nSelectors; i++) {
+ v = selectorMtf[i];
+ tmp = pos[v];
+ while (v > 0) {
+ pos[v] = pos[v - 1];
+ v--;
+ }
+ pos[0] = tmp;
+ selector[i] = tmp;
+ }
+ }
+
+ /* Now the coding tables */
+ for (t = 0; t < nGroups; t++) {
+ int curr = BsR(5);
+ for (i = 0; i < alphaSize; i++) {
+ while (BsR(1) == 1) {
+ if (BsR(1) == 0) {
+ curr++;
+ } else {
+ curr--;
+ }
+ }
+ len[t][i] = (char) curr;
+ }
+ }
+
+ /* Create the Huffman decoding tables */
+ for (t = 0; t < nGroups; t++) {
+ minLen = 32;
+ maxLen = 0;
+ for (i = 0; i < alphaSize; i++) {
+ if (len[t][i] > maxLen) {
+ maxLen = len[t][i];
+ }
+ if (len[t][i] < minLen) {
+ minLen = len[t][i];
+ }
+ }
+ HbCreateDecodeTables(limit[t], basev[t], perm[t], len[t], minLen,
+ maxLen, alphaSize);
+ minLens[t] = minLen;
+ }
+ }
+
+ private void GetAndMoveToFrontDecode() {
+ char[] yy = new char[256];
+ int i, j, nextSym, limitLast;
+ int EOB, groupNo, groupPos;
+
+ limitLast = BZip2Constants.baseBlockSize * blockSize100k;
+ origPtr = BsGetIntVS(24);
+
+ RecvDecodingTables();
+ EOB = nInUse + 1;
+ groupNo = -1;
+ groupPos = 0;
+
+ /*
+ Setting up the unzftab entries here is not strictly
+ necessary, but it does save having to do it later
+ in a separate pass, and so saves a block's worth of
+ cache misses.
+ */
+ for (i = 0; i <= 255; i++) {
+ unzftab[i] = 0;
+ }
+
+ for (i = 0; i <= 255; i++) {
+ yy[i] = (char) i;
+ }
+
+ last = -1;
+
+ {
+ int zt, zn, zvec, zj;
+ if (groupPos == 0) {
+ groupNo++;
+ groupPos = BZip2Constants.G_SIZE;
+ }
+ groupPos--;
+ zt = selector[groupNo];
+ zn = minLens[zt];
+ zvec = BsR(zn);
+ while (zvec > limit[zt][zn]) {
+ zn++;
+ {
+ {
+ while (bsLive < 1) {
+ int zzi;
+ char thech = '\0';
+ try {
+ thech = (char) bsStream.ReadByte();
+ } catch (IOException) {
+ CompressedStreamEOF();
+ }
+ if (thech == '\uffff') {
+ CompressedStreamEOF();
+ }
+ zzi = thech;
+ bsBuff = (bsBuff << 8) | (zzi & 0xff);
+ bsLive += 8;
+ }
+ }
+ zj = (bsBuff >> (bsLive - 1)) & 1;
+ bsLive--;
+ }
+ zvec = (zvec << 1) | zj;
+ }
+ nextSym = perm[zt][zvec - basev[zt][zn]];
+ }
+
+ while (true) {
+
+ if (nextSym == EOB) {
+ break;
+ }
+
+ if (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB) {
+ char ch;
+ int s = -1;
+ int N = 1;
+ do {
+ if (nextSym == BZip2Constants.RUNA) {
+ s = s + (0 + 1) * N;
+ } else if (nextSym == BZip2Constants.RUNB) {
+ s = s + (1 + 1) * N;
+ }
+ N = N * 2;
+ {
+ int zt, zn, zvec, zj;
+ if (groupPos == 0) {
+ groupNo++;
+ groupPos = BZip2Constants.G_SIZE;
+ }
+ groupPos--;
+ zt = selector[groupNo];
+ zn = minLens[zt];
+ zvec = BsR(zn);
+ while (zvec > limit[zt][zn]) {
+ zn++;
+ {
+ {
+ while (bsLive < 1) {
+ int zzi;
+ char thech = '\0';
+ try {
+ thech = (char) bsStream.ReadByte();
+ } catch (IOException) {
+ CompressedStreamEOF();
+ }
+ if (thech == '\uffff') {
+ CompressedStreamEOF();
+ }
+ zzi = thech;
+ bsBuff = (bsBuff << 8) | (zzi & 0xff);
+ bsLive += 8;
+ }
+ }
+ zj = (bsBuff >> (bsLive - 1)) & 1;
+ bsLive--;
+ }
+ zvec = (zvec << 1) | zj;
+ }
+ nextSym = perm[zt][zvec - basev[zt][zn]];
+ }
+ } while (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB);
+
+ s++;
+ ch = seqToUnseq[yy[0]];
+ unzftab[ch] += s;
+
+ while (s > 0) {
+ last++;
+ ll8[last] = ch;
+ s--;
+ }
+
+ if (last >= limitLast) {
+ BlockOverrun();
+ }
+ continue;
+ } else {
+ char tmp;
+ last++;
+ if (last >= limitLast) {
+ BlockOverrun();
+ }
+
+ tmp = yy[nextSym - 1];
+ unzftab[seqToUnseq[tmp]]++;
+ ll8[last] = seqToUnseq[tmp];
+
+ /*
+ This loop is hammered during decompression,
+ hence the unrolling.
+
+ for (j = nextSym-1; j > 0; j--) yy[j] = yy[j-1];
+ */
+
+ j = nextSym - 1;
+ for (; j > 3; j -= 4) {
+ yy[j] = yy[j - 1];
+ yy[j - 1] = yy[j - 2];
+ yy[j - 2] = yy[j - 3];
+ yy[j - 3] = yy[j - 4];
+ }
+ for (; j > 0; j--) {
+ yy[j] = yy[j - 1];
+ }
+
+ yy[0] = tmp;
+ {
+ int zt, zn, zvec, zj;
+ if (groupPos == 0) {
+ groupNo++;
+ groupPos = BZip2Constants.G_SIZE;
+ }
+ groupPos--;
+ zt = selector[groupNo];
+ zn = minLens[zt];
+ zvec = BsR(zn);
+ while (zvec > limit[zt][zn]) {
+ zn++;
+ {
+ {
+ while (bsLive < 1) {
+ int zzi;
+ char thech = '\0';
+ try {
+ thech = (char) bsStream.ReadByte();
+ } catch (IOException) {
+ CompressedStreamEOF();
+ }
+ zzi = thech;
+ bsBuff = (bsBuff << 8) | (zzi & 0xff);
+ bsLive += 8;
+ }
+ }
+ zj = (bsBuff >> (bsLive - 1)) & 1;
+ bsLive--;
+ }
+ zvec = (zvec << 1) | zj;
+ }
+ nextSym = perm[zt][zvec - basev[zt][zn]];
+ }
+ continue;
+ }
+ }
+ }
+
+ private void SetupBlock() {
+ int[] cftab = new int[257];
+ char ch;
+
+ cftab[0] = 0;
+ for (i = 1; i <= 256; i++) {
+ cftab[i] = unzftab[i - 1];
+ }
+ for (i = 1; i <= 256; i++) {
+ cftab[i] += cftab[i - 1];
+ }
+
+ for (i = 0; i <= last; i++) {
+ ch = (char) ll8[i];
+ tt[cftab[ch]] = i;
+ cftab[ch]++;
+ }
+ cftab = null;
+
+ tPos = tt[origPtr];
+
+ count = 0;
+ i2 = 0;
+ ch2 = 256; /* not a char and not EOF */
+
+ if (blockRandomised) {
+ rNToGo = 0;
+ rTPos = 0;
+ SetupRandPartA();
+ } else {
+ SetupNoRandPartA();
+ }
+ }
+
+ private void SetupRandPartA() {
+ if (i2 <= last) {
+ chPrev = ch2;
+ ch2 = ll8[tPos];
+ tPos = tt[tPos];
+ if (rNToGo == 0) {
+ rNToGo = BZip2Constants.rNums[rTPos];
+ rTPos++;
+ if (rTPos == 512) {
+ rTPos = 0;
+ }
+ }
+ rNToGo--;
+ ch2 ^= (int) ((rNToGo == 1) ? 1 : 0);
+ i2++;
+
+ currentChar = ch2;
+ currentState = RAND_PART_B_STATE;
+ mCrc.UpdateCRC(ch2);
+ } else {
+ EndBlock();
+ InitBlock();
+ SetupBlock();
+ }
+ }
+
+ private void SetupNoRandPartA() {
+ if (i2 <= last) {
+ chPrev = ch2;
+ ch2 = ll8[tPos];
+ tPos = tt[tPos];
+ i2++;
+
+ currentChar = ch2;
+ currentState = NO_RAND_PART_B_STATE;
+ mCrc.UpdateCRC(ch2);
+ } else {
+ EndBlock();
+ InitBlock();
+ SetupBlock();
+ }
+ }
+
+ private void SetupRandPartB() {
+ if (ch2 != chPrev) {
+ currentState = RAND_PART_A_STATE;
+ count = 1;
+ SetupRandPartA();
+ } else {
+ count++;
+ if (count >= 4) {
+ z = ll8[tPos];
+ tPos = tt[tPos];
+ if (rNToGo == 0) {
+ rNToGo = BZip2Constants.rNums[rTPos];
+ rTPos++;
+ if (rTPos == 512) {
+ rTPos = 0;
+ }
+ }
+ rNToGo--;
+ z ^= (char)((rNToGo == 1) ? 1 : 0);
+ j2 = 0;
+ currentState = RAND_PART_C_STATE;
+ SetupRandPartC();
+ } else {
+ currentState = RAND_PART_A_STATE;
+ SetupRandPartA();
+ }
+ }
+ }
+
+ private void SetupRandPartC() {
+ if (j2 < (int) z) {
+ currentChar = ch2;
+ mCrc.UpdateCRC(ch2);
+ j2++;
+ } else {
+ currentState = RAND_PART_A_STATE;
+ i2++;
+ count = 0;
+ SetupRandPartA();
+ }
+ }
+
+ private void SetupNoRandPartB() {
+ if (ch2 != chPrev) {
+ currentState = NO_RAND_PART_A_STATE;
+ count = 1;
+ SetupNoRandPartA();
+ } else {
+ count++;
+ if (count >= 4) {
+ z = ll8[tPos];
+ tPos = tt[tPos];
+ currentState = NO_RAND_PART_C_STATE;
+ j2 = 0;
+ SetupNoRandPartC();
+ } else {
+ currentState = NO_RAND_PART_A_STATE;
+ SetupNoRandPartA();
+ }
+ }
+ }
+
+ private void SetupNoRandPartC() {
+ if (j2 < (int) z) {
+ currentChar = ch2;
+ mCrc.UpdateCRC(ch2);
+ j2++;
+ } else {
+ currentState = NO_RAND_PART_A_STATE;
+ i2++;
+ count = 0;
+ SetupNoRandPartA();
+ }
+ }
+
+ private void SetDecompressStructureSizes(int newSize100k) {
+ if (!(0 <= newSize100k && newSize100k <= 9 && 0 <= blockSize100k
+ && blockSize100k <= 9)) {
+ // throw new IOException("Invalid block size");
+ }
+
+ blockSize100k = newSize100k;
+
+ if (newSize100k == 0) {
+ return;
+ }
+
+ int n = BZip2Constants.baseBlockSize * newSize100k;
+ ll8 = new char[n];
+ tt = new int[n];
+ }
+
+ public override void Flush() {
+ }
+
+ public override int Read(byte[] buffer, int offset, int count) {
+ int c = -1;
+ int k;
+ for (k = 0; k < count; ++k) {
+ c = ReadByte();
+ if (c == -1)
+ break;
+ buffer[k + offset] = (byte)c;
+ }
+ return k;
+ }
+
+ public override long Seek(long offset, SeekOrigin origin) {
+ return 0;
+ }
+
+ public override void SetLength(long value) {
+ }
+
+ public override void Write(byte[] buffer, int offset, int count) {
+ }
+
+ public override bool CanRead {
+ get {
+ return true;
+ }
+ }
+
+ public override bool CanSeek {
+ get {
+ return false;
+ }
+ }
+
+ public override bool CanWrite {
+ get {
+ return false;
+ }
+ }
+
+ public override long Length {
+ get {
+ return 0;
+ }
+ }
+
+ public override long Position {
+ get {
+ return 0;
+ }
+ set {
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/bzip2/src/CBZip2OutputStream.cs b/bc-sharp-crypto/bzip2/src/CBZip2OutputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ffac073fb817ef2f4afdd2cb697a8a4eb180ae16
--- /dev/null
+++ b/bc-sharp-crypto/bzip2/src/CBZip2OutputStream.cs
@@ -0,0 +1,1709 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*
+ * This package is based on the work done by Keiron Liddle, Aftex Software
+ * to whom the Ant project is very grateful for his
+ * great code.
+ */
+
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Apache.Bzip2
+{
+ /**
+ * An output stream that compresses into the BZip2 format (with the file
+ * header chars) into another stream.
+ *
+ * @author Keiron Liddle
+ *
+ * TODO: Update to BZip2 1.0.1
+ * NB: note this class has been modified to add a leading BZ to the
+ * start of the BZIP2 stream to make it compatible with other PGP programs.
+ */
+ public class CBZip2OutputStream : Stream
+ {
+ protected const int SETMASK = (1 << 21);
+ protected const int CLEARMASK = (~SETMASK);
+ protected const int GREATER_ICOST = 15;
+ protected const int LESSER_ICOST = 0;
+ protected const int SMALL_THRESH = 20;
+ protected const int DEPTH_THRESH = 10;
+
+ /*
+ If you are ever unlucky/improbable enough
+ to get a stack overflow whilst sorting,
+ increase the following constant and try
+ again. In practice I have never seen the
+ stack go above 27 elems, so the following
+ limit seems very generous.
+ */
+ protected const int QSORT_STACK_SIZE = 1000;
+ private bool finished;
+
+ private static void Panic() {
+ //System.out.Println("panic");
+ //throw new CError();
+ }
+
+ private void MakeMaps() {
+ int i;
+ nInUse = 0;
+ for (i = 0; i < 256; i++) {
+ if (inUse[i]) {
+ seqToUnseq[nInUse] = (char) i;
+ unseqToSeq[i] = (char) nInUse;
+ nInUse++;
+ }
+ }
+ }
+
+ protected static void HbMakeCodeLengths(char[] len, int[] freq,
+ int alphaSize, int maxLen) {
+ /*
+ Nodes and heap entries run from 1. Entry 0
+ for both the heap and nodes is a sentinel.
+ */
+ int nNodes, nHeap, n1, n2, i, j, k;
+ bool tooLong;
+
+ int[] heap = new int[BZip2Constants.MAX_ALPHA_SIZE + 2];
+ int[] weight = new int[BZip2Constants.MAX_ALPHA_SIZE * 2];
+ int[] parent = new int[BZip2Constants.MAX_ALPHA_SIZE * 2];
+
+ for (i = 0; i < alphaSize; i++) {
+ weight[i + 1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
+ }
+
+ while (true) {
+ nNodes = alphaSize;
+ nHeap = 0;
+
+ heap[0] = 0;
+ weight[0] = 0;
+ parent[0] = -2;
+
+ for (i = 1; i <= alphaSize; i++) {
+ parent[i] = -1;
+ nHeap++;
+ heap[nHeap] = i;
+ {
+ int zz, tmp;
+ zz = nHeap;
+ tmp = heap[zz];
+ while (weight[tmp] < weight[heap[zz >> 1]]) {
+ heap[zz] = heap[zz >> 1];
+ zz >>= 1;
+ }
+ heap[zz] = tmp;
+ }
+ }
+ if (!(nHeap < (BZip2Constants.MAX_ALPHA_SIZE + 2))) {
+ Panic();
+ }
+
+ while (nHeap > 1) {
+ n1 = heap[1];
+ heap[1] = heap[nHeap];
+ nHeap--;
+ {
+ int zz = 0, yy = 0, tmp = 0;
+ zz = 1;
+ tmp = heap[zz];
+ while (true) {
+ yy = zz << 1;
+ if (yy > nHeap) {
+ break;
+ }
+ if (yy < nHeap
+ && weight[heap[yy + 1]] < weight[heap[yy]]) {
+ yy++;
+ }
+ if (weight[tmp] < weight[heap[yy]]) {
+ break;
+ }
+ heap[zz] = heap[yy];
+ zz = yy;
+ }
+ heap[zz] = tmp;
+ }
+ n2 = heap[1];
+ heap[1] = heap[nHeap];
+ nHeap--;
+ {
+ int zz = 0, yy = 0, tmp = 0;
+ zz = 1;
+ tmp = heap[zz];
+ while (true) {
+ yy = zz << 1;
+ if (yy > nHeap) {
+ break;
+ }
+ if (yy < nHeap
+ && weight[heap[yy + 1]] < weight[heap[yy]]) {
+ yy++;
+ }
+ if (weight[tmp] < weight[heap[yy]]) {
+ break;
+ }
+ heap[zz] = heap[yy];
+ zz = yy;
+ }
+ heap[zz] = tmp;
+ }
+ nNodes++;
+ parent[n1] = parent[n2] = nNodes;
+
+ weight[nNodes] = (int)((uint)((weight[n1] & 0xffffff00)
+ + (weight[n2] & 0xffffff00))
+ | (uint)(1 + (((weight[n1] & 0x000000ff) >
+ (weight[n2] & 0x000000ff)) ?
+ (weight[n1] & 0x000000ff) :
+ (weight[n2] & 0x000000ff))));
+
+ parent[nNodes] = -1;
+ nHeap++;
+ heap[nHeap] = nNodes;
+ {
+ int zz = 0, tmp = 0;
+ zz = nHeap;
+ tmp = heap[zz];
+ while (weight[tmp] < weight[heap[zz >> 1]]) {
+ heap[zz] = heap[zz >> 1];
+ zz >>= 1;
+ }
+ heap[zz] = tmp;
+ }
+ }
+ if (!(nNodes < (BZip2Constants.MAX_ALPHA_SIZE * 2))) {
+ Panic();
+ }
+
+ tooLong = false;
+ for (i = 1; i <= alphaSize; i++) {
+ j = 0;
+ k = i;
+ while (parent[k] >= 0) {
+ k = parent[k];
+ j++;
+ }
+ len[i - 1] = (char) j;
+ if (j > maxLen) {
+ tooLong = true;
+ }
+ }
+
+ if (!tooLong) {
+ break;
+ }
+
+ for (i = 1; i < alphaSize; i++) {
+ j = weight[i] >> 8;
+ j = 1 + (j / 2);
+ weight[i] = j << 8;
+ }
+ }
+ }
+
+ /*
+ index of the last char in the block, so
+ the block size == last + 1.
+ */
+ int last;
+
+ /*
+ index in zptr[] of original string after sorting.
+ */
+ int origPtr;
+
+ /*
+ always: in the range 0 .. 9.
+ The current block size is 100000 * this number.
+ */
+ int blockSize100k;
+
+ bool blockRandomised;
+
+ int bytesOut;
+ int bsBuff;
+ int bsLive;
+ CRC mCrc = new CRC();
+
+ private bool[] inUse = new bool[256];
+ private int nInUse;
+
+ private char[] seqToUnseq = new char[256];
+ private char[] unseqToSeq = new char[256];
+
+ private char[] selector = new char[BZip2Constants.MAX_SELECTORS];
+ private char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS];
+
+ private char[] block;
+ private int[] quadrant;
+ private int[] zptr;
+ private short[] szptr;
+ private int[] ftab;
+
+ private int nMTF;
+
+ private int[] mtfFreq = new int[BZip2Constants.MAX_ALPHA_SIZE];
+
+ /*
+ * Used when sorting. If too many long comparisons
+ * happen, we stop sorting, randomise the block
+ * slightly, and try again.
+ */
+ private int workFactor;
+ private int workDone;
+ private int workLimit;
+ private bool firstAttempt;
+ private int nBlocksRandomised;
+
+ private int currentChar = -1;
+ private int runLength = 0;
+
+ public CBZip2OutputStream(Stream inStream) : this(inStream, 9) {
+ }
+
+ public CBZip2OutputStream(Stream inStream, int inBlockSize)
+ {
+ block = null;
+ quadrant = null;
+ zptr = null;
+ ftab = null;
+
+ inStream.WriteByte((byte)'B');
+ inStream.WriteByte((byte)'Z');
+
+ BsSetStream(inStream);
+
+ workFactor = 50;
+ if (inBlockSize > 9) {
+ inBlockSize = 9;
+ }
+ if (inBlockSize < 1) {
+ inBlockSize = 1;
+ }
+ blockSize100k = inBlockSize;
+ AllocateCompressStructures();
+ Initialize();
+ InitBlock();
+ }
+
+ /**
+ *
+ * modified by Oliver Merkel, 010128
+ *
+ */
+ public override void WriteByte(byte bv) {
+ int b = (256 + bv) % 256;
+ if (currentChar != -1) {
+ if (currentChar == b) {
+ runLength++;
+ if (runLength > 254) {
+ WriteRun();
+ currentChar = -1;
+ runLength = 0;
+ }
+ } else {
+ WriteRun();
+ runLength = 1;
+ currentChar = b;
+ }
+ } else {
+ currentChar = b;
+ runLength++;
+ }
+ }
+
+ private void WriteRun() {
+ if (last < allowableBlockSize) {
+ inUse[currentChar] = true;
+ for (int i = 0; i < runLength; i++) {
+ mCrc.UpdateCRC((char) currentChar);
+ }
+ switch (runLength) {
+ case 1:
+ last++;
+ block[last + 1] = (char) currentChar;
+ break;
+ case 2:
+ last++;
+ block[last + 1] = (char) currentChar;
+ last++;
+ block[last + 1] = (char) currentChar;
+ break;
+ case 3:
+ last++;
+ block[last + 1] = (char) currentChar;
+ last++;
+ block[last + 1] = (char) currentChar;
+ last++;
+ block[last + 1] = (char) currentChar;
+ break;
+ default:
+ inUse[runLength - 4] = true;
+ last++;
+ block[last + 1] = (char) currentChar;
+ last++;
+ block[last + 1] = (char) currentChar;
+ last++;
+ block[last + 1] = (char) currentChar;
+ last++;
+ block[last + 1] = (char) currentChar;
+ last++;
+ block[last + 1] = (char) (runLength - 4);
+ break;
+ }
+ } else {
+ EndBlock();
+ InitBlock();
+ WriteRun();
+ }
+ }
+
+ bool closed = false;
+
+// protected void Finalize() {
+// Close();
+// }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (closed)
+ return;
+
+ Finish();
+ closed = true;
+ Platform.Dispose(this.bsStream);
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close() {
+ if (closed)
+ return;
+
+ Finish();
+
+ closed = true;
+ Platform.Dispose(this.bsStream);
+
+ base.Close();
+ }
+#endif
+
+ public void Finish() {
+ if (finished) {
+ return;
+ }
+
+ if (runLength > 0) {
+ WriteRun();
+ }
+ currentChar = -1;
+ EndBlock();
+ EndCompression();
+ finished = true;
+ Flush();
+ }
+
+ public override void Flush() {
+ bsStream.Flush();
+ }
+
+ private int blockCRC, combinedCRC;
+
+ private void Initialize() {
+ bytesOut = 0;
+ nBlocksRandomised = 0;
+
+ /* Write `magic' bytes h indicating file-format == huffmanised,
+ followed by a digit indicating blockSize100k.
+ */
+ BsPutUChar('h');
+ BsPutUChar('0' + blockSize100k);
+
+ combinedCRC = 0;
+ }
+
+ private int allowableBlockSize;
+
+ private void InitBlock() {
+ // blockNo++;
+ mCrc.InitialiseCRC();
+ last = -1;
+ // ch = 0;
+
+ for (int i = 0; i < 256; i++) {
+ inUse[i] = false;
+ }
+
+ /* 20 is just a paranoia constant */
+ allowableBlockSize = BZip2Constants.baseBlockSize * blockSize100k - 20;
+ }
+
+ private void EndBlock() {
+ blockCRC = mCrc.GetFinalCRC();
+ combinedCRC = (combinedCRC << 1) | (int)(((uint)combinedCRC) >> 31);
+ combinedCRC ^= blockCRC;
+
+ /* sort the block and establish posn of original string */
+ DoReversibleTransformation();
+
+ /*
+ A 6-byte block header, the value chosen arbitrarily
+ as 0x314159265359 :-). A 32 bit value does not really
+ give a strong enough guarantee that the value will not
+ appear by chance in the compressed datastream. Worst-case
+ probability of this event, for a 900k block, is about
+ 2.0e-3 for 32 bits, 1.0e-5 for 40 bits and 4.0e-8 for 48 bits.
+ For a compressed file of size 100Gb -- about 100000 blocks --
+ only a 48-bit marker will do. NB: normal compression/
+ decompression do *not* rely on these statistical properties.
+ They are only important when trying to recover blocks from
+ damaged files.
+ */
+ BsPutUChar(0x31);
+ BsPutUChar(0x41);
+ BsPutUChar(0x59);
+ BsPutUChar(0x26);
+ BsPutUChar(0x53);
+ BsPutUChar(0x59);
+
+ /* Now the block's CRC, so it is in a known place. */
+ BsPutint(blockCRC);
+
+ /* Now a single bit indicating randomisation. */
+ if (blockRandomised) {
+ BsW(1, 1);
+ nBlocksRandomised++;
+ } else {
+ BsW(1, 0);
+ }
+
+ /* Finally, block's contents proper. */
+ MoveToFrontCodeAndSend();
+ }
+
+ private void EndCompression() {
+ /*
+ Now another magic 48-bit number, 0x177245385090, to
+ indicate the end of the last block. (Sqrt(pi), if
+ you want to know. I did want to use e, but it contains
+ too much repetition -- 27 18 28 18 28 46 -- for me
+ to feel statistically comfortable. Call me paranoid.)
+ */
+ BsPutUChar(0x17);
+ BsPutUChar(0x72);
+ BsPutUChar(0x45);
+ BsPutUChar(0x38);
+ BsPutUChar(0x50);
+ BsPutUChar(0x90);
+
+ BsPutint(combinedCRC);
+
+ BsFinishedWithStream();
+ }
+
+ private void HbAssignCodes(int[] code, char[] length, int minLen,
+ int maxLen, int alphaSize) {
+ int n, vec, i;
+
+ vec = 0;
+ for (n = minLen; n <= maxLen; n++) {
+ for (i = 0; i < alphaSize; i++) {
+ if (length[i] == n) {
+ code[i] = vec;
+ vec++;
+ }
+ };
+ vec <<= 1;
+ }
+ }
+
+ private void BsSetStream(Stream f) {
+ bsStream = f;
+ bsLive = 0;
+ bsBuff = 0;
+ bytesOut = 0;
+ }
+
+ private void BsFinishedWithStream() {
+ while (bsLive > 0) {
+ int ch = (bsBuff >> 24);
+ try {
+ bsStream.WriteByte((byte)ch); // write 8-bit
+ } catch (IOException e) {
+ throw e;
+ }
+ bsBuff <<= 8;
+ bsLive -= 8;
+ bytesOut++;
+ }
+ }
+
+ private void BsW(int n, int v) {
+ while (bsLive >= 8) {
+ int ch = (bsBuff >> 24);
+ try {
+ bsStream.WriteByte((byte)ch); // write 8-bit
+ } catch (IOException e) {
+ throw e;
+ }
+ bsBuff <<= 8;
+ bsLive -= 8;
+ bytesOut++;
+ }
+ bsBuff |= (v << (32 - bsLive - n));
+ bsLive += n;
+ }
+
+ private void BsPutUChar(int c) {
+ BsW(8, c);
+ }
+
+ private void BsPutint(int u) {
+ BsW(8, (u >> 24) & 0xff);
+ BsW(8, (u >> 16) & 0xff);
+ BsW(8, (u >> 8) & 0xff);
+ BsW(8, u & 0xff);
+ }
+
+ private void BsPutIntVS(int numBits, int c) {
+ BsW(numBits, c);
+ }
+
+ private void SendMTFValues() {
+ char[][] len = CBZip2InputStream.InitCharArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+
+ int v, t, i, j, gs, ge, totc, bt, bc, iter;
+ int nSelectors = 0, alphaSize, minLen, maxLen, selCtr;
+ int nGroups;
+
+ alphaSize = nInUse + 2;
+ for (t = 0; t < BZip2Constants.N_GROUPS; t++) {
+ for (v = 0; v < alphaSize; v++) {
+ len[t][v] = (char) GREATER_ICOST;
+ }
+ }
+
+ /* Decide how many coding tables to use */
+ if (nMTF <= 0) {
+ Panic();
+ }
+
+ if (nMTF < 200) {
+ nGroups = 2;
+ } else if (nMTF < 600) {
+ nGroups = 3;
+ } else if (nMTF < 1200) {
+ nGroups = 4;
+ } else if (nMTF < 2400) {
+ nGroups = 5;
+ } else {
+ nGroups = 6;
+ }
+
+ /* Generate an initial set of coding tables */ {
+ int nPart, remF, tFreq, aFreq;
+
+ nPart = nGroups;
+ remF = nMTF;
+ gs = 0;
+ while (nPart > 0) {
+ tFreq = remF / nPart;
+ ge = gs - 1;
+ aFreq = 0;
+ while (aFreq < tFreq && ge < alphaSize - 1) {
+ ge++;
+ aFreq += mtfFreq[ge];
+ }
+
+ if (ge > gs && nPart != nGroups && nPart != 1
+ && ((nGroups - nPart) % 2 == 1)) {
+ aFreq -= mtfFreq[ge];
+ ge--;
+ }
+
+ for (v = 0; v < alphaSize; v++) {
+ if (v >= gs && v <= ge) {
+ len[nPart - 1][v] = (char) LESSER_ICOST;
+ } else {
+ len[nPart - 1][v] = (char) GREATER_ICOST;
+ }
+ }
+
+ nPart--;
+ gs = ge + 1;
+ remF -= aFreq;
+ }
+ }
+
+ int[][] rfreq = CBZip2InputStream.InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+ int[] fave = new int[BZip2Constants.N_GROUPS];
+ short[] cost = new short[BZip2Constants.N_GROUPS];
+ /*
+ Iterate up to N_ITERS times to improve the tables.
+ */
+ for (iter = 0; iter < BZip2Constants.N_ITERS; iter++) {
+ for (t = 0; t < nGroups; t++) {
+ fave[t] = 0;
+ }
+
+ for (t = 0; t < nGroups; t++) {
+ for (v = 0; v < alphaSize; v++) {
+ rfreq[t][v] = 0;
+ }
+ }
+
+ nSelectors = 0;
+ totc = 0;
+ gs = 0;
+ while (true) {
+
+ /* Set group start & end marks. */
+ if (gs >= nMTF) {
+ break;
+ }
+ ge = gs + BZip2Constants.G_SIZE - 1;
+ if (ge >= nMTF) {
+ ge = nMTF - 1;
+ }
+
+ /*
+ Calculate the cost of this group as coded
+ by each of the coding tables.
+ */
+ for (t = 0; t < nGroups; t++) {
+ cost[t] = 0;
+ }
+
+ if (nGroups == 6) {
+ short cost0, cost1, cost2, cost3, cost4, cost5;
+ cost0 = cost1 = cost2 = cost3 = cost4 = cost5 = 0;
+ for (i = gs; i <= ge; i++) {
+ short icv = szptr[i];
+ cost0 += (short)len[0][icv];
+ cost1 += (short)len[1][icv];
+ cost2 += (short)len[2][icv];
+ cost3 += (short)len[3][icv];
+ cost4 += (short)len[4][icv];
+ cost5 += (short)len[5][icv];
+ }
+ cost[0] = cost0;
+ cost[1] = cost1;
+ cost[2] = cost2;
+ cost[3] = cost3;
+ cost[4] = cost4;
+ cost[5] = cost5;
+ } else {
+ for (i = gs; i <= ge; i++) {
+ short icv = szptr[i];
+ for (t = 0; t < nGroups; t++) {
+ cost[t] += (short)len[t][icv];
+ }
+ }
+ }
+
+ /*
+ Find the coding table which is best for this group,
+ and record its identity in the selector table.
+ */
+ bc = 999999999;
+ bt = -1;
+ for (t = 0; t < nGroups; t++) {
+ if (cost[t] < bc) {
+ bc = cost[t];
+ bt = t;
+ }
+ };
+ totc += bc;
+ fave[bt]++;
+ selector[nSelectors] = (char) bt;
+ nSelectors++;
+
+ /*
+ Increment the symbol frequencies for the selected table.
+ */
+ for (i = gs; i <= ge; i++) {
+ rfreq[bt][szptr[i]]++;
+ }
+
+ gs = ge + 1;
+ }
+
+ /*
+ Recompute the tables based on the accumulated frequencies.
+ */
+ for (t = 0; t < nGroups; t++) {
+ HbMakeCodeLengths(len[t], rfreq[t], alphaSize, 20);
+ }
+ }
+
+ rfreq = null;
+ fave = null;
+ cost = null;
+
+ if (!(nGroups < 8)) {
+ Panic();
+ }
+ if (!(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZip2Constants.G_SIZE)))) {
+ Panic();
+ }
+
+
+ /* Compute MTF values for the selectors. */
+ {
+ char[] pos = new char[BZip2Constants.N_GROUPS];
+ char ll_i, tmp2, tmp;
+ for (i = 0; i < nGroups; i++) {
+ pos[i] = (char) i;
+ }
+ for (i = 0; i < nSelectors; i++) {
+ ll_i = selector[i];
+ j = 0;
+ tmp = pos[j];
+ while (ll_i != tmp) {
+ j++;
+ tmp2 = tmp;
+ tmp = pos[j];
+ pos[j] = tmp2;
+ }
+ pos[0] = tmp;
+ selectorMtf[i] = (char) j;
+ }
+ }
+
+ int[][] code = CBZip2InputStream.InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+
+ /* Assign actual codes for the tables. */
+ for (t = 0; t < nGroups; t++) {
+ minLen = 32;
+ maxLen = 0;
+ for (i = 0; i < alphaSize; i++) {
+ if (len[t][i] > maxLen) {
+ maxLen = len[t][i];
+ }
+ if (len[t][i] < minLen) {
+ minLen = len[t][i];
+ }
+ }
+ if (maxLen > 20) {
+ Panic();
+ }
+ if (minLen < 1) {
+ Panic();
+ }
+ HbAssignCodes(code[t], len[t], minLen, maxLen, alphaSize);
+ }
+
+ /* Transmit the mapping table. */
+ {
+ bool[] inUse16 = new bool[16];
+ for (i = 0; i < 16; i++) {
+ inUse16[i] = false;
+ for (j = 0; j < 16; j++) {
+ if (inUse[i * 16 + j]) {
+ inUse16[i] = true;
+ }
+ }
+ }
+
+ for (i = 0; i < 16; i++) {
+ if (inUse16[i]) {
+ BsW(1, 1);
+ } else {
+ BsW(1, 0);
+ }
+ }
+
+ for (i = 0; i < 16; i++) {
+ if (inUse16[i]) {
+ for (j = 0; j < 16; j++) {
+ if (inUse[i * 16 + j]) {
+ BsW(1, 1);
+ } else {
+ BsW(1, 0);
+ }
+ }
+ }
+ }
+
+ }
+
+ /* Now the selectors. */
+ BsW(3, nGroups);
+ BsW(15, nSelectors);
+ for (i = 0; i < nSelectors; i++) {
+ for (j = 0; j < selectorMtf[i]; j++) {
+ BsW(1, 1);
+ }
+ BsW(1, 0);
+ }
+
+ /* Now the coding tables. */
+ for (t = 0; t < nGroups; t++) {
+ int curr = len[t][0];
+ BsW(5, curr);
+ for (i = 0; i < alphaSize; i++) {
+ while (curr < len[t][i]) {
+ BsW(2, 2);
+ curr++; /* 10 */
+ }
+ while (curr > len[t][i]) {
+ BsW(2, 3);
+ curr--; /* 11 */
+ }
+ BsW(1, 0);
+ }
+ }
+
+ /* And finally, the block data proper */
+ selCtr = 0;
+ gs = 0;
+ while (true) {
+ if (gs >= nMTF) {
+ break;
+ }
+ ge = gs + BZip2Constants.G_SIZE - 1;
+ if (ge >= nMTF) {
+ ge = nMTF - 1;
+ }
+ for (i = gs; i <= ge; i++) {
+ BsW(len[selector[selCtr]][szptr[i]],
+ code[selector[selCtr]][szptr[i]]);
+ }
+
+ gs = ge + 1;
+ selCtr++;
+ }
+ if (!(selCtr == nSelectors)) {
+ Panic();
+ }
+ }
+
+ private void MoveToFrontCodeAndSend() {
+ BsPutIntVS(24, origPtr);
+ GenerateMTFValues();
+ SendMTFValues();
+ }
+
+ private Stream bsStream;
+
+ private void SimpleSort(int lo, int hi, int d) {
+ int i, j, h, bigN, hp;
+ int v;
+
+ bigN = hi - lo + 1;
+ if (bigN < 2) {
+ return;
+ }
+
+ hp = 0;
+ while (incs[hp] < bigN) {
+ hp++;
+ }
+ hp--;
+
+ for (; hp >= 0; hp--) {
+ h = incs[hp];
+
+ i = lo + h;
+ while (true) {
+ /* copy 1 */
+ if (i > hi) {
+ break;
+ }
+ v = zptr[i];
+ j = i;
+ while (FullGtU(zptr[j - h] + d, v + d)) {
+ zptr[j] = zptr[j - h];
+ j = j - h;
+ if (j <= (lo + h - 1)) {
+ break;
+ }
+ }
+ zptr[j] = v;
+ i++;
+
+ /* copy 2 */
+ if (i > hi) {
+ break;
+ }
+ v = zptr[i];
+ j = i;
+ while (FullGtU(zptr[j - h] + d, v + d)) {
+ zptr[j] = zptr[j - h];
+ j = j - h;
+ if (j <= (lo + h - 1)) {
+ break;
+ }
+ }
+ zptr[j] = v;
+ i++;
+
+ /* copy 3 */
+ if (i > hi) {
+ break;
+ }
+ v = zptr[i];
+ j = i;
+ while (FullGtU(zptr[j - h] + d, v + d)) {
+ zptr[j] = zptr[j - h];
+ j = j - h;
+ if (j <= (lo + h - 1)) {
+ break;
+ }
+ }
+ zptr[j] = v;
+ i++;
+
+ if (workDone > workLimit && firstAttempt) {
+ return;
+ }
+ }
+ }
+ }
+
+ private void Vswap(int p1, int p2, int n) {
+ int temp = 0;
+ while (n > 0) {
+ temp = zptr[p1];
+ zptr[p1] = zptr[p2];
+ zptr[p2] = temp;
+ p1++;
+ p2++;
+ n--;
+ }
+ }
+
+ private char Med3(char a, char b, char c) {
+ char t;
+ if (a > b) {
+ t = a;
+ a = b;
+ b = t;
+ }
+ if (b > c) {
+ t = b;
+ b = c;
+ c = t;
+ }
+ if (a > b) {
+ b = a;
+ }
+ return b;
+ }
+
+ internal class StackElem {
+ internal int ll;
+ internal int hh;
+ internal int dd;
+ }
+
+ private void QSort3(int loSt, int hiSt, int dSt) {
+ int unLo, unHi, ltLo, gtHi, med, n, m;
+ int sp, lo, hi, d;
+ StackElem[] stack = new StackElem[QSORT_STACK_SIZE];
+ for (int count = 0; count < QSORT_STACK_SIZE; count++) {
+ stack[count] = new StackElem();
+ }
+
+ sp = 0;
+
+ stack[sp].ll = loSt;
+ stack[sp].hh = hiSt;
+ stack[sp].dd = dSt;
+ sp++;
+
+ while (sp > 0) {
+ if (sp >= QSORT_STACK_SIZE) {
+ Panic();
+ }
+
+ sp--;
+ lo = stack[sp].ll;
+ hi = stack[sp].hh;
+ d = stack[sp].dd;
+
+ if (hi - lo < SMALL_THRESH || d > DEPTH_THRESH) {
+ SimpleSort(lo, hi, d);
+ if (workDone > workLimit && firstAttempt) {
+ return;
+ }
+ continue;
+ }
+
+ med = Med3(block[zptr[lo] + d + 1],
+ block[zptr[hi ] + d + 1],
+ block[zptr[(lo + hi) >> 1] + d + 1]);
+
+ unLo = ltLo = lo;
+ unHi = gtHi = hi;
+
+ while (true) {
+ while (true) {
+ if (unLo > unHi) {
+ break;
+ }
+ n = ((int) block[zptr[unLo] + d + 1]) - med;
+ if (n == 0) {
+ int temp = 0;
+ temp = zptr[unLo];
+ zptr[unLo] = zptr[ltLo];
+ zptr[ltLo] = temp;
+ ltLo++;
+ unLo++;
+ continue;
+ };
+ if (n > 0) {
+ break;
+ }
+ unLo++;
+ }
+ while (true) {
+ if (unLo > unHi) {
+ break;
+ }
+ n = ((int) block[zptr[unHi] + d + 1]) - med;
+ if (n == 0) {
+ int temp = 0;
+ temp = zptr[unHi];
+ zptr[unHi] = zptr[gtHi];
+ zptr[gtHi] = temp;
+ gtHi--;
+ unHi--;
+ continue;
+ };
+ if (n < 0) {
+ break;
+ }
+ unHi--;
+ }
+ if (unLo > unHi) {
+ break;
+ }
+ int tempx = zptr[unLo];
+ zptr[unLo] = zptr[unHi];
+ zptr[unHi] = tempx;
+ unLo++;
+ unHi--;
+ }
+
+ if (gtHi < ltLo) {
+ stack[sp].ll = lo;
+ stack[sp].hh = hi;
+ stack[sp].dd = d + 1;
+ sp++;
+ continue;
+ }
+
+ n = ((ltLo - lo) < (unLo - ltLo)) ? (ltLo - lo) : (unLo - ltLo);
+ Vswap(lo, unLo - n, n);
+ m = ((hi - gtHi) < (gtHi - unHi)) ? (hi - gtHi) : (gtHi - unHi);
+ Vswap(unLo, hi - m + 1, m);
+
+ n = lo + unLo - ltLo - 1;
+ m = hi - (gtHi - unHi) + 1;
+
+ stack[sp].ll = lo;
+ stack[sp].hh = n;
+ stack[sp].dd = d;
+ sp++;
+
+ stack[sp].ll = n + 1;
+ stack[sp].hh = m - 1;
+ stack[sp].dd = d + 1;
+ sp++;
+
+ stack[sp].ll = m;
+ stack[sp].hh = hi;
+ stack[sp].dd = d;
+ sp++;
+ }
+ }
+
+ private void MainSort() {
+ int i, j, ss, sb;
+ int[] runningOrder = new int[256];
+ int[] copy = new int[256];
+ bool[] bigDone = new bool[256];
+ int c1, c2;
+ int numQSorted;
+
+ /*
+ In the various block-sized structures, live data runs
+ from 0 to last+NUM_OVERSHOOT_BYTES inclusive. First,
+ set up the overshoot area for block.
+ */
+
+ // if (verbosity >= 4) fprintf ( stderr, " sort initialise ...\n" );
+ for (i = 0; i < BZip2Constants.NUM_OVERSHOOT_BYTES; i++) {
+ block[last + i + 2] = block[(i % (last + 1)) + 1];
+ }
+ for (i = 0; i <= last + BZip2Constants.NUM_OVERSHOOT_BYTES; i++) {
+ quadrant[i] = 0;
+ }
+
+ block[0] = (char) (block[last + 1]);
+
+ if (last < 4000) {
+ /*
+ Use SimpleSort(), since the full sorting mechanism
+ has quite a large constant overhead.
+ */
+ for (i = 0; i <= last; i++) {
+ zptr[i] = i;
+ }
+ firstAttempt = false;
+ workDone = workLimit = 0;
+ SimpleSort(0, last, 0);
+ } else {
+ numQSorted = 0;
+ for (i = 0; i <= 255; i++) {
+ bigDone[i] = false;
+ }
+
+ for (i = 0; i <= 65536; i++) {
+ ftab[i] = 0;
+ }
+
+ c1 = block[0];
+ for (i = 0; i <= last; i++) {
+ c2 = block[i + 1];
+ ftab[(c1 << 8) + c2]++;
+ c1 = c2;
+ }
+
+ for (i = 1; i <= 65536; i++) {
+ ftab[i] += ftab[i - 1];
+ }
+
+ c1 = block[1];
+ for (i = 0; i < last; i++) {
+ c2 = block[i + 2];
+ j = (c1 << 8) + c2;
+ c1 = c2;
+ ftab[j]--;
+ zptr[ftab[j]] = i;
+ }
+
+ j = ((block[last + 1]) << 8) + (block[1]);
+ ftab[j]--;
+ zptr[ftab[j]] = last;
+
+ /*
+ Now ftab contains the first loc of every small bucket.
+ Calculate the running order, from smallest to largest
+ big bucket.
+ */
+
+ for (i = 0; i <= 255; i++) {
+ runningOrder[i] = i;
+ }
+
+ {
+ int vv;
+ int h = 1;
+ do {
+ h = 3 * h + 1;
+ }
+ while (h <= 256);
+ do {
+ h = h / 3;
+ for (i = h; i <= 255; i++) {
+ vv = runningOrder[i];
+ j = i;
+ while ((ftab[((runningOrder[j - h]) + 1) << 8]
+ - ftab[(runningOrder[j - h]) << 8]) >
+ (ftab[((vv) + 1) << 8] - ftab[(vv) << 8])) {
+ runningOrder[j] = runningOrder[j - h];
+ j = j - h;
+ if (j <= (h - 1)) {
+ break;
+ }
+ }
+ runningOrder[j] = vv;
+ }
+ } while (h != 1);
+ }
+
+ /*
+ The main sorting loop.
+ */
+ for (i = 0; i <= 255; i++) {
+
+ /*
+ Process big buckets, starting with the least full.
+ */
+ ss = runningOrder[i];
+
+ /*
+ Complete the big bucket [ss] by quicksorting
+ any unsorted small buckets [ss, j]. Hopefully
+ previous pointer-scanning phases have already
+ completed many of the small buckets [ss, j], so
+ we don't have to sort them at all.
+ */
+ for (j = 0; j <= 255; j++) {
+ sb = (ss << 8) + j;
+ if (!((ftab[sb] & SETMASK) == SETMASK)) {
+ int lo = ftab[sb] & CLEARMASK;
+ int hi = (ftab[sb + 1] & CLEARMASK) - 1;
+ if (hi > lo) {
+ QSort3(lo, hi, 2);
+ numQSorted += (hi - lo + 1);
+ if (workDone > workLimit && firstAttempt) {
+ return;
+ }
+ }
+ ftab[sb] |= SETMASK;
+ }
+ }
+
+ /*
+ The ss big bucket is now done. Record this fact,
+ and update the quadrant descriptors. Remember to
+ update quadrants in the overshoot area too, if
+ necessary. The "if (i < 255)" test merely skips
+ this updating for the last bucket processed, since
+ updating for the last bucket is pointless.
+ */
+ bigDone[ss] = true;
+
+ if (i < 255) {
+ int bbStart = ftab[ss << 8] & CLEARMASK;
+ int bbSize = (ftab[(ss + 1) << 8] & CLEARMASK) - bbStart;
+ int shifts = 0;
+
+ while ((bbSize >> shifts) > 65534) {
+ shifts++;
+ }
+
+ for (j = 0; j < bbSize; j++) {
+ int a2update = zptr[bbStart + j];
+ int qVal = (j >> shifts);
+ quadrant[a2update] = qVal;
+ if (a2update < BZip2Constants.NUM_OVERSHOOT_BYTES) {
+ quadrant[a2update + last + 1] = qVal;
+ }
+ }
+
+ if (!(((bbSize - 1) >> shifts) <= 65535)) {
+ Panic();
+ }
+ }
+
+ /*
+ Now scan this big bucket so as to synthesise the
+ sorted order for small buckets [t, ss] for all t != ss.
+ */
+ for (j = 0; j <= 255; j++) {
+ copy[j] = ftab[(j << 8) + ss] & CLEARMASK;
+ }
+
+ for (j = ftab[ss << 8] & CLEARMASK;
+ j < (ftab[(ss + 1) << 8] & CLEARMASK); j++) {
+ c1 = block[zptr[j]];
+ if (!bigDone[c1]) {
+ zptr[copy[c1]] = zptr[j] == 0 ? last : zptr[j] - 1;
+ copy[c1]++;
+ }
+ }
+
+ for (j = 0; j <= 255; j++) {
+ ftab[(j << 8) + ss] |= SETMASK;
+ }
+ }
+ }
+ }
+
+ private void RandomiseBlock() {
+ int i;
+ int rNToGo = 0;
+ int rTPos = 0;
+ for (i = 0; i < 256; i++) {
+ inUse[i] = false;
+ }
+
+ for (i = 0; i <= last; i++) {
+ if (rNToGo == 0) {
+ rNToGo = (char) BZip2Constants.rNums[rTPos];
+ rTPos++;
+ if (rTPos == 512) {
+ rTPos = 0;
+ }
+ }
+ rNToGo--;
+ block[i + 1] ^= (char)((rNToGo == 1) ? 1 : 0);
+ // handle 16 bit signed numbers
+ block[i + 1] &= (char)0xFF;
+
+ inUse[block[i + 1]] = true;
+ }
+ }
+
+ private void DoReversibleTransformation() {
+ int i;
+
+ workLimit = workFactor * last;
+ workDone = 0;
+ blockRandomised = false;
+ firstAttempt = true;
+
+ MainSort();
+
+ if (workDone > workLimit && firstAttempt) {
+ RandomiseBlock();
+ workLimit = workDone = 0;
+ blockRandomised = true;
+ firstAttempt = false;
+ MainSort();
+ }
+
+ origPtr = -1;
+ for (i = 0; i <= last; i++) {
+ if (zptr[i] == 0) {
+ origPtr = i;
+ break;
+ }
+ };
+
+ if (origPtr == -1) {
+ Panic();
+ }
+ }
+
+ private bool FullGtU(int i1, int i2) {
+ int k;
+ char c1, c2;
+ int s1, s2;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ i1++;
+ i2++;
+
+ k = last + 1;
+
+ do {
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ s1 = quadrant[i1];
+ s2 = quadrant[i2];
+ if (s1 != s2) {
+ return (s1 > s2);
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ s1 = quadrant[i1];
+ s2 = quadrant[i2];
+ if (s1 != s2) {
+ return (s1 > s2);
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ s1 = quadrant[i1];
+ s2 = quadrant[i2];
+ if (s1 != s2) {
+ return (s1 > s2);
+ }
+ i1++;
+ i2++;
+
+ c1 = block[i1 + 1];
+ c2 = block[i2 + 1];
+ if (c1 != c2) {
+ return (c1 > c2);
+ }
+ s1 = quadrant[i1];
+ s2 = quadrant[i2];
+ if (s1 != s2) {
+ return (s1 > s2);
+ }
+ i1++;
+ i2++;
+
+ if (i1 > last) {
+ i1 -= last;
+ i1--;
+ };
+ if (i2 > last) {
+ i2 -= last;
+ i2--;
+ };
+
+ k -= 4;
+ workDone++;
+ } while (k >= 0);
+
+ return false;
+ }
+
+ /*
+ Knuth's increments seem to work better
+ than Incerpi-Sedgewick here. Possibly
+ because the number of elems to sort is
+ usually small, typically <= 20.
+ */
+ private int[] incs = { 1, 4, 13, 40, 121, 364, 1093, 3280,
+ 9841, 29524, 88573, 265720,
+ 797161, 2391484 };
+
+ private void AllocateCompressStructures() {
+ int n = BZip2Constants.baseBlockSize * blockSize100k;
+ block = new char[(n + 1 + BZip2Constants.NUM_OVERSHOOT_BYTES)];
+ quadrant = new int[(n + BZip2Constants.NUM_OVERSHOOT_BYTES)];
+ zptr = new int[n];
+ ftab = new int[65537];
+
+ if (block == null || quadrant == null || zptr == null
+ || ftab == null) {
+ //int totalDraw = (n + 1 + NUM_OVERSHOOT_BYTES) + (n + NUM_OVERSHOOT_BYTES) + n + 65537;
+ //compressOutOfMemory ( totalDraw, n );
+ }
+
+ /*
+ The back end needs a place to store the MTF values
+ whilst it calculates the coding tables. We could
+ put them in the zptr array. However, these values
+ will fit in a short, so we overlay szptr at the
+ start of zptr, in the hope of reducing the number
+ of cache misses induced by the multiple traversals
+ of the MTF values when calculating coding tables.
+ Seems to improve compression speed by about 1%.
+ */
+ // szptr = zptr;
+
+
+ szptr = new short[2 * n];
+ }
+
+ private void GenerateMTFValues() {
+ char[] yy = new char[256];
+ int i, j;
+ char tmp;
+ char tmp2;
+ int zPend;
+ int wr;
+ int EOB;
+
+ MakeMaps();
+ EOB = nInUse + 1;
+
+ for (i = 0; i <= EOB; i++) {
+ mtfFreq[i] = 0;
+ }
+
+ wr = 0;
+ zPend = 0;
+ for (i = 0; i < nInUse; i++) {
+ yy[i] = (char) i;
+ }
+
+
+ for (i = 0; i <= last; i++) {
+ char ll_i;
+
+ ll_i = unseqToSeq[block[zptr[i]]];
+
+ j = 0;
+ tmp = yy[j];
+ while (ll_i != tmp) {
+ j++;
+ tmp2 = tmp;
+ tmp = yy[j];
+ yy[j] = tmp2;
+ };
+ yy[0] = tmp;
+
+ if (j == 0) {
+ zPend++;
+ } else {
+ if (zPend > 0) {
+ zPend--;
+ while (true) {
+ switch (zPend % 2) {
+ case 0:
+ szptr[wr] = (short) BZip2Constants.RUNA;
+ wr++;
+ mtfFreq[BZip2Constants.RUNA]++;
+ break;
+ case 1:
+ szptr[wr] = (short) BZip2Constants.RUNB;
+ wr++;
+ mtfFreq[BZip2Constants.RUNB]++;
+ break;
+ };
+ if (zPend < 2) {
+ break;
+ }
+ zPend = (zPend - 2) / 2;
+ };
+ zPend = 0;
+ }
+ szptr[wr] = (short) (j + 1);
+ wr++;
+ mtfFreq[j + 1]++;
+ }
+ }
+
+ if (zPend > 0) {
+ zPend--;
+ while (true) {
+ switch (zPend % 2) {
+ case 0:
+ szptr[wr] = (short) BZip2Constants.RUNA;
+ wr++;
+ mtfFreq[BZip2Constants.RUNA]++;
+ break;
+ case 1:
+ szptr[wr] = (short) BZip2Constants.RUNB;
+ wr++;
+ mtfFreq[BZip2Constants.RUNB]++;
+ break;
+ }
+ if (zPend < 2) {
+ break;
+ }
+ zPend = (zPend - 2) / 2;
+ }
+ }
+
+ szptr[wr] = (short) EOB;
+ wr++;
+ mtfFreq[EOB]++;
+
+ nMTF = wr;
+ }
+
+ public override int Read(byte[] buffer, int offset, int count) {
+ return 0;
+ }
+
+ public override long Seek(long offset, SeekOrigin origin) {
+ return 0;
+ }
+
+ public override void SetLength(long value) {
+ }
+
+ public override void Write(byte[] buffer, int offset, int count) {
+ for (int k = 0; k < count; ++k) {
+ WriteByte(buffer[k + offset]);
+ }
+ }
+
+ public override bool CanRead {
+ get {
+ return false;
+ }
+ }
+
+ public override bool CanSeek {
+ get {
+ return false;
+ }
+ }
+
+ public override bool CanWrite {
+ get {
+ return true;
+ }
+ }
+
+ public override long Length {
+ get {
+ return 0;
+ }
+ }
+
+ public override long Position {
+ get {
+ return 0;
+ }
+ set {
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/bzip2/src/CRC.cs b/bc-sharp-crypto/bzip2/src/CRC.cs
new file mode 100644
index 0000000000000000000000000000000000000000..278a9f3364988316a6f3856f9a35a295d4d6039e
--- /dev/null
+++ b/bc-sharp-crypto/bzip2/src/CRC.cs
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*
+ * This package is based on the work done by Keiron Liddle), Aftex Software
+ * to whom the Ant project is very grateful for his
+ * great code.
+ */
+
+using System;
+
+namespace Org.BouncyCastle.Apache.Bzip2
+{
+ /**
+ * A simple class the hold and calculate the CRC for sanity checking
+ * of the data.
+ *
+ * @author Keiron Liddle
+ */
+ internal class CRC
+ {
+ public static readonly int[] crc32Table = {
+ unchecked((int)0x00000000), unchecked((int)0x04c11db7), unchecked((int)0x09823b6e), unchecked((int)0x0d4326d9),
+ unchecked((int)0x130476dc), unchecked((int)0x17c56b6b), unchecked((int)0x1a864db2), unchecked((int)0x1e475005),
+ unchecked((int)0x2608edb8), unchecked((int)0x22c9f00f), unchecked((int)0x2f8ad6d6), unchecked((int)0x2b4bcb61),
+ unchecked((int)0x350c9b64), unchecked((int)0x31cd86d3), unchecked((int)0x3c8ea00a), unchecked((int)0x384fbdbd),
+ unchecked((int)0x4c11db70), unchecked((int)0x48d0c6c7), unchecked((int)0x4593e01e), unchecked((int)0x4152fda9),
+ unchecked((int)0x5f15adac), unchecked((int)0x5bd4b01b), unchecked((int)0x569796c2), unchecked((int)0x52568b75),
+ unchecked((int)0x6a1936c8), unchecked((int)0x6ed82b7f), unchecked((int)0x639b0da6), unchecked((int)0x675a1011),
+ unchecked((int)0x791d4014), unchecked((int)0x7ddc5da3), unchecked((int)0x709f7b7a), unchecked((int)0x745e66cd),
+ unchecked((int)0x9823b6e0), unchecked((int)0x9ce2ab57), unchecked((int)0x91a18d8e), unchecked((int)0x95609039),
+ unchecked((int)0x8b27c03c), unchecked((int)0x8fe6dd8b), unchecked((int)0x82a5fb52), unchecked((int)0x8664e6e5),
+ unchecked((int)0xbe2b5b58), unchecked((int)0xbaea46ef), unchecked((int)0xb7a96036), unchecked((int)0xb3687d81),
+ unchecked((int)0xad2f2d84), unchecked((int)0xa9ee3033), unchecked((int)0xa4ad16ea), unchecked((int)0xa06c0b5d),
+ unchecked((int)0xd4326d90), unchecked((int)0xd0f37027), unchecked((int)0xddb056fe), unchecked((int)0xd9714b49),
+ unchecked((int)0xc7361b4c), unchecked((int)0xc3f706fb), unchecked((int)0xceb42022), unchecked((int)0xca753d95),
+ unchecked((int)0xf23a8028), unchecked((int)0xf6fb9d9f), unchecked((int)0xfbb8bb46), unchecked((int)0xff79a6f1),
+ unchecked((int)0xe13ef6f4), unchecked((int)0xe5ffeb43), unchecked((int)0xe8bccd9a), unchecked((int)0xec7dd02d),
+ unchecked((int)0x34867077), unchecked((int)0x30476dc0), unchecked((int)0x3d044b19), unchecked((int)0x39c556ae),
+ unchecked((int)0x278206ab), unchecked((int)0x23431b1c), unchecked((int)0x2e003dc5), unchecked((int)0x2ac12072),
+ unchecked((int)0x128e9dcf), unchecked((int)0x164f8078), unchecked((int)0x1b0ca6a1), unchecked((int)0x1fcdbb16),
+ unchecked((int)0x018aeb13), unchecked((int)0x054bf6a4), unchecked((int)0x0808d07d), unchecked((int)0x0cc9cdca),
+ unchecked((int)0x7897ab07), unchecked((int)0x7c56b6b0), unchecked((int)0x71159069), unchecked((int)0x75d48dde),
+ unchecked((int)0x6b93dddb), unchecked((int)0x6f52c06c), unchecked((int)0x6211e6b5), unchecked((int)0x66d0fb02),
+ unchecked((int)0x5e9f46bf), unchecked((int)0x5a5e5b08), unchecked((int)0x571d7dd1), unchecked((int)0x53dc6066),
+ unchecked((int)0x4d9b3063), unchecked((int)0x495a2dd4), unchecked((int)0x44190b0d), unchecked((int)0x40d816ba),
+ unchecked((int)0xaca5c697), unchecked((int)0xa864db20), unchecked((int)0xa527fdf9), unchecked((int)0xa1e6e04e),
+ unchecked((int)0xbfa1b04b), unchecked((int)0xbb60adfc), unchecked((int)0xb6238b25), unchecked((int)0xb2e29692),
+ unchecked((int)0x8aad2b2f), unchecked((int)0x8e6c3698), unchecked((int)0x832f1041), unchecked((int)0x87ee0df6),
+ unchecked((int)0x99a95df3), unchecked((int)0x9d684044), unchecked((int)0x902b669d), unchecked((int)0x94ea7b2a),
+ unchecked((int)0xe0b41de7), unchecked((int)0xe4750050), unchecked((int)0xe9362689), unchecked((int)0xedf73b3e),
+ unchecked((int)0xf3b06b3b), unchecked((int)0xf771768c), unchecked((int)0xfa325055), unchecked((int)0xfef34de2),
+ unchecked((int)0xc6bcf05f), unchecked((int)0xc27dede8), unchecked((int)0xcf3ecb31), unchecked((int)0xcbffd686),
+ unchecked((int)0xd5b88683), unchecked((int)0xd1799b34), unchecked((int)0xdc3abded), unchecked((int)0xd8fba05a),
+ unchecked((int)0x690ce0ee), unchecked((int)0x6dcdfd59), unchecked((int)0x608edb80), unchecked((int)0x644fc637),
+ unchecked((int)0x7a089632), unchecked((int)0x7ec98b85), unchecked((int)0x738aad5c), unchecked((int)0x774bb0eb),
+ unchecked((int)0x4f040d56), unchecked((int)0x4bc510e1), unchecked((int)0x46863638), unchecked((int)0x42472b8f),
+ unchecked((int)0x5c007b8a), unchecked((int)0x58c1663d), unchecked((int)0x558240e4), unchecked((int)0x51435d53),
+ unchecked((int)0x251d3b9e), unchecked((int)0x21dc2629), unchecked((int)0x2c9f00f0), unchecked((int)0x285e1d47),
+ unchecked((int)0x36194d42), unchecked((int)0x32d850f5), unchecked((int)0x3f9b762c), unchecked((int)0x3b5a6b9b),
+ unchecked((int)0x0315d626), unchecked((int)0x07d4cb91), unchecked((int)0x0a97ed48), unchecked((int)0x0e56f0ff),
+ unchecked((int)0x1011a0fa), unchecked((int)0x14d0bd4d), unchecked((int)0x19939b94), unchecked((int)0x1d528623),
+ unchecked((int)0xf12f560e), unchecked((int)0xf5ee4bb9), unchecked((int)0xf8ad6d60), unchecked((int)0xfc6c70d7),
+ unchecked((int)0xe22b20d2), unchecked((int)0xe6ea3d65), unchecked((int)0xeba91bbc), unchecked((int)0xef68060b),
+ unchecked((int)0xd727bbb6), unchecked((int)0xd3e6a601), unchecked((int)0xdea580d8), unchecked((int)0xda649d6f),
+ unchecked((int)0xc423cd6a), unchecked((int)0xc0e2d0dd), unchecked((int)0xcda1f604), unchecked((int)0xc960ebb3),
+ unchecked((int)0xbd3e8d7e), unchecked((int)0xb9ff90c9), unchecked((int)0xb4bcb610), unchecked((int)0xb07daba7),
+ unchecked((int)0xae3afba2), unchecked((int)0xaafbe615), unchecked((int)0xa7b8c0cc), unchecked((int)0xa379dd7b),
+ unchecked((int)0x9b3660c6), unchecked((int)0x9ff77d71), unchecked((int)0x92b45ba8), unchecked((int)0x9675461f),
+ unchecked((int)0x8832161a), unchecked((int)0x8cf30bad), unchecked((int)0x81b02d74), unchecked((int)0x857130c3),
+ unchecked((int)0x5d8a9099), unchecked((int)0x594b8d2e), unchecked((int)0x5408abf7), unchecked((int)0x50c9b640),
+ unchecked((int)0x4e8ee645), unchecked((int)0x4a4ffbf2), unchecked((int)0x470cdd2b), unchecked((int)0x43cdc09c),
+ unchecked((int)0x7b827d21), unchecked((int)0x7f436096), unchecked((int)0x7200464f), unchecked((int)0x76c15bf8),
+ unchecked((int)0x68860bfd), unchecked((int)0x6c47164a), unchecked((int)0x61043093), unchecked((int)0x65c52d24),
+ unchecked((int)0x119b4be9), unchecked((int)0x155a565e), unchecked((int)0x18197087), unchecked((int)0x1cd86d30),
+ unchecked((int)0x029f3d35), unchecked((int)0x065e2082), unchecked((int)0x0b1d065b), unchecked((int)0x0fdc1bec),
+ unchecked((int)0x3793a651), unchecked((int)0x3352bbe6), unchecked((int)0x3e119d3f), unchecked((int)0x3ad08088),
+ unchecked((int)0x2497d08d), unchecked((int)0x2056cd3a), unchecked((int)0x2d15ebe3), unchecked((int)0x29d4f654),
+ unchecked((int)0xc5a92679), unchecked((int)0xc1683bce), unchecked((int)0xcc2b1d17), unchecked((int)0xc8ea00a0),
+ unchecked((int)0xd6ad50a5), unchecked((int)0xd26c4d12), unchecked((int)0xdf2f6bcb), unchecked((int)0xdbee767c),
+ unchecked((int)0xe3a1cbc1), unchecked((int)0xe760d676), unchecked((int)0xea23f0af), unchecked((int)0xeee2ed18),
+ unchecked((int)0xf0a5bd1d), unchecked((int)0xf464a0aa), unchecked((int)0xf9278673), unchecked((int)0xfde69bc4),
+ unchecked((int)0x89b8fd09), unchecked((int)0x8d79e0be), unchecked((int)0x803ac667), unchecked((int)0x84fbdbd0),
+ unchecked((int)0x9abc8bd5), unchecked((int)0x9e7d9662), unchecked((int)0x933eb0bb), unchecked((int)0x97ffad0c),
+ unchecked((int)0xafb010b1), unchecked((int)0xab710d06), unchecked((int)0xa6322bdf), unchecked((int)0xa2f33668),
+ unchecked((int)0xbcb4666d), unchecked((int)0xb8757bda), unchecked((int)0xb5365d03), unchecked((int)0xb1f740b4)
+ };
+
+ public CRC() {
+ InitialiseCRC();
+ }
+
+ internal void InitialiseCRC() {
+ globalCrc = unchecked((int)0xffffffff);
+ }
+
+ internal int GetFinalCRC() {
+ return ~globalCrc;
+ }
+
+ internal int GetGlobalCRC() {
+ return globalCrc;
+ }
+
+ internal void SetGlobalCRC(int newCrc) {
+ globalCrc = newCrc;
+ }
+
+ internal void UpdateCRC(int inCh) {
+ int temp = (globalCrc >> 24) ^ inCh;
+ if (temp < 0) {
+ temp = 256 + temp;
+ }
+ globalCrc = (globalCrc << 8) ^ CRC.crc32Table[temp];
+ }
+
+ internal int globalCrc;
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/asn1/ASN1Generator.cs b/bc-sharp-crypto/src/asn1/ASN1Generator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e560517363cb5ff4527e9793041a9bb04bf5ff36
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ASN1Generator.cs
@@ -0,0 +1,27 @@
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public abstract class Asn1Generator
+ {
+ private Stream _out;
+
+ protected Asn1Generator(
+ Stream outStream)
+ {
+ _out = outStream;
+ }
+
+ protected Stream Out
+ {
+ get { return _out; }
+ }
+
+ public abstract void AddObject(Asn1Encodable obj);
+
+ public abstract Stream GetRawOutputStream();
+
+ public abstract void Close();
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ASN1OctetStringParser.cs b/bc-sharp-crypto/src/asn1/ASN1OctetStringParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5815aa42f05798011251408353a1fe36df2eaeae
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ASN1OctetStringParser.cs
@@ -0,0 +1,10 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public interface Asn1OctetStringParser
+ : IAsn1Convertible
+ {
+ Stream GetOctetStream();
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ASN1SequenceParser.cs b/bc-sharp-crypto/src/asn1/ASN1SequenceParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9e88ac78838c87ab441746f7b178ed8f944e3106
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ASN1SequenceParser.cs
@@ -0,0 +1,8 @@
+namespace Org.BouncyCastle.Asn1
+{
+ public interface Asn1SequenceParser
+ : IAsn1Convertible
+ {
+ IAsn1Convertible ReadObject();
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ASN1SetParser.cs b/bc-sharp-crypto/src/asn1/ASN1SetParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d1b9c64e216a84e54d72ac218cd226de25b10b78
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ASN1SetParser.cs
@@ -0,0 +1,8 @@
+namespace Org.BouncyCastle.Asn1
+{
+ public interface Asn1SetParser
+ : IAsn1Convertible
+ {
+ IAsn1Convertible ReadObject();
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ASN1StreamParser.cs b/bc-sharp-crypto/src/asn1/ASN1StreamParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0c6b4413a40c90de8f1fc31c6cd2badf57e57c24
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ASN1StreamParser.cs
@@ -0,0 +1,234 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class Asn1StreamParser
+ {
+ private readonly Stream _in;
+ private readonly int _limit;
+
+ private readonly byte[][] tmpBuffers;
+
+ public Asn1StreamParser(
+ Stream inStream)
+ : this(inStream, Asn1InputStream.FindLimit(inStream))
+ {
+ }
+
+ public Asn1StreamParser(
+ Stream inStream,
+ int limit)
+ {
+ if (!inStream.CanRead)
+ throw new ArgumentException("Expected stream to be readable", "inStream");
+
+ this._in = inStream;
+ this._limit = limit;
+ this.tmpBuffers = new byte[16][];
+ }
+
+ public Asn1StreamParser(
+ byte[] encoding)
+ : this(new MemoryStream(encoding, false), encoding.Length)
+ {
+ }
+
+ internal IAsn1Convertible ReadIndef(int tagValue)
+ {
+ // Note: INDEF => CONSTRUCTED
+
+ // TODO There are other tags that may be constructed (e.g. BIT_STRING)
+ switch (tagValue)
+ {
+ case Asn1Tags.External:
+ return new DerExternalParser(this);
+ case Asn1Tags.OctetString:
+ return new BerOctetStringParser(this);
+ case Asn1Tags.Sequence:
+ return new BerSequenceParser(this);
+ case Asn1Tags.Set:
+ return new BerSetParser(this);
+ default:
+ throw new Asn1Exception("unknown BER object encountered: 0x" + tagValue.ToString("X"));
+ }
+ }
+
+ internal IAsn1Convertible ReadImplicit(bool constructed, int tag)
+ {
+ if (_in is IndefiniteLengthInputStream)
+ {
+ if (!constructed)
+ throw new IOException("indefinite length primitive encoding encountered");
+
+ return ReadIndef(tag);
+ }
+
+ if (constructed)
+ {
+ switch (tag)
+ {
+ case Asn1Tags.Set:
+ return new DerSetParser(this);
+ case Asn1Tags.Sequence:
+ return new DerSequenceParser(this);
+ case Asn1Tags.OctetString:
+ return new BerOctetStringParser(this);
+ }
+ }
+ else
+ {
+ switch (tag)
+ {
+ case Asn1Tags.Set:
+ throw new Asn1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)");
+ case Asn1Tags.Sequence:
+ throw new Asn1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)");
+ case Asn1Tags.OctetString:
+ return new DerOctetStringParser((DefiniteLengthInputStream)_in);
+ }
+ }
+
+ throw new Asn1Exception("implicit tagging not implemented");
+ }
+
+ internal Asn1Object ReadTaggedObject(bool constructed, int tag)
+ {
+ if (!constructed)
+ {
+ // Note: !CONSTRUCTED => IMPLICIT
+ DefiniteLengthInputStream defIn = (DefiniteLengthInputStream)_in;
+ return new DerTaggedObject(false, tag, new DerOctetString(defIn.ToArray()));
+ }
+
+ Asn1EncodableVector v = ReadVector();
+
+ if (_in is IndefiniteLengthInputStream)
+ {
+ return v.Count == 1
+ ? new BerTaggedObject(true, tag, v[0])
+ : new BerTaggedObject(false, tag, BerSequence.FromVector(v));
+ }
+
+ return v.Count == 1
+ ? new DerTaggedObject(true, tag, v[0])
+ : new DerTaggedObject(false, tag, DerSequence.FromVector(v));
+ }
+
+ public virtual IAsn1Convertible ReadObject()
+ {
+ int tag = _in.ReadByte();
+ if (tag == -1)
+ return null;
+
+ // turn of looking for "00" while we resolve the tag
+ Set00Check(false);
+
+ //
+ // calculate tag number
+ //
+ int tagNo = Asn1InputStream.ReadTagNumber(_in, tag);
+
+ bool isConstructed = (tag & Asn1Tags.Constructed) != 0;
+
+ //
+ // calculate length
+ //
+ int length = Asn1InputStream.ReadLength(_in, _limit);
+
+ if (length < 0) // indefinite length method
+ {
+ if (!isConstructed)
+ throw new IOException("indefinite length primitive encoding encountered");
+
+ IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit);
+ Asn1StreamParser sp = new Asn1StreamParser(indIn, _limit);
+
+ if ((tag & Asn1Tags.Application) != 0)
+ {
+ return new BerApplicationSpecificParser(tagNo, sp);
+ }
+
+ if ((tag & Asn1Tags.Tagged) != 0)
+ {
+ return new BerTaggedObjectParser(true, tagNo, sp);
+ }
+
+ return sp.ReadIndef(tagNo);
+ }
+ else
+ {
+ DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length);
+
+ if ((tag & Asn1Tags.Application) != 0)
+ {
+ return new DerApplicationSpecific(isConstructed, tagNo, defIn.ToArray());
+ }
+
+ if ((tag & Asn1Tags.Tagged) != 0)
+ {
+ return new BerTaggedObjectParser(isConstructed, tagNo, new Asn1StreamParser(defIn));
+ }
+
+ if (isConstructed)
+ {
+ // TODO There are other tags that may be constructed (e.g. BitString)
+ switch (tagNo)
+ {
+ case Asn1Tags.OctetString:
+ //
+ // yes, people actually do this...
+ //
+ return new BerOctetStringParser(new Asn1StreamParser(defIn));
+ case Asn1Tags.Sequence:
+ return new DerSequenceParser(new Asn1StreamParser(defIn));
+ case Asn1Tags.Set:
+ return new DerSetParser(new Asn1StreamParser(defIn));
+ case Asn1Tags.External:
+ return new DerExternalParser(new Asn1StreamParser(defIn));
+ default:
+ throw new IOException("unknown tag " + tagNo + " encountered");
+ }
+ }
+
+ // Some primitive encodings can be handled by parsers too...
+ switch (tagNo)
+ {
+ case Asn1Tags.OctetString:
+ return new DerOctetStringParser(defIn);
+ }
+
+ try
+ {
+ return Asn1InputStream.CreatePrimitiveDerObject(tagNo, defIn, tmpBuffers);
+ }
+ catch (ArgumentException e)
+ {
+ throw new Asn1Exception("corrupted stream detected", e);
+ }
+ }
+ }
+
+ private void Set00Check(
+ bool enabled)
+ {
+ if (_in is IndefiniteLengthInputStream)
+ {
+ ((IndefiniteLengthInputStream) _in).SetEofOn00(enabled);
+ }
+ }
+
+ internal Asn1EncodableVector ReadVector()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ IAsn1Convertible obj;
+ while ((obj = ReadObject()) != null)
+ {
+ v.Add(obj.ToAsn1Object());
+ }
+
+ return v;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ASN1TaggedObjectParser.cs b/bc-sharp-crypto/src/asn1/ASN1TaggedObjectParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..32327a269797dfcc19ac1ff28fc783651fccfa0d
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ASN1TaggedObjectParser.cs
@@ -0,0 +1,10 @@
+namespace Org.BouncyCastle.Asn1
+{
+ public interface Asn1TaggedObjectParser
+ : IAsn1Convertible
+ {
+ int TagNo { get; }
+
+ IAsn1Convertible GetObjectParser(int tag, bool isExplicit);
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/Asn1Encodable.cs b/bc-sharp-crypto/src/asn1/Asn1Encodable.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e3dd9a14cf2fee0a271a98689877a9a96a884376
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/Asn1Encodable.cs
@@ -0,0 +1,78 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public abstract class Asn1Encodable
+ : IAsn1Convertible
+ {
+ public const string Der = "DER";
+ public const string Ber = "BER";
+
+ public byte[] GetEncoded()
+ {
+ MemoryStream bOut = new MemoryStream();
+ Asn1OutputStream aOut = new Asn1OutputStream(bOut);
+
+ aOut.WriteObject(this);
+
+ return bOut.ToArray();
+ }
+
+ public byte[] GetEncoded(
+ string encoding)
+ {
+ if (encoding.Equals(Der))
+ {
+ MemoryStream bOut = new MemoryStream();
+ DerOutputStream dOut = new DerOutputStream(bOut);
+
+ dOut.WriteObject(this);
+
+ return bOut.ToArray();
+ }
+
+ return GetEncoded();
+ }
+
+ /**
+ * Return the DER encoding of the object, null if the DER encoding can not be made.
+ *
+ * @return a DER byte array, null otherwise.
+ */
+ public byte[] GetDerEncoded()
+ {
+ try
+ {
+ return GetEncoded(Der);
+ }
+ catch (IOException)
+ {
+ return null;
+ }
+ }
+
+ public sealed override int GetHashCode()
+ {
+ return ToAsn1Object().CallAsn1GetHashCode();
+ }
+
+ public sealed override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ IAsn1Convertible other = obj as IAsn1Convertible;
+
+ if (other == null)
+ return false;
+
+ Asn1Object o1 = ToAsn1Object();
+ Asn1Object o2 = other.ToAsn1Object();
+
+ return o1 == o2 || o1.CallAsn1Equals(o2);
+ }
+
+ public abstract Asn1Object ToAsn1Object();
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/Asn1EncodableVector.cs b/bc-sharp-crypto/src/asn1/Asn1EncodableVector.cs
new file mode 100644
index 0000000000000000000000000000000000000000..49532fe571e1f33496f700389e21ed8409a2f34b
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/Asn1EncodableVector.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class Asn1EncodableVector
+ : IEnumerable
+ {
+ private IList v = Platform.CreateArrayList();
+
+ public static Asn1EncodableVector FromEnumerable(
+ IEnumerable e)
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+ foreach (Asn1Encodable obj in e)
+ {
+ v.Add(obj);
+ }
+ return v;
+ }
+
+// public Asn1EncodableVector()
+// {
+// }
+
+ public Asn1EncodableVector(
+ params Asn1Encodable[] v)
+ {
+ Add(v);
+ }
+
+// public void Add(
+// Asn1Encodable obj)
+// {
+// v.Add(obj);
+// }
+
+ public void Add(
+ params Asn1Encodable[] objs)
+ {
+ foreach (Asn1Encodable obj in objs)
+ {
+ v.Add(obj);
+ }
+ }
+
+ public void AddOptional(
+ params Asn1Encodable[] objs)
+ {
+ if (objs != null)
+ {
+ foreach (Asn1Encodable obj in objs)
+ {
+ if (obj != null)
+ {
+ v.Add(obj);
+ }
+ }
+ }
+ }
+
+ public Asn1Encodable this[
+ int index]
+ {
+ get { return (Asn1Encodable) v[index]; }
+ }
+
+ [Obsolete("Use 'object[index]' syntax instead")]
+ public Asn1Encodable Get(
+ int index)
+ {
+ return this[index];
+ }
+
+ [Obsolete("Use 'Count' property instead")]
+ public int Size
+ {
+ get { return v.Count; }
+ }
+
+ public int Count
+ {
+ get { return v.Count; }
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return v.GetEnumerator();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/Asn1Exception.cs b/bc-sharp-crypto/src/asn1/Asn1Exception.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1dfe1732cd4a290f166e1e72455e3945064cd778
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/Asn1Exception.cs
@@ -0,0 +1,30 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class Asn1Exception
+ : IOException
+ {
+ public Asn1Exception()
+ : base()
+ {
+ }
+
+ public Asn1Exception(
+ string message)
+ : base(message)
+ {
+ }
+
+ public Asn1Exception(
+ string message,
+ Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/Asn1InputStream.cs b/bc-sharp-crypto/src/asn1/Asn1InputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a94ae52353584c88374f246c49c173e1f1c69a33
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/Asn1InputStream.cs
@@ -0,0 +1,371 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * a general purpose ASN.1 decoder - note: this class differs from the
+ * others in that it returns null after it has read the last object in
+ * the stream. If an ASN.1 Null is encountered a Der/BER Null object is
+ * returned.
+ */
+ public class Asn1InputStream
+ : FilterStream
+ {
+ private readonly int limit;
+
+ private readonly byte[][] tmpBuffers;
+
+ internal static int FindLimit(Stream input)
+ {
+ if (input is LimitedInputStream)
+ {
+ return ((LimitedInputStream)input).GetRemaining();
+ }
+ else if (input is MemoryStream)
+ {
+ MemoryStream mem = (MemoryStream)input;
+ return (int)(mem.Length - mem.Position);
+ }
+
+ return int.MaxValue;
+ }
+
+ public Asn1InputStream(
+ Stream inputStream)
+ : this(inputStream, FindLimit(inputStream))
+ {
+ }
+
+ /**
+ * Create an ASN1InputStream where no DER object will be longer than limit.
+ *
+ * @param input stream containing ASN.1 encoded data.
+ * @param limit maximum size of a DER encoded object.
+ */
+ public Asn1InputStream(
+ Stream inputStream,
+ int limit)
+ : base(inputStream)
+ {
+ this.limit = limit;
+ this.tmpBuffers = new byte[16][];
+ }
+
+ /**
+ * Create an ASN1InputStream based on the input byte array. The length of DER objects in
+ * the stream is automatically limited to the length of the input array.
+ *
+ * @param input array containing ASN.1 encoded data.
+ */
+ public Asn1InputStream(
+ byte[] input)
+ : this(new MemoryStream(input, false), input.Length)
+ {
+ }
+
+ /**
+ * build an object given its tag and the number of bytes to construct it from.
+ */
+ private Asn1Object BuildObject(
+ int tag,
+ int tagNo,
+ int length)
+ {
+ bool isConstructed = (tag & Asn1Tags.Constructed) != 0;
+
+ DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this.s, length);
+
+ if ((tag & Asn1Tags.Application) != 0)
+ {
+ return new DerApplicationSpecific(isConstructed, tagNo, defIn.ToArray());
+ }
+
+ if ((tag & Asn1Tags.Tagged) != 0)
+ {
+ return new Asn1StreamParser(defIn).ReadTaggedObject(isConstructed, tagNo);
+ }
+
+ if (isConstructed)
+ {
+ // TODO There are other tags that may be constructed (e.g. BitString)
+ switch (tagNo)
+ {
+ case Asn1Tags.OctetString:
+ //
+ // yes, people actually do this...
+ //
+ return new BerOctetString(BuildDerEncodableVector(defIn));
+ case Asn1Tags.Sequence:
+ return CreateDerSequence(defIn);
+ case Asn1Tags.Set:
+ return CreateDerSet(defIn);
+ case Asn1Tags.External:
+ return new DerExternal(BuildDerEncodableVector(defIn));
+ default:
+ throw new IOException("unknown tag " + tagNo + " encountered");
+ }
+ }
+
+ return CreatePrimitiveDerObject(tagNo, defIn, tmpBuffers);
+ }
+
+ internal Asn1EncodableVector BuildEncodableVector()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ Asn1Object o;
+ while ((o = ReadObject()) != null)
+ {
+ v.Add(o);
+ }
+
+ return v;
+ }
+
+ internal virtual Asn1EncodableVector BuildDerEncodableVector(
+ DefiniteLengthInputStream dIn)
+ {
+ return new Asn1InputStream(dIn).BuildEncodableVector();
+ }
+
+ internal virtual DerSequence CreateDerSequence(
+ DefiniteLengthInputStream dIn)
+ {
+ return DerSequence.FromVector(BuildDerEncodableVector(dIn));
+ }
+
+ internal virtual DerSet CreateDerSet(
+ DefiniteLengthInputStream dIn)
+ {
+ return DerSet.FromVector(BuildDerEncodableVector(dIn), false);
+ }
+
+ public Asn1Object ReadObject()
+ {
+ int tag = ReadByte();
+ if (tag <= 0)
+ {
+ if (tag == 0)
+ throw new IOException("unexpected end-of-contents marker");
+
+ return null;
+ }
+
+ //
+ // calculate tag number
+ //
+ int tagNo = ReadTagNumber(this.s, tag);
+
+ bool isConstructed = (tag & Asn1Tags.Constructed) != 0;
+
+ //
+ // calculate length
+ //
+ int length = ReadLength(this.s, limit);
+
+ if (length < 0) // indefinite length method
+ {
+ if (!isConstructed)
+ throw new IOException("indefinite length primitive encoding encountered");
+
+ IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this.s, limit);
+ Asn1StreamParser sp = new Asn1StreamParser(indIn, limit);
+
+ if ((tag & Asn1Tags.Application) != 0)
+ {
+ return new BerApplicationSpecificParser(tagNo, sp).ToAsn1Object();
+ }
+
+ if ((tag & Asn1Tags.Tagged) != 0)
+ {
+ return new BerTaggedObjectParser(true, tagNo, sp).ToAsn1Object();
+ }
+
+ // TODO There are other tags that may be constructed (e.g. BitString)
+ switch (tagNo)
+ {
+ case Asn1Tags.OctetString:
+ return new BerOctetStringParser(sp).ToAsn1Object();
+ case Asn1Tags.Sequence:
+ return new BerSequenceParser(sp).ToAsn1Object();
+ case Asn1Tags.Set:
+ return new BerSetParser(sp).ToAsn1Object();
+ case Asn1Tags.External:
+ return new DerExternalParser(sp).ToAsn1Object();
+ default:
+ throw new IOException("unknown BER object encountered");
+ }
+ }
+ else
+ {
+ try
+ {
+ return BuildObject(tag, tagNo, length);
+ }
+ catch (ArgumentException e)
+ {
+ throw new Asn1Exception("corrupted stream detected", e);
+ }
+ }
+ }
+
+ internal static int ReadTagNumber(
+ Stream s,
+ int tag)
+ {
+ int tagNo = tag & 0x1f;
+
+ //
+ // with tagged object tag number is bottom 5 bits, or stored at the start of the content
+ //
+ if (tagNo == 0x1f)
+ {
+ tagNo = 0;
+
+ int b = s.ReadByte();
+
+ // X.690-0207 8.1.2.4.2
+ // "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
+ if ((b & 0x7f) == 0) // Note: -1 will pass
+ {
+ throw new IOException("Corrupted stream - invalid high tag number found");
+ }
+
+ while ((b >= 0) && ((b & 0x80) != 0))
+ {
+ tagNo |= (b & 0x7f);
+ tagNo <<= 7;
+ b = s.ReadByte();
+ }
+
+ if (b < 0)
+ throw new EndOfStreamException("EOF found inside tag value.");
+
+ tagNo |= (b & 0x7f);
+ }
+
+ return tagNo;
+ }
+
+ internal static int ReadLength(
+ Stream s,
+ int limit)
+ {
+ int length = s.ReadByte();
+ if (length < 0)
+ throw new EndOfStreamException("EOF found when length expected");
+
+ if (length == 0x80)
+ return -1; // indefinite-length encoding
+
+ if (length > 127)
+ {
+ int size = length & 0x7f;
+
+ // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
+ if (size > 4)
+ throw new IOException("DER length more than 4 bytes: " + size);
+
+ length = 0;
+ for (int i = 0; i < size; i++)
+ {
+ int next = s.ReadByte();
+
+ if (next < 0)
+ throw new EndOfStreamException("EOF found reading length");
+
+ length = (length << 8) + next;
+ }
+
+ if (length < 0)
+ throw new IOException("Corrupted stream - negative length found");
+
+ if (length >= limit) // after all we must have read at least 1 byte
+ throw new IOException("Corrupted stream - out of bounds length found");
+ }
+
+ return length;
+ }
+
+ internal static byte[] GetBuffer(DefiniteLengthInputStream defIn, byte[][] tmpBuffers)
+ {
+ int len = defIn.GetRemaining();
+ if (len >= tmpBuffers.Length)
+ {
+ return defIn.ToArray();
+ }
+
+ byte[] buf = tmpBuffers[len];
+ if (buf == null)
+ {
+ buf = tmpBuffers[len] = new byte[len];
+ }
+
+ defIn.ReadAllIntoByteArray(buf);
+
+ return buf;
+ }
+
+ internal static Asn1Object CreatePrimitiveDerObject(
+ int tagNo,
+ DefiniteLengthInputStream defIn,
+ byte[][] tmpBuffers)
+ {
+ switch (tagNo)
+ {
+ case Asn1Tags.Boolean:
+ return DerBoolean.FromOctetString(GetBuffer(defIn, tmpBuffers));
+ case Asn1Tags.Enumerated:
+ return DerEnumerated.FromOctetString(GetBuffer(defIn, tmpBuffers));
+ case Asn1Tags.ObjectIdentifier:
+ return DerObjectIdentifier.FromOctetString(GetBuffer(defIn, tmpBuffers));
+ }
+
+ byte[] bytes = defIn.ToArray();
+
+ switch (tagNo)
+ {
+ case Asn1Tags.BitString:
+ return DerBitString.FromAsn1Octets(bytes);
+ case Asn1Tags.BmpString:
+ return new DerBmpString(bytes);
+ case Asn1Tags.GeneralizedTime:
+ return new DerGeneralizedTime(bytes);
+ case Asn1Tags.GeneralString:
+ return new DerGeneralString(bytes);
+ case Asn1Tags.GraphicString:
+ return new DerGraphicString(bytes);
+ case Asn1Tags.IA5String:
+ return new DerIA5String(bytes);
+ case Asn1Tags.Integer:
+ return new DerInteger(bytes);
+ case Asn1Tags.Null:
+ return DerNull.Instance; // actual content is ignored (enforce 0 length?)
+ case Asn1Tags.NumericString:
+ return new DerNumericString(bytes);
+ case Asn1Tags.OctetString:
+ return new DerOctetString(bytes);
+ case Asn1Tags.PrintableString:
+ return new DerPrintableString(bytes);
+ case Asn1Tags.T61String:
+ return new DerT61String(bytes);
+ case Asn1Tags.UniversalString:
+ return new DerUniversalString(bytes);
+ case Asn1Tags.UtcTime:
+ return new DerUtcTime(bytes);
+ case Asn1Tags.Utf8String:
+ return new DerUtf8String(bytes);
+ case Asn1Tags.VideotexString:
+ return new DerVideotexString(bytes);
+ case Asn1Tags.VisibleString:
+ return new DerVisibleString(bytes);
+ default:
+ throw new IOException("unknown tag " + tagNo + " encountered");
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/Asn1Null.cs b/bc-sharp-crypto/src/asn1/Asn1Null.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d54019f67a491d9e38b8e2daeb09e888dee04b10
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/Asn1Null.cs
@@ -0,0 +1,18 @@
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * A Null object.
+ */
+ public abstract class Asn1Null
+ : Asn1Object
+ {
+ internal Asn1Null()
+ {
+ }
+
+ public override string ToString()
+ {
+ return "NULL";
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/Asn1Object.cs b/bc-sharp-crypto/src/asn1/Asn1Object.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4faa81ac803ac27b6ed3503df974a90ab7b09ebc
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/Asn1Object.cs
@@ -0,0 +1,70 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public abstract class Asn1Object
+ : Asn1Encodable
+ {
+ /// Create a base ASN.1 object from a byte array.
+ /// The byte array to parse.
+ /// The base ASN.1 object represented by the byte array.
+ ///
+ /// If there is a problem parsing the data, or parsing an object did not exhaust the available data.
+ ///
+ public static Asn1Object FromByteArray(
+ byte[] data)
+ {
+ try
+ {
+ MemoryStream input = new MemoryStream(data, false);
+ Asn1InputStream asn1 = new Asn1InputStream(input, data.Length);
+ Asn1Object result = asn1.ReadObject();
+ if (input.Position != input.Length)
+ throw new IOException("extra data found after object");
+ return result;
+ }
+ catch (InvalidCastException)
+ {
+ throw new IOException("cannot recognise object in byte array");
+ }
+ }
+
+ /// Read a base ASN.1 object from a stream.
+ /// The stream to parse.
+ /// The base ASN.1 object represented by the byte array.
+ /// If there is a problem parsing the data.
+ public static Asn1Object FromStream(
+ Stream inStr)
+ {
+ try
+ {
+ return new Asn1InputStream(inStr).ReadObject();
+ }
+ catch (InvalidCastException)
+ {
+ throw new IOException("cannot recognise object in stream");
+ }
+ }
+
+ public sealed override Asn1Object ToAsn1Object()
+ {
+ return this;
+ }
+
+ internal abstract void Encode(DerOutputStream derOut);
+
+ protected abstract bool Asn1Equals(Asn1Object asn1Object);
+ protected abstract int Asn1GetHashCode();
+
+ internal bool CallAsn1Equals(Asn1Object obj)
+ {
+ return Asn1Equals(obj);
+ }
+
+ internal int CallAsn1GetHashCode()
+ {
+ return Asn1GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/Asn1OctetString.cs b/bc-sharp-crypto/src/asn1/Asn1OctetString.cs
new file mode 100644
index 0000000000000000000000000000000000000000..73b6e51bf11ea41658253785f52e376b43c4be9d
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/Asn1OctetString.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public abstract class Asn1OctetString
+ : Asn1Object, Asn1OctetStringParser
+ {
+ internal byte[] str;
+
+ /**
+ * return an Octet string from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static Asn1OctetString GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ Asn1Object o = obj.GetObject();
+
+ if (isExplicit || o is Asn1OctetString)
+ {
+ return GetInstance(o);
+ }
+
+ return BerOctetString.FromSequence(Asn1Sequence.GetInstance(o));
+ }
+
+ /**
+ * return an Octet string from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static Asn1OctetString GetInstance(object obj)
+ {
+ if (obj == null || obj is Asn1OctetString)
+ {
+ return (Asn1OctetString)obj;
+ }
+
+ // TODO: this needs to be deleted in V2
+ if (obj is Asn1TaggedObject)
+ return GetInstance(((Asn1TaggedObject)obj).GetObject());
+
+ throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
+ }
+
+ /**
+ * @param string the octets making up the octet string.
+ */
+ internal Asn1OctetString(
+ byte[] str)
+ {
+ if (str == null)
+ throw new ArgumentNullException("str");
+
+ this.str = str;
+ }
+
+ internal Asn1OctetString(
+ Asn1Encodable obj)
+ {
+ try
+ {
+ this.str = obj.GetEncoded(Asn1Encodable.Der);
+ }
+ catch (IOException e)
+ {
+ throw new ArgumentException("Error processing object : " + e.ToString());
+ }
+ }
+
+ public Stream GetOctetStream()
+ {
+ return new MemoryStream(str, false);
+ }
+
+ public Asn1OctetStringParser Parser
+ {
+ get { return this; }
+ }
+
+ public virtual byte[] GetOctets()
+ {
+ return str;
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ return Arrays.GetHashCode(GetOctets());
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerOctetString other = asn1Object as DerOctetString;
+
+ if (other == null)
+ return false;
+
+ return Arrays.AreEqual(GetOctets(), other.GetOctets());
+ }
+
+ public override string ToString()
+ {
+ return "#" + Hex.ToHexString(str);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/Asn1OutputStream.cs b/bc-sharp-crypto/src/asn1/Asn1OutputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..39c8b1e5ebe153a628ab1f5eded62cab2dc043e0
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/Asn1OutputStream.cs
@@ -0,0 +1,35 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class Asn1OutputStream
+ : DerOutputStream
+ {
+ public Asn1OutputStream(Stream os) : base(os)
+ {
+ }
+
+ [Obsolete("Use version taking an Asn1Encodable arg instead")]
+ public override void WriteObject(
+ object obj)
+ {
+ if (obj == null)
+ {
+ WriteNull();
+ }
+ else if (obj is Asn1Object)
+ {
+ ((Asn1Object)obj).Encode(this);
+ }
+ else if (obj is Asn1Encodable)
+ {
+ ((Asn1Encodable)obj).ToAsn1Object().Encode(this);
+ }
+ else
+ {
+ throw new IOException("object not Asn1Encodable");
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/Asn1ParsingException.cs b/bc-sharp-crypto/src/asn1/Asn1ParsingException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..84cdb780d11b732d5703e6183c278a16a8ed3add
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/Asn1ParsingException.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class Asn1ParsingException
+ : InvalidOperationException
+ {
+ public Asn1ParsingException()
+ : base()
+ {
+ }
+
+ public Asn1ParsingException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public Asn1ParsingException(
+ string message,
+ Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/Asn1Sequence.cs b/bc-sharp-crypto/src/asn1/Asn1Sequence.cs
new file mode 100644
index 0000000000000000000000000000000000000000..849f5e3081c6dc05372c9a3ca7e53aa5d0937e71
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/Asn1Sequence.cs
@@ -0,0 +1,268 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public abstract class Asn1Sequence
+ : Asn1Object, IEnumerable
+ {
+ private readonly IList seq;
+
+ /**
+ * return an Asn1Sequence from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static Asn1Sequence GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is Asn1Sequence)
+ {
+ return (Asn1Sequence)obj;
+ }
+ else if (obj is Asn1SequenceParser)
+ {
+ return Asn1Sequence.GetInstance(((Asn1SequenceParser)obj).ToAsn1Object());
+ }
+ else if (obj is byte[])
+ {
+ try
+ {
+ return Asn1Sequence.GetInstance(FromByteArray((byte[])obj));
+ }
+ catch (IOException e)
+ {
+ throw new ArgumentException("failed to construct sequence from byte[]: " + e.Message);
+ }
+ }
+ else if (obj is Asn1Encodable)
+ {
+ Asn1Object primitive = ((Asn1Encodable)obj).ToAsn1Object();
+
+ if (primitive is Asn1Sequence)
+ {
+ return (Asn1Sequence)primitive;
+ }
+ }
+
+ throw new ArgumentException("Unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * Return an ASN1 sequence from a tagged object. There is a special
+ * case here, if an object appears to have been explicitly tagged on
+ * reading but we were expecting it to be implicitly tagged in the
+ * normal course of events it indicates that we lost the surrounding
+ * sequence - so we need to add it back (this will happen if the tagged
+ * object is a sequence that contains other sequences). If you are
+ * dealing with implicitly tagged sequences you really should
+ * be using this method.
+ *
+ * @param obj the tagged object.
+ * @param explicitly true if the object is meant to be explicitly tagged,
+ * false otherwise.
+ * @exception ArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static Asn1Sequence GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ Asn1Object inner = obj.GetObject();
+
+ if (explicitly)
+ {
+ if (!obj.IsExplicit())
+ throw new ArgumentException("object implicit - explicit expected.");
+
+ return (Asn1Sequence) inner;
+ }
+
+ //
+ // constructed object which appears to be explicitly tagged
+ // when it should be implicit means we have to add the
+ // surrounding sequence.
+ //
+ if (obj.IsExplicit())
+ {
+ if (obj is BerTaggedObject)
+ {
+ return new BerSequence(inner);
+ }
+
+ return new DerSequence(inner);
+ }
+
+ if (inner is Asn1Sequence)
+ {
+ return (Asn1Sequence) inner;
+ }
+
+ throw new ArgumentException("Unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ protected internal Asn1Sequence(
+ int capacity)
+ {
+ seq = Platform.CreateArrayList(capacity);
+ }
+
+ public virtual IEnumerator GetEnumerator()
+ {
+ return seq.GetEnumerator();
+ }
+
+ [Obsolete("Use GetEnumerator() instead")]
+ public IEnumerator GetObjects()
+ {
+ return GetEnumerator();
+ }
+
+ private class Asn1SequenceParserImpl
+ : Asn1SequenceParser
+ {
+ private readonly Asn1Sequence outer;
+ private readonly int max;
+ private int index;
+
+ public Asn1SequenceParserImpl(
+ Asn1Sequence outer)
+ {
+ this.outer = outer;
+ this.max = outer.Count;
+ }
+
+ public IAsn1Convertible ReadObject()
+ {
+ if (index == max)
+ return null;
+
+ Asn1Encodable obj = outer[index++];
+
+ if (obj is Asn1Sequence)
+ return ((Asn1Sequence)obj).Parser;
+
+ if (obj is Asn1Set)
+ return ((Asn1Set)obj).Parser;
+
+ // NB: Asn1OctetString implements Asn1OctetStringParser directly
+// if (obj is Asn1OctetString)
+// return ((Asn1OctetString)obj).Parser;
+
+ return obj;
+ }
+
+ public Asn1Object ToAsn1Object()
+ {
+ return outer;
+ }
+ }
+
+ public virtual Asn1SequenceParser Parser
+ {
+ get { return new Asn1SequenceParserImpl(this); }
+ }
+
+ /**
+ * return the object at the sequence position indicated by index.
+ *
+ * @param index the sequence number (starting at zero) of the object
+ * @return the object at the sequence position indicated by index.
+ */
+ public virtual Asn1Encodable this[int index]
+ {
+ get { return (Asn1Encodable) seq[index]; }
+ }
+
+ [Obsolete("Use 'object[index]' syntax instead")]
+ public Asn1Encodable GetObjectAt(
+ int index)
+ {
+ return this[index];
+ }
+
+ [Obsolete("Use 'Count' property instead")]
+ public int Size
+ {
+ get { return Count; }
+ }
+
+ public virtual int Count
+ {
+ get { return seq.Count; }
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ int hc = Count;
+
+ foreach (object o in this)
+ {
+ hc *= 17;
+ if (o == null)
+ {
+ hc ^= DerNull.Instance.GetHashCode();
+ }
+ else
+ {
+ hc ^= o.GetHashCode();
+ }
+ }
+
+ return hc;
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ Asn1Sequence other = asn1Object as Asn1Sequence;
+
+ if (other == null)
+ return false;
+
+ if (Count != other.Count)
+ return false;
+
+ IEnumerator s1 = GetEnumerator();
+ IEnumerator s2 = other.GetEnumerator();
+
+ while (s1.MoveNext() && s2.MoveNext())
+ {
+ Asn1Object o1 = GetCurrent(s1).ToAsn1Object();
+ Asn1Object o2 = GetCurrent(s2).ToAsn1Object();
+
+ if (!o1.Equals(o2))
+ return false;
+ }
+
+ return true;
+ }
+
+ private Asn1Encodable GetCurrent(IEnumerator e)
+ {
+ Asn1Encodable encObj = (Asn1Encodable)e.Current;
+
+ // unfortunately null was allowed as a substitute for DER null
+ if (encObj == null)
+ return DerNull.Instance;
+
+ return encObj;
+ }
+
+ protected internal void AddObject(
+ Asn1Encodable obj)
+ {
+ seq.Add(obj);
+ }
+
+ public override string ToString()
+ {
+ return CollectionUtilities.ToString(seq);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/Asn1Set.cs b/bc-sharp-crypto/src/asn1/Asn1Set.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bf83dbdc1ef9d48f36e6dced6a537309c83bb030
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/Asn1Set.cs
@@ -0,0 +1,372 @@
+using System;
+using System.Collections;
+using System.IO;
+
+#if PORTABLE
+using System.Collections.Generic;
+using System.Linq;
+#endif
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1
+{
+ abstract public class Asn1Set
+ : Asn1Object, IEnumerable
+ {
+ private readonly IList _set;
+
+ /**
+ * return an ASN1Set from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static Asn1Set GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is Asn1Set)
+ {
+ return (Asn1Set)obj;
+ }
+ else if (obj is Asn1SetParser)
+ {
+ return Asn1Set.GetInstance(((Asn1SetParser)obj).ToAsn1Object());
+ }
+ else if (obj is byte[])
+ {
+ try
+ {
+ return Asn1Set.GetInstance(FromByteArray((byte[])obj));
+ }
+ catch (IOException e)
+ {
+ throw new ArgumentException("failed to construct set from byte[]: " + e.Message);
+ }
+ }
+ else if (obj is Asn1Encodable)
+ {
+ Asn1Object primitive = ((Asn1Encodable)obj).ToAsn1Object();
+
+ if (primitive is Asn1Set)
+ {
+ return (Asn1Set)primitive;
+ }
+ }
+
+ throw new ArgumentException("Unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * Return an ASN1 set from a tagged object. There is a special
+ * case here, if an object appears to have been explicitly tagged on
+ * reading but we were expecting it to be implicitly tagged in the
+ * normal course of events it indicates that we lost the surrounding
+ * set - so we need to add it back (this will happen if the tagged
+ * object is a sequence that contains other sequences). If you are
+ * dealing with implicitly tagged sets you really should
+ * be using this method.
+ *
+ * @param obj the tagged object.
+ * @param explicitly true if the object is meant to be explicitly tagged
+ * false otherwise.
+ * @exception ArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static Asn1Set GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ Asn1Object inner = obj.GetObject();
+
+ if (explicitly)
+ {
+ if (!obj.IsExplicit())
+ throw new ArgumentException("object implicit - explicit expected.");
+
+ return (Asn1Set) inner;
+ }
+
+ //
+ // constructed object which appears to be explicitly tagged
+ // and it's really implicit means we have to add the
+ // surrounding sequence.
+ //
+ if (obj.IsExplicit())
+ {
+ return new DerSet(inner);
+ }
+
+ if (inner is Asn1Set)
+ {
+ return (Asn1Set) inner;
+ }
+
+ //
+ // in this case the parser returns a sequence, convert it
+ // into a set.
+ //
+ if (inner is Asn1Sequence)
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+ Asn1Sequence s = (Asn1Sequence) inner;
+
+ foreach (Asn1Encodable ae in s)
+ {
+ v.Add(ae);
+ }
+
+ // TODO Should be able to construct set directly from sequence?
+ return new DerSet(v, false);
+ }
+
+ throw new ArgumentException("Unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ protected internal Asn1Set(
+ int capacity)
+ {
+ _set = Platform.CreateArrayList(capacity);
+ }
+
+ public virtual IEnumerator GetEnumerator()
+ {
+ return _set.GetEnumerator();
+ }
+
+ [Obsolete("Use GetEnumerator() instead")]
+ public IEnumerator GetObjects()
+ {
+ return GetEnumerator();
+ }
+
+ /**
+ * return the object at the set position indicated by index.
+ *
+ * @param index the set number (starting at zero) of the object
+ * @return the object at the set position indicated by index.
+ */
+ public virtual Asn1Encodable this[int index]
+ {
+ get { return (Asn1Encodable) _set[index]; }
+ }
+
+ [Obsolete("Use 'object[index]' syntax instead")]
+ public Asn1Encodable GetObjectAt(
+ int index)
+ {
+ return this[index];
+ }
+
+ [Obsolete("Use 'Count' property instead")]
+ public int Size
+ {
+ get { return Count; }
+ }
+
+ public virtual int Count
+ {
+ get { return _set.Count; }
+ }
+
+ public virtual Asn1Encodable[] ToArray()
+ {
+ Asn1Encodable[] values = new Asn1Encodable[this.Count];
+ for (int i = 0; i < this.Count; ++i)
+ {
+ values[i] = this[i];
+ }
+ return values;
+ }
+
+ private class Asn1SetParserImpl
+ : Asn1SetParser
+ {
+ private readonly Asn1Set outer;
+ private readonly int max;
+ private int index;
+
+ public Asn1SetParserImpl(
+ Asn1Set outer)
+ {
+ this.outer = outer;
+ this.max = outer.Count;
+ }
+
+ public IAsn1Convertible ReadObject()
+ {
+ if (index == max)
+ return null;
+
+ Asn1Encodable obj = outer[index++];
+ if (obj is Asn1Sequence)
+ return ((Asn1Sequence)obj).Parser;
+
+ if (obj is Asn1Set)
+ return ((Asn1Set)obj).Parser;
+
+ // NB: Asn1OctetString implements Asn1OctetStringParser directly
+// if (obj is Asn1OctetString)
+// return ((Asn1OctetString)obj).Parser;
+
+ return obj;
+ }
+
+ public virtual Asn1Object ToAsn1Object()
+ {
+ return outer;
+ }
+ }
+
+ public Asn1SetParser Parser
+ {
+ get { return new Asn1SetParserImpl(this); }
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ int hc = Count;
+
+ foreach (object o in this)
+ {
+ hc *= 17;
+ if (o == null)
+ {
+ hc ^= DerNull.Instance.GetHashCode();
+ }
+ else
+ {
+ hc ^= o.GetHashCode();
+ }
+ }
+
+ return hc;
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ Asn1Set other = asn1Object as Asn1Set;
+
+ if (other == null)
+ return false;
+
+ if (Count != other.Count)
+ {
+ return false;
+ }
+
+ IEnumerator s1 = GetEnumerator();
+ IEnumerator s2 = other.GetEnumerator();
+
+ while (s1.MoveNext() && s2.MoveNext())
+ {
+ Asn1Object o1 = GetCurrent(s1).ToAsn1Object();
+ Asn1Object o2 = GetCurrent(s2).ToAsn1Object();
+
+ if (!o1.Equals(o2))
+ return false;
+ }
+
+ return true;
+ }
+
+ private Asn1Encodable GetCurrent(IEnumerator e)
+ {
+ Asn1Encodable encObj = (Asn1Encodable)e.Current;
+
+ // unfortunately null was allowed as a substitute for DER null
+ if (encObj == null)
+ return DerNull.Instance;
+
+ return encObj;
+ }
+
+ protected internal void Sort()
+ {
+ if (_set.Count < 2)
+ return;
+
+#if PORTABLE
+ var sorted = _set.Cast()
+ .Select(a => new { Item = a, Key = a.GetEncoded(Asn1Encodable.Der) })
+ .OrderBy(t => t.Key, new DerComparer())
+ .Select(t => t.Item)
+ .ToList();
+
+ for (int i = 0; i < _set.Count; ++i)
+ {
+ _set[i] = sorted[i];
+ }
+#else
+ Asn1Encodable[] items = new Asn1Encodable[_set.Count];
+ byte[][] keys = new byte[_set.Count][];
+
+ for (int i = 0; i < _set.Count; ++i)
+ {
+ Asn1Encodable item = (Asn1Encodable)_set[i];
+ items[i] = item;
+ keys[i] = item.GetEncoded(Asn1Encodable.Der);
+ }
+
+ Array.Sort(keys, items, new DerComparer());
+
+ for (int i = 0; i < _set.Count; ++i)
+ {
+ _set[i] = items[i];
+ }
+#endif
+ }
+
+ protected internal void AddObject(Asn1Encodable obj)
+ {
+ _set.Add(obj);
+ }
+
+ public override string ToString()
+ {
+ return CollectionUtilities.ToString(_set);
+ }
+
+#if PORTABLE
+ private class DerComparer
+ : IComparer
+ {
+ public int Compare(byte[] x, byte[] y)
+ {
+ byte[] a = x, b = y;
+#else
+ private class DerComparer
+ : IComparer
+ {
+ public int Compare(object x, object y)
+ {
+ byte[] a = (byte[])x, b = (byte[])y;
+#endif
+ int len = System.Math.Min(a.Length, b.Length);
+ for (int i = 0; i != len; ++i)
+ {
+ byte ai = a[i], bi = b[i];
+ if (ai != bi)
+ return ai < bi ? -1 : 1;
+ }
+ if (a.Length > b.Length)
+ return AllZeroesFrom(a, len) ? 0 : 1;
+ if (a.Length < b.Length)
+ return AllZeroesFrom(b, len) ? 0 : -1;
+ return 0;
+ }
+
+ private bool AllZeroesFrom(byte[] bs, int pos)
+ {
+ while (pos < bs.Length)
+ {
+ if (bs[pos++] != 0)
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/Asn1TaggedObject.cs b/bc-sharp-crypto/src/asn1/Asn1TaggedObject.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a6d4b2c286f8e50f38737e478982fce946802aeb
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/Asn1TaggedObject.cs
@@ -0,0 +1,188 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * ASN.1 TaggedObject - in ASN.1 notation this is any object preceded by
+ * a [n] where n is some number - these are assumed to follow the construction
+ * rules (as with sequences).
+ */
+ public abstract class Asn1TaggedObject
+ : Asn1Object, Asn1TaggedObjectParser
+ {
+ internal static bool IsConstructed(bool isExplicit, Asn1Object obj)
+ {
+ if (isExplicit || obj is Asn1Sequence || obj is Asn1Set)
+ return true;
+ Asn1TaggedObject tagged = obj as Asn1TaggedObject;
+ if (tagged == null)
+ return false;
+ return IsConstructed(tagged.IsExplicit(), tagged.GetObject());
+ }
+
+ internal int tagNo;
+// internal bool empty;
+ internal bool explicitly = true;
+ internal Asn1Encodable obj;
+
+ static public Asn1TaggedObject GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ if (explicitly)
+ {
+ return (Asn1TaggedObject) obj.GetObject();
+ }
+
+ throw new ArgumentException("implicitly tagged tagged object");
+ }
+
+ static public Asn1TaggedObject GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is Asn1TaggedObject)
+ {
+ return (Asn1TaggedObject) obj;
+ }
+
+ throw new ArgumentException("Unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ protected Asn1TaggedObject(
+ int tagNo,
+ Asn1Encodable obj)
+ {
+ this.explicitly = true;
+ this.tagNo = tagNo;
+ this.obj = obj;
+ }
+
+ /**
+ * @param explicitly true if the object is explicitly tagged.
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ protected Asn1TaggedObject(
+ bool explicitly,
+ int tagNo,
+ Asn1Encodable obj)
+ {
+ // IAsn1Choice marker interface 'insists' on explicit tagging
+ this.explicitly = explicitly || (obj is IAsn1Choice);
+ this.tagNo = tagNo;
+ this.obj = obj;
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ Asn1TaggedObject other = asn1Object as Asn1TaggedObject;
+
+ if (other == null)
+ return false;
+
+ return this.tagNo == other.tagNo
+// && this.empty == other.empty
+ && this.explicitly == other.explicitly // TODO Should this be part of equality?
+ && Platform.Equals(GetObject(), other.GetObject());
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ int code = tagNo.GetHashCode();
+
+ // TODO: actually this is wrong - the problem is that a re-encoded
+ // object may end up with a different hashCode due to implicit
+ // tagging. As implicit tagging is ambiguous if a sequence is involved
+ // it seems the only correct method for both equals and hashCode is to
+ // compare the encodings...
+// code ^= explicitly.GetHashCode();
+
+ if (obj != null)
+ {
+ code ^= obj.GetHashCode();
+ }
+
+ return code;
+ }
+
+ public int TagNo
+ {
+ get { return tagNo; }
+ }
+
+ /**
+ * return whether or not the object may be explicitly tagged.
+ *
+ * Note: if the object has been read from an input stream, the only
+ * time you can be sure if isExplicit is returning the true state of
+ * affairs is if it returns false. An implicitly tagged object may appear
+ * to be explicitly tagged, so you need to understand the context under
+ * which the reading was done as well, see GetObject below.
+ */
+ public bool IsExplicit()
+ {
+ return explicitly;
+ }
+
+ public bool IsEmpty()
+ {
+ return false; //empty;
+ }
+
+ /**
+ * return whatever was following the tag.
+ *
+ * Note: tagged objects are generally context dependent if you're
+ * trying to extract a tagged object you should be going via the
+ * appropriate GetInstance method.
+ */
+ public Asn1Object GetObject()
+ {
+ if (obj != null)
+ {
+ return obj.ToAsn1Object();
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the object held in this tagged object as a parser assuming it has
+ * the type of the passed in tag. If the object doesn't have a parser
+ * associated with it, the base object is returned.
+ */
+ public IAsn1Convertible GetObjectParser(
+ int tag,
+ bool isExplicit)
+ {
+ switch (tag)
+ {
+ case Asn1Tags.Set:
+ return Asn1Set.GetInstance(this, isExplicit).Parser;
+ case Asn1Tags.Sequence:
+ return Asn1Sequence.GetInstance(this, isExplicit).Parser;
+ case Asn1Tags.OctetString:
+ return Asn1OctetString.GetInstance(this, isExplicit).Parser;
+ }
+
+ if (isExplicit)
+ {
+ return GetObject();
+ }
+
+ throw Platform.CreateNotImplementedException("implicit tagging for tag: " + tag);
+ }
+
+ public override string ToString()
+ {
+ return "[" + tagNo + "]" + obj;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/Asn1Tags.cs b/bc-sharp-crypto/src/asn1/Asn1Tags.cs
new file mode 100644
index 0000000000000000000000000000000000000000..32ac6bc6c0e4e9d780f3bc1d6e4a7ec7e783bc15
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/Asn1Tags.cs
@@ -0,0 +1,36 @@
+namespace Org.BouncyCastle.Asn1
+{
+ public class Asn1Tags
+ {
+ public const int Boolean = 0x01;
+ public const int Integer = 0x02;
+ public const int BitString = 0x03;
+ public const int OctetString = 0x04;
+ public const int Null = 0x05;
+ public const int ObjectIdentifier = 0x06;
+ public const int External = 0x08;
+ public const int Enumerated = 0x0a;
+ public const int Sequence = 0x10;
+ public const int SequenceOf = 0x10; // for completeness
+ public const int Set = 0x11;
+ public const int SetOf = 0x11; // for completeness
+
+ public const int NumericString = 0x12;
+ public const int PrintableString = 0x13;
+ public const int T61String = 0x14;
+ public const int VideotexString = 0x15;
+ public const int IA5String = 0x16;
+ public const int UtcTime = 0x17;
+ public const int GeneralizedTime = 0x18;
+ public const int GraphicString = 0x19;
+ public const int VisibleString = 0x1a;
+ public const int GeneralString = 0x1b;
+ public const int UniversalString = 0x1c;
+ public const int BmpString = 0x1e;
+ public const int Utf8String = 0x0c;
+
+ public const int Constructed = 0x20;
+ public const int Application = 0x40;
+ public const int Tagged = 0x80;
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/BERBitString.cs b/bc-sharp-crypto/src/asn1/BERBitString.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d8cd003300c57bd46305b55b7d54fef6e062595e
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/BERBitString.cs
@@ -0,0 +1,43 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class BerBitString
+ : DerBitString
+ {
+ public BerBitString(byte[] data, int padBits)
+ : base(data, padBits)
+ {
+ }
+
+ public BerBitString(byte[] data)
+ : base(data)
+ {
+ }
+
+ public BerBitString(int namedBits)
+ : base(namedBits)
+ {
+ }
+
+ public BerBitString(Asn1Encodable obj)
+ : base(obj)
+ {
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ if (derOut is Asn1OutputStream || derOut is BerOutputStream)
+ {
+ derOut.WriteEncoded(Asn1Tags.BitString, (byte)mPadBits, mData);
+ }
+ else
+ {
+ base.Encode(derOut);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/BERGenerator.cs b/bc-sharp-crypto/src/asn1/BERGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..271572c02eceb7b0e2984e7ddefad51a1b1f0d2f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/BERGenerator.cs
@@ -0,0 +1,102 @@
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class BerGenerator
+ : Asn1Generator
+ {
+ private bool _tagged = false;
+ private bool _isExplicit;
+ private int _tagNo;
+
+ protected BerGenerator(
+ Stream outStream)
+ : base(outStream)
+ {
+ }
+
+ public BerGenerator(
+ Stream outStream,
+ int tagNo,
+ bool isExplicit)
+ : base(outStream)
+ {
+ _tagged = true;
+ _isExplicit = isExplicit;
+ _tagNo = tagNo;
+ }
+
+ public override void AddObject(
+ Asn1Encodable obj)
+ {
+ new BerOutputStream(Out).WriteObject(obj);
+ }
+
+ public override Stream GetRawOutputStream()
+ {
+ return Out;
+ }
+
+ public override void Close()
+ {
+ WriteBerEnd();
+ }
+
+ private void WriteHdr(
+ int tag)
+ {
+ Out.WriteByte((byte) tag);
+ Out.WriteByte(0x80);
+ }
+
+ protected void WriteBerHeader(
+ int tag)
+ {
+ if (_tagged)
+ {
+ int tagNum = _tagNo | Asn1Tags.Tagged;
+
+ if (_isExplicit)
+ {
+ WriteHdr(tagNum | Asn1Tags.Constructed);
+ WriteHdr(tag);
+ }
+ else
+ {
+ if ((tag & Asn1Tags.Constructed) != 0)
+ {
+ WriteHdr(tagNum | Asn1Tags.Constructed);
+ }
+ else
+ {
+ WriteHdr(tagNum);
+ }
+ }
+ }
+ else
+ {
+ WriteHdr(tag);
+ }
+ }
+
+ protected void WriteBerBody(
+ Stream contentStream)
+ {
+ Streams.PipeAll(contentStream, Out);
+ }
+
+ protected void WriteBerEnd()
+ {
+ Out.WriteByte(0x00);
+ Out.WriteByte(0x00);
+
+ if (_tagged && _isExplicit) // write extra end for tag header
+ {
+ Out.WriteByte(0x00);
+ Out.WriteByte(0x00);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/BEROctetStringGenerator.cs b/bc-sharp-crypto/src/asn1/BEROctetStringGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f34538f3860dc3657587b02de4444aac57be8766
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/BEROctetStringGenerator.cs
@@ -0,0 +1,133 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class BerOctetStringGenerator
+ : BerGenerator
+ {
+ public BerOctetStringGenerator(Stream outStream)
+ : base(outStream)
+ {
+ WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.OctetString);
+ }
+
+ public BerOctetStringGenerator(
+ Stream outStream,
+ int tagNo,
+ bool isExplicit)
+ : base(outStream, tagNo, isExplicit)
+ {
+ WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.OctetString);
+ }
+
+ public Stream GetOctetOutputStream()
+ {
+ return GetOctetOutputStream(new byte[1000]); // limit for CER encoding.
+ }
+
+ public Stream GetOctetOutputStream(
+ int bufSize)
+ {
+ return bufSize < 1
+ ? GetOctetOutputStream()
+ : GetOctetOutputStream(new byte[bufSize]);
+ }
+
+ public Stream GetOctetOutputStream(
+ byte[] buf)
+ {
+ return new BufferedBerOctetStream(this, buf);
+ }
+
+ private class BufferedBerOctetStream
+ : BaseOutputStream
+ {
+ private byte[] _buf;
+ private int _off;
+ private readonly BerOctetStringGenerator _gen;
+ private readonly DerOutputStream _derOut;
+
+ internal BufferedBerOctetStream(
+ BerOctetStringGenerator gen,
+ byte[] buf)
+ {
+ _gen = gen;
+ _buf = buf;
+ _off = 0;
+ _derOut = new DerOutputStream(_gen.Out);
+ }
+
+ public override void WriteByte(
+ byte b)
+ {
+ _buf[_off++] = b;
+
+ if (_off == _buf.Length)
+ {
+ DerOctetString.Encode(_derOut, _buf, 0, _off);
+ _off = 0;
+ }
+ }
+
+ public override void Write(
+ byte[] buf,
+ int offset,
+ int len)
+ {
+ while (len > 0)
+ {
+ int numToCopy = System.Math.Min(len, _buf.Length - _off);
+
+ if (numToCopy == _buf.Length)
+ {
+ DerOctetString.Encode(_derOut, buf, offset, numToCopy);
+ }
+ else
+ {
+ Array.Copy(buf, offset, _buf, _off, numToCopy);
+
+ _off += numToCopy;
+ if (_off < _buf.Length)
+ break;
+
+ DerOctetString.Encode(_derOut, _buf, 0, _off);
+ _off = 0;
+ }
+
+ offset += numToCopy;
+ len -= numToCopy;
+ }
+ }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (_off != 0)
+ {
+ DerOctetString.Encode(_derOut, _buf, 0, _off);
+ }
+
+ _gen.WriteBerEnd();
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ if (_off != 0)
+ {
+ DerOctetString.Encode(_derOut, _buf, 0, _off);
+ }
+
+ _gen.WriteBerEnd();
+ base.Close();
+ }
+#endif
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/BEROctetStringParser.cs b/bc-sharp-crypto/src/asn1/BEROctetStringParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3bfd2a98d937c8247b2506b5d426bd53117682dd
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/BEROctetStringParser.cs
@@ -0,0 +1,36 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class BerOctetStringParser
+ : Asn1OctetStringParser
+ {
+ private readonly Asn1StreamParser _parser;
+
+ internal BerOctetStringParser(
+ Asn1StreamParser parser)
+ {
+ _parser = parser;
+ }
+
+ public Stream GetOctetStream()
+ {
+ return new ConstructedOctetStream(_parser);
+ }
+
+ public Asn1Object ToAsn1Object()
+ {
+ try
+ {
+ return new BerOctetString(Streams.ReadAll(GetOctetStream()));
+ }
+ catch (IOException e)
+ {
+ throw new Asn1ParsingException("IOException converting stream to byte array: " + e.Message, e);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/BERSequenceGenerator.cs b/bc-sharp-crypto/src/asn1/BERSequenceGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5ea2c9b82318b4fec79e3695f9b75f7ee2f108fc
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/BERSequenceGenerator.cs
@@ -0,0 +1,24 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class BerSequenceGenerator
+ : BerGenerator
+ {
+ public BerSequenceGenerator(
+ Stream outStream)
+ : base(outStream)
+ {
+ WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Sequence);
+ }
+
+ public BerSequenceGenerator(
+ Stream outStream,
+ int tagNo,
+ bool isExplicit)
+ : base(outStream, tagNo, isExplicit)
+ {
+ WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Sequence);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/BERSequenceParser.cs b/bc-sharp-crypto/src/asn1/BERSequenceParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8474b8d24f46ce63aeb5bc3ab5852eaea3e88eac
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/BERSequenceParser.cs
@@ -0,0 +1,24 @@
+namespace Org.BouncyCastle.Asn1
+{
+ public class BerSequenceParser
+ : Asn1SequenceParser
+ {
+ private readonly Asn1StreamParser _parser;
+
+ internal BerSequenceParser(
+ Asn1StreamParser parser)
+ {
+ this._parser = parser;
+ }
+
+ public IAsn1Convertible ReadObject()
+ {
+ return _parser.ReadObject();
+ }
+
+ public Asn1Object ToAsn1Object()
+ {
+ return new BerSequence(_parser.ReadVector());
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/BERSetGenerator.cs b/bc-sharp-crypto/src/asn1/BERSetGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..72b1f903a5f53716150240cf51bca4e3da4888e6
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/BERSetGenerator.cs
@@ -0,0 +1,24 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class BerSetGenerator
+ : BerGenerator
+ {
+ public BerSetGenerator(
+ Stream outStream)
+ : base(outStream)
+ {
+ WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Set);
+ }
+
+ public BerSetGenerator(
+ Stream outStream,
+ int tagNo,
+ bool isExplicit)
+ : base(outStream, tagNo, isExplicit)
+ {
+ WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Set);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/BERSetParser.cs b/bc-sharp-crypto/src/asn1/BERSetParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..aa9ccbc12424f12bfee3027adbd20a9f914d0b29
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/BERSetParser.cs
@@ -0,0 +1,24 @@
+namespace Org.BouncyCastle.Asn1
+{
+ public class BerSetParser
+ : Asn1SetParser
+ {
+ private readonly Asn1StreamParser _parser;
+
+ internal BerSetParser(
+ Asn1StreamParser parser)
+ {
+ this._parser = parser;
+ }
+
+ public IAsn1Convertible ReadObject()
+ {
+ return _parser.ReadObject();
+ }
+
+ public Asn1Object ToAsn1Object()
+ {
+ return new BerSet(_parser.ReadVector(), false);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/BERTaggedObjectParser.cs b/bc-sharp-crypto/src/asn1/BERTaggedObjectParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..354437a6a6ae0b7f73ca8a248009d0346e996051
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/BERTaggedObjectParser.cs
@@ -0,0 +1,71 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class BerTaggedObjectParser
+ : Asn1TaggedObjectParser
+ {
+ private bool _constructed;
+ private int _tagNumber;
+ private Asn1StreamParser _parser;
+
+ [Obsolete]
+ internal BerTaggedObjectParser(
+ int baseTag,
+ int tagNumber,
+ Stream contentStream)
+ : this((baseTag & Asn1Tags.Constructed) != 0, tagNumber, new Asn1StreamParser(contentStream))
+ {
+ }
+
+ internal BerTaggedObjectParser(
+ bool constructed,
+ int tagNumber,
+ Asn1StreamParser parser)
+ {
+ _constructed = constructed;
+ _tagNumber = tagNumber;
+ _parser = parser;
+ }
+
+ public bool IsConstructed
+ {
+ get { return _constructed; }
+ }
+
+ public int TagNo
+ {
+ get { return _tagNumber; }
+ }
+
+ public IAsn1Convertible GetObjectParser(
+ int tag,
+ bool isExplicit)
+ {
+ if (isExplicit)
+ {
+ if (!_constructed)
+ throw new IOException("Explicit tags must be constructed (see X.690 8.14.2)");
+
+ return _parser.ReadObject();
+ }
+
+ return _parser.ReadImplicit(_constructed, tag);
+ }
+
+ public Asn1Object ToAsn1Object()
+ {
+ try
+ {
+ return _parser.ReadTaggedObject(_constructed, _tagNumber);
+ }
+ catch (IOException e)
+ {
+ throw new Asn1ParsingException(e.Message);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/BerApplicationSpecific.cs b/bc-sharp-crypto/src/asn1/BerApplicationSpecific.cs
new file mode 100644
index 0000000000000000000000000000000000000000..65fbecbe138785f4d2682973c4e7e36d270fc12f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/BerApplicationSpecific.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class BerApplicationSpecific
+ : DerApplicationSpecific
+ {
+ public BerApplicationSpecific(
+ int tagNo,
+ Asn1EncodableVector vec)
+ : base(tagNo, vec)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/BerApplicationSpecificParser.cs b/bc-sharp-crypto/src/asn1/BerApplicationSpecificParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7d2c4b3e80c495f2195b14ca58ca493fb92dcecd
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/BerApplicationSpecificParser.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class BerApplicationSpecificParser
+ : IAsn1ApplicationSpecificParser
+ {
+ private readonly int tag;
+ private readonly Asn1StreamParser parser;
+
+ internal BerApplicationSpecificParser(
+ int tag,
+ Asn1StreamParser parser)
+ {
+ this.tag = tag;
+ this.parser = parser;
+ }
+
+ public IAsn1Convertible ReadObject()
+ {
+ return parser.ReadObject();
+ }
+
+ public Asn1Object ToAsn1Object()
+ {
+ return new BerApplicationSpecific(tag, parser.ReadVector());
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/BerNull.cs b/bc-sharp-crypto/src/asn1/BerNull.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0751bbac37a6c4947daeaf2f651dc749962e74ab
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/BerNull.cs
@@ -0,0 +1,35 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * A BER Null object.
+ */
+ public class BerNull
+ : DerNull
+ {
+ public static new readonly BerNull Instance = new BerNull(0);
+
+ [Obsolete("Use static Instance object")]
+ public BerNull()
+ {
+ }
+
+ private BerNull(int dummy) : base(dummy)
+ {
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ if (derOut is Asn1OutputStream || derOut is BerOutputStream)
+ {
+ derOut.WriteByte(Asn1Tags.Null);
+ }
+ else
+ {
+ base.Encode(derOut);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/BerOctetString.cs b/bc-sharp-crypto/src/asn1/BerOctetString.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a7c8ad33e46aaa8349ac84df8cbf71ea14f81bb7
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/BerOctetString.cs
@@ -0,0 +1,135 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class BerOctetString
+ : DerOctetString, IEnumerable
+ {
+ public static BerOctetString FromSequence(Asn1Sequence seq)
+ {
+ IList v = Platform.CreateArrayList();
+
+ foreach (Asn1Encodable obj in seq)
+ {
+ v.Add(obj);
+ }
+
+ return new BerOctetString(v);
+ }
+
+ private const int MaxLength = 1000;
+
+ /**
+ * convert a vector of octet strings into a single byte string
+ */
+ private static byte[] ToBytes(
+ IEnumerable octs)
+ {
+ MemoryStream bOut = new MemoryStream();
+ foreach (DerOctetString o in octs)
+ {
+ byte[] octets = o.GetOctets();
+ bOut.Write(octets, 0, octets.Length);
+ }
+ return bOut.ToArray();
+ }
+
+ private readonly IEnumerable octs;
+
+ /// The octets making up the octet string.
+ public BerOctetString(
+ byte[] str)
+ : base(str)
+ {
+ }
+
+ public BerOctetString(
+ IEnumerable octets)
+ : base(ToBytes(octets))
+ {
+ this.octs = octets;
+ }
+
+ public BerOctetString(
+ Asn1Object obj)
+ : base(obj)
+ {
+ }
+
+ public BerOctetString(
+ Asn1Encodable obj)
+ : base(obj.ToAsn1Object())
+ {
+ }
+
+ public override byte[] GetOctets()
+ {
+ return str;
+ }
+
+ /**
+ * return the DER octets that make up this string.
+ */
+ public IEnumerator GetEnumerator()
+ {
+ if (octs == null)
+ {
+ return GenerateOcts().GetEnumerator();
+ }
+
+ return octs.GetEnumerator();
+ }
+
+ [Obsolete("Use GetEnumerator() instead")]
+ public IEnumerator GetObjects()
+ {
+ return GetEnumerator();
+ }
+
+ private IList GenerateOcts()
+ {
+ IList vec = Platform.CreateArrayList();
+ for (int i = 0; i < str.Length; i += MaxLength)
+ {
+ int end = System.Math.Min(str.Length, i + MaxLength);
+
+ byte[] nStr = new byte[end - i];
+
+ Array.Copy(str, i, nStr, 0, nStr.Length);
+
+ vec.Add(new DerOctetString(nStr));
+ }
+ return vec;
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ if (derOut is Asn1OutputStream || derOut is BerOutputStream)
+ {
+ derOut.WriteByte(Asn1Tags.Constructed | Asn1Tags.OctetString);
+
+ derOut.WriteByte(0x80);
+
+ //
+ // write out the octet array
+ //
+ foreach (DerOctetString oct in this)
+ {
+ derOut.WriteObject(oct);
+ }
+
+ derOut.WriteByte(0x00);
+ derOut.WriteByte(0x00);
+ }
+ else
+ {
+ base.Encode(derOut);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/BerOutputStream.cs b/bc-sharp-crypto/src/asn1/BerOutputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b3ece10d33fee7ead23b84fa085612100f240f11
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/BerOutputStream.cs
@@ -0,0 +1,36 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ // TODO Make Obsolete in favour of Asn1OutputStream?
+ public class BerOutputStream
+ : DerOutputStream
+ {
+ public BerOutputStream(Stream os) : base(os)
+ {
+ }
+
+ [Obsolete("Use version taking an Asn1Encodable arg instead")]
+ public override void WriteObject(
+ object obj)
+ {
+ if (obj == null)
+ {
+ WriteNull();
+ }
+ else if (obj is Asn1Object)
+ {
+ ((Asn1Object)obj).Encode(this);
+ }
+ else if (obj is Asn1Encodable)
+ {
+ ((Asn1Encodable)obj).ToAsn1Object().Encode(this);
+ }
+ else
+ {
+ throw new IOException("object not BerEncodable");
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/BerSequence.cs b/bc-sharp-crypto/src/asn1/BerSequence.cs
new file mode 100644
index 0000000000000000000000000000000000000000..70b43fc79bf0c882b8420cb026b6ff324c02beb9
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/BerSequence.cs
@@ -0,0 +1,69 @@
+namespace Org.BouncyCastle.Asn1
+{
+ public class BerSequence
+ : DerSequence
+ {
+ public static new readonly BerSequence Empty = new BerSequence();
+
+ public static new BerSequence FromVector(
+ Asn1EncodableVector v)
+ {
+ return v.Count < 1 ? Empty : new BerSequence(v);
+ }
+
+ /**
+ * create an empty sequence
+ */
+ public BerSequence()
+ {
+ }
+
+ /**
+ * create a sequence containing one object
+ */
+ public BerSequence(
+ Asn1Encodable obj)
+ : base(obj)
+ {
+ }
+
+ public BerSequence(
+ params Asn1Encodable[] v)
+ : base(v)
+ {
+ }
+
+ /**
+ * create a sequence containing a vector of objects.
+ */
+ public BerSequence(
+ Asn1EncodableVector v)
+ : base(v)
+ {
+ }
+
+ /*
+ */
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ if (derOut is Asn1OutputStream || derOut is BerOutputStream)
+ {
+ derOut.WriteByte(Asn1Tags.Sequence | Asn1Tags.Constructed);
+ derOut.WriteByte(0x80);
+
+ foreach (Asn1Encodable o in this)
+ {
+ derOut.WriteObject(o);
+ }
+
+ derOut.WriteByte(0x00);
+ derOut.WriteByte(0x00);
+ }
+ else
+ {
+ base.Encode(derOut);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/BerSet.cs b/bc-sharp-crypto/src/asn1/BerSet.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a181e172d30f3ebe05f87628f4625be1014d19d7
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/BerSet.cs
@@ -0,0 +1,70 @@
+namespace Org.BouncyCastle.Asn1
+{
+ public class BerSet
+ : DerSet
+ {
+ public static new readonly BerSet Empty = new BerSet();
+
+ public static new BerSet FromVector(
+ Asn1EncodableVector v)
+ {
+ return v.Count < 1 ? Empty : new BerSet(v);
+ }
+
+ internal static new BerSet FromVector(
+ Asn1EncodableVector v,
+ bool needsSorting)
+ {
+ return v.Count < 1 ? Empty : new BerSet(v, needsSorting);
+ }
+
+ /**
+ * create an empty sequence
+ */
+ public BerSet()
+ {
+ }
+
+ /**
+ * create a set containing one object
+ */
+ public BerSet(Asn1Encodable obj) : base(obj)
+ {
+ }
+
+ /**
+ * create a set containing a vector of objects.
+ */
+ public BerSet(Asn1EncodableVector v) : base(v, false)
+ {
+ }
+
+ internal BerSet(Asn1EncodableVector v, bool needsSorting) : base(v, needsSorting)
+ {
+ }
+
+ /*
+ */
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ if (derOut is Asn1OutputStream || derOut is BerOutputStream)
+ {
+ derOut.WriteByte(Asn1Tags.Set | Asn1Tags.Constructed);
+ derOut.WriteByte(0x80);
+
+ foreach (Asn1Encodable o in this)
+ {
+ derOut.WriteObject(o);
+ }
+
+ derOut.WriteByte(0x00);
+ derOut.WriteByte(0x00);
+ }
+ else
+ {
+ base.Encode(derOut);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/BerTaggedObject.cs b/bc-sharp-crypto/src/asn1/BerTaggedObject.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fd0bdc2850ed34722df38f64039f370d561b56a6
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/BerTaggedObject.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * BER TaggedObject - in ASN.1 notation this is any object preceded by
+ * a [n] where n is some number - these are assumed to follow the construction
+ * rules (as with sequences).
+ */
+ public class BerTaggedObject
+ : DerTaggedObject
+ {
+ /**
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public BerTaggedObject(
+ int tagNo,
+ Asn1Encodable obj)
+ : base(tagNo, obj)
+ {
+ }
+
+ /**
+ * @param explicitly true if an explicitly tagged object.
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public BerTaggedObject(
+ bool explicitly,
+ int tagNo,
+ Asn1Encodable obj)
+ : base(explicitly, tagNo, obj)
+ {
+ }
+
+ /**
+ * create an implicitly tagged object that contains a zero
+ * length sequence.
+ */
+ public BerTaggedObject(
+ int tagNo)
+ : base(false, tagNo, BerSequence.Empty)
+ {
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ if (derOut is Asn1OutputStream || derOut is BerOutputStream)
+ {
+ derOut.WriteTag((byte)(Asn1Tags.Constructed | Asn1Tags.Tagged), tagNo);
+ derOut.WriteByte(0x80);
+
+ if (!IsEmpty())
+ {
+ if (!explicitly)
+ {
+ IEnumerable eObj;
+ if (obj is Asn1OctetString)
+ {
+ if (obj is BerOctetString)
+ {
+ eObj = (BerOctetString) obj;
+ }
+ else
+ {
+ Asn1OctetString octs = (Asn1OctetString)obj;
+ eObj = new BerOctetString(octs.GetOctets());
+ }
+ }
+ else if (obj is Asn1Sequence)
+ {
+ eObj = (Asn1Sequence) obj;
+ }
+ else if (obj is Asn1Set)
+ {
+ eObj = (Asn1Set) obj;
+ }
+ else
+ {
+ throw Platform.CreateNotImplementedException(Platform.GetTypeName(obj));
+ }
+
+ foreach (Asn1Encodable o in eObj)
+ {
+ derOut.WriteObject(o);
+ }
+ }
+ else
+ {
+ derOut.WriteObject(obj);
+ }
+ }
+
+ derOut.WriteByte(0x00);
+ derOut.WriteByte(0x00);
+ }
+ else
+ {
+ base.Encode(derOut);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ConstructedOctetStream.cs b/bc-sharp-crypto/src/asn1/ConstructedOctetStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1773b22ccf832cf4f54e07ddfec7e39fa9d30408
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ConstructedOctetStream.cs
@@ -0,0 +1,102 @@
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ internal class ConstructedOctetStream
+ : BaseInputStream
+ {
+ private readonly Asn1StreamParser _parser;
+
+ private bool _first = true;
+ private Stream _currentStream;
+
+ internal ConstructedOctetStream(
+ Asn1StreamParser parser)
+ {
+ _parser = parser;
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ if (_currentStream == null)
+ {
+ if (!_first)
+ return 0;
+
+ Asn1OctetStringParser s = (Asn1OctetStringParser)_parser.ReadObject();
+
+ if (s == null)
+ return 0;
+
+ _first = false;
+ _currentStream = s.GetOctetStream();
+ }
+
+ int totalRead = 0;
+
+ for (;;)
+ {
+ int numRead = _currentStream.Read(buffer, offset + totalRead, count - totalRead);
+
+ if (numRead > 0)
+ {
+ totalRead += numRead;
+
+ if (totalRead == count)
+ return totalRead;
+ }
+ else
+ {
+ Asn1OctetStringParser aos = (Asn1OctetStringParser)_parser.ReadObject();
+
+ if (aos == null)
+ {
+ _currentStream = null;
+ return totalRead;
+ }
+
+ _currentStream = aos.GetOctetStream();
+ }
+ }
+ }
+
+ public override int ReadByte()
+ {
+ if (_currentStream == null)
+ {
+ if (!_first)
+ return 0;
+
+ Asn1OctetStringParser s = (Asn1OctetStringParser)_parser.ReadObject();
+
+ if (s == null)
+ return 0;
+
+ _first = false;
+ _currentStream = s.GetOctetStream();
+ }
+
+ for (;;)
+ {
+ int b = _currentStream.ReadByte();
+
+ if (b >= 0)
+ {
+ return b;
+ }
+
+ Asn1OctetStringParser aos = (Asn1OctetStringParser)_parser.ReadObject();
+
+ if (aos == null)
+ {
+ _currentStream = null;
+ return -1;
+ }
+
+ _currentStream = aos.GetOctetStream();
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DERExternal.cs b/bc-sharp-crypto/src/asn1/DERExternal.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c299751933f0f8bad834194bcd0f902ddc717ef1
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DERExternal.cs
@@ -0,0 +1,202 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * Class representing the DER-type External
+ */
+ public class DerExternal
+ : Asn1Object
+ {
+ private DerObjectIdentifier directReference;
+ private DerInteger indirectReference;
+ private Asn1Object dataValueDescriptor;
+ private int encoding;
+ private Asn1Object externalContent;
+
+ public DerExternal(
+ Asn1EncodableVector vector)
+ {
+ int offset = 0;
+ Asn1Object enc = GetObjFromVector(vector, offset);
+ if (enc is DerObjectIdentifier)
+ {
+ directReference = (DerObjectIdentifier)enc;
+ offset++;
+ enc = GetObjFromVector(vector, offset);
+ }
+ if (enc is DerInteger)
+ {
+ indirectReference = (DerInteger) enc;
+ offset++;
+ enc = GetObjFromVector(vector, offset);
+ }
+ if (!(enc is Asn1TaggedObject))
+ {
+ dataValueDescriptor = enc;
+ offset++;
+ enc = GetObjFromVector(vector, offset);
+ }
+
+ if (vector.Count != offset + 1)
+ throw new ArgumentException("input vector too large", "vector");
+
+ if (!(enc is Asn1TaggedObject))
+ throw new ArgumentException("No tagged object found in vector. Structure doesn't seem to be of type External", "vector");
+
+ Asn1TaggedObject obj = (Asn1TaggedObject)enc;
+
+ // Use property accessor to include check on value
+ Encoding = obj.TagNo;
+
+ if (encoding < 0 || encoding > 2)
+ throw new InvalidOperationException("invalid encoding value");
+
+ externalContent = obj.GetObject();
+ }
+
+ /**
+ * Creates a new instance of DerExternal
+ * See X.690 for more informations about the meaning of these parameters
+ * @param directReference The direct reference or null
if not set.
+ * @param indirectReference The indirect reference or null
if not set.
+ * @param dataValueDescriptor The data value descriptor or null
if not set.
+ * @param externalData The external data in its encoded form.
+ */
+ public DerExternal(DerObjectIdentifier directReference, DerInteger indirectReference, Asn1Object dataValueDescriptor, DerTaggedObject externalData)
+ : this(directReference, indirectReference, dataValueDescriptor, externalData.TagNo, externalData.ToAsn1Object())
+ {
+ }
+
+ /**
+ * Creates a new instance of DerExternal.
+ * See X.690 for more informations about the meaning of these parameters
+ * @param directReference The direct reference or null
if not set.
+ * @param indirectReference The indirect reference or null
if not set.
+ * @param dataValueDescriptor The data value descriptor or null
if not set.
+ * @param encoding The encoding to be used for the external data
+ * @param externalData The external data
+ */
+ public DerExternal(DerObjectIdentifier directReference, DerInteger indirectReference, Asn1Object dataValueDescriptor, int encoding, Asn1Object externalData)
+ {
+ DirectReference = directReference;
+ IndirectReference = indirectReference;
+ DataValueDescriptor = dataValueDescriptor;
+ Encoding = encoding;
+ ExternalContent = externalData.ToAsn1Object();
+ }
+
+ internal override void Encode(DerOutputStream derOut)
+ {
+ MemoryStream ms = new MemoryStream();
+ WriteEncodable(ms, directReference);
+ WriteEncodable(ms, indirectReference);
+ WriteEncodable(ms, dataValueDescriptor);
+ WriteEncodable(ms, new DerTaggedObject(Asn1Tags.External, externalContent));
+
+ derOut.WriteEncoded(Asn1Tags.Constructed, Asn1Tags.External, ms.ToArray());
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ int ret = externalContent.GetHashCode();
+ if (directReference != null)
+ {
+ ret ^= directReference.GetHashCode();
+ }
+ if (indirectReference != null)
+ {
+ ret ^= indirectReference.GetHashCode();
+ }
+ if (dataValueDescriptor != null)
+ {
+ ret ^= dataValueDescriptor.GetHashCode();
+ }
+ return ret;
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ if (this == asn1Object)
+ return true;
+
+ DerExternal other = asn1Object as DerExternal;
+
+ if (other == null)
+ return false;
+
+ return Platform.Equals(directReference, other.directReference)
+ && Platform.Equals(indirectReference, other.indirectReference)
+ && Platform.Equals(dataValueDescriptor, other.dataValueDescriptor)
+ && externalContent.Equals(other.externalContent);
+ }
+
+ public Asn1Object DataValueDescriptor
+ {
+ get { return dataValueDescriptor; }
+ set { this.dataValueDescriptor = value; }
+ }
+
+ public DerObjectIdentifier DirectReference
+ {
+ get { return directReference; }
+ set { this.directReference = value; }
+ }
+
+ /**
+ * The encoding of the content. Valid values are
+ *
+ * 0
single-ASN1-type
+ * 1
OCTET STRING
+ * 2
BIT STRING
+ *
+ */
+ public int Encoding
+ {
+ get
+ {
+ return encoding;
+ }
+ set
+ {
+ if (encoding < 0 || encoding > 2)
+ throw new InvalidOperationException("invalid encoding value: " + encoding);
+
+ this.encoding = value;
+ }
+ }
+
+ public Asn1Object ExternalContent
+ {
+ get { return externalContent; }
+ set { this.externalContent = value; }
+ }
+
+ public DerInteger IndirectReference
+ {
+ get { return indirectReference; }
+ set { this.indirectReference = value; }
+ }
+
+ private static Asn1Object GetObjFromVector(Asn1EncodableVector v, int index)
+ {
+ if (v.Count <= index)
+ throw new ArgumentException("too few objects in input vector", "v");
+
+ return v[index].ToAsn1Object();
+ }
+
+ private static void WriteEncodable(MemoryStream ms, Asn1Encodable e)
+ {
+ if (e != null)
+ {
+ byte[] bs = e.GetDerEncoded();
+ ms.Write(bs, 0, bs.Length);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DERExternalParser.cs b/bc-sharp-crypto/src/asn1/DERExternalParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..70e426fed1101514d305a6a3c8973b87cc0a6e09
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DERExternalParser.cs
@@ -0,0 +1,26 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class DerExternalParser
+ : Asn1Encodable
+ {
+ private readonly Asn1StreamParser _parser;
+
+ public DerExternalParser(Asn1StreamParser parser)
+ {
+ this._parser = parser;
+ }
+
+ public IAsn1Convertible ReadObject()
+ {
+ return _parser.ReadObject();
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerExternal(_parser.ReadVector());
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DERGenerator.cs b/bc-sharp-crypto/src/asn1/DERGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..aab40fefa4d063c3a13fc5b21b55bc191bd653c5
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DERGenerator.cs
@@ -0,0 +1,107 @@
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public abstract class DerGenerator
+ : Asn1Generator
+ {
+ private bool _tagged = false;
+ private bool _isExplicit;
+ private int _tagNo;
+
+ protected DerGenerator(
+ Stream outStream)
+ : base(outStream)
+ {
+ }
+
+ protected DerGenerator(
+ Stream outStream,
+ int tagNo,
+ bool isExplicit)
+ : base(outStream)
+ {
+ _tagged = true;
+ _isExplicit = isExplicit;
+ _tagNo = tagNo;
+ }
+
+ private static void WriteLength(
+ Stream outStr,
+ int length)
+ {
+ if (length > 127)
+ {
+ int size = 1;
+ int val = length;
+
+ while ((val >>= 8) != 0)
+ {
+ size++;
+ }
+
+ outStr.WriteByte((byte)(size | 0x80));
+
+ for (int i = (size - 1) * 8; i >= 0; i -= 8)
+ {
+ outStr.WriteByte((byte)(length >> i));
+ }
+ }
+ else
+ {
+ outStr.WriteByte((byte)length);
+ }
+ }
+
+ internal static void WriteDerEncoded(
+ Stream outStream,
+ int tag,
+ byte[] bytes)
+ {
+ outStream.WriteByte((byte) tag);
+ WriteLength(outStream, bytes.Length);
+ outStream.Write(bytes, 0, bytes.Length);
+ }
+
+ internal void WriteDerEncoded(
+ int tag,
+ byte[] bytes)
+ {
+ if (_tagged)
+ {
+ int tagNum = _tagNo | Asn1Tags.Tagged;
+
+ if (_isExplicit)
+ {
+ int newTag = _tagNo | Asn1Tags.Constructed | Asn1Tags.Tagged;
+ MemoryStream bOut = new MemoryStream();
+ WriteDerEncoded(bOut, tag, bytes);
+ WriteDerEncoded(Out, newTag, bOut.ToArray());
+ }
+ else
+ {
+ if ((tag & Asn1Tags.Constructed) != 0)
+ {
+ tagNum |= Asn1Tags.Constructed;
+ }
+
+ WriteDerEncoded(Out, tagNum, bytes);
+ }
+ }
+ else
+ {
+ WriteDerEncoded(Out, tag, bytes);
+ }
+ }
+
+ internal static void WriteDerEncoded(
+ Stream outStr,
+ int tag,
+ Stream inStr)
+ {
+ WriteDerEncoded(outStr, tag, Streams.ReadAll(inStr));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DEROctetStringParser.cs b/bc-sharp-crypto/src/asn1/DEROctetStringParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b0d3ad8cf564af484f3127fae6e036ca9e3573d7
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DEROctetStringParser.cs
@@ -0,0 +1,36 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class DerOctetStringParser
+ : Asn1OctetStringParser
+ {
+ private readonly DefiniteLengthInputStream stream;
+
+ internal DerOctetStringParser(
+ DefiniteLengthInputStream stream)
+ {
+ this.stream = stream;
+ }
+
+ public Stream GetOctetStream()
+ {
+ return stream;
+ }
+
+ public Asn1Object ToAsn1Object()
+ {
+ try
+ {
+ return new DerOctetString(stream.ToArray());
+ }
+ catch (IOException e)
+ {
+ throw new InvalidOperationException("IOException converting stream to byte array: " + e.Message, e);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DERSequenceGenerator.cs b/bc-sharp-crypto/src/asn1/DERSequenceGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4c2bfd012387e7991ef9ae9c7f4dcb673f8794ff
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DERSequenceGenerator.cs
@@ -0,0 +1,40 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class DerSequenceGenerator
+ : DerGenerator
+ {
+ private readonly MemoryStream _bOut = new MemoryStream();
+
+ public DerSequenceGenerator(
+ Stream outStream)
+ : base(outStream)
+ {
+ }
+
+ public DerSequenceGenerator(
+ Stream outStream,
+ int tagNo,
+ bool isExplicit)
+ : base(outStream, tagNo, isExplicit)
+ {
+ }
+
+ public override void AddObject(
+ Asn1Encodable obj)
+ {
+ new DerOutputStream(_bOut).WriteObject(obj);
+ }
+
+ public override Stream GetRawOutputStream()
+ {
+ return _bOut;
+ }
+
+ public override void Close()
+ {
+ WriteDerEncoded(Asn1Tags.Constructed | Asn1Tags.Sequence, _bOut.ToArray());
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DERSequenceParser.cs b/bc-sharp-crypto/src/asn1/DERSequenceParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..69c2b9b2d895b4f394875035e022ac5b827b3b9c
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DERSequenceParser.cs
@@ -0,0 +1,24 @@
+namespace Org.BouncyCastle.Asn1
+{
+ public class DerSequenceParser
+ : Asn1SequenceParser
+ {
+ private readonly Asn1StreamParser _parser;
+
+ internal DerSequenceParser(
+ Asn1StreamParser parser)
+ {
+ this._parser = parser;
+ }
+
+ public IAsn1Convertible ReadObject()
+ {
+ return _parser.ReadObject();
+ }
+
+ public Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(_parser.ReadVector());
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DERSetGenerator.cs b/bc-sharp-crypto/src/asn1/DERSetGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..455ca88acea30e62f47d65e8ec52f111425a2c81
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DERSetGenerator.cs
@@ -0,0 +1,40 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class DerSetGenerator
+ : DerGenerator
+ {
+ private readonly MemoryStream _bOut = new MemoryStream();
+
+ public DerSetGenerator(
+ Stream outStream)
+ : base(outStream)
+ {
+ }
+
+ public DerSetGenerator(
+ Stream outStream,
+ int tagNo,
+ bool isExplicit)
+ : base(outStream, tagNo, isExplicit)
+ {
+ }
+
+ public override void AddObject(
+ Asn1Encodable obj)
+ {
+ new DerOutputStream(_bOut).WriteObject(obj);
+ }
+
+ public override Stream GetRawOutputStream()
+ {
+ return _bOut;
+ }
+
+ public override void Close()
+ {
+ WriteDerEncoded(Asn1Tags.Constructed | Asn1Tags.Set, _bOut.ToArray());
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DERSetParser.cs b/bc-sharp-crypto/src/asn1/DERSetParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d67f135beb69f24738f96e13d308bc9607cb498c
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DERSetParser.cs
@@ -0,0 +1,24 @@
+namespace Org.BouncyCastle.Asn1
+{
+ public class DerSetParser
+ : Asn1SetParser
+ {
+ private readonly Asn1StreamParser _parser;
+
+ internal DerSetParser(
+ Asn1StreamParser parser)
+ {
+ this._parser = parser;
+ }
+
+ public IAsn1Convertible ReadObject()
+ {
+ return _parser.ReadObject();
+ }
+
+ public Asn1Object ToAsn1Object()
+ {
+ return new DerSet(_parser.ReadVector(), false);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DefiniteLengthInputStream.cs b/bc-sharp-crypto/src/asn1/DefiniteLengthInputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4ae803c0eab92a949d45398420454042b188953d
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DefiniteLengthInputStream.cs
@@ -0,0 +1,100 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ class DefiniteLengthInputStream
+ : LimitedInputStream
+ {
+ private static readonly byte[] EmptyBytes = new byte[0];
+
+ private readonly int _originalLength;
+ private int _remaining;
+
+ internal DefiniteLengthInputStream(
+ Stream inStream,
+ int length)
+ : base(inStream, length)
+ {
+ if (length < 0)
+ throw new ArgumentException("negative lengths not allowed", "length");
+
+ this._originalLength = length;
+ this._remaining = length;
+
+ if (length == 0)
+ {
+ SetParentEofDetect(true);
+ }
+ }
+
+ internal int Remaining
+ {
+ get { return _remaining; }
+ }
+
+ public override int ReadByte()
+ {
+ if (_remaining == 0)
+ return -1;
+
+ int b = _in.ReadByte();
+
+ if (b < 0)
+ throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining);
+
+ if (--_remaining == 0)
+ {
+ SetParentEofDetect(true);
+ }
+
+ return b;
+ }
+
+ public override int Read(
+ byte[] buf,
+ int off,
+ int len)
+ {
+ if (_remaining == 0)
+ return 0;
+
+ int toRead = System.Math.Min(len, _remaining);
+ int numRead = _in.Read(buf, off, toRead);
+
+ if (numRead < 1)
+ throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining);
+
+ if ((_remaining -= numRead) == 0)
+ {
+ SetParentEofDetect(true);
+ }
+
+ return numRead;
+ }
+
+ internal void ReadAllIntoByteArray(byte[] buf)
+ {
+ if (_remaining != buf.Length)
+ throw new ArgumentException("buffer length not right for data");
+
+ if ((_remaining -= Streams.ReadFully(_in, buf)) != 0)
+ throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining);
+ SetParentEofDetect(true);
+ }
+
+ internal byte[] ToArray()
+ {
+ if (_remaining == 0)
+ return EmptyBytes;
+
+ byte[] bytes = new byte[_remaining];
+ if ((_remaining -= Streams.ReadFully(_in, bytes)) != 0)
+ throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining);
+ SetParentEofDetect(true);
+ return bytes;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerApplicationSpecific.cs b/bc-sharp-crypto/src/asn1/DerApplicationSpecific.cs
new file mode 100644
index 0000000000000000000000000000000000000000..52467fabe679dd8724677bf9eb15994776565386
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerApplicationSpecific.cs
@@ -0,0 +1,237 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * Base class for an application specific object
+ */
+ public class DerApplicationSpecific
+ : Asn1Object
+ {
+ private readonly bool isConstructed;
+ private readonly int tag;
+ private readonly byte[] octets;
+
+ internal DerApplicationSpecific(
+ bool isConstructed,
+ int tag,
+ byte[] octets)
+ {
+ this.isConstructed = isConstructed;
+ this.tag = tag;
+ this.octets = octets;
+ }
+
+ public DerApplicationSpecific(
+ int tag,
+ byte[] octets)
+ : this(false, tag, octets)
+ {
+ }
+
+ public DerApplicationSpecific(
+ int tag,
+ Asn1Encodable obj)
+ : this(true, tag, obj)
+ {
+ }
+
+ public DerApplicationSpecific(
+ bool isExplicit,
+ int tag,
+ Asn1Encodable obj)
+ {
+ Asn1Object asn1Obj = obj.ToAsn1Object();
+
+ byte[] data = asn1Obj.GetDerEncoded();
+
+ this.isConstructed = Asn1TaggedObject.IsConstructed(isExplicit, asn1Obj);
+ this.tag = tag;
+
+ if (isExplicit)
+ {
+ this.octets = data;
+ }
+ else
+ {
+ int lenBytes = GetLengthOfHeader(data);
+ byte[] tmp = new byte[data.Length - lenBytes];
+ Array.Copy(data, lenBytes, tmp, 0, tmp.Length);
+ this.octets = tmp;
+ }
+ }
+
+ public DerApplicationSpecific(
+ int tagNo,
+ Asn1EncodableVector vec)
+ {
+ this.tag = tagNo;
+ this.isConstructed = true;
+ MemoryStream bOut = new MemoryStream();
+
+ for (int i = 0; i != vec.Count; i++)
+ {
+ try
+ {
+ byte[] bs = vec[i].GetDerEncoded();
+ bOut.Write(bs, 0, bs.Length);
+ }
+ catch (IOException e)
+ {
+ throw new InvalidOperationException("malformed object", e);
+ }
+ }
+ this.octets = bOut.ToArray();
+ }
+
+ private int GetLengthOfHeader(
+ byte[] data)
+ {
+ int length = data[1]; // TODO: assumes 1 byte tag
+
+ if (length == 0x80)
+ {
+ return 2; // indefinite-length encoding
+ }
+
+ if (length > 127)
+ {
+ int size = length & 0x7f;
+
+ // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
+ if (size > 4)
+ {
+ throw new InvalidOperationException("DER length more than 4 bytes: " + size);
+ }
+
+ return size + 2;
+ }
+
+ return 2;
+ }
+
+ public bool IsConstructed()
+ {
+ return isConstructed;
+ }
+
+ public byte[] GetContents()
+ {
+ return octets;
+ }
+
+ public int ApplicationTag
+ {
+ get { return tag; }
+ }
+
+ /**
+ * Return the enclosed object assuming explicit tagging.
+ *
+ * @return the resulting object
+ * @throws IOException if reconstruction fails.
+ */
+ public Asn1Object GetObject()
+ {
+ return FromByteArray(GetContents());
+ }
+
+ /**
+ * Return the enclosed object assuming implicit tagging.
+ *
+ * @param derTagNo the type tag that should be applied to the object's contents.
+ * @return the resulting object
+ * @throws IOException if reconstruction fails.
+ */
+ public Asn1Object GetObject(
+ int derTagNo)
+ {
+ if (derTagNo >= 0x1f)
+ throw new IOException("unsupported tag number");
+
+ byte[] orig = this.GetEncoded();
+ byte[] tmp = ReplaceTagNumber(derTagNo, orig);
+
+ if ((orig[0] & Asn1Tags.Constructed) != 0)
+ {
+ tmp[0] |= Asn1Tags.Constructed;
+ }
+
+ return FromByteArray(tmp);
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ int classBits = Asn1Tags.Application;
+ if (isConstructed)
+ {
+ classBits |= Asn1Tags.Constructed;
+ }
+
+ derOut.WriteEncoded(classBits, tag, octets);
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerApplicationSpecific other = asn1Object as DerApplicationSpecific;
+
+ if (other == null)
+ return false;
+
+ return this.isConstructed == other.isConstructed
+ && this.tag == other.tag
+ && Arrays.AreEqual(this.octets, other.octets);
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ return isConstructed.GetHashCode() ^ tag.GetHashCode() ^ Arrays.GetHashCode(octets);
+ }
+
+ private byte[] ReplaceTagNumber(
+ int newTag,
+ byte[] input)
+ {
+ int tagNo = input[0] & 0x1f;
+ int index = 1;
+ //
+ // with tagged object tag number is bottom 5 bits, or stored at the start of the content
+ //
+ if (tagNo == 0x1f)
+ {
+ tagNo = 0;
+
+ int b = input[index++] & 0xff;
+
+ // X.690-0207 8.1.2.4.2
+ // "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
+ if ((b & 0x7f) == 0) // Note: -1 will pass
+ {
+ throw new InvalidOperationException("corrupted stream - invalid high tag number found");
+ }
+
+ while ((b >= 0) && ((b & 0x80) != 0))
+ {
+ tagNo |= (b & 0x7f);
+ tagNo <<= 7;
+ b = input[index++] & 0xff;
+ }
+
+ tagNo |= (b & 0x7f);
+ }
+
+ byte[] tmp = new byte[input.Length - index + 1];
+
+ Array.Copy(input, index, tmp, 1, tmp.Length - 1);
+
+ tmp[0] = (byte)newTag;
+
+ return tmp;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerBMPString.cs b/bc-sharp-crypto/src/asn1/DerBMPString.cs
new file mode 100644
index 0000000000000000000000000000000000000000..33d950ff80526450f793ce66bae671b47c235e35
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerBMPString.cs
@@ -0,0 +1,117 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * Der BMPString object.
+ */
+ public class DerBmpString
+ : DerStringBase
+ {
+ private readonly string str;
+
+ /**
+ * return a BMP string from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static DerBmpString GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is DerBmpString)
+ {
+ return (DerBmpString)obj;
+ }
+
+ throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
+ }
+
+ /**
+ * return a BMP string from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DerBmpString GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ Asn1Object o = obj.GetObject();
+
+ if (isExplicit || o is DerBmpString)
+ {
+ return GetInstance(o);
+ }
+
+ return new DerBmpString(Asn1OctetString.GetInstance(o).GetOctets());
+ }
+
+ /**
+ * basic constructor - byte encoded string.
+ */
+ public DerBmpString(
+ byte[] str)
+ {
+ if (str == null)
+ throw new ArgumentNullException("str");
+
+ char[] cs = new char[str.Length / 2];
+
+ for (int i = 0; i != cs.Length; i++)
+ {
+ cs[i] = (char)((str[2 * i] << 8) | (str[2 * i + 1] & 0xff));
+ }
+
+ this.str = new string(cs);
+ }
+
+ /**
+ * basic constructor
+ */
+ public DerBmpString(
+ string str)
+ {
+ if (str == null)
+ throw new ArgumentNullException("str");
+
+ this.str = str;
+ }
+
+ public override string GetString()
+ {
+ return str;
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerBmpString other = asn1Object as DerBmpString;
+
+ if (other == null)
+ return false;
+
+ return this.str.Equals(other.str);
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ char[] c = str.ToCharArray();
+ byte[] b = new byte[c.Length * 2];
+
+ for (int i = 0; i != c.Length; i++)
+ {
+ b[2 * i] = (byte)(c[i] >> 8);
+ b[2 * i + 1] = (byte)c[i];
+ }
+
+ derOut.WriteEncoded(Asn1Tags.BmpString, b);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerBitString.cs b/bc-sharp-crypto/src/asn1/DerBitString.cs
new file mode 100644
index 0000000000000000000000000000000000000000..26adc575bad81ef74fa3be5d51ce464fe466cfc0
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerBitString.cs
@@ -0,0 +1,276 @@
+using System;
+using System.Diagnostics;
+using System.Text;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class DerBitString
+ : DerStringBase
+ {
+ private static readonly char[] table
+ = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+ protected readonly byte[] mData;
+ protected readonly int mPadBits;
+
+ /**
+ * return a Bit string from the passed in object
+ *
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static DerBitString GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is DerBitString)
+ {
+ return (DerBitString) obj;
+ }
+ if (obj is byte[])
+ {
+ try
+ {
+ return (DerBitString)FromByteArray((byte[])obj);
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("encoding error in GetInstance: " + e.ToString());
+ }
+ }
+
+ throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
+ }
+
+ /**
+ * return a Bit string from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DerBitString GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ Asn1Object o = obj.GetObject();
+
+ if (isExplicit || o is DerBitString)
+ {
+ return GetInstance(o);
+ }
+
+ return FromAsn1Octets(((Asn1OctetString)o).GetOctets());
+ }
+
+ /**
+ * @param data the octets making up the bit string.
+ * @param padBits the number of extra bits at the end of the string.
+ */
+ public DerBitString(
+ byte[] data,
+ int padBits)
+ {
+ if (data == null)
+ throw new ArgumentNullException("data");
+ if (padBits < 0 || padBits > 7)
+ throw new ArgumentException("must be in the range 0 to 7", "padBits");
+ if (data.Length == 0 && padBits != 0)
+ throw new ArgumentException("if 'data' is empty, 'padBits' must be 0");
+
+ this.mData = Arrays.Clone(data);
+ this.mPadBits = padBits;
+ }
+
+ public DerBitString(
+ byte[] data)
+ : this(data, 0)
+ {
+ }
+
+ public DerBitString(
+ int namedBits)
+ {
+ if (namedBits == 0)
+ {
+ this.mData = new byte[0];
+ this.mPadBits = 0;
+ return;
+ }
+
+ int bits = BigInteger.BitLen(namedBits);
+ int bytes = (bits + 7) / 8;
+
+ Debug.Assert(0 < bytes && bytes <= 4);
+
+ byte[] data = new byte[bytes];
+ --bytes;
+
+ for (int i = 0; i < bytes; i++)
+ {
+ data[i] = (byte)namedBits;
+ namedBits >>= 8;
+ }
+
+ Debug.Assert((namedBits & 0xFF) != 0);
+
+ data[bytes] = (byte)namedBits;
+
+ int padBits = 0;
+ while ((namedBits & (1 << padBits)) == 0)
+ {
+ ++padBits;
+ }
+
+ Debug.Assert(padBits < 8);
+
+ this.mData = data;
+ this.mPadBits = padBits;
+ }
+
+ public DerBitString(
+ Asn1Encodable obj)
+ : this(obj.GetDerEncoded())
+ {
+ }
+
+ /**
+ * Return the octets contained in this BIT STRING, checking that this BIT STRING really
+ * does represent an octet aligned string. Only use this method when the standard you are
+ * following dictates that the BIT STRING will be octet aligned.
+ *
+ * @return a copy of the octet aligned data.
+ */
+ public virtual byte[] GetOctets()
+ {
+ if (mPadBits != 0)
+ throw new InvalidOperationException("attempt to get non-octet aligned data from BIT STRING");
+
+ return Arrays.Clone(mData);
+ }
+
+ public virtual byte[] GetBytes()
+ {
+ byte[] data = Arrays.Clone(mData);
+
+ // DER requires pad bits be zero
+ if (mPadBits > 0)
+ {
+ data[data.Length - 1] &= (byte)(0xFF << mPadBits);
+ }
+
+ return data;
+ }
+
+ public virtual int PadBits
+ {
+ get { return mPadBits; }
+ }
+
+ /**
+ * @return the value of the bit string as an int (truncating if necessary)
+ */
+ public virtual int IntValue
+ {
+ get
+ {
+ int value = 0, length = System.Math.Min(4, mData.Length);
+ for (int i = 0; i < length; ++i)
+ {
+ value |= (int)mData[i] << (8 * i);
+ }
+ if (mPadBits > 0 && length == mData.Length)
+ {
+ int mask = (1 << mPadBits) - 1;
+ value &= ~(mask << (8 * (length - 1)));
+ }
+ return value;
+ }
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ if (mPadBits > 0)
+ {
+ int last = mData[mData.Length - 1];
+ int mask = (1 << mPadBits) - 1;
+ int unusedBits = last & mask;
+
+ if (unusedBits != 0)
+ {
+ byte[] contents = Arrays.Prepend(mData, (byte)mPadBits);
+
+ /*
+ * X.690-0207 11.2.1: Each unused bit in the final octet of the encoding of a bit string value shall be set to zero.
+ */
+ contents[contents.Length - 1] = (byte)(last ^ unusedBits);
+
+ derOut.WriteEncoded(Asn1Tags.BitString, contents);
+ return;
+ }
+ }
+
+ derOut.WriteEncoded(Asn1Tags.BitString, (byte)mPadBits, mData);
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ return mPadBits.GetHashCode() ^ Arrays.GetHashCode(mData);
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerBitString other = asn1Object as DerBitString;
+
+ if (other == null)
+ return false;
+
+ return this.mPadBits == other.mPadBits
+ && Arrays.AreEqual(this.mData, other.mData);
+ }
+
+ public override string GetString()
+ {
+ StringBuilder buffer = new StringBuilder("#");
+
+ byte[] str = GetDerEncoded();
+
+ for (int i = 0; i != str.Length; i++)
+ {
+ uint ubyte = str[i];
+ buffer.Append(table[(ubyte >> 4) & 0xf]);
+ buffer.Append(table[str[i] & 0xf]);
+ }
+
+ return buffer.ToString();
+ }
+
+ internal static DerBitString FromAsn1Octets(byte[] octets)
+ {
+ if (octets.Length < 1)
+ throw new ArgumentException("truncated BIT STRING detected", "octets");
+
+ int padBits = octets[0];
+ byte[] data = Arrays.CopyOfRange(octets, 1, octets.Length);
+
+ if (padBits > 0 && padBits < 8 && data.Length > 0)
+ {
+ int last = data[data.Length - 1];
+ int mask = (1 << padBits) - 1;
+
+ if ((last & mask) != 0)
+ {
+ return new BerBitString(data, padBits);
+ }
+ }
+
+ return new DerBitString(data, padBits);
+ }
+ }
+}
+
diff --git a/bc-sharp-crypto/src/asn1/DerBoolean.cs b/bc-sharp-crypto/src/asn1/DerBoolean.cs
new file mode 100644
index 0000000000000000000000000000000000000000..709f4ddce5cc2ff78fb0daa46b5390757b5df4a6
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerBoolean.cs
@@ -0,0 +1,124 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class DerBoolean
+ : Asn1Object
+ {
+ private readonly byte value;
+
+ public static readonly DerBoolean False = new DerBoolean(false);
+ public static readonly DerBoolean True = new DerBoolean(true);
+
+ /**
+ * return a bool from the passed in object.
+ *
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static DerBoolean GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is DerBoolean)
+ {
+ return (DerBoolean) obj;
+ }
+
+ throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
+ }
+
+ /**
+ * return a DerBoolean from the passed in bool.
+ */
+ public static DerBoolean GetInstance(
+ bool value)
+ {
+ return value ? True : False;
+ }
+
+ /**
+ * return a Boolean from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DerBoolean GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ Asn1Object o = obj.GetObject();
+
+ if (isExplicit || o is DerBoolean)
+ {
+ return GetInstance(o);
+ }
+
+ return FromOctetString(((Asn1OctetString)o).GetOctets());
+ }
+
+ public DerBoolean(
+ byte[] val)
+ {
+ if (val.Length != 1)
+ throw new ArgumentException("byte value should have 1 byte in it", "val");
+
+ // TODO Are there any constraints on the possible byte values?
+ this.value = val[0];
+ }
+
+ private DerBoolean(
+ bool value)
+ {
+ this.value = value ? (byte)0xff : (byte)0;
+ }
+
+ public bool IsTrue
+ {
+ get { return value != 0; }
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ // TODO Should we make sure the byte value is one of '0' or '0xff' here?
+ derOut.WriteEncoded(Asn1Tags.Boolean, new byte[]{ value });
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerBoolean other = asn1Object as DerBoolean;
+
+ if (other == null)
+ return false;
+
+ return IsTrue == other.IsTrue;
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ return IsTrue.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return IsTrue ? "TRUE" : "FALSE";
+ }
+
+ internal static DerBoolean FromOctetString(byte[] value)
+ {
+ if (value.Length != 1)
+ {
+ throw new ArgumentException("BOOLEAN value should have 1 byte in it", "value");
+ }
+
+ byte b = value[0];
+
+ return b == 0 ? False : b == 0xFF ? True : new DerBoolean(value);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerEnumerated.cs b/bc-sharp-crypto/src/asn1/DerEnumerated.cs
new file mode 100644
index 0000000000000000000000000000000000000000..db27065bb586beb4ac45665cec6513fd1ec352b7
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerEnumerated.cs
@@ -0,0 +1,135 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class DerEnumerated
+ : Asn1Object
+ {
+ private readonly byte[] bytes;
+
+ /**
+ * return an integer from the passed in object
+ *
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static DerEnumerated GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is DerEnumerated)
+ {
+ return (DerEnumerated)obj;
+ }
+
+ throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
+ }
+
+ /**
+ * return an Enumerated from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DerEnumerated GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ Asn1Object o = obj.GetObject();
+
+ if (isExplicit || o is DerEnumerated)
+ {
+ return GetInstance(o);
+ }
+
+ return FromOctetString(((Asn1OctetString)o).GetOctets());
+ }
+
+ public DerEnumerated(
+ int val)
+ {
+ bytes = BigInteger.ValueOf(val).ToByteArray();
+ }
+
+ public DerEnumerated(
+ BigInteger val)
+ {
+ bytes = val.ToByteArray();
+ }
+
+ public DerEnumerated(
+ byte[] bytes)
+ {
+ if (bytes.Length > 1)
+ {
+ if (bytes[0] == 0 && (bytes[1] & 0x80) == 0)
+ {
+ throw new ArgumentException("malformed enumerated");
+ }
+ if (bytes[0] == (byte)0xff && (bytes[1] & 0x80) != 0)
+ {
+ throw new ArgumentException("malformed enumerated");
+ }
+ }
+ this.bytes = Arrays.Clone(bytes);
+ }
+
+ public BigInteger Value
+ {
+ get { return new BigInteger(bytes); }
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ derOut.WriteEncoded(Asn1Tags.Enumerated, bytes);
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerEnumerated other = asn1Object as DerEnumerated;
+
+ if (other == null)
+ return false;
+
+ return Arrays.AreEqual(this.bytes, other.bytes);
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ return Arrays.GetHashCode(bytes);
+ }
+
+ private static readonly DerEnumerated[] cache = new DerEnumerated[12];
+
+ internal static DerEnumerated FromOctetString(byte[] enc)
+ {
+ if (enc.Length == 0)
+ {
+ throw new ArgumentException("ENUMERATED has zero length", "enc");
+ }
+
+ if (enc.Length == 1)
+ {
+ int value = enc[0];
+ if (value < cache.Length)
+ {
+ DerEnumerated cached = cache[value];
+ if (cached != null)
+ {
+ return cached;
+ }
+
+ return cache[value] = new DerEnumerated(Arrays.Clone(enc));
+ }
+ }
+
+ return new DerEnumerated(Arrays.Clone(enc));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerGeneralString.cs b/bc-sharp-crypto/src/asn1/DerGeneralString.cs
new file mode 100644
index 0000000000000000000000000000000000000000..553b0e09cebf5d3efc601a2df9d627799e73c77e
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerGeneralString.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class DerGeneralString
+ : DerStringBase
+ {
+ private readonly string str;
+
+ public static DerGeneralString GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is DerGeneralString)
+ {
+ return (DerGeneralString) obj;
+ }
+
+ throw new ArgumentException("illegal object in GetInstance: "
+ + Platform.GetTypeName(obj));
+ }
+
+ public static DerGeneralString GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ Asn1Object o = obj.GetObject();
+
+ if (isExplicit || o is DerGeneralString)
+ {
+ return GetInstance(o);
+ }
+
+ return new DerGeneralString(((Asn1OctetString)o).GetOctets());
+ }
+
+ public DerGeneralString(
+ byte[] str)
+ : this(Strings.FromAsciiByteArray(str))
+ {
+ }
+
+ public DerGeneralString(
+ string str)
+ {
+ if (str == null)
+ throw new ArgumentNullException("str");
+
+ this.str = str;
+ }
+
+ public override string GetString()
+ {
+ return str;
+ }
+
+ public byte[] GetOctets()
+ {
+ return Strings.ToAsciiByteArray(str);
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ derOut.WriteEncoded(Asn1Tags.GeneralString, GetOctets());
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerGeneralString other = asn1Object as DerGeneralString;
+
+ if (other == null)
+ return false;
+
+ return this.str.Equals(other.str);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerGeneralizedTime.cs b/bc-sharp-crypto/src/asn1/DerGeneralizedTime.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b224ebe425f749e523ed01f16ea0699c3211932c
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerGeneralizedTime.cs
@@ -0,0 +1,320 @@
+using System;
+using System.Globalization;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * Generalized time object.
+ */
+ public class DerGeneralizedTime
+ : Asn1Object
+ {
+ private readonly string time;
+
+ /**
+ * return a generalized time from the passed in object
+ *
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static DerGeneralizedTime GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is DerGeneralizedTime)
+ {
+ return (DerGeneralizedTime)obj;
+ }
+
+ throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * return a Generalized Time object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DerGeneralizedTime GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ Asn1Object o = obj.GetObject();
+
+ if (isExplicit || o is DerGeneralizedTime)
+ {
+ return GetInstance(o);
+ }
+
+ return new DerGeneralizedTime(((Asn1OctetString)o).GetOctets());
+ }
+
+ /**
+ * The correct format for this is YYYYMMDDHHMMSS[.f]Z, or without the Z
+ * for local time, or Z+-HHMM on the end, for difference between local
+ * time and UTC time. The fractional second amount f must consist of at
+ * least one number with trailing zeroes removed.
+ *
+ * @param time the time string.
+ * @exception ArgumentException if string is an illegal format.
+ */
+ public DerGeneralizedTime(
+ string time)
+ {
+ this.time = time;
+
+ try
+ {
+ ToDateTime();
+ }
+ catch (FormatException e)
+ {
+ throw new ArgumentException("invalid date string: " + e.Message);
+ }
+ }
+
+ /**
+ * base constructor from a local time object
+ */
+ public DerGeneralizedTime(
+ DateTime time)
+ {
+#if PORTABLE
+ this.time = time.ToUniversalTime().ToString(@"yyyyMMddHHmmss\Z");
+#else
+ this.time = time.ToString(@"yyyyMMddHHmmss\Z");
+#endif
+ }
+
+ internal DerGeneralizedTime(
+ byte[] bytes)
+ {
+ //
+ // explicitly convert to characters
+ //
+ this.time = Strings.FromAsciiByteArray(bytes);
+ }
+
+ /**
+ * Return the time.
+ * @return The time string as it appeared in the encoded object.
+ */
+ public string TimeString
+ {
+ get { return time; }
+ }
+
+ /**
+ * return the time - always in the form of
+ * YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm).
+ *
+ * Normally in a certificate we would expect "Z" rather than "GMT",
+ * however adding the "GMT" means we can just use:
+ *
+ * dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
+ *
+ * To read in the time and Get a date which is compatible with our local
+ * time zone.
+ */
+ public string GetTime()
+ {
+ //
+ // standardise the format.
+ //
+ if (time[time.Length - 1] == 'Z')
+ {
+ return time.Substring(0, time.Length - 1) + "GMT+00:00";
+ }
+ else
+ {
+ int signPos = time.Length - 5;
+ char sign = time[signPos];
+ if (sign == '-' || sign == '+')
+ {
+ return time.Substring(0, signPos)
+ + "GMT"
+ + time.Substring(signPos, 3)
+ + ":"
+ + time.Substring(signPos + 3);
+ }
+ else
+ {
+ signPos = time.Length - 3;
+ sign = time[signPos];
+ if (sign == '-' || sign == '+')
+ {
+ return time.Substring(0, signPos)
+ + "GMT"
+ + time.Substring(signPos)
+ + ":00";
+ }
+ }
+ }
+
+ return time + CalculateGmtOffset();
+ }
+
+ private string CalculateGmtOffset()
+ {
+ char sign = '+';
+ DateTime time = ToDateTime();
+
+#if SILVERLIGHT || PORTABLE
+ long offset = time.Ticks - time.ToUniversalTime().Ticks;
+ if (offset < 0)
+ {
+ sign = '-';
+ offset = -offset;
+ }
+ int hours = (int)(offset / TimeSpan.TicksPerHour);
+ int minutes = (int)(offset / TimeSpan.TicksPerMinute) % 60;
+#else
+ // Note: GetUtcOffset incorporates Daylight Savings offset
+ TimeSpan offset = TimeZone.CurrentTimeZone.GetUtcOffset(time);
+ if (offset.CompareTo(TimeSpan.Zero) < 0)
+ {
+ sign = '-';
+ offset = offset.Duration();
+ }
+ int hours = offset.Hours;
+ int minutes = offset.Minutes;
+#endif
+
+ return "GMT" + sign + Convert(hours) + ":" + Convert(minutes);
+ }
+
+ private static string Convert(
+ int time)
+ {
+ if (time < 10)
+ {
+ return "0" + time;
+ }
+
+ return time.ToString();
+ }
+
+ public DateTime ToDateTime()
+ {
+ string formatStr;
+ string d = time;
+ bool makeUniversal = false;
+
+ if (Platform.EndsWith(d, "Z"))
+ {
+ if (HasFractionalSeconds)
+ {
+ int fCount = d.Length - d.IndexOf('.') - 2;
+ formatStr = @"yyyyMMddHHmmss." + FString(fCount) + @"\Z";
+ }
+ else
+ {
+ formatStr = @"yyyyMMddHHmmss\Z";
+ }
+ }
+ else if (time.IndexOf('-') > 0 || time.IndexOf('+') > 0)
+ {
+ d = GetTime();
+ makeUniversal = true;
+
+ if (HasFractionalSeconds)
+ {
+ int fCount = Platform.IndexOf(d, "GMT") - 1 - d.IndexOf('.');
+ formatStr = @"yyyyMMddHHmmss." + FString(fCount) + @"'GMT'zzz";
+ }
+ else
+ {
+ formatStr = @"yyyyMMddHHmmss'GMT'zzz";
+ }
+ }
+ else
+ {
+ if (HasFractionalSeconds)
+ {
+ int fCount = d.Length - 1 - d.IndexOf('.');
+ formatStr = @"yyyyMMddHHmmss." + FString(fCount);
+ }
+ else
+ {
+ formatStr = @"yyyyMMddHHmmss";
+ }
+
+ // TODO?
+// dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID()));
+ }
+
+ return ParseDateString(d, formatStr, makeUniversal);
+ }
+
+ private string FString(
+ int count)
+ {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < count; ++i)
+ {
+ sb.Append('f');
+ }
+ return sb.ToString();
+ }
+
+ private DateTime ParseDateString(string s, string format, bool makeUniversal)
+ {
+ /*
+ * NOTE: DateTime.Kind and DateTimeStyles.AssumeUniversal not available in .NET 1.1
+ */
+ DateTimeStyles style = DateTimeStyles.None;
+ if (Platform.EndsWith(format, "Z"))
+ {
+ try
+ {
+ style = (DateTimeStyles)Enums.GetEnumValue(typeof(DateTimeStyles), "AssumeUniversal");
+ }
+ catch (Exception)
+ {
+ }
+
+ style |= DateTimeStyles.AdjustToUniversal;
+ }
+
+ DateTime dt = DateTime.ParseExact(s, format, DateTimeFormatInfo.InvariantInfo, style);
+
+ return makeUniversal ? dt.ToUniversalTime() : dt;
+ }
+
+ private bool HasFractionalSeconds
+ {
+ get { return time.IndexOf('.') == 14; }
+ }
+
+ private byte[] GetOctets()
+ {
+ return Strings.ToAsciiByteArray(time);
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ derOut.WriteEncoded(Asn1Tags.GeneralizedTime, GetOctets());
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerGeneralizedTime other = asn1Object as DerGeneralizedTime;
+
+ if (other == null)
+ return false;
+
+ return this.time.Equals(other.time);
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ return time.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerGraphicString.cs b/bc-sharp-crypto/src/asn1/DerGraphicString.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f213f461db5c056bf1bf4f3a98a488fe50f2c125
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerGraphicString.cs
@@ -0,0 +1,103 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class DerGraphicString
+ : DerStringBase
+ {
+ private readonly byte[] mString;
+
+ /**
+ * return a Graphic String from the passed in object
+ *
+ * @param obj a DerGraphicString or an object that can be converted into one.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ * @return a DerGraphicString instance, or null.
+ */
+ public static DerGraphicString GetInstance(object obj)
+ {
+ if (obj == null || obj is DerGraphicString)
+ {
+ return (DerGraphicString)obj;
+ }
+
+ if (obj is byte[])
+ {
+ try
+ {
+ return (DerGraphicString)FromByteArray((byte[])obj);
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("encoding error in GetInstance: " + e.ToString(), "obj");
+ }
+ }
+
+ throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * return a Graphic String from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the tagged object cannot
+ * be converted.
+ * @return a DerGraphicString instance, or null.
+ */
+ public static DerGraphicString GetInstance(Asn1TaggedObject obj, bool isExplicit)
+ {
+ Asn1Object o = obj.GetObject();
+
+ if (isExplicit || o is DerGraphicString)
+ {
+ return GetInstance(o);
+ }
+
+ return new DerGraphicString(((Asn1OctetString)o).GetOctets());
+ }
+
+ /**
+ * basic constructor - with bytes.
+ * @param string the byte encoding of the characters making up the string.
+ */
+ public DerGraphicString(byte[] encoding)
+ {
+ this.mString = Arrays.Clone(encoding);
+ }
+
+ public override string GetString()
+ {
+ return Strings.FromByteArray(mString);
+ }
+
+ public byte[] GetOctets()
+ {
+ return Arrays.Clone(mString);
+ }
+
+ internal override void Encode(DerOutputStream derOut)
+ {
+ derOut.WriteEncoded(Asn1Tags.GraphicString, mString);
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ return Arrays.GetHashCode(mString);
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerGraphicString other = asn1Object as DerGraphicString;
+
+ if (other == null)
+ return false;
+
+ return Arrays.AreEqual(mString, other.mString);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerIA5String.cs b/bc-sharp-crypto/src/asn1/DerIA5String.cs
new file mode 100644
index 0000000000000000000000000000000000000000..63e91582eee98ce573b15ec935f6ed69f107c879
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerIA5String.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * Der IA5String object - this is an ascii string.
+ */
+ public class DerIA5String
+ : DerStringBase
+ {
+ private readonly string str;
+
+ /**
+ * return a IA5 string from the passed in object
+ *
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static DerIA5String GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is DerIA5String)
+ {
+ return (DerIA5String)obj;
+ }
+
+ throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
+ }
+
+ /**
+ * return an IA5 string from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DerIA5String GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ Asn1Object o = obj.GetObject();
+
+ if (isExplicit || o is DerIA5String)
+ {
+ return GetInstance(o);
+ }
+
+ return new DerIA5String(((Asn1OctetString)o).GetOctets());
+ }
+
+ /**
+ * basic constructor - with bytes.
+ */
+ public DerIA5String(
+ byte[] str)
+ : this(Strings.FromAsciiByteArray(str), false)
+ {
+ }
+
+ /**
+ * basic constructor - without validation.
+ */
+ public DerIA5String(
+ string str)
+ : this(str, false)
+ {
+ }
+
+ /**
+ * Constructor with optional validation.
+ *
+ * @param string the base string to wrap.
+ * @param validate whether or not to check the string.
+ * @throws ArgumentException if validate is true and the string
+ * contains characters that should not be in an IA5String.
+ */
+ public DerIA5String(
+ string str,
+ bool validate)
+ {
+ if (str == null)
+ throw new ArgumentNullException("str");
+ if (validate && !IsIA5String(str))
+ throw new ArgumentException("string contains illegal characters", "str");
+
+ this.str = str;
+ }
+
+ public override string GetString()
+ {
+ return str;
+ }
+
+ public byte[] GetOctets()
+ {
+ return Strings.ToAsciiByteArray(str);
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ derOut.WriteEncoded(Asn1Tags.IA5String, GetOctets());
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ return this.str.GetHashCode();
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerIA5String other = asn1Object as DerIA5String;
+
+ if (other == null)
+ return false;
+
+ return this.str.Equals(other.str);
+ }
+
+ /**
+ * return true if the passed in String can be represented without
+ * loss as an IA5String, false otherwise.
+ *
+ * @return true if in printable set, false otherwise.
+ */
+ public static bool IsIA5String(
+ string str)
+ {
+ foreach (char ch in str)
+ {
+ if (ch > 0x007f)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerInteger.cs b/bc-sharp-crypto/src/asn1/DerInteger.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5b240d281ba65ea443caac5c11713b177fcffcce
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerInteger.cs
@@ -0,0 +1,128 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class DerInteger
+ : Asn1Object
+ {
+ private readonly byte[] bytes;
+
+ /**
+ * return an integer from the passed in object
+ *
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static DerInteger GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is DerInteger)
+ {
+ return (DerInteger)obj;
+ }
+
+ throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
+ }
+
+ /**
+ * return an Integer from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param isExplicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DerInteger GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ if (obj == null)
+ throw new ArgumentNullException("obj");
+
+ Asn1Object o = obj.GetObject();
+
+ if (isExplicit || o is DerInteger)
+ {
+ return GetInstance(o);
+ }
+
+ return new DerInteger(Asn1OctetString.GetInstance(o).GetOctets());
+ }
+
+ public DerInteger(
+ int value)
+ {
+ bytes = BigInteger.ValueOf(value).ToByteArray();
+ }
+
+ public DerInteger(
+ BigInteger value)
+ {
+ if (value == null)
+ throw new ArgumentNullException("value");
+
+ bytes = value.ToByteArray();
+ }
+
+ public DerInteger(
+ byte[] bytes)
+ {
+ if (bytes.Length > 1)
+ {
+ if (bytes[0] == 0 && (bytes[1] & 0x80) == 0)
+ {
+ throw new ArgumentException("malformed integer");
+ }
+ if (bytes[0] == (byte)0xff && (bytes[1] & 0x80) != 0)
+ {
+ throw new ArgumentException("malformed integer");
+ }
+ }
+ this.bytes = Arrays.Clone(bytes);
+ }
+
+ public BigInteger Value
+ {
+ get { return new BigInteger(bytes); }
+ }
+
+ /**
+ * in some cases positive values Get crammed into a space,
+ * that's not quite big enough...
+ */
+ public BigInteger PositiveValue
+ {
+ get { return new BigInteger(1, bytes); }
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ derOut.WriteEncoded(Asn1Tags.Integer, bytes);
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ return Arrays.GetHashCode(bytes);
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerInteger other = asn1Object as DerInteger;
+
+ if (other == null)
+ return false;
+
+ return Arrays.AreEqual(this.bytes, other.bytes);
+ }
+
+ public override string ToString()
+ {
+ return Value.ToString();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerNull.cs b/bc-sharp-crypto/src/asn1/DerNull.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a802f64860da2bf8f6bba0e8cf9afcf962ec09a1
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerNull.cs
@@ -0,0 +1,41 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * A Null object.
+ */
+ public class DerNull
+ : Asn1Null
+ {
+ public static readonly DerNull Instance = new DerNull(0);
+
+ byte[] zeroBytes = new byte[0];
+
+ [Obsolete("Use static Instance object")]
+ public DerNull()
+ {
+ }
+
+ protected internal DerNull(int dummy)
+ {
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ derOut.WriteEncoded(Asn1Tags.Null, zeroBytes);
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ return asn1Object is DerNull;
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ return -1;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerNumericString.cs b/bc-sharp-crypto/src/asn1/DerNumericString.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a729f9e8ea5908b1ee591a58904c4f035dc8037d
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerNumericString.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * Der NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }.
+ */
+ public class DerNumericString
+ : DerStringBase
+ {
+ private readonly string str;
+
+ /**
+ * return a Numeric string from the passed in object
+ *
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static DerNumericString GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is DerNumericString)
+ {
+ return (DerNumericString)obj;
+ }
+
+ throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
+ }
+
+ /**
+ * return an Numeric string from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DerNumericString GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ Asn1Object o = obj.GetObject();
+
+ if (isExplicit || o is DerNumericString)
+ {
+ return GetInstance(o);
+ }
+
+ return new DerNumericString(Asn1OctetString.GetInstance(o).GetOctets());
+ }
+
+ /**
+ * basic constructor - with bytes.
+ */
+ public DerNumericString(
+ byte[] str)
+ : this(Strings.FromAsciiByteArray(str), false)
+ {
+ }
+
+ /**
+ * basic constructor - without validation..
+ */
+ public DerNumericString(
+ string str)
+ : this(str, false)
+ {
+ }
+
+ /**
+ * Constructor with optional validation.
+ *
+ * @param string the base string to wrap.
+ * @param validate whether or not to check the string.
+ * @throws ArgumentException if validate is true and the string
+ * contains characters that should not be in a NumericString.
+ */
+ public DerNumericString(
+ string str,
+ bool validate)
+ {
+ if (str == null)
+ throw new ArgumentNullException("str");
+ if (validate && !IsNumericString(str))
+ throw new ArgumentException("string contains illegal characters", "str");
+
+ this.str = str;
+ }
+
+ public override string GetString()
+ {
+ return str;
+ }
+
+ public byte[] GetOctets()
+ {
+ return Strings.ToAsciiByteArray(str);
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ derOut.WriteEncoded(Asn1Tags.NumericString, GetOctets());
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerNumericString other = asn1Object as DerNumericString;
+
+ if (other == null)
+ return false;
+
+ return this.str.Equals(other.str);
+ }
+
+ /**
+ * Return true if the string can be represented as a NumericString ('0'..'9', ' ')
+ *
+ * @param str string to validate.
+ * @return true if numeric, fale otherwise.
+ */
+ public static bool IsNumericString(
+ string str)
+ {
+ foreach (char ch in str)
+ {
+ if (ch > 0x007f || (ch != ' ' && !char.IsDigit(ch)))
+ return false;
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerObjectIdentifier.cs b/bc-sharp-crypto/src/asn1/DerObjectIdentifier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6ac2b7e9e3f394bd51fa4fdb77545342e407f60f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerObjectIdentifier.cs
@@ -0,0 +1,347 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class DerObjectIdentifier
+ : Asn1Object
+ {
+ private readonly string identifier;
+
+ private byte[] body = null;
+
+ /**
+ * return an Oid from the passed in object
+ *
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static DerObjectIdentifier GetInstance(object obj)
+ {
+ if (obj == null || obj is DerObjectIdentifier)
+ return (DerObjectIdentifier) obj;
+ if (obj is byte[])
+ return FromOctetString((byte[])obj);
+ throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * return an object Identifier from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DerObjectIdentifier GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(obj.GetObject());
+ }
+
+ public DerObjectIdentifier(
+ string identifier)
+ {
+ if (identifier == null)
+ throw new ArgumentNullException("identifier");
+ if (!IsValidIdentifier(identifier))
+ throw new FormatException("string " + identifier + " not an OID");
+
+ this.identifier = identifier;
+ }
+
+ internal DerObjectIdentifier(DerObjectIdentifier oid, string branchID)
+ {
+ if (!IsValidBranchID(branchID, 0))
+ throw new ArgumentException("string " + branchID + " not a valid OID branch", "branchID");
+
+ this.identifier = oid.Id + "." + branchID;
+ }
+
+ // TODO Change to ID?
+ public string Id
+ {
+ get { return identifier; }
+ }
+
+ public virtual DerObjectIdentifier Branch(string branchID)
+ {
+ return new DerObjectIdentifier(this, branchID);
+ }
+
+ /**
+ * Return true if this oid is an extension of the passed in branch, stem.
+ * @param stem the arc or branch that is a possible parent.
+ * @return true if the branch is on the passed in stem, false otherwise.
+ */
+ public virtual bool On(DerObjectIdentifier stem)
+ {
+ string id = Id, stemId = stem.Id;
+ return id.Length > stemId.Length && id[stemId.Length] == '.' && Platform.StartsWith(id, stemId);
+ }
+
+ internal DerObjectIdentifier(byte[] bytes)
+ {
+ this.identifier = MakeOidStringFromBytes(bytes);
+ this.body = Arrays.Clone(bytes);
+ }
+
+ private void WriteField(
+ Stream outputStream,
+ long fieldValue)
+ {
+ byte[] result = new byte[9];
+ int pos = 8;
+ result[pos] = (byte)(fieldValue & 0x7f);
+ while (fieldValue >= (1L << 7))
+ {
+ fieldValue >>= 7;
+ result[--pos] = (byte)((fieldValue & 0x7f) | 0x80);
+ }
+ outputStream.Write(result, pos, 9 - pos);
+ }
+
+ private void WriteField(
+ Stream outputStream,
+ BigInteger fieldValue)
+ {
+ int byteCount = (fieldValue.BitLength + 6) / 7;
+ if (byteCount == 0)
+ {
+ outputStream.WriteByte(0);
+ }
+ else
+ {
+ BigInteger tmpValue = fieldValue;
+ byte[] tmp = new byte[byteCount];
+ for (int i = byteCount-1; i >= 0; i--)
+ {
+ tmp[i] = (byte) ((tmpValue.IntValue & 0x7f) | 0x80);
+ tmpValue = tmpValue.ShiftRight(7);
+ }
+ tmp[byteCount-1] &= 0x7f;
+ outputStream.Write(tmp, 0, tmp.Length);
+ }
+ }
+
+ private void DoOutput(MemoryStream bOut)
+ {
+ OidTokenizer tok = new OidTokenizer(identifier);
+
+ string token = tok.NextToken();
+ int first = int.Parse(token) * 40;
+
+ token = tok.NextToken();
+ if (token.Length <= 18)
+ {
+ WriteField(bOut, first + Int64.Parse(token));
+ }
+ else
+ {
+ WriteField(bOut, new BigInteger(token).Add(BigInteger.ValueOf(first)));
+ }
+
+ while (tok.HasMoreTokens)
+ {
+ token = tok.NextToken();
+ if (token.Length <= 18)
+ {
+ WriteField(bOut, Int64.Parse(token));
+ }
+ else
+ {
+ WriteField(bOut, new BigInteger(token));
+ }
+ }
+ }
+
+ internal byte[] GetBody()
+ {
+ lock (this)
+ {
+ if (body == null)
+ {
+ MemoryStream bOut = new MemoryStream();
+ DoOutput(bOut);
+ body = bOut.ToArray();
+ }
+ }
+
+ return body;
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ derOut.WriteEncoded(Asn1Tags.ObjectIdentifier, GetBody());
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ return identifier.GetHashCode();
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerObjectIdentifier other = asn1Object as DerObjectIdentifier;
+
+ if (other == null)
+ return false;
+
+ return this.identifier.Equals(other.identifier);
+ }
+
+ public override string ToString()
+ {
+ return identifier;
+ }
+
+ private static bool IsValidBranchID(
+ String branchID, int start)
+ {
+ bool periodAllowed = false;
+
+ int pos = branchID.Length;
+ while (--pos >= start)
+ {
+ char ch = branchID[pos];
+
+ // TODO Leading zeroes?
+ if ('0' <= ch && ch <= '9')
+ {
+ periodAllowed = true;
+ continue;
+ }
+
+ if (ch == '.')
+ {
+ if (!periodAllowed)
+ return false;
+
+ periodAllowed = false;
+ continue;
+ }
+
+ return false;
+ }
+
+ return periodAllowed;
+ }
+
+ private static bool IsValidIdentifier(string identifier)
+ {
+ if (identifier.Length < 3 || identifier[1] != '.')
+ return false;
+
+ char first = identifier[0];
+ if (first < '0' || first > '2')
+ return false;
+
+ return IsValidBranchID(identifier, 2);
+ }
+
+ private const long LONG_LIMIT = (long.MaxValue >> 7) - 0x7f;
+
+ private static string MakeOidStringFromBytes(
+ byte[] bytes)
+ {
+ StringBuilder objId = new StringBuilder();
+ long value = 0;
+ BigInteger bigValue = null;
+ bool first = true;
+
+ for (int i = 0; i != bytes.Length; i++)
+ {
+ int b = bytes[i];
+
+ if (value <= LONG_LIMIT)
+ {
+ value += (b & 0x7f);
+ if ((b & 0x80) == 0) // end of number reached
+ {
+ if (first)
+ {
+ if (value < 40)
+ {
+ objId.Append('0');
+ }
+ else if (value < 80)
+ {
+ objId.Append('1');
+ value -= 40;
+ }
+ else
+ {
+ objId.Append('2');
+ value -= 80;
+ }
+ first = false;
+ }
+
+ objId.Append('.');
+ objId.Append(value);
+ value = 0;
+ }
+ else
+ {
+ value <<= 7;
+ }
+ }
+ else
+ {
+ if (bigValue == null)
+ {
+ bigValue = BigInteger.ValueOf(value);
+ }
+ bigValue = bigValue.Or(BigInteger.ValueOf(b & 0x7f));
+ if ((b & 0x80) == 0)
+ {
+ if (first)
+ {
+ objId.Append('2');
+ bigValue = bigValue.Subtract(BigInteger.ValueOf(80));
+ first = false;
+ }
+
+ objId.Append('.');
+ objId.Append(bigValue);
+ bigValue = null;
+ value = 0;
+ }
+ else
+ {
+ bigValue = bigValue.ShiftLeft(7);
+ }
+ }
+ }
+
+ return objId.ToString();
+ }
+
+ private static readonly DerObjectIdentifier[] cache = new DerObjectIdentifier[1024];
+
+ internal static DerObjectIdentifier FromOctetString(byte[] enc)
+ {
+ int hashCode = Arrays.GetHashCode(enc);
+ int first = hashCode & 1023;
+
+ lock (cache)
+ {
+ DerObjectIdentifier entry = cache[first];
+ if (entry != null && Arrays.AreEqual(enc, entry.GetBody()))
+ {
+ return entry;
+ }
+
+ return cache[first] = new DerObjectIdentifier(enc);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerOctetString.cs b/bc-sharp-crypto/src/asn1/DerOctetString.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c046c94027e4792f71cc423f9bdea78d1dee27fa
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerOctetString.cs
@@ -0,0 +1,34 @@
+namespace Org.BouncyCastle.Asn1
+{
+ public class DerOctetString
+ : Asn1OctetString
+ {
+ /// The octets making up the octet string.
+ public DerOctetString(
+ byte[] str)
+ : base(str)
+ {
+ }
+
+ public DerOctetString(
+ Asn1Encodable obj)
+ : base(obj)
+ {
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ derOut.WriteEncoded(Asn1Tags.OctetString, str);
+ }
+
+ internal static void Encode(
+ DerOutputStream derOut,
+ byte[] bytes,
+ int offset,
+ int length)
+ {
+ derOut.WriteEncoded(Asn1Tags.OctetString, bytes, offset, length);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerOutputStream.cs b/bc-sharp-crypto/src/asn1/DerOutputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..69d5d5f28054e236177ef907055b70b074aace3b
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerOutputStream.cs
@@ -0,0 +1,171 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class DerOutputStream
+ : FilterStream
+ {
+ public DerOutputStream(Stream os)
+ : base(os)
+ {
+ }
+
+ private void WriteLength(
+ int length)
+ {
+ if (length > 127)
+ {
+ int size = 1;
+ uint val = (uint)length;
+
+ while ((val >>= 8) != 0)
+ {
+ size++;
+ }
+
+ WriteByte((byte)(size | 0x80));
+
+ for (int i = (size - 1) * 8; i >= 0; i -= 8)
+ {
+ WriteByte((byte)(length >> i));
+ }
+ }
+ else
+ {
+ WriteByte((byte)length);
+ }
+ }
+
+ internal void WriteEncoded(
+ int tag,
+ byte[] bytes)
+ {
+ WriteByte((byte)tag);
+ WriteLength(bytes.Length);
+ Write(bytes, 0, bytes.Length);
+ }
+
+ internal void WriteEncoded(
+ int tag,
+ byte first,
+ byte[] bytes)
+ {
+ WriteByte((byte)tag);
+ WriteLength(bytes.Length + 1);
+ WriteByte(first);
+ Write(bytes, 0, bytes.Length);
+ }
+
+ internal void WriteEncoded(
+ int tag,
+ byte[] bytes,
+ int offset,
+ int length)
+ {
+ WriteByte((byte)tag);
+ WriteLength(length);
+ Write(bytes, offset, length);
+ }
+
+ internal void WriteTag(
+ int flags,
+ int tagNo)
+ {
+ if (tagNo < 31)
+ {
+ WriteByte((byte)(flags | tagNo));
+ }
+ else
+ {
+ WriteByte((byte)(flags | 0x1f));
+ if (tagNo < 128)
+ {
+ WriteByte((byte)tagNo);
+ }
+ else
+ {
+ byte[] stack = new byte[5];
+ int pos = stack.Length;
+
+ stack[--pos] = (byte)(tagNo & 0x7F);
+
+ do
+ {
+ tagNo >>= 7;
+ stack[--pos] = (byte)(tagNo & 0x7F | 0x80);
+ }
+ while (tagNo > 127);
+
+ Write(stack, pos, stack.Length - pos);
+ }
+ }
+ }
+
+ internal void WriteEncoded(
+ int flags,
+ int tagNo,
+ byte[] bytes)
+ {
+ WriteTag(flags, tagNo);
+ WriteLength(bytes.Length);
+ Write(bytes, 0, bytes.Length);
+ }
+
+ protected void WriteNull()
+ {
+ WriteByte(Asn1Tags.Null);
+ WriteByte(0x00);
+ }
+
+ [Obsolete("Use version taking an Asn1Encodable arg instead")]
+ public virtual void WriteObject(
+ object obj)
+ {
+ if (obj == null)
+ {
+ WriteNull();
+ }
+ else if (obj is Asn1Object)
+ {
+ ((Asn1Object)obj).Encode(this);
+ }
+ else if (obj is Asn1Encodable)
+ {
+ ((Asn1Encodable)obj).ToAsn1Object().Encode(this);
+ }
+ else
+ {
+ throw new IOException("object not Asn1Object");
+ }
+ }
+
+ public virtual void WriteObject(
+ Asn1Encodable obj)
+ {
+ if (obj == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ obj.ToAsn1Object().Encode(this);
+ }
+ }
+
+ public virtual void WriteObject(
+ Asn1Object obj)
+ {
+ if (obj == null)
+ {
+ WriteNull();
+ }
+ else
+ {
+ obj.Encode(this);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerPrintableString.cs b/bc-sharp-crypto/src/asn1/DerPrintableString.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e1797346d54dcbaebea30a08863773d795f0387b
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerPrintableString.cs
@@ -0,0 +1,163 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * Der PrintableString object.
+ */
+ public class DerPrintableString
+ : DerStringBase
+ {
+ private readonly string str;
+
+ /**
+ * return a printable string from the passed in object.
+ *
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static DerPrintableString GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is DerPrintableString)
+ {
+ return (DerPrintableString)obj;
+ }
+
+ throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
+ }
+
+ /**
+ * return a Printable string from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DerPrintableString GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ Asn1Object o = obj.GetObject();
+
+ if (isExplicit || o is DerPrintableString)
+ {
+ return GetInstance(o);
+ }
+
+ return new DerPrintableString(Asn1OctetString.GetInstance(o).GetOctets());
+ }
+
+ /**
+ * basic constructor - byte encoded string.
+ */
+ public DerPrintableString(
+ byte[] str)
+ : this(Strings.FromAsciiByteArray(str), false)
+ {
+ }
+
+ /**
+ * basic constructor - this does not validate the string
+ */
+ public DerPrintableString(
+ string str)
+ : this(str, false)
+ {
+ }
+
+ /**
+ * Constructor with optional validation.
+ *
+ * @param string the base string to wrap.
+ * @param validate whether or not to check the string.
+ * @throws ArgumentException if validate is true and the string
+ * contains characters that should not be in a PrintableString.
+ */
+ public DerPrintableString(
+ string str,
+ bool validate)
+ {
+ if (str == null)
+ throw new ArgumentNullException("str");
+ if (validate && !IsPrintableString(str))
+ throw new ArgumentException("string contains illegal characters", "str");
+
+ this.str = str;
+ }
+
+ public override string GetString()
+ {
+ return str;
+ }
+
+ public byte[] GetOctets()
+ {
+ return Strings.ToAsciiByteArray(str);
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ derOut.WriteEncoded(Asn1Tags.PrintableString, GetOctets());
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerPrintableString other = asn1Object as DerPrintableString;
+
+ if (other == null)
+ return false;
+
+ return this.str.Equals(other.str);
+ }
+
+ /**
+ * return true if the passed in String can be represented without
+ * loss as a PrintableString, false otherwise.
+ *
+ * @return true if in printable set, false otherwise.
+ */
+ public static bool IsPrintableString(
+ string str)
+ {
+ foreach (char ch in str)
+ {
+ if (ch > 0x007f)
+ return false;
+
+ if (char.IsLetterOrDigit(ch))
+ continue;
+
+// if (char.IsPunctuation(ch))
+// continue;
+
+ switch (ch)
+ {
+ case ' ':
+ case '\'':
+ case '(':
+ case ')':
+ case '+':
+ case '-':
+ case '.':
+ case ':':
+ case '=':
+ case '?':
+ case '/':
+ case ',':
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerSequence.cs b/bc-sharp-crypto/src/asn1/DerSequence.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a76cf288261ea58f55f02002237dabece82ba2ed
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerSequence.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class DerSequence
+ : Asn1Sequence
+ {
+ public static readonly DerSequence Empty = new DerSequence();
+
+ public static DerSequence FromVector(
+ Asn1EncodableVector v)
+ {
+ return v.Count < 1 ? Empty : new DerSequence(v);
+ }
+
+ /**
+ * create an empty sequence
+ */
+ public DerSequence()
+ : base(0)
+ {
+ }
+
+ /**
+ * create a sequence containing one object
+ */
+ public DerSequence(
+ Asn1Encodable obj)
+ : base(1)
+ {
+ AddObject(obj);
+ }
+
+ public DerSequence(
+ params Asn1Encodable[] v)
+ : base(v.Length)
+ {
+ foreach (Asn1Encodable ae in v)
+ {
+ AddObject(ae);
+ }
+ }
+
+ /**
+ * create a sequence containing a vector of objects.
+ */
+ public DerSequence(
+ Asn1EncodableVector v)
+ : base(v.Count)
+ {
+ foreach (Asn1Encodable ae in v)
+ {
+ AddObject(ae);
+ }
+ }
+
+ /*
+ * A note on the implementation:
+ *
+ * As Der requires the constructed, definite-length model to
+ * be used for structured types, this varies slightly from the
+ * ASN.1 descriptions given. Rather than just outputing Sequence,
+ * we also have to specify Constructed, and the objects length.
+ */
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ // TODO Intermediate buffer could be avoided if we could calculate expected length
+ MemoryStream bOut = new MemoryStream();
+ DerOutputStream dOut = new DerOutputStream(bOut);
+
+ foreach (Asn1Encodable obj in this)
+ {
+ dOut.WriteObject(obj);
+ }
+
+ Platform.Dispose(dOut);
+
+ byte[] bytes = bOut.ToArray();
+
+ derOut.WriteEncoded(Asn1Tags.Sequence | Asn1Tags.Constructed, bytes);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerSet.cs b/bc-sharp-crypto/src/asn1/DerSet.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3df1a6766775f9bafaf4031850bc9cbe9d520f55
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerSet.cs
@@ -0,0 +1,111 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * A Der encoded set object
+ */
+ public class DerSet
+ : Asn1Set
+ {
+ public static readonly DerSet Empty = new DerSet();
+
+ public static DerSet FromVector(
+ Asn1EncodableVector v)
+ {
+ return v.Count < 1 ? Empty : new DerSet(v);
+ }
+
+ internal static DerSet FromVector(
+ Asn1EncodableVector v,
+ bool needsSorting)
+ {
+ return v.Count < 1 ? Empty : new DerSet(v, needsSorting);
+ }
+
+ /**
+ * create an empty set
+ */
+ public DerSet()
+ : base(0)
+ {
+ }
+
+ /**
+ * @param obj - a single object that makes up the set.
+ */
+ public DerSet(
+ Asn1Encodable obj)
+ : base(1)
+ {
+ AddObject(obj);
+ }
+
+ public DerSet(
+ params Asn1Encodable[] v)
+ : base(v.Length)
+ {
+ foreach (Asn1Encodable o in v)
+ {
+ AddObject(o);
+ }
+
+ Sort();
+ }
+
+ /**
+ * @param v - a vector of objects making up the set.
+ */
+ public DerSet(
+ Asn1EncodableVector v)
+ : this(v, true)
+ {
+ }
+
+ internal DerSet(
+ Asn1EncodableVector v,
+ bool needsSorting)
+ : base(v.Count)
+ {
+ foreach (Asn1Encodable o in v)
+ {
+ AddObject(o);
+ }
+
+ if (needsSorting)
+ {
+ Sort();
+ }
+ }
+
+ /*
+ * A note on the implementation:
+ *
+ * As Der requires the constructed, definite-length model to
+ * be used for structured types, this varies slightly from the
+ * ASN.1 descriptions given. Rather than just outputing Set,
+ * we also have to specify Constructed, and the objects length.
+ */
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ // TODO Intermediate buffer could be avoided if we could calculate expected length
+ MemoryStream bOut = new MemoryStream();
+ DerOutputStream dOut = new DerOutputStream(bOut);
+
+ foreach (Asn1Encodable obj in this)
+ {
+ dOut.WriteObject(obj);
+ }
+
+ Platform.Dispose(dOut);
+
+ byte[] bytes = bOut.ToArray();
+
+ derOut.WriteEncoded(Asn1Tags.Set | Asn1Tags.Constructed, bytes);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerStringBase.cs b/bc-sharp-crypto/src/asn1/DerStringBase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2a5fb041e085f5600d54264f16f58b7a11c8e93f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerStringBase.cs
@@ -0,0 +1,22 @@
+namespace Org.BouncyCastle.Asn1
+{
+ public abstract class DerStringBase
+ : Asn1Object, IAsn1String
+ {
+ protected DerStringBase()
+ {
+ }
+
+ public abstract string GetString();
+
+ public override string ToString()
+ {
+ return GetString();
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ return GetString().GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerT61String.cs b/bc-sharp-crypto/src/asn1/DerT61String.cs
new file mode 100644
index 0000000000000000000000000000000000000000..746ccfe703f5693899a815b8cbe6d0dc0dd1eb95
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerT61String.cs
@@ -0,0 +1,102 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * Der T61String (also the teletex string) - 8-bit characters
+ */
+ public class DerT61String
+ : DerStringBase
+ {
+ private readonly string str;
+
+ /**
+ * return a T61 string from the passed in object.
+ *
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static DerT61String GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is DerT61String)
+ {
+ return (DerT61String)obj;
+ }
+
+ throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
+ }
+
+ /**
+ * return an T61 string from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DerT61String GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ Asn1Object o = obj.GetObject();
+
+ if (isExplicit || o is DerT61String)
+ {
+ return GetInstance(o);
+ }
+
+ return new DerT61String(Asn1OctetString.GetInstance(o).GetOctets());
+ }
+
+ /**
+ * basic constructor - with bytes.
+ */
+ public DerT61String(
+ byte[] str)
+ : this(Strings.FromByteArray(str))
+ {
+ }
+
+ /**
+ * basic constructor - with string.
+ */
+ public DerT61String(
+ string str)
+ {
+ if (str == null)
+ throw new ArgumentNullException("str");
+
+ this.str = str;
+ }
+
+ public override string GetString()
+ {
+ return str;
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ derOut.WriteEncoded(Asn1Tags.T61String, GetOctets());
+ }
+
+ public byte[] GetOctets()
+ {
+ return Strings.ToByteArray(str);
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerT61String other = asn1Object as DerT61String;
+
+ if (other == null)
+ return false;
+
+ return this.str.Equals(other.str);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerTaggedObject.cs b/bc-sharp-crypto/src/asn1/DerTaggedObject.cs
new file mode 100644
index 0000000000000000000000000000000000000000..717d724b626de57b4bccbf35fee98a202bdb6d0c
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerTaggedObject.cs
@@ -0,0 +1,72 @@
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * DER TaggedObject - in ASN.1 notation this is any object preceded by
+ * a [n] where n is some number - these are assumed to follow the construction
+ * rules (as with sequences).
+ */
+ public class DerTaggedObject
+ : Asn1TaggedObject
+ {
+ /**
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public DerTaggedObject(
+ int tagNo,
+ Asn1Encodable obj)
+ : base(tagNo, obj)
+ {
+ }
+
+ /**
+ * @param explicitly true if an explicitly tagged object.
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public DerTaggedObject(
+ bool explicitly,
+ int tagNo,
+ Asn1Encodable obj)
+ : base(explicitly, tagNo, obj)
+ {
+ }
+
+ /**
+ * create an implicitly tagged object that contains a zero
+ * length sequence.
+ */
+ public DerTaggedObject(
+ int tagNo)
+ : base(false, tagNo, DerSequence.Empty)
+ {
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ if (!IsEmpty())
+ {
+ byte[] bytes = obj.GetDerEncoded();
+
+ if (explicitly)
+ {
+ derOut.WriteEncoded(Asn1Tags.Constructed | Asn1Tags.Tagged, tagNo, bytes);
+ }
+ else
+ {
+ //
+ // need to mark constructed types... (preserve Constructed tag)
+ //
+ int flags = (bytes[0] & Asn1Tags.Constructed) | Asn1Tags.Tagged;
+ derOut.WriteTag(flags, tagNo);
+ derOut.Write(bytes, 1, bytes.Length - 1);
+ }
+ }
+ else
+ {
+ derOut.WriteEncoded(Asn1Tags.Constructed | Asn1Tags.Tagged, tagNo, new byte[0]);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerUTCTime.cs b/bc-sharp-crypto/src/asn1/DerUTCTime.cs
new file mode 100644
index 0000000000000000000000000000000000000000..99af8bf6bf3c245b3f9de2e4267c4692edb56a85
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerUTCTime.cs
@@ -0,0 +1,267 @@
+using System;
+using System.Globalization;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * UTC time object.
+ */
+ public class DerUtcTime
+ : Asn1Object
+ {
+ private readonly string time;
+
+ /**
+ * return an UTC Time from the passed in object.
+ *
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static DerUtcTime GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is DerUtcTime)
+ {
+ return (DerUtcTime)obj;
+ }
+
+ throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
+ }
+
+ /**
+ * return an UTC Time from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DerUtcTime GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ Asn1Object o = obj.GetObject();
+
+ if (isExplicit || o is DerUtcTime)
+ {
+ return GetInstance(o);
+ }
+
+ return new DerUtcTime(((Asn1OctetString)o).GetOctets());
+ }
+
+ /**
+ * The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were
+ * never encoded. When you're creating one of these objects from scratch, that's
+ * what you want to use, otherwise we'll try to deal with whatever Gets read from
+ * the input stream... (this is why the input format is different from the GetTime()
+ * method output).
+ *
+ * @param time the time string.
+ */
+ public DerUtcTime(
+ string time)
+ {
+ if (time == null)
+ throw new ArgumentNullException("time");
+
+ this.time = time;
+
+ try
+ {
+ ToDateTime();
+ }
+ catch (FormatException e)
+ {
+ throw new ArgumentException("invalid date string: " + e.Message);
+ }
+ }
+
+ /**
+ * base constructor from a DateTime object
+ */
+ public DerUtcTime(
+ DateTime time)
+ {
+#if PORTABLE
+ this.time = time.ToUniversalTime().ToString("yyMMddHHmmss", CultureInfo.InvariantCulture) + "Z";
+#else
+ this.time = time.ToString("yyMMddHHmmss", CultureInfo.InvariantCulture) + "Z";
+#endif
+ }
+
+ internal DerUtcTime(
+ byte[] bytes)
+ {
+ //
+ // explicitly convert to characters
+ //
+ this.time = Strings.FromAsciiByteArray(bytes);
+ }
+
+// public DateTime ToDateTime()
+// {
+// string tm = this.AdjustedTimeString;
+//
+// return new DateTime(
+// Int16.Parse(tm.Substring(0, 4)),
+// Int16.Parse(tm.Substring(4, 2)),
+// Int16.Parse(tm.Substring(6, 2)),
+// Int16.Parse(tm.Substring(8, 2)),
+// Int16.Parse(tm.Substring(10, 2)),
+// Int16.Parse(tm.Substring(12, 2)));
+// }
+
+ /**
+ * return the time as a date based on whatever a 2 digit year will return. For
+ * standardised processing use ToAdjustedDateTime().
+ *
+ * @return the resulting date
+ * @exception ParseException if the date string cannot be parsed.
+ */
+ public DateTime ToDateTime()
+ {
+ return ParseDateString(TimeString, @"yyMMddHHmmss'GMT'zzz");
+ }
+
+ /**
+ * return the time as an adjusted date
+ * in the range of 1950 - 2049.
+ *
+ * @return a date in the range of 1950 to 2049.
+ * @exception ParseException if the date string cannot be parsed.
+ */
+ public DateTime ToAdjustedDateTime()
+ {
+ return ParseDateString(AdjustedTimeString, @"yyyyMMddHHmmss'GMT'zzz");
+ }
+
+ private DateTime ParseDateString(
+ string dateStr,
+ string formatStr)
+ {
+ DateTime dt = DateTime.ParseExact(
+ dateStr,
+ formatStr,
+ DateTimeFormatInfo.InvariantInfo);
+
+ return dt.ToUniversalTime();
+ }
+
+ /**
+ * return the time - always in the form of
+ * YYMMDDhhmmssGMT(+hh:mm|-hh:mm).
+ *
+ * Normally in a certificate we would expect "Z" rather than "GMT",
+ * however adding the "GMT" means we can just use:
+ *
+ * dateF = new SimpleDateFormat("yyMMddHHmmssz");
+ *
+ * To read in the time and Get a date which is compatible with our local
+ * time zone.
+ *
+ * Note: In some cases, due to the local date processing, this
+ * may lead to unexpected results. If you want to stick the normal
+ * convention of 1950 to 2049 use the GetAdjustedTime() method.
+ */
+ public string TimeString
+ {
+ get
+ {
+ //
+ // standardise the format.
+ //
+ if (time.IndexOf('-') < 0 && time.IndexOf('+') < 0)
+ {
+ if (time.Length == 11)
+ {
+ return time.Substring(0, 10) + "00GMT+00:00";
+ }
+ else
+ {
+ return time.Substring(0, 12) + "GMT+00:00";
+ }
+ }
+ else
+ {
+ int index = time.IndexOf('-');
+ if (index < 0)
+ {
+ index = time.IndexOf('+');
+ }
+ string d = time;
+
+ if (index == time.Length - 3)
+ {
+ d += "00";
+ }
+
+ if (index == 10)
+ {
+ return d.Substring(0, 10) + "00GMT" + d.Substring(10, 3) + ":" + d.Substring(13, 2);
+ }
+ else
+ {
+ return d.Substring(0, 12) + "GMT" + d.Substring(12, 3) + ":" + d.Substring(15, 2);
+ }
+ }
+ }
+ }
+
+ [Obsolete("Use 'AdjustedTimeString' property instead")]
+ public string AdjustedTime
+ {
+ get { return AdjustedTimeString; }
+ }
+
+ ///
+ /// Return a time string as an adjusted date with a 4 digit year.
+ /// This goes in the range of 1950 - 2049.
+ ///
+ public string AdjustedTimeString
+ {
+ get
+ {
+ string d = TimeString;
+ string c = d[0] < '5' ? "20" : "19";
+
+ return c + d;
+ }
+ }
+
+ private byte[] GetOctets()
+ {
+ return Strings.ToAsciiByteArray(time);
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ derOut.WriteEncoded(Asn1Tags.UtcTime, GetOctets());
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerUtcTime other = asn1Object as DerUtcTime;
+
+ if (other == null)
+ return false;
+
+ return this.time.Equals(other.time);
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ return time.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return time;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerUTF8String.cs b/bc-sharp-crypto/src/asn1/DerUTF8String.cs
new file mode 100644
index 0000000000000000000000000000000000000000..758a5068ddb180969029ec98f281aa68b2048689
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerUTF8String.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * Der UTF8String object.
+ */
+ public class DerUtf8String
+ : DerStringBase
+ {
+ private readonly string str;
+
+ /**
+ * return an UTF8 string from the passed in object.
+ *
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static DerUtf8String GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is DerUtf8String)
+ {
+ return (DerUtf8String)obj;
+ }
+
+ throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
+ }
+
+ /**
+ * return an UTF8 string from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DerUtf8String GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ Asn1Object o = obj.GetObject();
+
+ if (isExplicit || o is DerUtf8String)
+ {
+ return GetInstance(o);
+ }
+
+ return new DerUtf8String(Asn1OctetString.GetInstance(o).GetOctets());
+ }
+
+ /**
+ * basic constructor - byte encoded string.
+ */
+ public DerUtf8String(
+ byte[] str)
+ : this(Encoding.UTF8.GetString(str, 0, str.Length))
+ {
+ }
+
+ /**
+ * basic constructor
+ */
+ public DerUtf8String(
+ string str)
+ {
+ if (str == null)
+ throw new ArgumentNullException("str");
+
+ this.str = str;
+ }
+
+ public override string GetString()
+ {
+ return str;
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerUtf8String other = asn1Object as DerUtf8String;
+
+ if (other == null)
+ return false;
+
+ return this.str.Equals(other.str);
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ derOut.WriteEncoded(Asn1Tags.Utf8String, Encoding.UTF8.GetBytes(str));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerUniversalString.cs b/bc-sharp-crypto/src/asn1/DerUniversalString.cs
new file mode 100644
index 0000000000000000000000000000000000000000..284d0f8c59b5b001f2ce38d75ac31adc6d59cb36
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerUniversalString.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * Der UniversalString object.
+ */
+ public class DerUniversalString
+ : DerStringBase
+ {
+ private static readonly char[] table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+ private readonly byte[] str;
+
+ /**
+ * return a Universal string from the passed in object.
+ *
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static DerUniversalString GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is DerUniversalString)
+ {
+ return (DerUniversalString)obj;
+ }
+
+ throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
+ }
+
+ /**
+ * return a Universal string from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DerUniversalString GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ Asn1Object o = obj.GetObject();
+
+ if (isExplicit || o is DerUniversalString)
+ {
+ return GetInstance(o);
+ }
+
+ return new DerUniversalString(Asn1OctetString.GetInstance(o).GetOctets());
+ }
+
+ /**
+ * basic constructor - byte encoded string.
+ */
+ public DerUniversalString(
+ byte[] str)
+ {
+ if (str == null)
+ throw new ArgumentNullException("str");
+
+ this.str = str;
+ }
+
+ public override string GetString()
+ {
+ StringBuilder buffer = new StringBuilder("#");
+ byte[] enc = GetDerEncoded();
+
+ for (int i = 0; i != enc.Length; i++)
+ {
+ uint ubyte = enc[i];
+ buffer.Append(table[(ubyte >> 4) & 0xf]);
+ buffer.Append(table[enc[i] & 0xf]);
+ }
+
+ return buffer.ToString();
+ }
+
+ public byte[] GetOctets()
+ {
+ return (byte[]) str.Clone();
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ derOut.WriteEncoded(Asn1Tags.UniversalString, this.str);
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerUniversalString other = asn1Object as DerUniversalString;
+
+ if (other == null)
+ return false;
+
+// return this.GetString().Equals(other.GetString());
+ return Arrays.AreEqual(this.str, other.str);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerVideotexString.cs b/bc-sharp-crypto/src/asn1/DerVideotexString.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b254010448137c35b336cfd8c4a14fd4bc5ed3cb
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerVideotexString.cs
@@ -0,0 +1,103 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class DerVideotexString
+ : DerStringBase
+ {
+ private readonly byte[] mString;
+
+ /**
+ * return a Videotex String from the passed in object
+ *
+ * @param obj a DERVideotexString or an object that can be converted into one.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ * @return a DERVideotexString instance, or null.
+ */
+ public static DerVideotexString GetInstance(object obj)
+ {
+ if (obj == null || obj is DerVideotexString)
+ {
+ return (DerVideotexString)obj;
+ }
+
+ if (obj is byte[])
+ {
+ try
+ {
+ return (DerVideotexString)FromByteArray((byte[])obj);
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("encoding error in GetInstance: " + e.ToString(), "obj");
+ }
+ }
+
+ throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * return a Videotex String from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the tagged object cannot
+ * be converted.
+ * @return a DERVideotexString instance, or null.
+ */
+ public static DerVideotexString GetInstance(Asn1TaggedObject obj, bool isExplicit)
+ {
+ Asn1Object o = obj.GetObject();
+
+ if (isExplicit || o is DerVideotexString)
+ {
+ return GetInstance(o);
+ }
+
+ return new DerVideotexString(((Asn1OctetString)o).GetOctets());
+ }
+
+ /**
+ * basic constructor - with bytes.
+ * @param string the byte encoding of the characters making up the string.
+ */
+ public DerVideotexString(byte[] encoding)
+ {
+ this.mString = Arrays.Clone(encoding);
+ }
+
+ public override string GetString()
+ {
+ return Strings.FromByteArray(mString);
+ }
+
+ public byte[] GetOctets()
+ {
+ return Arrays.Clone(mString);
+ }
+
+ internal override void Encode(DerOutputStream derOut)
+ {
+ derOut.WriteEncoded(Asn1Tags.VideotexString, mString);
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ return Arrays.GetHashCode(mString);
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerVideotexString other = asn1Object as DerVideotexString;
+
+ if (other == null)
+ return false;
+
+ return Arrays.AreEqual(mString, other.mString);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/DerVisibleString.cs b/bc-sharp-crypto/src/asn1/DerVisibleString.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e1112201a3321e2a3e4690c460af7155c21704de
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/DerVisibleString.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * Der VisibleString object.
+ */
+ public class DerVisibleString
+ : DerStringBase
+ {
+ private readonly string str;
+
+ /**
+ * return a Visible string from the passed in object.
+ *
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static DerVisibleString GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is DerVisibleString)
+ {
+ return (DerVisibleString)obj;
+ }
+
+ if (obj is Asn1OctetString)
+ {
+ return new DerVisibleString(((Asn1OctetString)obj).GetOctets());
+ }
+
+ if (obj is Asn1TaggedObject)
+ {
+ return GetInstance(((Asn1TaggedObject)obj).GetObject());
+ }
+
+ throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
+ }
+
+ /**
+ * return a Visible string from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DerVisibleString GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(obj.GetObject());
+ }
+
+ /**
+ * basic constructor - byte encoded string.
+ */
+ public DerVisibleString(
+ byte[] str)
+ : this(Strings.FromAsciiByteArray(str))
+ {
+ }
+
+ /**
+ * basic constructor
+ */
+ public DerVisibleString(
+ string str)
+ {
+ if (str == null)
+ throw new ArgumentNullException("str");
+
+ this.str = str;
+ }
+
+ public override string GetString()
+ {
+ return str;
+ }
+
+ public byte[] GetOctets()
+ {
+ return Strings.ToAsciiByteArray(str);
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ derOut.WriteEncoded(Asn1Tags.VisibleString, GetOctets());
+ }
+
+ protected override bool Asn1Equals(
+ Asn1Object asn1Object)
+ {
+ DerVisibleString other = asn1Object as DerVisibleString;
+
+ if (other == null)
+ return false;
+
+ return this.str.Equals(other.str);
+ }
+
+ protected override int Asn1GetHashCode()
+ {
+ return this.str.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/IAsn1ApplicationSpecificParser.cs b/bc-sharp-crypto/src/asn1/IAsn1ApplicationSpecificParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..89cf64c70d5402a274cb823965176076da0a3e49
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/IAsn1ApplicationSpecificParser.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public interface IAsn1ApplicationSpecificParser
+ : IAsn1Convertible
+ {
+ IAsn1Convertible ReadObject();
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/IAsn1Choice.cs b/bc-sharp-crypto/src/asn1/IAsn1Choice.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ecd76e4274c625a363d513c765c00a20fe7cfcff
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/IAsn1Choice.cs
@@ -0,0 +1,17 @@
+
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * Marker interface for CHOICE objects - if you implement this in a roll-your-own
+ * object, any attempt to tag the object implicitly will convert the tag to an
+ * explicit one as the encoding rules require.
+ *
+ * If you use this interface your class should also implement the getInstance
+ * pattern which takes a tag object and the tagging mode used.
+ *
+ */
+ public interface IAsn1Choice
+ {
+ // marker interface
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/IAsn1Convertible.cs b/bc-sharp-crypto/src/asn1/IAsn1Convertible.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d3f83afc920efa1b51948dc547aa18205ea10026
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/IAsn1Convertible.cs
@@ -0,0 +1,7 @@
+namespace Org.BouncyCastle.Asn1
+{
+ public interface IAsn1Convertible
+ {
+ Asn1Object ToAsn1Object();
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/IAsn1String.cs b/bc-sharp-crypto/src/asn1/IAsn1String.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cbc2635ff6173d5551b4de882161f0039c7f4683
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/IAsn1String.cs
@@ -0,0 +1,10 @@
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * basic interface for Der string objects.
+ */
+ public interface IAsn1String
+ {
+ string GetString();
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/IndefiniteLengthInputStream.cs b/bc-sharp-crypto/src/asn1/IndefiniteLengthInputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..09d0e3a4294b1bc14f70cc7d3204190d387a2dd9
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/IndefiniteLengthInputStream.cs
@@ -0,0 +1,170 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ class IndefiniteLengthInputStream
+ : LimitedInputStream
+ {
+ private int _lookAhead;
+ private bool _eofOn00 = true;
+
+ internal IndefiniteLengthInputStream(
+ Stream inStream,
+ int limit)
+ : base(inStream, limit)
+ {
+ _lookAhead = RequireByte();
+ CheckForEof();
+ }
+
+ internal void SetEofOn00(
+ bool eofOn00)
+ {
+ _eofOn00 = eofOn00;
+ if (_eofOn00)
+ {
+ CheckForEof();
+ }
+ }
+
+ private bool CheckForEof()
+ {
+ if (_lookAhead == 0x00)
+ {
+ int extra = RequireByte();
+ if (extra != 0)
+ {
+ throw new IOException("malformed end-of-contents marker");
+ }
+
+ _lookAhead = -1;
+ SetParentEofDetect(true);
+ return true;
+ }
+ return _lookAhead < 0;
+ }
+
+ public override int Read(
+ byte[] buffer,
+ int offset,
+ int count)
+ {
+ // Only use this optimisation if we aren't checking for 00
+ if (_eofOn00 || count <= 1)
+ return base.Read(buffer, offset, count);
+
+ if (_lookAhead < 0)
+ return 0;
+
+ int numRead = _in.Read(buffer, offset + 1, count - 1);
+
+ if (numRead <= 0)
+ {
+ // Corrupted stream
+ throw new EndOfStreamException();
+ }
+
+ buffer[offset] = (byte)_lookAhead;
+ _lookAhead = RequireByte();
+
+ return numRead + 1;
+ }
+
+ public override int ReadByte()
+ {
+ if (_eofOn00 && CheckForEof())
+ return -1;
+
+ int result = _lookAhead;
+ _lookAhead = RequireByte();
+ return result;
+ }
+
+ private int RequireByte()
+ {
+ int b = _in.ReadByte();
+ if (b < 0)
+ {
+ // Corrupted stream
+ throw new EndOfStreamException();
+ }
+ return b;
+ }
+ }
+}
+
+//using System;
+//using System.IO;
+
+//namespace Org.BouncyCastle.Asn1
+//{
+// class IndefiniteLengthInputStream
+// : LimitedInputStream
+// {
+// private bool _eofReached = false;
+// private bool _eofOn00 = true;
+
+// internal IndefiniteLengthInputStream(
+// Stream inStream,
+// int limit)
+// : base(inStream, limit)
+// {
+// }
+
+// internal void SetEofOn00(
+// bool eofOn00)
+// {
+// _eofOn00 = eofOn00;
+// }
+
+// public override int Read(
+// byte[] buffer,
+// int offset,
+// int count)
+// {
+// if (_eofReached)
+// return 0;
+
+// if (_eofOn00)
+// return base.Read(buffer, offset, count);
+
+// int numRead = _in.Read(buffer, offset, count);
+
+// if (numRead <= 0)
+// throw new EndOfStreamException();
+
+// return numRead;
+// }
+
+// public override int ReadByte()
+// {
+// if (_eofReached)
+// return -1;
+
+// int b1 = _in.ReadByte();
+
+// if (b1 < 0)
+// throw new EndOfStreamException();
+
+// if (b1 == 0 && _eofOn00)
+// {
+// int b2 = _in.ReadByte();
+
+// if (b2 < 0)
+// throw new EndOfStreamException();
+
+// if (b2 == 0)
+// {
+// _eofReached = true;
+// SetParentEofDetect(true);
+// return -1;
+// }
+
+// throw new InvalidDataException();
+// }
+
+// return b1;
+// }
+// }
+//}
diff --git a/bc-sharp-crypto/src/asn1/LazyASN1InputStream.cs b/bc-sharp-crypto/src/asn1/LazyASN1InputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4cf2305fdd1274a3ca75cac4664928e9aa21c715
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/LazyASN1InputStream.cs
@@ -0,0 +1,33 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ public class LazyAsn1InputStream
+ : Asn1InputStream
+ {
+ public LazyAsn1InputStream(
+ byte[] input)
+ : base(input)
+ {
+ }
+
+ public LazyAsn1InputStream(
+ Stream inputStream)
+ : base(inputStream)
+ {
+ }
+
+ internal override DerSequence CreateDerSequence(
+ DefiniteLengthInputStream dIn)
+ {
+ return new LazyDerSequence(dIn.ToArray());
+ }
+
+ internal override DerSet CreateDerSet(
+ DefiniteLengthInputStream dIn)
+ {
+ return new LazyDerSet(dIn.ToArray());
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/LazyDERSequence.cs b/bc-sharp-crypto/src/asn1/LazyDERSequence.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7301bc1589f701353aae7026a1bb0a0a0c58ad23
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/LazyDERSequence.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+
+namespace Org.BouncyCastle.Asn1
+{
+ internal class LazyDerSequence
+ : DerSequence
+ {
+ private byte[] encoded;
+
+ internal LazyDerSequence(
+ byte[] encoded)
+ {
+ this.encoded = encoded;
+ }
+
+ private void Parse()
+ {
+ lock (this)
+ {
+ if (encoded != null)
+ {
+ Asn1InputStream e = new LazyAsn1InputStream(encoded);
+
+ Asn1Object o;
+ while ((o = e.ReadObject()) != null)
+ {
+ AddObject(o);
+ }
+
+ encoded = null;
+ }
+ }
+ }
+
+ public override Asn1Encodable this[int index]
+ {
+ get
+ {
+ Parse();
+
+ return base[index];
+ }
+ }
+
+ public override IEnumerator GetEnumerator()
+ {
+ Parse();
+
+ return base.GetEnumerator();
+ }
+
+ public override int Count
+ {
+ get
+ {
+ Parse();
+
+ return base.Count;
+ }
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ lock (this)
+ {
+ if (encoded == null)
+ {
+ base.Encode(derOut);
+ }
+ else
+ {
+ derOut.WriteEncoded(Asn1Tags.Sequence | Asn1Tags.Constructed, encoded);
+ }
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/LazyDERSet.cs b/bc-sharp-crypto/src/asn1/LazyDERSet.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e6c9319dd7c5514af854136691f3051146cc0971
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/LazyDERSet.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+
+namespace Org.BouncyCastle.Asn1
+{
+ internal class LazyDerSet
+ : DerSet
+ {
+ private byte[] encoded;
+
+ internal LazyDerSet(
+ byte[] encoded)
+ {
+ this.encoded = encoded;
+ }
+
+ private void Parse()
+ {
+ lock (this)
+ {
+ if (encoded != null)
+ {
+ Asn1InputStream e = new LazyAsn1InputStream(encoded);
+
+ Asn1Object o;
+ while ((o = e.ReadObject()) != null)
+ {
+ AddObject(o);
+ }
+
+ encoded = null;
+ }
+ }
+ }
+
+ public override Asn1Encodable this[int index]
+ {
+ get
+ {
+ Parse();
+
+ return base[index];
+ }
+ }
+
+ public override IEnumerator GetEnumerator()
+ {
+ Parse();
+
+ return base.GetEnumerator();
+ }
+
+ public override int Count
+ {
+ get
+ {
+ Parse();
+
+ return base.Count;
+ }
+ }
+
+ internal override void Encode(
+ DerOutputStream derOut)
+ {
+ lock (this)
+ {
+ if (encoded == null)
+ {
+ base.Encode(derOut);
+ }
+ else
+ {
+ derOut.WriteEncoded(Asn1Tags.Set | Asn1Tags.Constructed, encoded);
+ }
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/LimitedInputStream.cs b/bc-sharp-crypto/src/asn1/LimitedInputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..62486aa7780bf6c43862b34dffd8628d4ca633b2
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/LimitedInputStream.cs
@@ -0,0 +1,35 @@
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+ internal abstract class LimitedInputStream
+ : BaseInputStream
+ {
+ protected readonly Stream _in;
+ private int _limit;
+
+ internal LimitedInputStream(
+ Stream inStream,
+ int limit)
+ {
+ this._in = inStream;
+ this._limit = limit;
+ }
+
+ internal virtual int GetRemaining()
+ {
+ // TODO: maybe one day this can become more accurate
+ return _limit;
+ }
+
+ protected virtual void SetParentEofDetect(bool on)
+ {
+ if (_in is IndefiniteLengthInputStream)
+ {
+ ((IndefiniteLengthInputStream)_in).SetEofOn00(on);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/OidTokenizer.cs b/bc-sharp-crypto/src/asn1/OidTokenizer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6e76e8c8bf9e48b7d5047b2928b0019cd31a8c18
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/OidTokenizer.cs
@@ -0,0 +1,45 @@
+namespace Org.BouncyCastle.Asn1
+{
+ /**
+ * class for breaking up an Oid into it's component tokens, ala
+ * java.util.StringTokenizer. We need this class as some of the
+ * lightweight Java environment don't support classes like
+ * StringTokenizer.
+ */
+ public class OidTokenizer
+ {
+ private string oid;
+ private int index;
+
+ public OidTokenizer(
+ string oid)
+ {
+ this.oid = oid;
+ }
+
+ public bool HasMoreTokens
+ {
+ get { return index != -1; }
+ }
+
+ public string NextToken()
+ {
+ if (index == -1)
+ {
+ return null;
+ }
+
+ int end = oid.IndexOf('.', index);
+ if (end == -1)
+ {
+ string lastToken = oid.Substring(index);
+ index = -1;
+ return lastToken;
+ }
+
+ string nextToken = oid.Substring(index, end - index);
+ index = end + 1;
+ return nextToken;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/anssi/ANSSINamedCurves.cs b/bc-sharp-crypto/src/asn1/anssi/ANSSINamedCurves.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d0c90ebf1861cf5fd274861f8d03e3c752c492cd
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/anssi/ANSSINamedCurves.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.Anssi
+{
+ public class AnssiNamedCurves
+ {
+ private static ECCurve ConfigureCurve(ECCurve curve)
+ {
+ return curve;
+ }
+
+ private static BigInteger FromHex(string hex)
+ {
+ return new BigInteger(1, Hex.Decode(hex));
+ }
+
+ /*
+ * FRP256v1
+ */
+ internal class Frp256v1Holder
+ : X9ECParametersHolder
+ {
+ private Frp256v1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Frp256v1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger p = FromHex("F1FD178C0B3AD58F10126DE8CE42435B3961ADBCABC8CA6DE8FCF353D86E9C03");
+ BigInteger a = FromHex("F1FD178C0B3AD58F10126DE8CE42435B3961ADBCABC8CA6DE8FCF353D86E9C00");
+ BigInteger b = FromHex("EE353FCA5428A9300D4ABA754A44C00FDFEC0C9AE4B1A1803075ED967B7BB73F");
+ byte[] S = null;
+ BigInteger n = FromHex("F1FD178C0B3AD58F10126DE8CE42435B53DC67E140D2BF941FFDD459C6D655E1");
+ BigInteger h = BigInteger.One;
+
+ ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "B6B3D4C356C139EB31183D4749D423958C27D2DCAF98B70164C97A2DD98F5CFF"
+ + "6142E0F7C8B204911F9271F0F3ECEF8C2701C307E8E4C9E183115A1554062CFB"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+
+ private static readonly IDictionary objIds = Platform.CreateHashtable();
+ private static readonly IDictionary curves = Platform.CreateHashtable();
+ private static readonly IDictionary names = Platform.CreateHashtable();
+
+ private static void DefineCurve(
+ string name,
+ DerObjectIdentifier oid,
+ X9ECParametersHolder holder)
+ {
+ objIds.Add(Platform.ToUpperInvariant(name), oid);
+ names.Add(oid, name);
+ curves.Add(oid, holder);
+ }
+
+ static AnssiNamedCurves()
+ {
+ DefineCurve("FRP256v1", AnssiObjectIdentifiers.FRP256v1, Frp256v1Holder.Instance);
+ }
+
+ public static X9ECParameters GetByName(
+ string name)
+ {
+ DerObjectIdentifier oid = GetOid(name);
+ return oid == null ? null : GetByOid(oid);
+ }
+
+ /**
+ * return the X9ECParameters object for the named curve represented by
+ * the passed in object identifier. Null if the curve isn't present.
+ *
+ * @param oid an object identifier representing a named curve, if present.
+ */
+ public static X9ECParameters GetByOid(
+ DerObjectIdentifier oid)
+ {
+ X9ECParametersHolder holder = (X9ECParametersHolder)curves[oid];
+ return holder == null ? null : holder.Parameters;
+ }
+
+ /**
+ * return the object identifier signified by the passed in name. Null
+ * if there is no object identifier associated with name.
+ *
+ * @return the object identifier associated with name, if present.
+ */
+ public static DerObjectIdentifier GetOid(
+ string name)
+ {
+ return (DerObjectIdentifier)objIds[Platform.ToUpperInvariant(name)];
+ }
+
+ /**
+ * return the named curve name represented by the given object identifier.
+ */
+ public static string GetName(
+ DerObjectIdentifier oid)
+ {
+ return (string)names[oid];
+ }
+
+ /**
+ * returns an enumeration containing the name strings for curves
+ * contained in this structure.
+ */
+ public static IEnumerable Names
+ {
+ get { return new EnumerableProxy(names.Values); }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/anssi/ANSSIObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/anssi/ANSSIObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d230832b5b01838aa0366e383e0a84aa9e0f31dc
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/anssi/ANSSIObjectIdentifiers.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Anssi
+{
+ public sealed class AnssiObjectIdentifiers
+ {
+ private AnssiObjectIdentifiers()
+ {
+ }
+
+ public static readonly DerObjectIdentifier FRP256v1 = new DerObjectIdentifier("1.2.250.1.223.101.256.1");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/bc/BCObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/bc/BCObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..075e5384cfcfb4d113d52f2fa3996e05efc5dd64
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/bc/BCObjectIdentifiers.cs
@@ -0,0 +1,39 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.BC
+{
+ public abstract class BCObjectIdentifiers
+ {
+ // iso.org.dod.internet.private.enterprise.legion-of-the-bouncy-castle
+ // 1.3.6.1.4.1.22554
+ public static readonly DerObjectIdentifier bc = new DerObjectIdentifier("1.3.6.1.4.1.22554");
+
+ // pbe(1) algorithms
+ public static readonly DerObjectIdentifier bc_pbe = new DerObjectIdentifier(bc + ".1");
+
+ // SHA-1(1)
+ public static readonly DerObjectIdentifier bc_pbe_sha1 = new DerObjectIdentifier(bc_pbe + ".1");
+
+ // SHA-2(2) . (SHA-256(1)|SHA-384(2)|SHA-512(3)|SHA-224(4))
+ public static readonly DerObjectIdentifier bc_pbe_sha256 = new DerObjectIdentifier(bc_pbe + ".2.1");
+ public static readonly DerObjectIdentifier bc_pbe_sha384 = new DerObjectIdentifier(bc_pbe + ".2.2");
+ public static readonly DerObjectIdentifier bc_pbe_sha512 = new DerObjectIdentifier(bc_pbe + ".2.3");
+ public static readonly DerObjectIdentifier bc_pbe_sha224 = new DerObjectIdentifier(bc_pbe + ".2.4");
+
+ // PKCS-5(1)|PKCS-12(2)
+ public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs5 = new DerObjectIdentifier(bc_pbe_sha1 + ".1");
+ public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12 = new DerObjectIdentifier(bc_pbe_sha1 + ".2");
+
+ public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs5 = new DerObjectIdentifier(bc_pbe_sha256 + ".1");
+ public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12 = new DerObjectIdentifier(bc_pbe_sha256 + ".2");
+
+ // AES(1) . (CBC-128(2)|CBC-192(22)|CBC-256(42))
+ public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12_aes128_cbc = new DerObjectIdentifier(bc_pbe_sha1_pkcs12 + ".1.2");
+ public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12_aes192_cbc = new DerObjectIdentifier(bc_pbe_sha1_pkcs12 + ".1.22");
+ public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12_aes256_cbc = new DerObjectIdentifier(bc_pbe_sha1_pkcs12 + ".1.42");
+
+ public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12_aes128_cbc = new DerObjectIdentifier(bc_pbe_sha256_pkcs12 + ".1.2");
+ public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12_aes192_cbc = new DerObjectIdentifier(bc_pbe_sha256_pkcs12 + ".1.22");
+ public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12_aes256_cbc = new DerObjectIdentifier(bc_pbe_sha256_pkcs12 + ".1.42");
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/asn1/cmp/CAKeyUpdAnnContent.cs b/bc-sharp-crypto/src/asn1/cmp/CAKeyUpdAnnContent.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b74bac87abd1d0a3da5dde8785d9c40cf5ea7613
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/CAKeyUpdAnnContent.cs
@@ -0,0 +1,62 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class CAKeyUpdAnnContent
+ : Asn1Encodable
+ {
+ private readonly CmpCertificate oldWithNew;
+ private readonly CmpCertificate newWithOld;
+ private readonly CmpCertificate newWithNew;
+
+ private CAKeyUpdAnnContent(Asn1Sequence seq)
+ {
+ oldWithNew = CmpCertificate.GetInstance(seq[0]);
+ newWithOld = CmpCertificate.GetInstance(seq[1]);
+ newWithNew = CmpCertificate.GetInstance(seq[2]);
+ }
+
+ public static CAKeyUpdAnnContent GetInstance(object obj)
+ {
+ if (obj is CAKeyUpdAnnContent)
+ return (CAKeyUpdAnnContent)obj;
+
+ if (obj is Asn1Sequence)
+ return new CAKeyUpdAnnContent((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public virtual CmpCertificate OldWithNew
+ {
+ get { return oldWithNew; }
+ }
+
+ public virtual CmpCertificate NewWithOld
+ {
+ get { return newWithOld; }
+ }
+
+ public virtual CmpCertificate NewWithNew
+ {
+ get { return newWithNew; }
+ }
+
+ /**
+ *
+ * CAKeyUpdAnnContent ::= SEQUENCE {
+ * oldWithNew CmpCertificate, -- old pub signed with new priv
+ * newWithOld CmpCertificate, -- new pub signed with old priv
+ * newWithNew CmpCertificate -- new pub signed with new priv
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(oldWithNew, newWithOld, newWithNew);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/CertConfirmContent.cs b/bc-sharp-crypto/src/asn1/cmp/CertConfirmContent.cs
new file mode 100644
index 0000000000000000000000000000000000000000..370a9e7d645fe280ecf2fb3a592f57d00a1f0ae9
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/CertConfirmContent.cs
@@ -0,0 +1,49 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class CertConfirmContent
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence content;
+
+ private CertConfirmContent(Asn1Sequence seq)
+ {
+ content = seq;
+ }
+
+ public static CertConfirmContent GetInstance(object obj)
+ {
+ if (obj is CertConfirmContent)
+ return (CertConfirmContent)obj;
+
+ if (obj is Asn1Sequence)
+ return new CertConfirmContent((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public virtual CertStatus[] ToCertStatusArray()
+ {
+ CertStatus[] result = new CertStatus[content.Count];
+ for (int i = 0; i != result.Length; i++)
+ {
+ result[i] = CertStatus.GetInstance(content[i]);
+ }
+ return result;
+ }
+
+ /**
+ *
+ * CertConfirmContent ::= SEQUENCE OF CertStatus
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return content;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/CertOrEncCert.cs b/bc-sharp-crypto/src/asn1/cmp/CertOrEncCert.cs
new file mode 100644
index 0000000000000000000000000000000000000000..eb200e1e8becae609182477a031885b884970c30
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/CertOrEncCert.cs
@@ -0,0 +1,86 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class CertOrEncCert
+ : Asn1Encodable, IAsn1Choice
+ {
+ private readonly CmpCertificate certificate;
+ private readonly EncryptedValue encryptedCert;
+
+ private CertOrEncCert(Asn1TaggedObject tagged)
+ {
+ if (tagged.TagNo == 0)
+ {
+ certificate = CmpCertificate.GetInstance(tagged.GetObject());
+ }
+ else if (tagged.TagNo == 1)
+ {
+ encryptedCert = EncryptedValue.GetInstance(tagged.GetObject());
+ }
+ else
+ {
+ throw new ArgumentException("unknown tag: " + tagged.TagNo, "tagged");
+ }
+ }
+
+ public static CertOrEncCert GetInstance(object obj)
+ {
+ if (obj is CertOrEncCert)
+ return (CertOrEncCert)obj;
+
+ if (obj is Asn1TaggedObject)
+ return new CertOrEncCert((Asn1TaggedObject)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public CertOrEncCert(CmpCertificate certificate)
+ {
+ if (certificate == null)
+ throw new ArgumentNullException("certificate");
+
+ this.certificate = certificate;
+ }
+
+ public CertOrEncCert(EncryptedValue encryptedCert)
+ {
+ if (encryptedCert == null)
+ throw new ArgumentNullException("encryptedCert");
+
+ this.encryptedCert = encryptedCert;
+ }
+
+ public virtual CmpCertificate Certificate
+ {
+ get { return certificate; }
+ }
+
+ public virtual EncryptedValue EncryptedCert
+ {
+ get { return encryptedCert; }
+ }
+
+ /**
+ *
+ * CertOrEncCert ::= CHOICE {
+ * certificate [0] CMPCertificate,
+ * encryptedCert [1] EncryptedValue
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ if (certificate != null)
+ {
+ return new DerTaggedObject(true, 0, certificate);
+ }
+
+ return new DerTaggedObject(true, 1, encryptedCert);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/CertRepMessage.cs b/bc-sharp-crypto/src/asn1/cmp/CertRepMessage.cs
new file mode 100644
index 0000000000000000000000000000000000000000..82869784dfd9199c40f5f25bd151d07b187a11ee
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/CertRepMessage.cs
@@ -0,0 +1,96 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class CertRepMessage
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence caPubs;
+ private readonly Asn1Sequence response;
+
+ private CertRepMessage(Asn1Sequence seq)
+ {
+ int index = 0;
+
+ if (seq.Count > 1)
+ {
+ caPubs = Asn1Sequence.GetInstance((Asn1TaggedObject)seq[index++], true);
+ }
+
+ response = Asn1Sequence.GetInstance(seq[index]);
+ }
+
+ public static CertRepMessage GetInstance(object obj)
+ {
+ if (obj is CertRepMessage)
+ return (CertRepMessage)obj;
+
+ if (obj is Asn1Sequence)
+ return new CertRepMessage((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public CertRepMessage(CmpCertificate[] caPubs, CertResponse[] response)
+ {
+ if (response == null)
+ throw new ArgumentNullException("response");
+
+ if (caPubs != null)
+ {
+ this.caPubs = new DerSequence(caPubs);
+ }
+
+ this.response = new DerSequence(response);
+ }
+
+ public virtual CmpCertificate[] GetCAPubs()
+ {
+ if (caPubs == null)
+ return null;
+
+ CmpCertificate[] results = new CmpCertificate[caPubs.Count];
+ for (int i = 0; i != results.Length; ++i)
+ {
+ results[i] = CmpCertificate.GetInstance(caPubs[i]);
+ }
+ return results;
+ }
+
+ public virtual CertResponse[] GetResponse()
+ {
+ CertResponse[] results = new CertResponse[response.Count];
+ for (int i = 0; i != results.Length; ++i)
+ {
+ results[i] = CertResponse.GetInstance(response[i]);
+ }
+ return results;
+ }
+
+ /**
+ *
+ * CertRepMessage ::= SEQUENCE {
+ * caPubs [1] SEQUENCE SIZE (1..MAX) OF CMPCertificate
+ * OPTIONAL,
+ * response SEQUENCE OF CertResponse
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (caPubs != null)
+ {
+ v.Add(new DerTaggedObject(true, 1, caPubs));
+ }
+
+ v.Add(response);
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/CertResponse.cs b/bc-sharp-crypto/src/asn1/cmp/CertResponse.cs
new file mode 100644
index 0000000000000000000000000000000000000000..843fd9299dff97b302470d40342e8f2d076d9bf9
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/CertResponse.cs
@@ -0,0 +1,116 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class CertResponse
+ : Asn1Encodable
+ {
+ private readonly DerInteger certReqId;
+ private readonly PkiStatusInfo status;
+ private readonly CertifiedKeyPair certifiedKeyPair;
+ private readonly Asn1OctetString rspInfo;
+
+ private CertResponse(Asn1Sequence seq)
+ {
+ certReqId = DerInteger.GetInstance(seq[0]);
+ status = PkiStatusInfo.GetInstance(seq[1]);
+
+ if (seq.Count >= 3)
+ {
+ if (seq.Count == 3)
+ {
+ Asn1Encodable o = seq[2];
+ if (o is Asn1OctetString)
+ {
+ rspInfo = Asn1OctetString.GetInstance(o);
+ }
+ else
+ {
+ certifiedKeyPair = CertifiedKeyPair.GetInstance(o);
+ }
+ }
+ else
+ {
+ certifiedKeyPair = CertifiedKeyPair.GetInstance(seq[2]);
+ rspInfo = Asn1OctetString.GetInstance(seq[3]);
+ }
+ }
+ }
+
+ public static CertResponse GetInstance(object obj)
+ {
+ if (obj is CertResponse)
+ return (CertResponse)obj;
+
+ if (obj is Asn1Sequence)
+ return new CertResponse((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public CertResponse(
+ DerInteger certReqId,
+ PkiStatusInfo status)
+ : this(certReqId, status, null, null)
+ {
+ }
+
+ public CertResponse(
+ DerInteger certReqId,
+ PkiStatusInfo status,
+ CertifiedKeyPair certifiedKeyPair,
+ Asn1OctetString rspInfo)
+ {
+ if (certReqId == null)
+ throw new ArgumentNullException("certReqId");
+
+ if (status == null)
+ throw new ArgumentNullException("status");
+
+ this.certReqId = certReqId;
+ this.status = status;
+ this.certifiedKeyPair = certifiedKeyPair;
+ this.rspInfo = rspInfo;
+ }
+
+ public virtual DerInteger CertReqID
+ {
+ get { return certReqId; }
+ }
+
+ public virtual PkiStatusInfo Status
+ {
+ get { return status; }
+ }
+
+ public virtual CertifiedKeyPair CertifiedKeyPair
+ {
+ get { return certifiedKeyPair; }
+ }
+
+ /**
+ *
+ * CertResponse ::= SEQUENCE {
+ * certReqId INTEGER,
+ * -- to match this response with corresponding request (a value
+ * -- of -1 is to be used if certReqId is not specified in the
+ * -- corresponding request)
+ * status PKIStatusInfo,
+ * certifiedKeyPair CertifiedKeyPair OPTIONAL,
+ * rspInfo OCTET STRING OPTIONAL
+ * -- analogous to the id-regInfo-utf8Pairs string defined
+ * -- for regInfo in CertReqMsg [CRMF]
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(certReqId, status);
+ v.AddOptional(certifiedKeyPair, rspInfo);
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/CertStatus.cs b/bc-sharp-crypto/src/asn1/cmp/CertStatus.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d437b57b263001f1b18b733351388026e4d792ac
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/CertStatus.cs
@@ -0,0 +1,85 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class CertStatus
+ : Asn1Encodable
+ {
+ private readonly Asn1OctetString certHash;
+ private readonly DerInteger certReqId;
+ private readonly PkiStatusInfo statusInfo;
+
+ private CertStatus(Asn1Sequence seq)
+ {
+ certHash = Asn1OctetString.GetInstance(seq[0]);
+ certReqId = DerInteger.GetInstance(seq[1]);
+
+ if (seq.Count > 2)
+ {
+ statusInfo = PkiStatusInfo.GetInstance(seq[2]);
+ }
+ }
+
+ public CertStatus(byte[] certHash, BigInteger certReqId)
+ {
+ this.certHash = new DerOctetString(certHash);
+ this.certReqId = new DerInteger(certReqId);
+ }
+
+ public CertStatus(byte[] certHash, BigInteger certReqId, PkiStatusInfo statusInfo)
+ {
+ this.certHash = new DerOctetString(certHash);
+ this.certReqId = new DerInteger(certReqId);
+ this.statusInfo = statusInfo;
+ }
+
+ public static CertStatus GetInstance(object obj)
+ {
+ if (obj is CertStatus)
+ return (CertStatus)obj;
+
+ if (obj is Asn1Sequence)
+ return new CertStatus((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public virtual Asn1OctetString CertHash
+ {
+ get { return certHash; }
+ }
+
+ public virtual DerInteger CertReqID
+ {
+ get { return certReqId; }
+ }
+
+ public virtual PkiStatusInfo StatusInfo
+ {
+ get { return statusInfo; }
+ }
+
+ /**
+ *
+ * CertStatus ::= SEQUENCE {
+ * certHash OCTET STRING,
+ * -- the hash of the certificate, using the same hash algorithm
+ * -- as is used to create and verify the certificate signature
+ * certReqId INTEGER,
+ * -- to match this confirmation with the corresponding req/rep
+ * statusInfo PKIStatusInfo OPTIONAL
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(certHash, certReqId);
+ v.AddOptional(statusInfo);
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/CertifiedKeyPair.cs b/bc-sharp-crypto/src/asn1/cmp/CertifiedKeyPair.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c06f00019993f04fd26ef13442b93f22d5323e57
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/CertifiedKeyPair.cs
@@ -0,0 +1,115 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class CertifiedKeyPair
+ : Asn1Encodable
+ {
+ private readonly CertOrEncCert certOrEncCert;
+ private readonly EncryptedValue privateKey;
+ private readonly PkiPublicationInfo publicationInfo;
+
+ private CertifiedKeyPair(Asn1Sequence seq)
+ {
+ certOrEncCert = CertOrEncCert.GetInstance(seq[0]);
+
+ if (seq.Count >= 2)
+ {
+ if (seq.Count == 2)
+ {
+ Asn1TaggedObject tagged = Asn1TaggedObject.GetInstance(seq[1]);
+ if (tagged.TagNo == 0)
+ {
+ privateKey = EncryptedValue.GetInstance(tagged.GetObject());
+ }
+ else
+ {
+ publicationInfo = PkiPublicationInfo.GetInstance(tagged.GetObject());
+ }
+ }
+ else
+ {
+ privateKey = EncryptedValue.GetInstance(Asn1TaggedObject.GetInstance(seq[1]));
+ publicationInfo = PkiPublicationInfo.GetInstance(Asn1TaggedObject.GetInstance(seq[2]));
+ }
+ }
+ }
+
+ public static CertifiedKeyPair GetInstance(object obj)
+ {
+ if (obj is CertifiedKeyPair)
+ return (CertifiedKeyPair)obj;
+
+ if (obj is Asn1Sequence)
+ return new CertifiedKeyPair((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public CertifiedKeyPair(
+ CertOrEncCert certOrEncCert)
+ : this(certOrEncCert, null, null)
+ {
+ }
+
+ public CertifiedKeyPair(
+ CertOrEncCert certOrEncCert,
+ EncryptedValue privateKey,
+ PkiPublicationInfo publicationInfo
+ )
+ {
+ if (certOrEncCert == null)
+ throw new ArgumentNullException("certOrEncCert");
+
+ this.certOrEncCert = certOrEncCert;
+ this.privateKey = privateKey;
+ this.publicationInfo = publicationInfo;
+ }
+
+ public virtual CertOrEncCert CertOrEncCert
+ {
+ get { return certOrEncCert; }
+ }
+
+ public virtual EncryptedValue PrivateKey
+ {
+ get { return privateKey; }
+ }
+
+ public virtual PkiPublicationInfo PublicationInfo
+ {
+ get { return publicationInfo; }
+ }
+
+ /**
+ *
+ * CertifiedKeyPair ::= SEQUENCE {
+ * certOrEncCert CertOrEncCert,
+ * privateKey [0] EncryptedValue OPTIONAL,
+ * -- see [CRMF] for comment on encoding
+ * publicationInfo [1] PKIPublicationInfo OPTIONAL
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(certOrEncCert);
+
+ if (privateKey != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, privateKey));
+ }
+
+ if (publicationInfo != null)
+ {
+ v.Add(new DerTaggedObject(true, 1, publicationInfo));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/Challenge.cs b/bc-sharp-crypto/src/asn1/cmp/Challenge.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5c78c2a2b2827fdf4697a85320508e5206024fd0
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/Challenge.cs
@@ -0,0 +1,80 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class Challenge
+ : Asn1Encodable
+ {
+ private readonly AlgorithmIdentifier owf;
+ private readonly Asn1OctetString witness;
+ private readonly Asn1OctetString challenge;
+
+ private Challenge(Asn1Sequence seq)
+ {
+ int index = 0;
+
+ if (seq.Count == 3)
+ {
+ owf = AlgorithmIdentifier.GetInstance(seq[index++]);
+ }
+
+ witness = Asn1OctetString.GetInstance(seq[index++]);
+ challenge = Asn1OctetString.GetInstance(seq[index]);
+ }
+
+ public static Challenge GetInstance(object obj)
+ {
+ if (obj is Challenge)
+ return (Challenge)obj;
+
+ if (obj is Asn1Sequence)
+ return new Challenge((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public virtual AlgorithmIdentifier Owf
+ {
+ get { return owf; }
+ }
+
+ /**
+ *
+ * Challenge ::= SEQUENCE {
+ * owf AlgorithmIdentifier OPTIONAL,
+ *
+ * -- MUST be present in the first Challenge; MAY be omitted in
+ * -- any subsequent Challenge in POPODecKeyChallContent (if
+ * -- omitted, then the owf used in the immediately preceding
+ * -- Challenge is to be used).
+ *
+ * witness OCTET STRING,
+ * -- the result of applying the one-way function (owf) to a
+ * -- randomly-generated INTEGER, A. [Note that a different
+ * -- INTEGER MUST be used for each Challenge.]
+ * challenge OCTET STRING
+ * -- the encryption (under the public key for which the cert.
+ * -- request is being made) of Rand, where Rand is specified as
+ * -- Rand ::= SEQUENCE {
+ * -- int INTEGER,
+ * -- - the randomly-generated INTEGER A (above)
+ * -- sender GeneralName
+ * -- - the sender's name (as included in PKIHeader)
+ * -- }
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+ v.AddOptional(owf);
+ v.Add(witness);
+ v.Add(challenge);
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/CmpCertificate.cs b/bc-sharp-crypto/src/asn1/cmp/CmpCertificate.cs
new file mode 100644
index 0000000000000000000000000000000000000000..33356b486db4b26bea13aa4a1553c67880d4cf91
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/CmpCertificate.cs
@@ -0,0 +1,81 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class CmpCertificate
+ : Asn1Encodable, IAsn1Choice
+ {
+ private readonly X509CertificateStructure x509v3PKCert;
+ private readonly AttributeCertificate x509v2AttrCert;
+
+ /**
+ * Note: the addition of attribute certificates is a BC extension.
+ */
+ public CmpCertificate(AttributeCertificate x509v2AttrCert)
+ {
+ this.x509v2AttrCert = x509v2AttrCert;
+ }
+
+ public CmpCertificate(X509CertificateStructure x509v3PKCert)
+ {
+ if (x509v3PKCert.Version != 3)
+ throw new ArgumentException("only version 3 certificates allowed", "x509v3PKCert");
+
+ this.x509v3PKCert = x509v3PKCert;
+ }
+
+ public static CmpCertificate GetInstance(object obj)
+ {
+ if (obj is CmpCertificate)
+ return (CmpCertificate)obj;
+
+ if (obj is Asn1Sequence)
+ return new CmpCertificate(X509CertificateStructure.GetInstance(obj));
+
+ if (obj is Asn1TaggedObject)
+ return new CmpCertificate(AttributeCertificate.GetInstance(((Asn1TaggedObject)obj).GetObject()));
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public virtual bool IsX509v3PKCert
+ {
+ get { return x509v3PKCert != null; }
+ }
+
+ public virtual X509CertificateStructure X509v3PKCert
+ {
+ get { return x509v3PKCert; }
+ }
+
+ public virtual AttributeCertificate X509v2AttrCert
+ {
+ get { return x509v2AttrCert; }
+ }
+
+ /**
+ *
+ * CMPCertificate ::= CHOICE {
+ * x509v3PKCert Certificate
+ * x509v2AttrCert [1] AttributeCertificate
+ * }
+ *
+ * Note: the addition of attribute certificates is a BC extension.
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ if (x509v2AttrCert != null)
+ {
+ // explicit following CMP conventions
+ return new DerTaggedObject(true, 1, x509v2AttrCert);
+ }
+
+ return x509v3PKCert.ToAsn1Object();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/CmpObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/cmp/CmpObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7e827417532d61667d7a8d2c270d3f0feca2575b
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/CmpObjectIdentifiers.cs
@@ -0,0 +1,106 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public abstract class CmpObjectIdentifiers
+ {
+ // RFC 4210
+
+ // id-PasswordBasedMac OBJECT IDENTIFIER ::= {1 2 840 113533 7 66 13}
+ public static readonly DerObjectIdentifier passwordBasedMac = new DerObjectIdentifier("1.2.840.113533.7.66.13");
+
+ // id-DHBasedMac OBJECT IDENTIFIER ::= {1 2 840 113533 7 66 30}
+ public static readonly DerObjectIdentifier dhBasedMac = new DerObjectIdentifier("1.2.840.113533.7.66.30");
+
+ // Example InfoTypeAndValue contents include, but are not limited
+ // to, the following (un-comment in this ASN.1 module and use as
+ // appropriate for a given environment):
+ //
+ // id-it-caProtEncCert OBJECT IDENTIFIER ::= {id-it 1}
+ // CAProtEncCertValue ::= CMPCertificate
+ // id-it-signKeyPairTypes OBJECT IDENTIFIER ::= {id-it 2}
+ // SignKeyPairTypesValue ::= SEQUENCE OF AlgorithmIdentifier
+ // id-it-encKeyPairTypes OBJECT IDENTIFIER ::= {id-it 3}
+ // EncKeyPairTypesValue ::= SEQUENCE OF AlgorithmIdentifier
+ // id-it-preferredSymmAlg OBJECT IDENTIFIER ::= {id-it 4}
+ // PreferredSymmAlgValue ::= AlgorithmIdentifier
+ // id-it-caKeyUpdateInfo OBJECT IDENTIFIER ::= {id-it 5}
+ // CAKeyUpdateInfoValue ::= CAKeyUpdAnnContent
+ // id-it-currentCRL OBJECT IDENTIFIER ::= {id-it 6}
+ // CurrentCRLValue ::= CertificateList
+ // id-it-unsupportedOIDs OBJECT IDENTIFIER ::= {id-it 7}
+ // UnsupportedOIDsValue ::= SEQUENCE OF OBJECT IDENTIFIER
+ // id-it-keyPairParamReq OBJECT IDENTIFIER ::= {id-it 10}
+ // KeyPairParamReqValue ::= OBJECT IDENTIFIER
+ // id-it-keyPairParamRep OBJECT IDENTIFIER ::= {id-it 11}
+ // KeyPairParamRepValue ::= AlgorithmIdentifer
+ // id-it-revPassphrase OBJECT IDENTIFIER ::= {id-it 12}
+ // RevPassphraseValue ::= EncryptedValue
+ // id-it-implicitConfirm OBJECT IDENTIFIER ::= {id-it 13}
+ // ImplicitConfirmValue ::= NULL
+ // id-it-confirmWaitTime OBJECT IDENTIFIER ::= {id-it 14}
+ // ConfirmWaitTimeValue ::= GeneralizedTime
+ // id-it-origPKIMessage OBJECT IDENTIFIER ::= {id-it 15}
+ // OrigPKIMessageValue ::= PKIMessages
+ // id-it-suppLangTags OBJECT IDENTIFIER ::= {id-it 16}
+ // SuppLangTagsValue ::= SEQUENCE OF UTF8String
+ //
+ // where
+ //
+ // id-pkix OBJECT IDENTIFIER ::= {
+ // iso(1) identified-organization(3)
+ // dod(6) internet(1) security(5) mechanisms(5) pkix(7)}
+ // and
+ // id-it OBJECT IDENTIFIER ::= {id-pkix 4}
+ public static readonly DerObjectIdentifier it_caProtEncCert = new DerObjectIdentifier("1.3.6.1.5.5.7.4.1");
+ public static readonly DerObjectIdentifier it_signKeyPairTypes = new DerObjectIdentifier("1.3.6.1.5.5.7.4.2");
+ public static readonly DerObjectIdentifier it_encKeyPairTypes = new DerObjectIdentifier("1.3.6.1.5.5.7.4.3");
+ public static readonly DerObjectIdentifier it_preferredSymAlg = new DerObjectIdentifier("1.3.6.1.5.5.7.4.4");
+ public static readonly DerObjectIdentifier it_caKeyUpdateInfo = new DerObjectIdentifier("1.3.6.1.5.5.7.4.5");
+ public static readonly DerObjectIdentifier it_currentCRL = new DerObjectIdentifier("1.3.6.1.5.5.7.4.6");
+ public static readonly DerObjectIdentifier it_unsupportedOIDs = new DerObjectIdentifier("1.3.6.1.5.5.7.4.7");
+ public static readonly DerObjectIdentifier it_keyPairParamReq = new DerObjectIdentifier("1.3.6.1.5.5.7.4.10");
+ public static readonly DerObjectIdentifier it_keyPairParamRep = new DerObjectIdentifier("1.3.6.1.5.5.7.4.11");
+ public static readonly DerObjectIdentifier it_revPassphrase = new DerObjectIdentifier("1.3.6.1.5.5.7.4.12");
+ public static readonly DerObjectIdentifier it_implicitConfirm = new DerObjectIdentifier("1.3.6.1.5.5.7.4.13");
+ public static readonly DerObjectIdentifier it_confirmWaitTime = new DerObjectIdentifier("1.3.6.1.5.5.7.4.14");
+ public static readonly DerObjectIdentifier it_origPKIMessage = new DerObjectIdentifier("1.3.6.1.5.5.7.4.15");
+ public static readonly DerObjectIdentifier it_suppLangTags = new DerObjectIdentifier("1.3.6.1.5.5.7.4.16");
+
+ // RFC 4211
+
+ // id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
+ // dod(6) internet(1) security(5) mechanisms(5) pkix(7) }
+ //
+ // arc for Internet X.509 PKI protocols and their components
+ // id-pkip OBJECT IDENTIFIER :: { id-pkix pkip(5) }
+ //
+ // arc for Registration Controls in CRMF
+ // id-regCtrl OBJECT IDENTIFIER ::= { id-pkip regCtrl(1) }
+ //
+ // arc for Registration Info in CRMF
+ // id-regInfo OBJECT IDENTIFIER ::= { id-pkip id-regInfo(2) }
+
+ public static readonly DerObjectIdentifier regCtrl_regToken = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.1");
+ public static readonly DerObjectIdentifier regCtrl_authenticator = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.2");
+ public static readonly DerObjectIdentifier regCtrl_pkiPublicationInfo = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.3");
+ public static readonly DerObjectIdentifier regCtrl_pkiArchiveOptions = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.4");
+ public static readonly DerObjectIdentifier regCtrl_oldCertID = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.5");
+ public static readonly DerObjectIdentifier regCtrl_protocolEncrKey = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.6");
+
+ // From RFC4210:
+ // id-regCtrl-altCertTemplate OBJECT IDENTIFIER ::= {id-regCtrl 7}
+ public static readonly DerObjectIdentifier regCtrl_altCertTemplate = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.7");
+
+ public static readonly DerObjectIdentifier regInfo_utf8Pairs = new DerObjectIdentifier("1.3.6.1.5.5.7.5.2.1");
+ public static readonly DerObjectIdentifier regInfo_certReq = new DerObjectIdentifier("1.3.6.1.5.5.7.5.2.2");
+
+ // id-smime OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ // us(840) rsadsi(113549) pkcs(1) pkcs9(9) 16 }
+ //
+ // id-ct OBJECT IDENTIFIER ::= { id-smime 1 } -- content types
+ //
+ // id-ct-encKeyWithID OBJECT IDENTIFIER ::= {id-ct 21}
+ public static readonly DerObjectIdentifier ct_encKeyWithID = new DerObjectIdentifier("1.2.840.113549.1.9.16.1.21");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/CrlAnnContent.cs b/bc-sharp-crypto/src/asn1/cmp/CrlAnnContent.cs
new file mode 100644
index 0000000000000000000000000000000000000000..db8ecfa405961a309915c6f399bcec908ef1f0c9
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/CrlAnnContent.cs
@@ -0,0 +1,50 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class CrlAnnContent
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence content;
+
+ private CrlAnnContent(Asn1Sequence seq)
+ {
+ content = seq;
+ }
+
+ public static CrlAnnContent GetInstance(object obj)
+ {
+ if (obj is CrlAnnContent)
+ return (CrlAnnContent)obj;
+
+ if (obj is Asn1Sequence)
+ return new CrlAnnContent((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public virtual CertificateList[] ToCertificateListArray()
+ {
+ CertificateList[] result = new CertificateList[content.Count];
+ for (int i = 0; i != result.Length; ++ i)
+ {
+ result[i] = CertificateList.GetInstance(content[i]);
+ }
+ return result;
+ }
+
+ /**
+ *
+ * CrlAnnContent ::= SEQUENCE OF CertificateList
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return content;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/ErrorMsgContent.cs b/bc-sharp-crypto/src/asn1/cmp/ErrorMsgContent.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5d2132bb8e1abc03daa2d02fc00e4caefd4df34e
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/ErrorMsgContent.cs
@@ -0,0 +1,95 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class ErrorMsgContent
+ : Asn1Encodable
+ {
+ private readonly PkiStatusInfo pkiStatusInfo;
+ private readonly DerInteger errorCode;
+ private readonly PkiFreeText errorDetails;
+
+ private ErrorMsgContent(Asn1Sequence seq)
+ {
+ pkiStatusInfo = PkiStatusInfo.GetInstance(seq[0]);
+
+ for (int pos = 1; pos < seq.Count; ++pos)
+ {
+ Asn1Encodable ae = seq[pos];
+ if (ae is DerInteger)
+ {
+ errorCode = DerInteger.GetInstance(ae);
+ }
+ else
+ {
+ errorDetails = PkiFreeText.GetInstance(ae);
+ }
+ }
+ }
+
+ public static ErrorMsgContent GetInstance(object obj)
+ {
+ if (obj is ErrorMsgContent)
+ return (ErrorMsgContent)obj;
+
+ if (obj is Asn1Sequence)
+ return new ErrorMsgContent((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public ErrorMsgContent(PkiStatusInfo pkiStatusInfo)
+ : this(pkiStatusInfo, null, null)
+ {
+ }
+
+ public ErrorMsgContent(
+ PkiStatusInfo pkiStatusInfo,
+ DerInteger errorCode,
+ PkiFreeText errorDetails)
+ {
+ if (pkiStatusInfo == null)
+ throw new ArgumentNullException("pkiStatusInfo");
+
+ this.pkiStatusInfo = pkiStatusInfo;
+ this.errorCode = errorCode;
+ this.errorDetails = errorDetails;
+ }
+
+ public virtual PkiStatusInfo PkiStatusInfo
+ {
+ get { return pkiStatusInfo; }
+ }
+
+ public virtual DerInteger ErrorCode
+ {
+ get { return errorCode; }
+ }
+
+ public virtual PkiFreeText ErrorDetails
+ {
+ get { return errorDetails; }
+ }
+
+ /**
+ *
+ * ErrorMsgContent ::= SEQUENCE {
+ * pKIStatusInfo PKIStatusInfo,
+ * errorCode INTEGER OPTIONAL,
+ * -- implementation-specific error codes
+ * errorDetails PKIFreeText OPTIONAL
+ * -- implementation-specific error details
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(pkiStatusInfo);
+ v.AddOptional(errorCode, errorDetails);
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/GenMsgContent.cs b/bc-sharp-crypto/src/asn1/cmp/GenMsgContent.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f3142b5c6a489e46107161e24bd778e08f7f6843
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/GenMsgContent.cs
@@ -0,0 +1,54 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class GenMsgContent
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence content;
+
+ private GenMsgContent(Asn1Sequence seq)
+ {
+ content = seq;
+ }
+
+ public static GenMsgContent GetInstance(object obj)
+ {
+ if (obj is GenMsgContent)
+ return (GenMsgContent)obj;
+
+ if (obj is Asn1Sequence)
+ return new GenMsgContent((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public GenMsgContent(params InfoTypeAndValue[] itv)
+ {
+ content = new DerSequence(itv);
+ }
+
+ public virtual InfoTypeAndValue[] ToInfoTypeAndValueArray()
+ {
+ InfoTypeAndValue[] result = new InfoTypeAndValue[content.Count];
+ for (int i = 0; i != result.Length; ++i)
+ {
+ result[i] = InfoTypeAndValue.GetInstance(content[i]);
+ }
+ return result;
+ }
+
+ /**
+ *
+ * GenMsgContent ::= SEQUENCE OF InfoTypeAndValue
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return content;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/GenRepContent.cs b/bc-sharp-crypto/src/asn1/cmp/GenRepContent.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3c3573e37b648b03575e67f31a702ec26dcfd343
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/GenRepContent.cs
@@ -0,0 +1,54 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class GenRepContent
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence content;
+
+ private GenRepContent(Asn1Sequence seq)
+ {
+ content = seq;
+ }
+
+ public static GenRepContent GetInstance(object obj)
+ {
+ if (obj is GenRepContent)
+ return (GenRepContent)obj;
+
+ if (obj is Asn1Sequence)
+ return new GenRepContent((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public GenRepContent(params InfoTypeAndValue[] itv)
+ {
+ content = new DerSequence(itv);
+ }
+
+ public virtual InfoTypeAndValue[] ToInfoTypeAndValueArray()
+ {
+ InfoTypeAndValue[] result = new InfoTypeAndValue[content.Count];
+ for (int i = 0; i != result.Length; ++i)
+ {
+ result[i] = InfoTypeAndValue.GetInstance(content[i]);
+ }
+ return result;
+ }
+
+ /**
+ *
+ * GenRepContent ::= SEQUENCE OF InfoTypeAndValue
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return content;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/InfoTypeAndValue.cs b/bc-sharp-crypto/src/asn1/cmp/InfoTypeAndValue.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0ce6f73ba18c6dee81c1be6414a9fae24316169a
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/InfoTypeAndValue.cs
@@ -0,0 +1,123 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ /**
+ * Example InfoTypeAndValue contents include, but are not limited
+ * to, the following (un-comment in this ASN.1 module and use as
+ * appropriate for a given environment):
+ *
+ * id-it-caProtEncCert OBJECT IDENTIFIER ::= {id-it 1}
+ * CAProtEncCertValue ::= CMPCertificate
+ * id-it-signKeyPairTypes OBJECT IDENTIFIER ::= {id-it 2}
+ * SignKeyPairTypesValue ::= SEQUENCE OF AlgorithmIdentifier
+ * id-it-encKeyPairTypes OBJECT IDENTIFIER ::= {id-it 3}
+ * EncKeyPairTypesValue ::= SEQUENCE OF AlgorithmIdentifier
+ * id-it-preferredSymmAlg OBJECT IDENTIFIER ::= {id-it 4}
+ * PreferredSymmAlgValue ::= AlgorithmIdentifier
+ * id-it-caKeyUpdateInfo OBJECT IDENTIFIER ::= {id-it 5}
+ * CAKeyUpdateInfoValue ::= CAKeyUpdAnnContent
+ * id-it-currentCRL OBJECT IDENTIFIER ::= {id-it 6}
+ * CurrentCRLValue ::= CertificateList
+ * id-it-unsupportedOIDs OBJECT IDENTIFIER ::= {id-it 7}
+ * UnsupportedOIDsValue ::= SEQUENCE OF OBJECT IDENTIFIER
+ * id-it-keyPairParamReq OBJECT IDENTIFIER ::= {id-it 10}
+ * KeyPairParamReqValue ::= OBJECT IDENTIFIER
+ * id-it-keyPairParamRep OBJECT IDENTIFIER ::= {id-it 11}
+ * KeyPairParamRepValue ::= AlgorithmIdentifer
+ * id-it-revPassphrase OBJECT IDENTIFIER ::= {id-it 12}
+ * RevPassphraseValue ::= EncryptedValue
+ * id-it-implicitConfirm OBJECT IDENTIFIER ::= {id-it 13}
+ * ImplicitConfirmValue ::= NULL
+ * id-it-confirmWaitTime OBJECT IDENTIFIER ::= {id-it 14}
+ * ConfirmWaitTimeValue ::= GeneralizedTime
+ * id-it-origPKIMessage OBJECT IDENTIFIER ::= {id-it 15}
+ * OrigPKIMessageValue ::= PKIMessages
+ * id-it-suppLangTags OBJECT IDENTIFIER ::= {id-it 16}
+ * SuppLangTagsValue ::= SEQUENCE OF UTF8String
+ *
+ * where
+ *
+ * id-pkix OBJECT IDENTIFIER ::= {
+ * iso(1) identified-organization(3)
+ * dod(6) internet(1) security(5) mechanisms(5) pkix(7)}
+ * and
+ * id-it OBJECT IDENTIFIER ::= {id-pkix 4}
+ *
+ */
+ public class InfoTypeAndValue
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier infoType;
+ private readonly Asn1Encodable infoValue;
+
+ private InfoTypeAndValue(Asn1Sequence seq)
+ {
+ infoType = DerObjectIdentifier.GetInstance(seq[0]);
+
+ if (seq.Count > 1)
+ {
+ infoValue = (Asn1Encodable)seq[1];
+ }
+ }
+
+ public static InfoTypeAndValue GetInstance(object obj)
+ {
+ if (obj is InfoTypeAndValue)
+ return (InfoTypeAndValue)obj;
+
+ if (obj is Asn1Sequence)
+ return new InfoTypeAndValue((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public InfoTypeAndValue(
+ DerObjectIdentifier infoType)
+ {
+ this.infoType = infoType;
+ this.infoValue = null;
+ }
+
+ public InfoTypeAndValue(
+ DerObjectIdentifier infoType,
+ Asn1Encodable optionalValue)
+ {
+ this.infoType = infoType;
+ this.infoValue = optionalValue;
+ }
+
+ public virtual DerObjectIdentifier InfoType
+ {
+ get { return infoType; }
+ }
+
+ public virtual Asn1Encodable InfoValue
+ {
+ get { return infoValue; }
+ }
+
+ /**
+ *
+ * InfoTypeAndValue ::= SEQUENCE {
+ * infoType OBJECT IDENTIFIER,
+ * infoValue ANY DEFINED BY infoType OPTIONAL
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(infoType);
+
+ if (infoValue != null)
+ {
+ v.Add(infoValue);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/KeyRecRepContent.cs b/bc-sharp-crypto/src/asn1/cmp/KeyRecRepContent.cs
new file mode 100644
index 0000000000000000000000000000000000000000..00c4612b9384f3ae0070af7a8ffd61bace66957f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/KeyRecRepContent.cs
@@ -0,0 +1,117 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class KeyRecRepContent
+ : Asn1Encodable
+ {
+ private readonly PkiStatusInfo status;
+ private readonly CmpCertificate newSigCert;
+ private readonly Asn1Sequence caCerts;
+ private readonly Asn1Sequence keyPairHist;
+
+ private KeyRecRepContent(Asn1Sequence seq)
+ {
+ status = PkiStatusInfo.GetInstance(seq[0]);
+
+ for (int pos = 1; pos < seq.Count; ++pos)
+ {
+ Asn1TaggedObject tObj = Asn1TaggedObject.GetInstance(seq[pos]);
+
+ switch (tObj.TagNo)
+ {
+ case 0:
+ newSigCert = CmpCertificate.GetInstance(tObj.GetObject());
+ break;
+ case 1:
+ caCerts = Asn1Sequence.GetInstance(tObj.GetObject());
+ break;
+ case 2:
+ keyPairHist = Asn1Sequence.GetInstance(tObj.GetObject());
+ break;
+ default:
+ throw new ArgumentException("unknown tag number: " + tObj.TagNo, "seq");
+ }
+ }
+ }
+
+ public static KeyRecRepContent GetInstance(object obj)
+ {
+ if (obj is KeyRecRepContent)
+ return (KeyRecRepContent)obj;
+
+ if (obj is Asn1Sequence)
+ return new KeyRecRepContent((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public virtual PkiStatusInfo Status
+ {
+ get { return status; }
+ }
+
+ public virtual CmpCertificate NewSigCert
+ {
+ get { return newSigCert; }
+ }
+
+ public virtual CmpCertificate[] GetCACerts()
+ {
+ if (caCerts == null)
+ return null;
+
+ CmpCertificate[] results = new CmpCertificate[caCerts.Count];
+ for (int i = 0; i != results.Length; ++i)
+ {
+ results[i] = CmpCertificate.GetInstance(caCerts[i]);
+ }
+ return results;
+ }
+
+ public virtual CertifiedKeyPair[] GetKeyPairHist()
+ {
+ if (keyPairHist == null)
+ return null;
+
+ CertifiedKeyPair[] results = new CertifiedKeyPair[keyPairHist.Count];
+ for (int i = 0; i != results.Length; ++i)
+ {
+ results[i] = CertifiedKeyPair.GetInstance(keyPairHist[i]);
+ }
+ return results;
+ }
+
+ /**
+ *
+ * KeyRecRepContent ::= SEQUENCE {
+ * status PKIStatusInfo,
+ * newSigCert [0] CMPCertificate OPTIONAL,
+ * caCerts [1] SEQUENCE SIZE (1..MAX) OF
+ * CMPCertificate OPTIONAL,
+ * keyPairHist [2] SEQUENCE SIZE (1..MAX) OF
+ * CertifiedKeyPair OPTIONAL
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(status);
+ AddOptional(v, 0, newSigCert);
+ AddOptional(v, 1, caCerts);
+ AddOptional(v, 2, keyPairHist);
+ return new DerSequence(v);
+ }
+
+ private void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+ {
+ if (obj != null)
+ {
+ v.Add(new DerTaggedObject(true, tagNo, obj));
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/OobCertHash.cs b/bc-sharp-crypto/src/asn1/cmp/OobCertHash.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cd8192b4097bedfc75eb05dadb3afa539e3dc2e1
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/OobCertHash.cs
@@ -0,0 +1,88 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class OobCertHash
+ : Asn1Encodable
+ {
+ private readonly AlgorithmIdentifier hashAlg;
+ private readonly CertId certId;
+ private readonly DerBitString hashVal;
+
+ private OobCertHash(Asn1Sequence seq)
+ {
+ int index = seq.Count - 1;
+
+ hashVal = DerBitString.GetInstance(seq[index--]);
+
+ for (int i = index; i >= 0; i--)
+ {
+ Asn1TaggedObject tObj = (Asn1TaggedObject)seq[i];
+
+ if (tObj.TagNo == 0)
+ {
+ hashAlg = AlgorithmIdentifier.GetInstance(tObj, true);
+ }
+ else
+ {
+ certId = CertId.GetInstance(tObj, true);
+ }
+ }
+ }
+
+ public static OobCertHash GetInstance(object obj)
+ {
+ if (obj is OobCertHash)
+ return (OobCertHash)obj;
+
+ if (obj is Asn1Sequence)
+ return new OobCertHash((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public virtual AlgorithmIdentifier HashAlg
+ {
+ get { return hashAlg; }
+ }
+
+ public virtual CertId CertID
+ {
+ get { return certId; }
+ }
+
+ /**
+ *
+ * OobCertHash ::= SEQUENCE {
+ * hashAlg [0] AlgorithmIdentifier OPTIONAL,
+ * certId [1] CertId OPTIONAL,
+ * hashVal BIT STRING
+ * -- hashVal is calculated over the Der encoding of the
+ * -- self-signed certificate with the identifier certID.
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+ AddOptional(v, 0, hashAlg);
+ AddOptional(v, 1, certId);
+ v.Add(hashVal);
+ return new DerSequence(v);
+ }
+
+ private void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+ {
+ if (obj != null)
+ {
+ v.Add(new DerTaggedObject(true, tagNo, obj));
+ }
+ }
+ }
+}
+
diff --git a/bc-sharp-crypto/src/asn1/cmp/PKIBody.cs b/bc-sharp-crypto/src/asn1/cmp/PKIBody.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f17eed64d5a158334ee3983ad38ccd835ba0d2b0
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/PKIBody.cs
@@ -0,0 +1,187 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class PkiBody
+ : Asn1Encodable, IAsn1Choice
+ {
+ public const int TYPE_INIT_REQ = 0;
+ public const int TYPE_INIT_REP = 1;
+ public const int TYPE_CERT_REQ = 2;
+ public const int TYPE_CERT_REP = 3;
+ public const int TYPE_P10_CERT_REQ = 4;
+ public const int TYPE_POPO_CHALL = 5;
+ public const int TYPE_POPO_REP = 6;
+ public const int TYPE_KEY_UPDATE_REQ = 7;
+ public const int TYPE_KEY_UPDATE_REP = 8;
+ public const int TYPE_KEY_RECOVERY_REQ = 9;
+ public const int TYPE_KEY_RECOVERY_REP = 10;
+ public const int TYPE_REVOCATION_REQ = 11;
+ public const int TYPE_REVOCATION_REP = 12;
+ public const int TYPE_CROSS_CERT_REQ = 13;
+ public const int TYPE_CROSS_CERT_REP = 14;
+ public const int TYPE_CA_KEY_UPDATE_ANN = 15;
+ public const int TYPE_CERT_ANN = 16;
+ public const int TYPE_REVOCATION_ANN = 17;
+ public const int TYPE_CRL_ANN = 18;
+ public const int TYPE_CONFIRM = 19;
+ public const int TYPE_NESTED = 20;
+ public const int TYPE_GEN_MSG = 21;
+ public const int TYPE_GEN_REP = 22;
+ public const int TYPE_ERROR = 23;
+ public const int TYPE_CERT_CONFIRM = 24;
+ public const int TYPE_POLL_REQ = 25;
+ public const int TYPE_POLL_REP = 26;
+
+ private int tagNo;
+ private Asn1Encodable body;
+
+ public static PkiBody GetInstance(object obj)
+ {
+ if (obj is PkiBody)
+ return (PkiBody)obj;
+
+ if (obj is Asn1TaggedObject)
+ return new PkiBody((Asn1TaggedObject)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private PkiBody(Asn1TaggedObject tagged)
+ {
+ tagNo = tagged.TagNo;
+ body = GetBodyForType(tagNo, tagged.GetObject());
+ }
+
+ /**
+ * Creates a new PkiBody.
+ * @param type one of the TYPE_* constants
+ * @param content message content
+ */
+ public PkiBody(
+ int type,
+ Asn1Encodable content)
+ {
+ tagNo = type;
+ body = GetBodyForType(type, content);
+ }
+
+ private static Asn1Encodable GetBodyForType(
+ int type,
+ Asn1Encodable o)
+ {
+ switch (type)
+ {
+ case TYPE_INIT_REQ:
+ return CertReqMessages.GetInstance(o);
+ case TYPE_INIT_REP:
+ return CertRepMessage.GetInstance(o);
+ case TYPE_CERT_REQ:
+ return CertReqMessages.GetInstance(o);
+ case TYPE_CERT_REP:
+ return CertRepMessage.GetInstance(o);
+ case TYPE_P10_CERT_REQ:
+ return CertificationRequest.GetInstance(o);
+ case TYPE_POPO_CHALL:
+ return PopoDecKeyChallContent.GetInstance(o);
+ case TYPE_POPO_REP:
+ return PopoDecKeyRespContent.GetInstance(o);
+ case TYPE_KEY_UPDATE_REQ:
+ return CertReqMessages.GetInstance(o);
+ case TYPE_KEY_UPDATE_REP:
+ return CertRepMessage.GetInstance(o);
+ case TYPE_KEY_RECOVERY_REQ:
+ return CertReqMessages.GetInstance(o);
+ case TYPE_KEY_RECOVERY_REP:
+ return KeyRecRepContent.GetInstance(o);
+ case TYPE_REVOCATION_REQ:
+ return RevReqContent.GetInstance(o);
+ case TYPE_REVOCATION_REP:
+ return RevRepContent.GetInstance(o);
+ case TYPE_CROSS_CERT_REQ:
+ return CertReqMessages.GetInstance(o);
+ case TYPE_CROSS_CERT_REP:
+ return CertRepMessage.GetInstance(o);
+ case TYPE_CA_KEY_UPDATE_ANN:
+ return CAKeyUpdAnnContent.GetInstance(o);
+ case TYPE_CERT_ANN:
+ return CmpCertificate.GetInstance(o);
+ case TYPE_REVOCATION_ANN:
+ return RevAnnContent.GetInstance(o);
+ case TYPE_CRL_ANN:
+ return CrlAnnContent.GetInstance(o);
+ case TYPE_CONFIRM:
+ return PkiConfirmContent.GetInstance(o);
+ case TYPE_NESTED:
+ return PkiMessages.GetInstance(o);
+ case TYPE_GEN_MSG:
+ return GenMsgContent.GetInstance(o);
+ case TYPE_GEN_REP:
+ return GenRepContent.GetInstance(o);
+ case TYPE_ERROR:
+ return ErrorMsgContent.GetInstance(o);
+ case TYPE_CERT_CONFIRM:
+ return CertConfirmContent.GetInstance(o);
+ case TYPE_POLL_REQ:
+ return PollReqContent.GetInstance(o);
+ case TYPE_POLL_REP:
+ return PollRepContent.GetInstance(o);
+ default:
+ throw new ArgumentException("unknown tag number: " + type, "type");
+ }
+ }
+
+ public virtual int Type
+ {
+ get { return tagNo; }
+ }
+
+ public virtual Asn1Encodable Content
+ {
+ get { return body; }
+ }
+
+ /**
+ *
+ * PkiBody ::= CHOICE { -- message-specific body elements
+ * ir [0] CertReqMessages, --Initialization Request
+ * ip [1] CertRepMessage, --Initialization Response
+ * cr [2] CertReqMessages, --Certification Request
+ * cp [3] CertRepMessage, --Certification Response
+ * p10cr [4] CertificationRequest, --imported from [PKCS10]
+ * popdecc [5] POPODecKeyChallContent, --pop Challenge
+ * popdecr [6] POPODecKeyRespContent, --pop Response
+ * kur [7] CertReqMessages, --Key Update Request
+ * kup [8] CertRepMessage, --Key Update Response
+ * krr [9] CertReqMessages, --Key Recovery Request
+ * krp [10] KeyRecRepContent, --Key Recovery Response
+ * rr [11] RevReqContent, --Revocation Request
+ * rp [12] RevRepContent, --Revocation Response
+ * ccr [13] CertReqMessages, --Cross-Cert. Request
+ * ccp [14] CertRepMessage, --Cross-Cert. Response
+ * ckuann [15] CAKeyUpdAnnContent, --CA Key Update Ann.
+ * cann [16] CertAnnContent, --Certificate Ann.
+ * rann [17] RevAnnContent, --Revocation Ann.
+ * crlann [18] CRLAnnContent, --CRL Announcement
+ * pkiconf [19] PKIConfirmContent, --Confirmation
+ * nested [20] NestedMessageContent, --Nested Message
+ * genm [21] GenMsgContent, --General Message
+ * genp [22] GenRepContent, --General Response
+ * error [23] ErrorMsgContent, --Error Message
+ * certConf [24] CertConfirmContent, --Certificate confirm
+ * pollReq [25] PollReqContent, --Polling request
+ * pollRep [26] PollRepContent --Polling response
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerTaggedObject(true, tagNo, body);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/PKIConfirmContent.cs b/bc-sharp-crypto/src/asn1/cmp/PKIConfirmContent.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d154427a4a72761721551b643495b42b47c7af1c
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/PKIConfirmContent.cs
@@ -0,0 +1,36 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class PkiConfirmContent
+ : Asn1Encodable
+ {
+ public static PkiConfirmContent GetInstance(object obj)
+ {
+ if (obj is PkiConfirmContent)
+ return (PkiConfirmContent)obj;
+
+ if (obj is Asn1Null)
+ return new PkiConfirmContent();
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public PkiConfirmContent()
+ {
+ }
+
+ /**
+ *
+ * PkiConfirmContent ::= NULL
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return DerNull.Instance;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/PKIFailureInfo.cs b/bc-sharp-crypto/src/asn1/cmp/PKIFailureInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..75a3ff0d7ceb5ae0f948353a8a5e2bbf8546353b
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/PKIFailureInfo.cs
@@ -0,0 +1,96 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ /**
+ *
+ * PKIFailureInfo ::= BIT STRING {
+ * badAlg (0),
+ * -- unrecognized or unsupported Algorithm Identifier
+ * badMessageCheck (1), -- integrity check failed (e.g., signature did not verify)
+ * badRequest (2),
+ * -- transaction not permitted or supported
+ * badTime (3), -- messageTime was not sufficiently close to the system time, as defined by local policy
+ * badCertId (4), -- no certificate could be found matching the provided criteria
+ * badDataFormat (5),
+ * -- the data submitted has the wrong format
+ * wrongAuthority (6), -- the authority indicated in the request is different from the one creating the response token
+ * incorrectData (7), -- the requester's data is incorrect (for notary services)
+ * missingTimeStamp (8), -- when the timestamp is missing but should be there (by policy)
+ * badPOP (9) -- the proof-of-possession failed
+ * certRevoked (10),
+ * certConfirmed (11),
+ * wrongIntegrity (12),
+ * badRecipientNonce (13),
+ * timeNotAvailable (14),
+ * -- the TSA's time source is not available
+ * unacceptedPolicy (15),
+ * -- the requested TSA policy is not supported by the TSA
+ * unacceptedExtension (16),
+ * -- the requested extension is not supported by the TSA
+ * addInfoNotAvailable (17)
+ * -- the additional information requested could not be understood
+ * -- or is not available
+ * badSenderNonce (18),
+ * badCertTemplate (19),
+ * signerNotTrusted (20),
+ * transactionIdInUse (21),
+ * unsupportedVersion (22),
+ * notAuthorized (23),
+ * systemUnavail (24),
+ * systemFailure (25),
+ * -- the request cannot be handled due to system failure
+ * duplicateCertReq (26)
+ *
+ */
+ public class PkiFailureInfo
+ : DerBitString
+ {
+ public const int BadAlg = (1 << 7); // unrecognized or unsupported Algorithm Identifier
+ public const int BadMessageCheck = (1 << 6); // integrity check failed (e.g., signature did not verify)
+ public const int BadRequest = (1 << 5);
+ public const int BadTime = (1 << 4); // -- messageTime was not sufficiently close to the system time, as defined by local policy
+ public const int BadCertId = (1 << 3); // no certificate could be found matching the provided criteria
+ public const int BadDataFormat = (1 << 2);
+ public const int WrongAuthority = (1 << 1); // the authority indicated in the request is different from the one creating the response token
+ public const int IncorrectData = 1; // the requester's data is incorrect (for notary services)
+ public const int MissingTimeStamp = (1 << 15); // when the timestamp is missing but should be there (by policy)
+ public const int BadPop = (1 << 14); // the proof-of-possession failed
+ public const int CertRevoked = (1 << 13);
+ public const int CertConfirmed = (1 << 12);
+ public const int WrongIntegrity = (1 << 11);
+ public const int BadRecipientNonce = (1 << 10);
+ public const int TimeNotAvailable = (1 << 9); // the TSA's time source is not available
+ public const int UnacceptedPolicy = (1 << 8); // the requested TSA policy is not supported by the TSA
+ public const int UnacceptedExtension = (1 << 23); //the requested extension is not supported by the TSA
+ public const int AddInfoNotAvailable = (1 << 22); //the additional information requested could not be understood or is not available
+ public const int BadSenderNonce = (1 << 21);
+ public const int BadCertTemplate = (1 << 20);
+ public const int SignerNotTrusted = (1 << 19);
+ public const int TransactionIdInUse = (1 << 18);
+ public const int UnsupportedVersion = (1 << 17);
+ public const int NotAuthorized = (1 << 16);
+ public const int SystemUnavail = (1 << 31);
+ public const int SystemFailure = (1 << 30); //the request cannot be handled due to system failure
+ public const int DuplicateCertReq = (1 << 29);
+
+ /**
+ * Basic constructor.
+ */
+ public PkiFailureInfo(int info)
+ : base(info)
+ {
+ }
+
+ public PkiFailureInfo(
+ DerBitString info)
+ : base(info.GetBytes(), info.PadBits)
+ {
+ }
+
+ public override string ToString()
+ {
+ return "PkiFailureInfo: 0x" + this.IntValue.ToString("X");
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/PKIFreeText.cs b/bc-sharp-crypto/src/asn1/cmp/PKIFreeText.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fef525465311fb12653cacb05d4c57274900e8d1
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/PKIFreeText.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class PkiFreeText
+ : Asn1Encodable
+ {
+ internal Asn1Sequence strings;
+
+ public static PkiFreeText GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ public static PkiFreeText GetInstance(
+ object obj)
+ {
+ if (obj is PkiFreeText)
+ {
+ return (PkiFreeText)obj;
+ }
+ else if (obj is Asn1Sequence)
+ {
+ return new PkiFreeText((Asn1Sequence)obj);
+ }
+
+ throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public PkiFreeText(
+ Asn1Sequence seq)
+ {
+ foreach (object o in seq)
+ {
+ if (!(o is DerUtf8String))
+ {
+ throw new ArgumentException("attempt to insert non UTF8 STRING into PkiFreeText");
+ }
+ }
+
+ this.strings = seq;
+ }
+
+ public PkiFreeText(
+ DerUtf8String p)
+ {
+ strings = new DerSequence(p);
+ }
+
+ /**
+ * Return the number of string elements present.
+ *
+ * @return number of elements present.
+ */
+ [Obsolete("Use 'Count' property instead")]
+ public int Size
+ {
+ get { return strings.Count; }
+ }
+
+ public int Count
+ {
+ get { return strings.Count; }
+ }
+
+ /**
+ * Return the UTF8STRING at index.
+ *
+ * @param index index of the string of interest
+ * @return the string at index.
+ */
+ public DerUtf8String this[int index]
+ {
+ get { return (DerUtf8String) strings[index]; }
+ }
+
+ [Obsolete("Use 'object[index]' syntax instead")]
+ public DerUtf8String GetStringAt(
+ int index)
+ {
+ return this[index];
+ }
+
+ /**
+ *
+ * PkiFreeText ::= SEQUENCE SIZE (1..MAX) OF UTF8String
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return strings;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/PKIHeader.cs b/bc-sharp-crypto/src/asn1/cmp/PKIHeader.cs
new file mode 100644
index 0000000000000000000000000000000000000000..577cb45df53a405a15471af209fb5bad97f240c0
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/PKIHeader.cs
@@ -0,0 +1,238 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class PkiHeader
+ : Asn1Encodable
+ {
+ /**
+ * Value for a "null" recipient or sender.
+ */
+ public static readonly GeneralName NULL_NAME = new GeneralName(X509Name.GetInstance(new DerSequence()));
+
+ public static readonly int CMP_1999 = 1;
+ public static readonly int CMP_2000 = 2;
+
+ private readonly DerInteger pvno;
+ private readonly GeneralName sender;
+ private readonly GeneralName recipient;
+ private readonly DerGeneralizedTime messageTime;
+ private readonly AlgorithmIdentifier protectionAlg;
+ private readonly Asn1OctetString senderKID; // KeyIdentifier
+ private readonly Asn1OctetString recipKID; // KeyIdentifier
+ private readonly Asn1OctetString transactionID;
+ private readonly Asn1OctetString senderNonce;
+ private readonly Asn1OctetString recipNonce;
+ private readonly PkiFreeText freeText;
+ private readonly Asn1Sequence generalInfo;
+
+ private PkiHeader(Asn1Sequence seq)
+ {
+ pvno = DerInteger.GetInstance(seq[0]);
+ sender = GeneralName.GetInstance(seq[1]);
+ recipient = GeneralName.GetInstance(seq[2]);
+
+ for (int pos = 3; pos < seq.Count; ++pos)
+ {
+ Asn1TaggedObject tObj = (Asn1TaggedObject)seq[pos];
+
+ switch (tObj.TagNo)
+ {
+ case 0:
+ messageTime = DerGeneralizedTime.GetInstance(tObj, true);
+ break;
+ case 1:
+ protectionAlg = AlgorithmIdentifier.GetInstance(tObj, true);
+ break;
+ case 2:
+ senderKID = Asn1OctetString.GetInstance(tObj, true);
+ break;
+ case 3:
+ recipKID = Asn1OctetString.GetInstance(tObj, true);
+ break;
+ case 4:
+ transactionID = Asn1OctetString.GetInstance(tObj, true);
+ break;
+ case 5:
+ senderNonce = Asn1OctetString.GetInstance(tObj, true);
+ break;
+ case 6:
+ recipNonce = Asn1OctetString.GetInstance(tObj, true);
+ break;
+ case 7:
+ freeText = PkiFreeText.GetInstance(tObj, true);
+ break;
+ case 8:
+ generalInfo = Asn1Sequence.GetInstance(tObj, true);
+ break;
+ default:
+ throw new ArgumentException("unknown tag number: " + tObj.TagNo, "seq");
+ }
+ }
+ }
+
+ public static PkiHeader GetInstance(object obj)
+ {
+ if (obj is PkiHeader)
+ return (PkiHeader)obj;
+
+ if (obj is Asn1Sequence)
+ return new PkiHeader((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public PkiHeader(
+ int pvno,
+ GeneralName sender,
+ GeneralName recipient)
+ : this(new DerInteger(pvno), sender, recipient)
+ {
+ }
+
+ private PkiHeader(
+ DerInteger pvno,
+ GeneralName sender,
+ GeneralName recipient)
+ {
+ this.pvno = pvno;
+ this.sender = sender;
+ this.recipient = recipient;
+ }
+
+ public virtual DerInteger Pvno
+ {
+ get { return pvno; }
+ }
+
+ public virtual GeneralName Sender
+ {
+ get { return sender; }
+ }
+
+ public virtual GeneralName Recipient
+ {
+ get { return recipient; }
+ }
+
+ public virtual DerGeneralizedTime MessageTime
+ {
+ get { return messageTime; }
+ }
+
+ public virtual AlgorithmIdentifier ProtectionAlg
+ {
+ get { return protectionAlg; }
+ }
+
+ public virtual Asn1OctetString SenderKID
+ {
+ get { return senderKID; }
+ }
+
+ public virtual Asn1OctetString RecipKID
+ {
+ get { return recipKID; }
+ }
+
+ public virtual Asn1OctetString TransactionID
+ {
+ get { return transactionID; }
+ }
+
+ public virtual Asn1OctetString SenderNonce
+ {
+ get { return senderNonce; }
+ }
+
+ public virtual Asn1OctetString RecipNonce
+ {
+ get { return recipNonce; }
+ }
+
+ public virtual PkiFreeText FreeText
+ {
+ get { return freeText; }
+ }
+
+ public virtual InfoTypeAndValue[] GetGeneralInfo()
+ {
+ if (generalInfo == null)
+ {
+ return null;
+ }
+ InfoTypeAndValue[] results = new InfoTypeAndValue[generalInfo.Count];
+ for (int i = 0; i < results.Length; i++)
+ {
+ results[i] = InfoTypeAndValue.GetInstance(generalInfo[i]);
+ }
+ return results;
+ }
+
+ /**
+ *
+ * PkiHeader ::= SEQUENCE {
+ * pvno INTEGER { cmp1999(1), cmp2000(2) },
+ * sender GeneralName,
+ * -- identifies the sender
+ * recipient GeneralName,
+ * -- identifies the intended recipient
+ * messageTime [0] GeneralizedTime OPTIONAL,
+ * -- time of production of this message (used when sender
+ * -- believes that the transport will be "suitable"; i.e.,
+ * -- that the time will still be meaningful upon receipt)
+ * protectionAlg [1] AlgorithmIdentifier OPTIONAL,
+ * -- algorithm used for calculation of protection bits
+ * senderKID [2] KeyIdentifier OPTIONAL,
+ * recipKID [3] KeyIdentifier OPTIONAL,
+ * -- to identify specific keys used for protection
+ * transactionID [4] OCTET STRING OPTIONAL,
+ * -- identifies the transaction; i.e., this will be the same in
+ * -- corresponding request, response, certConf, and PKIConf
+ * -- messages
+ * senderNonce [5] OCTET STRING OPTIONAL,
+ * recipNonce [6] OCTET STRING OPTIONAL,
+ * -- nonces used to provide replay protection, senderNonce
+ * -- is inserted by the creator of this message; recipNonce
+ * -- is a nonce previously inserted in a related message by
+ * -- the intended recipient of this message
+ * freeText [7] PKIFreeText OPTIONAL,
+ * -- this may be used to indicate context-specific instructions
+ * -- (this field is intended for human consumption)
+ * generalInfo [8] SEQUENCE SIZE (1..MAX) OF
+ * InfoTypeAndValue OPTIONAL
+ * -- this may be used to convey context-specific information
+ * -- (this field not primarily intended for human consumption)
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(pvno, sender, recipient);
+
+ AddOptional(v, 0, messageTime);
+ AddOptional(v, 1, protectionAlg);
+ AddOptional(v, 2, senderKID);
+ AddOptional(v, 3, recipKID);
+ AddOptional(v, 4, transactionID);
+ AddOptional(v, 5, senderNonce);
+ AddOptional(v, 6, recipNonce);
+ AddOptional(v, 7, freeText);
+ AddOptional(v, 8, generalInfo);
+
+ return new DerSequence(v);
+ }
+
+ private static void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+ {
+ if (obj != null)
+ {
+ v.Add(new DerTaggedObject(true, tagNo, obj));
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/PKIHeaderBuilder.cs b/bc-sharp-crypto/src/asn1/cmp/PKIHeaderBuilder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..00073c06266613dd58cf8f99b9fde5f19d6e5d93
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/PKIHeaderBuilder.cs
@@ -0,0 +1,223 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class PkiHeaderBuilder
+ {
+ private DerInteger pvno;
+ private GeneralName sender;
+ private GeneralName recipient;
+ private DerGeneralizedTime messageTime;
+ private AlgorithmIdentifier protectionAlg;
+ private Asn1OctetString senderKID; // KeyIdentifier
+ private Asn1OctetString recipKID; // KeyIdentifier
+ private Asn1OctetString transactionID;
+ private Asn1OctetString senderNonce;
+ private Asn1OctetString recipNonce;
+ private PkiFreeText freeText;
+ private Asn1Sequence generalInfo;
+
+ public PkiHeaderBuilder(
+ int pvno,
+ GeneralName sender,
+ GeneralName recipient)
+ : this(new DerInteger(pvno), sender, recipient)
+ {
+ }
+
+ private PkiHeaderBuilder(
+ DerInteger pvno,
+ GeneralName sender,
+ GeneralName recipient)
+ {
+ this.pvno = pvno;
+ this.sender = sender;
+ this.recipient = recipient;
+ }
+
+ public virtual PkiHeaderBuilder SetMessageTime(DerGeneralizedTime time)
+ {
+ messageTime = time;
+ return this;
+ }
+
+ public virtual PkiHeaderBuilder SetProtectionAlg(AlgorithmIdentifier aid)
+ {
+ protectionAlg = aid;
+ return this;
+ }
+
+ public virtual PkiHeaderBuilder SetSenderKID(byte[] kid)
+ {
+ return SetSenderKID(kid == null ? null : new DerOctetString(kid));
+ }
+
+ public virtual PkiHeaderBuilder SetSenderKID(Asn1OctetString kid)
+ {
+ senderKID = kid;
+ return this;
+ }
+
+ public virtual PkiHeaderBuilder SetRecipKID(byte[] kid)
+ {
+ return SetRecipKID(kid == null ? null : new DerOctetString(kid));
+ }
+
+ public virtual PkiHeaderBuilder SetRecipKID(DerOctetString kid)
+ {
+ recipKID = kid;
+ return this;
+ }
+
+ public virtual PkiHeaderBuilder SetTransactionID(byte[] tid)
+ {
+ return SetTransactionID(tid == null ? null : new DerOctetString(tid));
+ }
+
+ public virtual PkiHeaderBuilder SetTransactionID(Asn1OctetString tid)
+ {
+ transactionID = tid;
+ return this;
+ }
+
+ public virtual PkiHeaderBuilder SetSenderNonce(byte[] nonce)
+ {
+ return SetSenderNonce(nonce == null ? null : new DerOctetString(nonce));
+ }
+
+ public virtual PkiHeaderBuilder SetSenderNonce(Asn1OctetString nonce)
+ {
+ senderNonce = nonce;
+ return this;
+ }
+
+ public virtual PkiHeaderBuilder SetRecipNonce(byte[] nonce)
+ {
+ return SetRecipNonce(nonce == null ? null : new DerOctetString(nonce));
+ }
+
+ public virtual PkiHeaderBuilder SetRecipNonce(Asn1OctetString nonce)
+ {
+ recipNonce = nonce;
+ return this;
+ }
+
+ public virtual PkiHeaderBuilder SetFreeText(PkiFreeText text)
+ {
+ freeText = text;
+ return this;
+ }
+
+ public virtual PkiHeaderBuilder SetGeneralInfo(InfoTypeAndValue genInfo)
+ {
+ return SetGeneralInfo(MakeGeneralInfoSeq(genInfo));
+ }
+
+ public virtual PkiHeaderBuilder SetGeneralInfo(InfoTypeAndValue[] genInfos)
+ {
+ return SetGeneralInfo(MakeGeneralInfoSeq(genInfos));
+ }
+
+ public virtual PkiHeaderBuilder SetGeneralInfo(Asn1Sequence seqOfInfoTypeAndValue)
+ {
+ generalInfo = seqOfInfoTypeAndValue;
+ return this;
+ }
+
+ private static Asn1Sequence MakeGeneralInfoSeq(
+ InfoTypeAndValue generalInfo)
+ {
+ return new DerSequence(generalInfo);
+ }
+
+ private static Asn1Sequence MakeGeneralInfoSeq(
+ InfoTypeAndValue[] generalInfos)
+ {
+ Asn1Sequence genInfoSeq = null;
+ if (generalInfos != null)
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+ for (int i = 0; i < generalInfos.Length; ++i)
+ {
+ v.Add(generalInfos[i]);
+ }
+ genInfoSeq = new DerSequence(v);
+ }
+ return genInfoSeq;
+ }
+
+ /**
+ *
+ * PKIHeader ::= SEQUENCE {
+ * pvno INTEGER { cmp1999(1), cmp2000(2) },
+ * sender GeneralName,
+ * -- identifies the sender
+ * recipient GeneralName,
+ * -- identifies the intended recipient
+ * messageTime [0] GeneralizedTime OPTIONAL,
+ * -- time of production of this message (used when sender
+ * -- believes that the transport will be "suitable"; i.e.,
+ * -- that the time will still be meaningful upon receipt)
+ * protectionAlg [1] AlgorithmIdentifier OPTIONAL,
+ * -- algorithm used for calculation of protection bits
+ * senderKID [2] KeyIdentifier OPTIONAL,
+ * recipKID [3] KeyIdentifier OPTIONAL,
+ * -- to identify specific keys used for protection
+ * transactionID [4] OCTET STRING OPTIONAL,
+ * -- identifies the transaction; i.e., this will be the same in
+ * -- corresponding request, response, certConf, and PKIConf
+ * -- messages
+ * senderNonce [5] OCTET STRING OPTIONAL,
+ * recipNonce [6] OCTET STRING OPTIONAL,
+ * -- nonces used to provide replay protection, senderNonce
+ * -- is inserted by the creator of this message; recipNonce
+ * -- is a nonce previously inserted in a related message by
+ * -- the intended recipient of this message
+ * freeText [7] PKIFreeText OPTIONAL,
+ * -- this may be used to indicate context-specific instructions
+ * -- (this field is intended for human consumption)
+ * generalInfo [8] SEQUENCE SIZE (1..MAX) OF
+ * InfoTypeAndValue OPTIONAL
+ * -- this may be used to convey context-specific information
+ * -- (this field not primarily intended for human consumption)
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public virtual PkiHeader Build()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(pvno, sender, recipient);
+ AddOptional(v, 0, messageTime);
+ AddOptional(v, 1, protectionAlg);
+ AddOptional(v, 2, senderKID);
+ AddOptional(v, 3, recipKID);
+ AddOptional(v, 4, transactionID);
+ AddOptional(v, 5, senderNonce);
+ AddOptional(v, 6, recipNonce);
+ AddOptional(v, 7, freeText);
+ AddOptional(v, 8, generalInfo);
+
+ messageTime = null;
+ protectionAlg = null;
+ senderKID = null;
+ recipKID = null;
+ transactionID = null;
+ senderNonce = null;
+ recipNonce = null;
+ freeText = null;
+ generalInfo = null;
+
+ return PkiHeader.GetInstance(new DerSequence(v));
+ }
+
+ private void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+ {
+ if (obj != null)
+ {
+ v.Add(new DerTaggedObject(true, tagNo, obj));
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/PKIMessage.cs b/bc-sharp-crypto/src/asn1/cmp/PKIMessage.cs
new file mode 100644
index 0000000000000000000000000000000000000000..086a2d93853d027ba24e0fbc3853221a8ebb2b41
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/PKIMessage.cs
@@ -0,0 +1,140 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class PkiMessage
+ : Asn1Encodable
+ {
+ private readonly PkiHeader header;
+ private readonly PkiBody body;
+ private readonly DerBitString protection;
+ private readonly Asn1Sequence extraCerts;
+
+ private PkiMessage(Asn1Sequence seq)
+ {
+ header = PkiHeader.GetInstance(seq[0]);
+ body = PkiBody.GetInstance(seq[1]);
+
+ for (int pos = 2; pos < seq.Count; ++pos)
+ {
+ Asn1TaggedObject tObj = (Asn1TaggedObject)seq[pos].ToAsn1Object();
+
+ if (tObj.TagNo == 0)
+ {
+ protection = DerBitString.GetInstance(tObj, true);
+ }
+ else
+ {
+ extraCerts = Asn1Sequence.GetInstance(tObj, true);
+ }
+ }
+ }
+
+ public static PkiMessage GetInstance(object obj)
+ {
+ if (obj is PkiMessage)
+ return (PkiMessage)obj;
+
+ if (obj != null)
+ return new PkiMessage(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ /**
+ * Creates a new PkiMessage.
+ *
+ * @param header message header
+ * @param body message body
+ * @param protection message protection (may be null)
+ * @param extraCerts extra certificates (may be null)
+ */
+ public PkiMessage(
+ PkiHeader header,
+ PkiBody body,
+ DerBitString protection,
+ CmpCertificate[] extraCerts)
+ {
+ this.header = header;
+ this.body = body;
+ this.protection = protection;
+ if (extraCerts != null)
+ {
+ this.extraCerts = new DerSequence(extraCerts);
+ }
+ }
+
+ public PkiMessage(
+ PkiHeader header,
+ PkiBody body,
+ DerBitString protection)
+ : this(header, body, protection, null)
+ {
+ }
+
+ public PkiMessage(
+ PkiHeader header,
+ PkiBody body)
+ : this(header, body, null, null)
+ {
+ }
+
+ public virtual PkiHeader Header
+ {
+ get { return header; }
+ }
+
+ public virtual PkiBody Body
+ {
+ get { return body; }
+ }
+
+ public virtual DerBitString Protection
+ {
+ get { return protection; }
+ }
+
+ public virtual CmpCertificate[] GetExtraCerts()
+ {
+ if (extraCerts == null)
+ return null;
+
+ CmpCertificate[] results = new CmpCertificate[extraCerts.Count];
+ for (int i = 0; i < results.Length; ++i)
+ {
+ results[i] = CmpCertificate.GetInstance(extraCerts[i]);
+ }
+ return results;
+ }
+
+ /**
+ *
+ * PkiMessage ::= SEQUENCE {
+ * header PKIHeader,
+ * body PKIBody,
+ * protection [0] PKIProtection OPTIONAL,
+ * extraCerts [1] SEQUENCE SIZE (1..MAX) OF CMPCertificate
+ * OPTIONAL
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(header, body);
+
+ AddOptional(v, 0, protection);
+ AddOptional(v, 1, extraCerts);
+
+ return new DerSequence(v);
+ }
+
+ private static void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+ {
+ if (obj != null)
+ {
+ v.Add(new DerTaggedObject(true, tagNo, obj));
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/PKIMessages.cs b/bc-sharp-crypto/src/asn1/cmp/PKIMessages.cs
new file mode 100644
index 0000000000000000000000000000000000000000..eb01e544ad712aedae1462c24599e7f70951381f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/PKIMessages.cs
@@ -0,0 +1,54 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class PkiMessages
+ : Asn1Encodable
+ {
+ private Asn1Sequence content;
+
+ private PkiMessages(Asn1Sequence seq)
+ {
+ content = seq;
+ }
+
+ public static PkiMessages GetInstance(object obj)
+ {
+ if (obj is PkiMessages)
+ return (PkiMessages)obj;
+
+ if (obj is Asn1Sequence)
+ return new PkiMessages((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public PkiMessages(params PkiMessage[] msgs)
+ {
+ content = new DerSequence(msgs);
+ }
+
+ public virtual PkiMessage[] ToPkiMessageArray()
+ {
+ PkiMessage[] result = new PkiMessage[content.Count];
+ for (int i = 0; i != result.Length; ++i)
+ {
+ result[i] = PkiMessage.GetInstance(content[i]);
+ }
+ return result;
+ }
+
+ /**
+ *
+ * PkiMessages ::= SEQUENCE SIZE (1..MAX) OF PkiMessage
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return content;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/PKIStatus.cs b/bc-sharp-crypto/src/asn1/cmp/PKIStatus.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ba757dfcf15d8a3ae4134d2ab502bd8ef9024b05
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/PKIStatus.cs
@@ -0,0 +1,63 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public enum PkiStatus
+ {
+ Granted = 0,
+ GrantedWithMods = 1,
+ Rejection = 2,
+ Waiting = 3,
+ RevocationWarning = 4,
+ RevocationNotification = 5,
+ KeyUpdateWarning = 6,
+ }
+
+ public class PkiStatusEncodable
+ : Asn1Encodable
+ {
+ public static readonly PkiStatusEncodable granted = new PkiStatusEncodable(PkiStatus.Granted);
+ public static readonly PkiStatusEncodable grantedWithMods = new PkiStatusEncodable(PkiStatus.GrantedWithMods);
+ public static readonly PkiStatusEncodable rejection = new PkiStatusEncodable(PkiStatus.Rejection);
+ public static readonly PkiStatusEncodable waiting = new PkiStatusEncodable(PkiStatus.Waiting);
+ public static readonly PkiStatusEncodable revocationWarning = new PkiStatusEncodable(PkiStatus.RevocationWarning);
+ public static readonly PkiStatusEncodable revocationNotification = new PkiStatusEncodable(PkiStatus.RevocationNotification);
+ public static readonly PkiStatusEncodable keyUpdateWaiting = new PkiStatusEncodable(PkiStatus.KeyUpdateWarning);
+
+ private readonly DerInteger status;
+
+ private PkiStatusEncodable(PkiStatus status)
+ : this(new DerInteger((int)status))
+ {
+ }
+
+ private PkiStatusEncodable(DerInteger status)
+ {
+ this.status = status;
+ }
+
+ public static PkiStatusEncodable GetInstance(object obj)
+ {
+ if (obj is PkiStatusEncodable)
+ return (PkiStatusEncodable)obj;
+
+ if (obj is DerInteger)
+ return new PkiStatusEncodable((DerInteger)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public virtual BigInteger Value
+ {
+ get { return status.Value; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return status;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/PKIStatusInfo.cs b/bc-sharp-crypto/src/asn1/cmp/PKIStatusInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b19bf74594c715726e9ac20f4e6a7b020ce0c9e8
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/PKIStatusInfo.cs
@@ -0,0 +1,166 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class PkiStatusInfo
+ : Asn1Encodable
+ {
+ DerInteger status;
+ PkiFreeText statusString;
+ DerBitString failInfo;
+
+ public static PkiStatusInfo GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ public static PkiStatusInfo GetInstance(
+ object obj)
+ {
+ if (obj is PkiStatusInfo)
+ {
+ return (PkiStatusInfo)obj;
+ }
+ else if (obj is Asn1Sequence)
+ {
+ return new PkiStatusInfo((Asn1Sequence)obj);
+ }
+
+ throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public PkiStatusInfo(
+ Asn1Sequence seq)
+ {
+ this.status = DerInteger.GetInstance(seq[0]);
+
+ this.statusString = null;
+ this.failInfo = null;
+
+ if (seq.Count > 2)
+ {
+ this.statusString = PkiFreeText.GetInstance(seq[1]);
+ this.failInfo = DerBitString.GetInstance(seq[2]);
+ }
+ else if (seq.Count > 1)
+ {
+ object obj = seq[1];
+ if (obj is DerBitString)
+ {
+ this.failInfo = DerBitString.GetInstance(obj);
+ }
+ else
+ {
+ this.statusString = PkiFreeText.GetInstance(obj);
+ }
+ }
+ }
+
+ /**
+ * @param status
+ */
+ public PkiStatusInfo(int status)
+ {
+ this.status = new DerInteger(status);
+ }
+
+ /**
+ * @param status
+ * @param statusString
+ */
+ public PkiStatusInfo(
+ int status,
+ PkiFreeText statusString)
+ {
+ this.status = new DerInteger(status);
+ this.statusString = statusString;
+ }
+
+ public PkiStatusInfo(
+ int status,
+ PkiFreeText statusString,
+ PkiFailureInfo failInfo)
+ {
+ this.status = new DerInteger(status);
+ this.statusString = statusString;
+ this.failInfo = failInfo;
+ }
+
+ public BigInteger Status
+ {
+ get
+ {
+ return status.Value;
+ }
+ }
+
+ public PkiFreeText StatusString
+ {
+ get
+ {
+ return statusString;
+ }
+ }
+
+ public DerBitString FailInfo
+ {
+ get
+ {
+ return failInfo;
+ }
+ }
+
+ /**
+ *
+ * PkiStatusInfo ::= SEQUENCE {
+ * status PKIStatus, (INTEGER)
+ * statusString PkiFreeText OPTIONAL,
+ * failInfo PkiFailureInfo OPTIONAL (BIT STRING)
+ * }
+ *
+ * PKIStatus:
+ * granted (0), -- you got exactly what you asked for
+ * grantedWithMods (1), -- you got something like what you asked for
+ * rejection (2), -- you don't get it, more information elsewhere in the message
+ * waiting (3), -- the request body part has not yet been processed, expect to hear more later
+ * revocationWarning (4), -- this message contains a warning that a revocation is imminent
+ * revocationNotification (5), -- notification that a revocation has occurred
+ * keyUpdateWarning (6) -- update already done for the oldCertId specified in CertReqMsg
+ *
+ * PkiFailureInfo:
+ * badAlg (0), -- unrecognized or unsupported Algorithm Identifier
+ * badMessageCheck (1), -- integrity check failed (e.g., signature did not verify)
+ * badRequest (2), -- transaction not permitted or supported
+ * badTime (3), -- messageTime was not sufficiently close to the system time, as defined by local policy
+ * badCertId (4), -- no certificate could be found matching the provided criteria
+ * badDataFormat (5), -- the data submitted has the wrong format
+ * wrongAuthority (6), -- the authority indicated in the request is different from the one creating the response token
+ * incorrectData (7), -- the requester's data is incorrect (for notary services)
+ * missingTimeStamp (8), -- when the timestamp is missing but should be there (by policy)
+ * badPOP (9) -- the proof-of-possession failed
+ *
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(status);
+
+ if (statusString != null)
+ {
+ v.Add(statusString);
+ }
+
+ if (failInfo!= null)
+ {
+ v.Add(failInfo);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/PbmParameter.cs b/bc-sharp-crypto/src/asn1/cmp/PbmParameter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..206b89ba1b0dccf3e426d457d5c36053d6e3e82e
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/PbmParameter.cs
@@ -0,0 +1,101 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class PbmParameter
+ : Asn1Encodable
+ {
+ private Asn1OctetString salt;
+ private AlgorithmIdentifier owf;
+ private DerInteger iterationCount;
+ private AlgorithmIdentifier mac;
+
+ private PbmParameter(Asn1Sequence seq)
+ {
+ salt = Asn1OctetString.GetInstance(seq[0]);
+ owf = AlgorithmIdentifier.GetInstance(seq[1]);
+ iterationCount = DerInteger.GetInstance(seq[2]);
+ mac = AlgorithmIdentifier.GetInstance(seq[3]);
+ }
+
+ public static PbmParameter GetInstance(object obj)
+ {
+ if (obj is PbmParameter)
+ return (PbmParameter)obj;
+
+ if (obj is Asn1Sequence)
+ return new PbmParameter((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public PbmParameter(
+ byte[] salt,
+ AlgorithmIdentifier owf,
+ int iterationCount,
+ AlgorithmIdentifier mac)
+ : this(new DerOctetString(salt), owf, new DerInteger(iterationCount), mac)
+ {
+ }
+
+ public PbmParameter(
+ Asn1OctetString salt,
+ AlgorithmIdentifier owf,
+ DerInteger iterationCount,
+ AlgorithmIdentifier mac)
+ {
+ this.salt = salt;
+ this.owf = owf;
+ this.iterationCount = iterationCount;
+ this.mac = mac;
+ }
+
+ public virtual Asn1OctetString Salt
+ {
+ get { return salt; }
+ }
+
+ public virtual AlgorithmIdentifier Owf
+ {
+ get { return owf; }
+ }
+
+ public virtual DerInteger IterationCount
+ {
+ get { return iterationCount; }
+ }
+
+ public virtual AlgorithmIdentifier Mac
+ {
+ get { return mac; }
+ }
+
+ /**
+ *
+ * PbmParameter ::= SEQUENCE {
+ * salt OCTET STRING,
+ * -- note: implementations MAY wish to limit acceptable sizes
+ * -- of this string to values appropriate for their environment
+ * -- in order to reduce the risk of denial-of-service attacks
+ * owf AlgorithmIdentifier,
+ * -- AlgId for a One-Way Function (SHA-1 recommended)
+ * iterationCount INTEGER,
+ * -- number of times the OWF is applied
+ * -- note: implementations MAY wish to limit acceptable sizes
+ * -- of this integer to values appropriate for their environment
+ * -- in order to reduce the risk of denial-of-service attacks
+ * mac AlgorithmIdentifier
+ * -- the MAC AlgId (e.g., DES-MAC, Triple-DES-MAC [PKCS11],
+ * } -- or HMAC [RFC2104, RFC2202])
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(salt, owf, iterationCount, mac);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/PollRepContent.cs b/bc-sharp-crypto/src/asn1/cmp/PollRepContent.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f8bb098a2aa8cb8412a8d31e4bd512d587264ed7
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/PollRepContent.cs
@@ -0,0 +1,68 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class PollRepContent
+ : Asn1Encodable
+ {
+ private readonly DerInteger certReqId;
+ private readonly DerInteger checkAfter;
+ private readonly PkiFreeText reason;
+
+ private PollRepContent(Asn1Sequence seq)
+ {
+ certReqId = DerInteger.GetInstance(seq[0]);
+ checkAfter = DerInteger.GetInstance(seq[1]);
+
+ if (seq.Count > 2)
+ {
+ reason = PkiFreeText.GetInstance(seq[2]);
+ }
+ }
+
+ public static PollRepContent GetInstance(object obj)
+ {
+ if (obj is PollRepContent)
+ return (PollRepContent)obj;
+
+ if (obj is Asn1Sequence)
+ return new PollRepContent((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public virtual DerInteger CertReqID
+ {
+ get { return certReqId; }
+ }
+
+ public virtual DerInteger CheckAfter
+ {
+ get { return checkAfter; }
+ }
+
+ public virtual PkiFreeText Reason
+ {
+ get { return reason; }
+ }
+
+ /**
+ *
+ * PollRepContent ::= SEQUENCE OF SEQUENCE {
+ * certReqId INTEGER,
+ * checkAfter INTEGER, -- time in seconds
+ * reason PKIFreeText OPTIONAL
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(certReqId, checkAfter);
+ v.AddOptional(reason);
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/PollReqContent.cs b/bc-sharp-crypto/src/asn1/cmp/PollReqContent.cs
new file mode 100644
index 0000000000000000000000000000000000000000..dd9b0c352a126020ac53a05ce38fbf5664d3d6fe
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/PollReqContent.cs
@@ -0,0 +1,61 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class PollReqContent
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence content;
+
+ private PollReqContent(Asn1Sequence seq)
+ {
+ content = seq;
+ }
+
+ public static PollReqContent GetInstance(object obj)
+ {
+ if (obj is PollReqContent)
+ return (PollReqContent)obj;
+
+ if (obj is Asn1Sequence)
+ return new PollReqContent((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public virtual DerInteger[][] GetCertReqIDs()
+ {
+ DerInteger[][] result = new DerInteger[content.Count][];
+ for (int i = 0; i != result.Length; ++i)
+ {
+ result[i] = SequenceToDerIntegerArray((Asn1Sequence)content[i]);
+ }
+ return result;
+ }
+
+ private static DerInteger[] SequenceToDerIntegerArray(Asn1Sequence seq)
+ {
+ DerInteger[] result = new DerInteger[seq.Count];
+ for (int i = 0; i != result.Length; ++i)
+ {
+ result[i] = DerInteger.GetInstance(seq[i]);
+ }
+ return result;
+ }
+
+ /**
+ *
+ * PollReqContent ::= SEQUENCE OF SEQUENCE {
+ * certReqId INTEGER
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return content;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/PopoDecKeyChallContent.cs b/bc-sharp-crypto/src/asn1/cmp/PopoDecKeyChallContent.cs
new file mode 100644
index 0000000000000000000000000000000000000000..03a13a5d5148dc3242347a3914e12671c01a3e99
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/PopoDecKeyChallContent.cs
@@ -0,0 +1,49 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class PopoDecKeyChallContent
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence content;
+
+ private PopoDecKeyChallContent(Asn1Sequence seq)
+ {
+ content = seq;
+ }
+
+ public static PopoDecKeyChallContent GetInstance(object obj)
+ {
+ if (obj is PopoDecKeyChallContent)
+ return (PopoDecKeyChallContent)obj;
+
+ if (obj is Asn1Sequence)
+ return new PopoDecKeyChallContent((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public virtual Challenge[] ToChallengeArray()
+ {
+ Challenge[] result = new Challenge[content.Count];
+ for (int i = 0; i != result.Length; ++i)
+ {
+ result[i] = Challenge.GetInstance(content[i]);
+ }
+ return result;
+ }
+
+ /**
+ *
+ * PopoDecKeyChallContent ::= SEQUENCE OF Challenge
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return content;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/PopoDecKeyRespContent.cs b/bc-sharp-crypto/src/asn1/cmp/PopoDecKeyRespContent.cs
new file mode 100644
index 0000000000000000000000000000000000000000..73f59b7c1023d5e4079bc7c3fb893c3b09281c23
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/PopoDecKeyRespContent.cs
@@ -0,0 +1,49 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class PopoDecKeyRespContent
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence content;
+
+ private PopoDecKeyRespContent(Asn1Sequence seq)
+ {
+ content = seq;
+ }
+
+ public static PopoDecKeyRespContent GetInstance(object obj)
+ {
+ if (obj is PopoDecKeyRespContent)
+ return (PopoDecKeyRespContent)obj;
+
+ if (obj is Asn1Sequence)
+ return new PopoDecKeyRespContent((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public virtual DerInteger[] ToDerIntegerArray()
+ {
+ DerInteger[] result = new DerInteger[content.Count];
+ for (int i = 0; i != result.Length; ++i)
+ {
+ result[i] = DerInteger.GetInstance(content[i]);
+ }
+ return result;
+ }
+
+ /**
+ *
+ * PopoDecKeyRespContent ::= SEQUENCE OF INTEGER
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return content;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/ProtectedPart.cs b/bc-sharp-crypto/src/asn1/cmp/ProtectedPart.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ed90708f9de5ae386c545c9ba7c14962c7b7947e
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/ProtectedPart.cs
@@ -0,0 +1,60 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class ProtectedPart
+ : Asn1Encodable
+ {
+ private readonly PkiHeader header;
+ private readonly PkiBody body;
+
+ private ProtectedPart(Asn1Sequence seq)
+ {
+ header = PkiHeader.GetInstance(seq[0]);
+ body = PkiBody.GetInstance(seq[1]);
+ }
+
+ public static ProtectedPart GetInstance(object obj)
+ {
+ if (obj is ProtectedPart)
+ return (ProtectedPart)obj;
+
+ if (obj is Asn1Sequence)
+ return new ProtectedPart((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public ProtectedPart(PkiHeader header, PkiBody body)
+ {
+ this.header = header;
+ this.body = body;
+ }
+
+ public virtual PkiHeader Header
+ {
+ get { return header; }
+ }
+
+ public virtual PkiBody Body
+ {
+ get { return body; }
+ }
+
+ /**
+ *
+ * ProtectedPart ::= SEQUENCE {
+ * header PKIHeader,
+ * body PKIBody
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(header, body);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/RevAnnContent.cs b/bc-sharp-crypto/src/asn1/cmp/RevAnnContent.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d5d42625cfc3385f34f77cc08e945f7c01fdb057
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/RevAnnContent.cs
@@ -0,0 +1,87 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class RevAnnContent
+ : Asn1Encodable
+ {
+ private readonly PkiStatusEncodable status;
+ private readonly CertId certId;
+ private readonly DerGeneralizedTime willBeRevokedAt;
+ private readonly DerGeneralizedTime badSinceDate;
+ private readonly X509Extensions crlDetails;
+
+ private RevAnnContent(Asn1Sequence seq)
+ {
+ status = PkiStatusEncodable.GetInstance(seq[0]);
+ certId = CertId.GetInstance(seq[1]);
+ willBeRevokedAt = DerGeneralizedTime.GetInstance(seq[2]);
+ badSinceDate = DerGeneralizedTime.GetInstance(seq[3]);
+
+ if (seq.Count > 4)
+ {
+ crlDetails = X509Extensions.GetInstance(seq[4]);
+ }
+ }
+
+ public static RevAnnContent GetInstance(object obj)
+ {
+ if (obj is RevAnnContent)
+ return (RevAnnContent)obj;
+
+ if (obj is Asn1Sequence)
+ return new RevAnnContent((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public virtual PkiStatusEncodable Status
+ {
+ get { return status; }
+ }
+
+ public virtual CertId CertID
+ {
+ get { return certId; }
+ }
+
+ public virtual DerGeneralizedTime WillBeRevokedAt
+ {
+ get { return willBeRevokedAt; }
+ }
+
+ public virtual DerGeneralizedTime BadSinceDate
+ {
+ get { return badSinceDate; }
+ }
+
+ public virtual X509Extensions CrlDetails
+ {
+ get { return crlDetails; }
+ }
+
+ /**
+ *
+ * RevAnnContent ::= SEQUENCE {
+ * status PKIStatus,
+ * certId CertId,
+ * willBeRevokedAt GeneralizedTime,
+ * badSinceDate GeneralizedTime,
+ * crlDetails Extensions OPTIONAL
+ * -- extra CRL details (e.g., crl number, reason, location, etc.)
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(status, certId, willBeRevokedAt, badSinceDate);
+ v.AddOptional(crlDetails);
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/RevDetails.cs b/bc-sharp-crypto/src/asn1/cmp/RevDetails.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7d2a65ab9838d8ebfcc3a417d9f6b67a8ad2e2dd
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/RevDetails.cs
@@ -0,0 +1,75 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class RevDetails
+ : Asn1Encodable
+ {
+ private readonly CertTemplate certDetails;
+ private readonly X509Extensions crlEntryDetails;
+
+ private RevDetails(Asn1Sequence seq)
+ {
+ certDetails = CertTemplate.GetInstance(seq[0]);
+ crlEntryDetails = seq.Count <= 1
+ ? null
+ : X509Extensions.GetInstance(seq[1]);
+ }
+
+ public static RevDetails GetInstance(object obj)
+ {
+ if (obj is RevDetails)
+ return (RevDetails)obj;
+
+ if (obj is Asn1Sequence)
+ return new RevDetails((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public RevDetails(CertTemplate certDetails)
+ : this(certDetails, null)
+ {
+ }
+
+ public RevDetails(CertTemplate certDetails, X509Extensions crlEntryDetails)
+ {
+ this.certDetails = certDetails;
+ this.crlEntryDetails = crlEntryDetails;
+ }
+
+ public virtual CertTemplate CertDetails
+ {
+ get { return certDetails; }
+ }
+
+ public virtual X509Extensions CrlEntryDetails
+ {
+ get { return crlEntryDetails; }
+ }
+
+ /**
+ *
+ * RevDetails ::= SEQUENCE {
+ * certDetails CertTemplate,
+ * -- allows requester to specify as much as they can about
+ * -- the cert. for which revocation is requested
+ * -- (e.g., for cases in which serialNumber is not available)
+ * crlEntryDetails Extensions OPTIONAL
+ * -- requested crlEntryExtensions
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(certDetails);
+ v.AddOptional(crlEntryDetails);
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/RevRepContent.cs b/bc-sharp-crypto/src/asn1/cmp/RevRepContent.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8e382a60d01317a545d2787c34a65bf2c04e02b6
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/RevRepContent.cs
@@ -0,0 +1,113 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class RevRepContent
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence status;
+ private readonly Asn1Sequence revCerts;
+ private readonly Asn1Sequence crls;
+
+ private RevRepContent(Asn1Sequence seq)
+ {
+ status = Asn1Sequence.GetInstance(seq[0]);
+
+ for (int pos = 1; pos < seq.Count; ++pos)
+ {
+ Asn1TaggedObject tObj = Asn1TaggedObject.GetInstance(seq[pos]);
+
+ if (tObj.TagNo == 0)
+ {
+ revCerts = Asn1Sequence.GetInstance(tObj, true);
+ }
+ else
+ {
+ crls = Asn1Sequence.GetInstance(tObj, true);
+ }
+ }
+ }
+
+ public static RevRepContent GetInstance(object obj)
+ {
+ if (obj is RevRepContent)
+ return (RevRepContent)obj;
+
+ if (obj is Asn1Sequence)
+ return new RevRepContent((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public virtual PkiStatusInfo[] GetStatus()
+ {
+ PkiStatusInfo[] results = new PkiStatusInfo[status.Count];
+ for (int i = 0; i != results.Length; ++i)
+ {
+ results[i] = PkiStatusInfo.GetInstance(status[i]);
+ }
+ return results;
+ }
+
+ public virtual CertId[] GetRevCerts()
+ {
+ if (revCerts == null)
+ return null;
+
+ CertId[] results = new CertId[revCerts.Count];
+ for (int i = 0; i != results.Length; ++i)
+ {
+ results[i] = CertId.GetInstance(revCerts[i]);
+ }
+ return results;
+ }
+
+ public virtual CertificateList[] GetCrls()
+ {
+ if (crls == null)
+ return null;
+
+ CertificateList[] results = new CertificateList[crls.Count];
+ for (int i = 0; i != results.Length; ++i)
+ {
+ results[i] = CertificateList.GetInstance(crls[i]);
+ }
+ return results;
+ }
+
+ /**
+ *
+ * RevRepContent ::= SEQUENCE {
+ * status SEQUENCE SIZE (1..MAX) OF PKIStatusInfo,
+ * -- in same order as was sent in RevReqContent
+ * revCerts [0] SEQUENCE SIZE (1..MAX) OF CertId OPTIONAL,
+ * -- IDs for which revocation was requested
+ * -- (same order as status)
+ * crls [1] SEQUENCE SIZE (1..MAX) OF CertificateList OPTIONAL
+ * -- the resulting CRLs (there may be more than one)
+ * }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(status);
+ AddOptional(v, 0, revCerts);
+ AddOptional(v, 1, crls);
+ return new DerSequence(v);
+ }
+
+ private void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+ {
+ if (obj != null)
+ {
+ v.Add(new DerTaggedObject(true, tagNo, obj));
+ }
+ }
+ }
+}
+
diff --git a/bc-sharp-crypto/src/asn1/cmp/RevRepContentBuilder.cs b/bc-sharp-crypto/src/asn1/cmp/RevRepContentBuilder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cc17d1d4cc25df5edea2697a7452cb24a10c52d9
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/RevRepContentBuilder.cs
@@ -0,0 +1,55 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class RevRepContentBuilder
+ {
+ private readonly Asn1EncodableVector status = new Asn1EncodableVector();
+ private readonly Asn1EncodableVector revCerts = new Asn1EncodableVector();
+ private readonly Asn1EncodableVector crls = new Asn1EncodableVector();
+
+ public virtual RevRepContentBuilder Add(PkiStatusInfo status)
+ {
+ this.status.Add(status);
+ return this;
+ }
+
+ public virtual RevRepContentBuilder Add(PkiStatusInfo status, CertId certId)
+ {
+ if (this.status.Count != this.revCerts.Count)
+ throw new InvalidOperationException("status and revCerts sequence must be in common order");
+
+ this.status.Add(status);
+ this.revCerts.Add(certId);
+ return this;
+ }
+
+ public virtual RevRepContentBuilder AddCrl(CertificateList crl)
+ {
+ this.crls.Add(crl);
+ return this;
+ }
+
+ public virtual RevRepContent Build()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ v.Add(new DerSequence(status));
+
+ if (revCerts.Count != 0)
+ {
+ v.Add(new DerTaggedObject(true, 0, new DerSequence(revCerts)));
+ }
+
+ if (crls.Count != 0)
+ {
+ v.Add(new DerTaggedObject(true, 1, new DerSequence(crls)));
+ }
+
+ return RevRepContent.GetInstance(new DerSequence(v));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cmp/RevReqContent.cs b/bc-sharp-crypto/src/asn1/cmp/RevReqContent.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1522d3789e94554b9b97598d32ecffdd6e686fdb
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cmp/RevReqContent.cs
@@ -0,0 +1,54 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+ public class RevReqContent
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence content;
+
+ private RevReqContent(Asn1Sequence seq)
+ {
+ content = seq;
+ }
+
+ public static RevReqContent GetInstance(object obj)
+ {
+ if (obj is RevReqContent)
+ return (RevReqContent)obj;
+
+ if (obj is Asn1Sequence)
+ return new RevReqContent((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public RevReqContent(params RevDetails[] revDetails)
+ {
+ this.content = new DerSequence(revDetails);
+ }
+
+ public virtual RevDetails[] ToRevDetailsArray()
+ {
+ RevDetails[] result = new RevDetails[content.Count];
+ for (int i = 0; i != result.Length; ++i)
+ {
+ result[i] = RevDetails.GetInstance(content[i]);
+ }
+ return result;
+ }
+
+ /**
+ *
+ * RevReqContent ::= SEQUENCE OF RevDetails
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return content;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/Attribute.cs b/bc-sharp-crypto/src/asn1/cms/Attribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..69ac44148f00c195fd0035f2e76512917a20fdfc
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/Attribute.cs
@@ -0,0 +1,70 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class Attribute
+ : Asn1Encodable
+ {
+ private DerObjectIdentifier attrType;
+ private Asn1Set attrValues;
+
+ /**
+ * return an Attribute object from the given object.
+ *
+ * @param o the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static Attribute GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is Attribute)
+ return (Attribute) obj;
+
+ if (obj is Asn1Sequence)
+ return new Attribute((Asn1Sequence) obj);
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public Attribute(
+ Asn1Sequence seq)
+ {
+ attrType = (DerObjectIdentifier)seq[0];
+ attrValues = (Asn1Set)seq[1];
+ }
+
+ public Attribute(
+ DerObjectIdentifier attrType,
+ Asn1Set attrValues)
+ {
+ this.attrType = attrType;
+ this.attrValues = attrValues;
+ }
+
+ public DerObjectIdentifier AttrType
+ {
+ get { return attrType; }
+ }
+
+ public Asn1Set AttrValues
+ {
+ get { return attrValues; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Attribute ::= SEQUENCE {
+ * attrType OBJECT IDENTIFIER,
+ * attrValues SET OF AttributeValue
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(attrType, attrValues);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/AttributeTable.cs b/bc-sharp-crypto/src/asn1/cms/AttributeTable.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8d357f1a66b6b3e234a44b681111d91077aa8d65
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/AttributeTable.cs
@@ -0,0 +1,231 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class AttributeTable
+ {
+ private readonly IDictionary attributes;
+
+#if !(SILVERLIGHT || PORTABLE)
+ [Obsolete]
+ public AttributeTable(
+ Hashtable attrs)
+ {
+ this.attributes = Platform.CreateHashtable(attrs);
+ }
+#endif
+
+ public AttributeTable(
+ IDictionary attrs)
+ {
+ this.attributes = Platform.CreateHashtable(attrs);
+ }
+
+ public AttributeTable(
+ Asn1EncodableVector v)
+ {
+ this.attributes = Platform.CreateHashtable(v.Count);
+
+ foreach (Asn1Encodable o in v)
+ {
+ Attribute a = Attribute.GetInstance(o);
+
+ AddAttribute(a);
+ }
+ }
+
+ public AttributeTable(
+ Asn1Set s)
+ {
+ this.attributes = Platform.CreateHashtable(s.Count);
+
+ for (int i = 0; i != s.Count; i++)
+ {
+ Attribute a = Attribute.GetInstance(s[i]);
+
+ AddAttribute(a);
+ }
+ }
+
+ public AttributeTable(
+ Attributes attrs)
+ : this(Asn1Set.GetInstance(attrs.ToAsn1Object()))
+ {
+ }
+
+ private void AddAttribute(
+ Attribute a)
+ {
+ DerObjectIdentifier oid = a.AttrType;
+ object obj = attributes[oid];
+
+ if (obj == null)
+ {
+ attributes[oid] = a;
+ }
+ else
+ {
+ IList v;
+
+ if (obj is Attribute)
+ {
+ v = Platform.CreateArrayList();
+
+ v.Add(obj);
+ v.Add(a);
+ }
+ else
+ {
+ v = (IList) obj;
+
+ v.Add(a);
+ }
+
+ attributes[oid] = v;
+ }
+ }
+
+ /// Return the first attribute matching the given OBJECT IDENTIFIER
+ public Attribute this[DerObjectIdentifier oid]
+ {
+ get
+ {
+ object obj = attributes[oid];
+
+ if (obj is IList)
+ {
+ return (Attribute)((IList)obj)[0];
+ }
+
+ return (Attribute) obj;
+ }
+ }
+
+ [Obsolete("Use 'object[oid]' syntax instead")]
+ public Attribute Get(
+ DerObjectIdentifier oid)
+ {
+ return this[oid];
+ }
+
+ /**
+ * Return all the attributes matching the OBJECT IDENTIFIER oid. The vector will be
+ * empty if there are no attributes of the required type present.
+ *
+ * @param oid type of attribute required.
+ * @return a vector of all the attributes found of type oid.
+ */
+ public Asn1EncodableVector GetAll(
+ DerObjectIdentifier oid)
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ object obj = attributes[oid];
+
+ if (obj is IList)
+ {
+ foreach (Attribute a in (IList)obj)
+ {
+ v.Add(a);
+ }
+ }
+ else if (obj != null)
+ {
+ v.Add((Attribute) obj);
+ }
+
+ return v;
+ }
+
+ public int Count
+ {
+ get
+ {
+ int total = 0;
+
+ foreach (object o in attributes.Values)
+ {
+ if (o is IList)
+ {
+ total += ((IList)o).Count;
+ }
+ else
+ {
+ ++total;
+ }
+ }
+
+ return total;
+ }
+ }
+
+ public IDictionary ToDictionary()
+ {
+ return Platform.CreateHashtable(attributes);
+ }
+
+#if !(SILVERLIGHT || PORTABLE)
+ [Obsolete("Use 'ToDictionary' instead")]
+ public Hashtable ToHashtable()
+ {
+ return new Hashtable(attributes);
+ }
+#endif
+
+ public Asn1EncodableVector ToAsn1EncodableVector()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ foreach (object obj in attributes.Values)
+ {
+ if (obj is IList)
+ {
+ foreach (object el in (IList)obj)
+ {
+ v.Add(Attribute.GetInstance(el));
+ }
+ }
+ else
+ {
+ v.Add(Attribute.GetInstance(obj));
+ }
+ }
+
+ return v;
+ }
+
+ public Attributes ToAttributes()
+ {
+ return new Attributes(this.ToAsn1EncodableVector());
+ }
+
+ /**
+ * Return a new table with the passed in attribute added.
+ *
+ * @param attrType
+ * @param attrValue
+ * @return
+ */
+ public AttributeTable Add(DerObjectIdentifier attrType, Asn1Encodable attrValue)
+ {
+ AttributeTable newTable = new AttributeTable(attributes);
+
+ newTable.AddAttribute(new Attribute(attrType, new DerSet(attrValue)));
+
+ return newTable;
+ }
+
+ public AttributeTable Remove(DerObjectIdentifier attrType)
+ {
+ AttributeTable newTable = new AttributeTable(attributes);
+
+ newTable.attributes.Remove(attrType);
+
+ return newTable;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/Attributes.cs b/bc-sharp-crypto/src/asn1/cms/Attributes.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5b6b1303486e255fb99dd181b3d08c98b8fee6fb
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/Attributes.cs
@@ -0,0 +1,55 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class Attributes
+ : Asn1Encodable
+ {
+ private readonly Asn1Set attributes;
+
+ private Attributes(Asn1Set attributes)
+ {
+ this.attributes = attributes;
+ }
+
+ public Attributes(Asn1EncodableVector v)
+ {
+ attributes = new BerSet(v);
+ }
+
+ public static Attributes GetInstance(object obj)
+ {
+ if (obj is Attributes)
+ return (Attributes)obj;
+
+ if (obj != null)
+ return new Attributes(Asn1Set.GetInstance(obj));
+
+ return null;
+ }
+
+ public virtual Attribute[] GetAttributes()
+ {
+ Attribute[] rv = new Attribute[attributes.Count];
+
+ for (int i = 0; i != rv.Length; i++)
+ {
+ rv[i] = Attribute.GetInstance(attributes[i]);
+ }
+
+ return rv;
+ }
+
+ /**
+ *
+ * Attributes ::=
+ * SET SIZE(1..MAX) OF Attribute -- according to RFC 5652
+ *
+ * @return
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return attributes;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/AuthEnvelopedData.cs b/bc-sharp-crypto/src/asn1/cms/AuthEnvelopedData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c30ec6bbdcb15a1fcf72c34da224ec7af37924fb
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/AuthEnvelopedData.cs
@@ -0,0 +1,205 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class AuthEnvelopedData
+ : Asn1Encodable
+ {
+ private DerInteger version;
+ private OriginatorInfo originatorInfo;
+ private Asn1Set recipientInfos;
+ private EncryptedContentInfo authEncryptedContentInfo;
+ private Asn1Set authAttrs;
+ private Asn1OctetString mac;
+ private Asn1Set unauthAttrs;
+
+ public AuthEnvelopedData(
+ OriginatorInfo originatorInfo,
+ Asn1Set recipientInfos,
+ EncryptedContentInfo authEncryptedContentInfo,
+ Asn1Set authAttrs,
+ Asn1OctetString mac,
+ Asn1Set unauthAttrs)
+ {
+ // "It MUST be set to 0."
+ this.version = new DerInteger(0);
+
+ this.originatorInfo = originatorInfo;
+
+ // TODO
+ // "There MUST be at least one element in the collection."
+ this.recipientInfos = recipientInfos;
+
+ this.authEncryptedContentInfo = authEncryptedContentInfo;
+
+ // TODO
+ // "The authAttrs MUST be present if the content type carried in
+ // EncryptedContentInfo is not id-data."
+ this.authAttrs = authAttrs;
+
+ this.mac = mac;
+
+ this.unauthAttrs = unauthAttrs;
+ }
+
+ private AuthEnvelopedData(
+ Asn1Sequence seq)
+ {
+ int index = 0;
+
+ // TODO
+ // "It MUST be set to 0."
+ Asn1Object tmp = seq[index++].ToAsn1Object();
+ version = (DerInteger)tmp;
+
+ tmp = seq[index++].ToAsn1Object();
+ if (tmp is Asn1TaggedObject)
+ {
+ originatorInfo = OriginatorInfo.GetInstance((Asn1TaggedObject)tmp, false);
+ tmp = seq[index++].ToAsn1Object();
+ }
+
+ // TODO
+ // "There MUST be at least one element in the collection."
+ recipientInfos = Asn1Set.GetInstance(tmp);
+
+ tmp = seq[index++].ToAsn1Object();
+ authEncryptedContentInfo = EncryptedContentInfo.GetInstance(tmp);
+
+ tmp = seq[index++].ToAsn1Object();
+ if (tmp is Asn1TaggedObject)
+ {
+ authAttrs = Asn1Set.GetInstance((Asn1TaggedObject)tmp, false);
+ tmp = seq[index++].ToAsn1Object();
+ }
+ else
+ {
+ // TODO
+ // "The authAttrs MUST be present if the content type carried in
+ // EncryptedContentInfo is not id-data."
+ }
+
+ mac = Asn1OctetString.GetInstance(tmp);
+
+ if (seq.Count > index)
+ {
+ tmp = seq[index++].ToAsn1Object();
+ unauthAttrs = Asn1Set.GetInstance((Asn1TaggedObject)tmp, false);
+ }
+ }
+
+ /**
+ * return an AuthEnvelopedData object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param isExplicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws ArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static AuthEnvelopedData GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ /**
+ * return an AuthEnvelopedData object from the given object.
+ *
+ * @param obj the object we want converted.
+ * @throws ArgumentException if the object cannot be converted.
+ */
+ public static AuthEnvelopedData GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is AuthEnvelopedData)
+ return (AuthEnvelopedData)obj;
+
+ if (obj is Asn1Sequence)
+ return new AuthEnvelopedData((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid AuthEnvelopedData: " + Platform.GetTypeName(obj));
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public OriginatorInfo OriginatorInfo
+ {
+ get { return originatorInfo; }
+ }
+
+ public Asn1Set RecipientInfos
+ {
+ get { return recipientInfos; }
+ }
+
+ public EncryptedContentInfo AuthEncryptedContentInfo
+ {
+ get { return authEncryptedContentInfo; }
+ }
+
+ public Asn1Set AuthAttrs
+ {
+ get { return authAttrs; }
+ }
+
+ public Asn1OctetString Mac
+ {
+ get { return mac; }
+ }
+
+ public Asn1Set UnauthAttrs
+ {
+ get { return unauthAttrs; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * AuthEnvelopedData ::= SEQUENCE {
+ * version CMSVersion,
+ * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+ * recipientInfos RecipientInfos,
+ * authEncryptedContentInfo EncryptedContentInfo,
+ * authAttrs [1] IMPLICIT AuthAttributes OPTIONAL,
+ * mac MessageAuthenticationCode,
+ * unauthAttrs [2] IMPLICIT UnauthAttributes OPTIONAL }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(version);
+
+ if (originatorInfo != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, originatorInfo));
+ }
+
+ v.Add(recipientInfos, authEncryptedContentInfo);
+
+ // "authAttrs optionally contains the authenticated attributes."
+ if (authAttrs != null)
+ {
+ // "AuthAttributes MUST be DER encoded, even if the rest of the
+ // AuthEnvelopedData structure is BER encoded."
+ v.Add(new DerTaggedObject(false, 1, authAttrs));
+ }
+
+ v.Add(mac);
+
+ // "unauthAttrs optionally contains the unauthenticated attributes."
+ if (unauthAttrs != null)
+ {
+ v.Add(new DerTaggedObject(false, 2, unauthAttrs));
+ }
+
+ return new BerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/AuthEnvelopedDataParser.cs b/bc-sharp-crypto/src/asn1/cms/AuthEnvelopedDataParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..35cb3bfccfd14e516abe71ca2ea66239a6ab07a3
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/AuthEnvelopedDataParser.cs
@@ -0,0 +1,145 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ *
+ * AuthEnvelopedData ::= SEQUENCE {
+ * version CMSVersion,
+ * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+ * recipientInfos RecipientInfos,
+ * authEncryptedContentInfo EncryptedContentInfo,
+ * authAttrs [1] IMPLICIT AuthAttributes OPTIONAL,
+ * mac MessageAuthenticationCode,
+ * unauthAttrs [2] IMPLICIT UnauthAttributes OPTIONAL }
+ *
+ */
+ public class AuthEnvelopedDataParser
+ {
+ private Asn1SequenceParser seq;
+ private DerInteger version;
+ private IAsn1Convertible nextObject;
+ private bool originatorInfoCalled;
+
+ public AuthEnvelopedDataParser(
+ Asn1SequenceParser seq)
+ {
+ this.seq = seq;
+
+ // TODO
+ // "It MUST be set to 0."
+ this.version = (DerInteger)seq.ReadObject();
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public OriginatorInfo GetOriginatorInfo()
+ {
+ originatorInfoCalled = true;
+
+ if (nextObject == null)
+ {
+ nextObject = seq.ReadObject();
+ }
+
+ if (nextObject is Asn1TaggedObjectParser && ((Asn1TaggedObjectParser)nextObject).TagNo == 0)
+ {
+ Asn1SequenceParser originatorInfo = (Asn1SequenceParser) ((Asn1TaggedObjectParser)nextObject).GetObjectParser(Asn1Tags.Sequence, false);
+ nextObject = null;
+ return OriginatorInfo.GetInstance(originatorInfo.ToAsn1Object());
+ }
+
+ return null;
+ }
+
+ public Asn1SetParser GetRecipientInfos()
+ {
+ if (!originatorInfoCalled)
+ {
+ GetOriginatorInfo();
+ }
+
+ if (nextObject == null)
+ {
+ nextObject = seq.ReadObject();
+ }
+
+ Asn1SetParser recipientInfos = (Asn1SetParser)nextObject;
+ nextObject = null;
+ return recipientInfos;
+ }
+
+ public EncryptedContentInfoParser GetAuthEncryptedContentInfo()
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.ReadObject();
+ }
+
+ if (nextObject != null)
+ {
+ Asn1SequenceParser o = (Asn1SequenceParser) nextObject;
+ nextObject = null;
+ return new EncryptedContentInfoParser(o);
+ }
+
+ return null;
+ }
+
+ public Asn1SetParser GetAuthAttrs()
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.ReadObject();
+ }
+
+ if (nextObject is Asn1TaggedObjectParser)
+ {
+ IAsn1Convertible o = nextObject;
+ nextObject = null;
+ return (Asn1SetParser)((Asn1TaggedObjectParser)o).GetObjectParser(Asn1Tags.Set, false);
+ }
+
+ // TODO
+ // "The authAttrs MUST be present if the content type carried in
+ // EncryptedContentInfo is not id-data."
+
+ return null;
+ }
+
+ public Asn1OctetString GetMac()
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.ReadObject();
+ }
+
+ IAsn1Convertible o = nextObject;
+ nextObject = null;
+
+ return Asn1OctetString.GetInstance(o.ToAsn1Object());
+ }
+
+ public Asn1SetParser GetUnauthAttrs()
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.ReadObject();
+ }
+
+ if (nextObject != null)
+ {
+ IAsn1Convertible o = nextObject;
+ nextObject = null;
+ return (Asn1SetParser)((Asn1TaggedObjectParser)o).GetObjectParser(Asn1Tags.Set, false);
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/AuthenticatedData.cs b/bc-sharp-crypto/src/asn1/cms/AuthenticatedData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6f13a6f30c17c582164c7b6d218638b7cb4aa88d
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/AuthenticatedData.cs
@@ -0,0 +1,271 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class AuthenticatedData
+ : Asn1Encodable
+ {
+ private DerInteger version;
+ private OriginatorInfo originatorInfo;
+ private Asn1Set recipientInfos;
+ private AlgorithmIdentifier macAlgorithm;
+ private AlgorithmIdentifier digestAlgorithm;
+ private ContentInfo encapsulatedContentInfo;
+ private Asn1Set authAttrs;
+ private Asn1OctetString mac;
+ private Asn1Set unauthAttrs;
+
+ public AuthenticatedData(
+ OriginatorInfo originatorInfo,
+ Asn1Set recipientInfos,
+ AlgorithmIdentifier macAlgorithm,
+ AlgorithmIdentifier digestAlgorithm,
+ ContentInfo encapsulatedContent,
+ Asn1Set authAttrs,
+ Asn1OctetString mac,
+ Asn1Set unauthAttrs)
+ {
+ if (digestAlgorithm != null || authAttrs != null)
+ {
+ if (digestAlgorithm == null || authAttrs == null)
+ {
+ throw new ArgumentException("digestAlgorithm and authAttrs must be set together");
+ }
+ }
+
+ version = new DerInteger(CalculateVersion(originatorInfo));
+
+ this.originatorInfo = originatorInfo;
+ this.macAlgorithm = macAlgorithm;
+ this.digestAlgorithm = digestAlgorithm;
+ this.recipientInfos = recipientInfos;
+ this.encapsulatedContentInfo = encapsulatedContent;
+ this.authAttrs = authAttrs;
+ this.mac = mac;
+ this.unauthAttrs = unauthAttrs;
+ }
+
+ private AuthenticatedData(
+ Asn1Sequence seq)
+ {
+ int index = 0;
+
+ version = (DerInteger)seq[index++];
+
+ Asn1Encodable tmp = seq[index++];
+ if (tmp is Asn1TaggedObject)
+ {
+ originatorInfo = OriginatorInfo.GetInstance((Asn1TaggedObject)tmp, false);
+ tmp = seq[index++];
+ }
+
+ recipientInfos = Asn1Set.GetInstance(tmp);
+ macAlgorithm = AlgorithmIdentifier.GetInstance(seq[index++]);
+
+ tmp = seq[index++];
+ if (tmp is Asn1TaggedObject)
+ {
+ digestAlgorithm = AlgorithmIdentifier.GetInstance((Asn1TaggedObject)tmp, false);
+ tmp = seq[index++];
+ }
+
+ encapsulatedContentInfo = ContentInfo.GetInstance(tmp);
+
+ tmp = seq[index++];
+ if (tmp is Asn1TaggedObject)
+ {
+ authAttrs = Asn1Set.GetInstance((Asn1TaggedObject)tmp, false);
+ tmp = seq[index++];
+ }
+
+ mac = Asn1OctetString.GetInstance(tmp);
+
+ if (seq.Count > index)
+ {
+ unauthAttrs = Asn1Set.GetInstance((Asn1TaggedObject)seq[index], false);
+ }
+ }
+
+ /**
+ * return an AuthenticatedData object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param isExplicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws ArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static AuthenticatedData GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ /**
+ * return an AuthenticatedData object from the given object.
+ *
+ * @param obj the object we want converted.
+ * @throws ArgumentException if the object cannot be converted.
+ */
+ public static AuthenticatedData GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is AuthenticatedData)
+ {
+ return (AuthenticatedData)obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new AuthenticatedData((Asn1Sequence)obj);
+ }
+
+ throw new ArgumentException("Invalid AuthenticatedData: " + Platform.GetTypeName(obj));
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public OriginatorInfo OriginatorInfo
+ {
+ get { return originatorInfo; }
+ }
+
+ public Asn1Set RecipientInfos
+ {
+ get { return recipientInfos; }
+ }
+
+ public AlgorithmIdentifier MacAlgorithm
+ {
+ get { return macAlgorithm; }
+ }
+
+ public AlgorithmIdentifier DigestAlgorithm
+ {
+ get { return digestAlgorithm; }
+ }
+
+ public ContentInfo EncapsulatedContentInfo
+ {
+ get { return encapsulatedContentInfo; }
+ }
+
+ public Asn1Set AuthAttrs
+ {
+ get { return authAttrs; }
+ }
+
+ public Asn1OctetString Mac
+ {
+ get { return mac; }
+ }
+
+ public Asn1Set UnauthAttrs
+ {
+ get { return unauthAttrs; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * AuthenticatedData ::= SEQUENCE {
+ * version CMSVersion,
+ * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+ * recipientInfos RecipientInfos,
+ * macAlgorithm MessageAuthenticationCodeAlgorithm,
+ * digestAlgorithm [1] DigestAlgorithmIdentifier OPTIONAL,
+ * encapContentInfo EncapsulatedContentInfo,
+ * authAttrs [2] IMPLICIT AuthAttributes OPTIONAL,
+ * mac MessageAuthenticationCode,
+ * unauthAttrs [3] IMPLICIT UnauthAttributes OPTIONAL }
+ *
+ * AuthAttributes ::= SET SIZE (1..MAX) OF Attribute
+ *
+ * UnauthAttributes ::= SET SIZE (1..MAX) OF Attribute
+ *
+ * MessageAuthenticationCode ::= OCTET STRING
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(version);
+
+ if (originatorInfo != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, originatorInfo));
+ }
+
+ v.Add(recipientInfos, macAlgorithm);
+
+ if (digestAlgorithm != null)
+ {
+ v.Add(new DerTaggedObject(false, 1, digestAlgorithm));
+ }
+
+ v.Add(encapsulatedContentInfo);
+
+ if (authAttrs != null)
+ {
+ v.Add(new DerTaggedObject(false, 2, authAttrs));
+ }
+
+ v.Add(mac);
+
+ if (unauthAttrs != null)
+ {
+ v.Add(new DerTaggedObject(false, 3, unauthAttrs));
+ }
+
+ return new BerSequence(v);
+ }
+
+ public static int CalculateVersion(OriginatorInfo origInfo)
+ {
+ if (origInfo == null)
+ return 0;
+
+ int ver = 0;
+
+ foreach (object obj in origInfo.Certificates)
+ {
+ if (obj is Asn1TaggedObject)
+ {
+ Asn1TaggedObject tag = (Asn1TaggedObject)obj;
+
+ if (tag.TagNo == 2)
+ {
+ ver = 1;
+ }
+ else if (tag.TagNo == 3)
+ {
+ ver = 3;
+ break;
+ }
+ }
+ }
+
+ foreach (object obj in origInfo.Crls)
+ {
+ if (obj is Asn1TaggedObject)
+ {
+ Asn1TaggedObject tag = (Asn1TaggedObject)obj;
+
+ if (tag.TagNo == 1)
+ {
+ ver = 3;
+ break;
+ }
+ }
+ }
+
+ return ver;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/AuthenticatedDataParser.cs b/bc-sharp-crypto/src/asn1/cms/AuthenticatedDataParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4b80d1b02104e037902f62527d6b078dafce6023
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/AuthenticatedDataParser.cs
@@ -0,0 +1,182 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * AuthenticatedData ::= SEQUENCE {
+ * version CMSVersion,
+ * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+ * recipientInfos RecipientInfos,
+ * macAlgorithm MessageAuthenticationCodeAlgorithm,
+ * digestAlgorithm [1] DigestAlgorithmIdentifier OPTIONAL,
+ * encapContentInfo EncapsulatedContentInfo,
+ * authAttrs [2] IMPLICIT AuthAttributes OPTIONAL,
+ * mac MessageAuthenticationCode,
+ * unauthAttrs [3] IMPLICIT UnauthAttributes OPTIONAL }
+ *
+ * AuthAttributes ::= SET SIZE (1..MAX) OF Attribute
+ *
+ * UnauthAttributes ::= SET SIZE (1..MAX) OF Attribute
+ *
+ * MessageAuthenticationCode ::= OCTET STRING
+ *
+ */
+ public class AuthenticatedDataParser
+ {
+ private Asn1SequenceParser seq;
+ private DerInteger version;
+ private IAsn1Convertible nextObject;
+ private bool originatorInfoCalled;
+
+ public AuthenticatedDataParser(
+ Asn1SequenceParser seq)
+ {
+ this.seq = seq;
+ this.version = (DerInteger)seq.ReadObject();
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public OriginatorInfo GetOriginatorInfo()
+ {
+ originatorInfoCalled = true;
+
+ if (nextObject == null)
+ {
+ nextObject = seq.ReadObject();
+ }
+
+ if (nextObject is Asn1TaggedObjectParser && ((Asn1TaggedObjectParser)nextObject).TagNo == 0)
+ {
+ Asn1SequenceParser originatorInfo = (Asn1SequenceParser) ((Asn1TaggedObjectParser)nextObject).GetObjectParser(Asn1Tags.Sequence, false);
+ nextObject = null;
+ return OriginatorInfo.GetInstance(originatorInfo.ToAsn1Object());
+ }
+
+ return null;
+ }
+
+ public Asn1SetParser GetRecipientInfos()
+ {
+ if (!originatorInfoCalled)
+ {
+ GetOriginatorInfo();
+ }
+
+ if (nextObject == null)
+ {
+ nextObject = seq.ReadObject();
+ }
+
+ Asn1SetParser recipientInfos = (Asn1SetParser)nextObject;
+ nextObject = null;
+ return recipientInfos;
+ }
+
+ public AlgorithmIdentifier GetMacAlgorithm()
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.ReadObject();
+ }
+
+ if (nextObject != null)
+ {
+ Asn1SequenceParser o = (Asn1SequenceParser)nextObject;
+ nextObject = null;
+ return AlgorithmIdentifier.GetInstance(o.ToAsn1Object());
+ }
+
+ return null;
+ }
+
+ public AlgorithmIdentifier GetDigestAlgorithm()
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.ReadObject();
+ }
+
+ if (nextObject is Asn1TaggedObjectParser)
+ {
+ AlgorithmIdentifier obj = AlgorithmIdentifier.GetInstance(
+ (Asn1TaggedObject)nextObject.ToAsn1Object(), false);
+ nextObject = null;
+ return obj;
+ }
+
+ return null;
+ }
+
+ public ContentInfoParser GetEnapsulatedContentInfo()
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.ReadObject();
+ }
+
+ if (nextObject != null)
+ {
+ Asn1SequenceParser o = (Asn1SequenceParser)nextObject;
+ nextObject = null;
+ return new ContentInfoParser(o);
+ }
+
+ return null;
+ }
+
+ public Asn1SetParser GetAuthAttrs()
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.ReadObject();
+ }
+
+ if (nextObject is Asn1TaggedObjectParser)
+ {
+ IAsn1Convertible o = nextObject;
+ nextObject = null;
+ return (Asn1SetParser)((Asn1TaggedObjectParser)o).GetObjectParser(Asn1Tags.Set, false);
+ }
+
+ return null;
+ }
+
+ public Asn1OctetString GetMac()
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.ReadObject();
+ }
+
+ IAsn1Convertible o = nextObject;
+ nextObject = null;
+
+ return Asn1OctetString.GetInstance(o.ToAsn1Object());
+ }
+
+ public Asn1SetParser GetUnauthAttrs()
+ {
+ if (nextObject == null)
+ {
+ nextObject = seq.ReadObject();
+ }
+
+ if (nextObject != null)
+ {
+ IAsn1Convertible o = nextObject;
+ nextObject = null;
+ return (Asn1SetParser)((Asn1TaggedObjectParser)o).GetObjectParser(Asn1Tags.Set, false);
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/CMSAttributes.cs b/bc-sharp-crypto/src/asn1/cms/CMSAttributes.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fca2b673804a5f3c38c550a8acd387d3bd8f7f3a
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/CMSAttributes.cs
@@ -0,0 +1,14 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public abstract class CmsAttributes
+ {
+ public static readonly DerObjectIdentifier ContentType = PkcsObjectIdentifiers.Pkcs9AtContentType;
+ public static readonly DerObjectIdentifier MessageDigest = PkcsObjectIdentifiers.Pkcs9AtMessageDigest;
+ public static readonly DerObjectIdentifier SigningTime = PkcsObjectIdentifiers.Pkcs9AtSigningTime;
+ public static readonly DerObjectIdentifier CounterSignature = PkcsObjectIdentifiers.Pkcs9AtCounterSignature;
+ public static readonly DerObjectIdentifier ContentHint = PkcsObjectIdentifiers.IdAAContentHint;
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/CMSObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/cms/CMSObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2ad0a3c7cd0e1cc3fce4d2832ee166e8b0ce35ab
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/CMSObjectIdentifiers.cs
@@ -0,0 +1,28 @@
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public abstract class CmsObjectIdentifiers
+ {
+ public static readonly DerObjectIdentifier Data = PkcsObjectIdentifiers.Data;
+ public static readonly DerObjectIdentifier SignedData = PkcsObjectIdentifiers.SignedData;
+ public static readonly DerObjectIdentifier EnvelopedData = PkcsObjectIdentifiers.EnvelopedData;
+ public static readonly DerObjectIdentifier SignedAndEnvelopedData = PkcsObjectIdentifiers.SignedAndEnvelopedData;
+ public static readonly DerObjectIdentifier DigestedData = PkcsObjectIdentifiers.DigestedData;
+ public static readonly DerObjectIdentifier EncryptedData = PkcsObjectIdentifiers.EncryptedData;
+ public static readonly DerObjectIdentifier AuthenticatedData = PkcsObjectIdentifiers.IdCTAuthData;
+ public static readonly DerObjectIdentifier CompressedData = PkcsObjectIdentifiers.IdCTCompressedData;
+ public static readonly DerObjectIdentifier AuthEnvelopedData = PkcsObjectIdentifiers.IdCTAuthEnvelopedData;
+ public static readonly DerObjectIdentifier timestampedData = PkcsObjectIdentifiers.IdCTTimestampedData;
+
+ /**
+ * The other Revocation Info arc
+ * id-ri OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
+ * dod(6) internet(1) security(5) mechanisms(5) pkix(7) ri(16) }
+ */
+ public static readonly DerObjectIdentifier id_ri = new DerObjectIdentifier("1.3.6.1.5.5.7.16");
+
+ public static readonly DerObjectIdentifier id_ri_ocsp_response = id_ri.Branch("2");
+ public static readonly DerObjectIdentifier id_ri_scvp = id_ri.Branch("4");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/CompressedData.cs b/bc-sharp-crypto/src/asn1/cms/CompressedData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..154ed35c0daaed662446a84c01f44d805a36f55f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/CompressedData.cs
@@ -0,0 +1,96 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ /**
+ * RFC 3274 - CMS Compressed Data.
+ *
+ * CompressedData ::= Sequence {
+ * version CMSVersion,
+ * compressionAlgorithm CompressionAlgorithmIdentifier,
+ * encapContentInfo EncapsulatedContentInfo
+ * }
+ *
+ */
+ public class CompressedData
+ : Asn1Encodable
+ {
+ private DerInteger version;
+ private AlgorithmIdentifier compressionAlgorithm;
+ private ContentInfo encapContentInfo;
+
+ public CompressedData(
+ AlgorithmIdentifier compressionAlgorithm,
+ ContentInfo encapContentInfo)
+ {
+ this.version = new DerInteger(0);
+ this.compressionAlgorithm = compressionAlgorithm;
+ this.encapContentInfo = encapContentInfo;
+ }
+
+ public CompressedData(
+ Asn1Sequence seq)
+ {
+ this.version = (DerInteger) seq[0];
+ this.compressionAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+ this.encapContentInfo = ContentInfo.GetInstance(seq[2]);
+ }
+
+ /**
+ * return a CompressedData object from a tagged object.
+ *
+ * @param ato the tagged object holding the object we want.
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static CompressedData GetInstance(
+ Asn1TaggedObject ato,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(ato, explicitly));
+ }
+
+ /**
+ * return a CompressedData object from the given object.
+ *
+ * @param _obj the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static CompressedData GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is CompressedData)
+ return (CompressedData)obj;
+
+ if (obj is Asn1Sequence)
+ return new CompressedData((Asn1Sequence) obj);
+
+ throw new ArgumentException("Invalid CompressedData: " + Platform.GetTypeName(obj));
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public AlgorithmIdentifier CompressionAlgorithmIdentifier
+ {
+ get { return compressionAlgorithm; }
+ }
+
+ public ContentInfo EncapContentInfo
+ {
+ get { return encapContentInfo; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new BerSequence(version, compressionAlgorithm, encapContentInfo);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/CompressedDataParser.cs b/bc-sharp-crypto/src/asn1/cms/CompressedDataParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7c53453df3a95d7ec7e2475d4aaa011f097db972
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/CompressedDataParser.cs
@@ -0,0 +1,47 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ /**
+ * RFC 3274 - CMS Compressed Data.
+ *
+ * CompressedData ::= SEQUENCE {
+ * version CMSVersion,
+ * compressionAlgorithm CompressionAlgorithmIdentifier,
+ * encapContentInfo EncapsulatedContentInfo
+ * }
+ *
+ */
+ public class CompressedDataParser
+ {
+ private DerInteger _version;
+ private AlgorithmIdentifier _compressionAlgorithm;
+ private ContentInfoParser _encapContentInfo;
+
+ public CompressedDataParser(
+ Asn1SequenceParser seq)
+ {
+ this._version = (DerInteger)seq.ReadObject();
+ this._compressionAlgorithm = AlgorithmIdentifier.GetInstance(seq.ReadObject().ToAsn1Object());
+ this._encapContentInfo = new ContentInfoParser((Asn1SequenceParser)seq.ReadObject());
+ }
+
+ public DerInteger Version
+ {
+ get { return _version; }
+ }
+
+ public AlgorithmIdentifier CompressionAlgorithmIdentifier
+ {
+ get { return _compressionAlgorithm; }
+ }
+
+ public ContentInfoParser GetEncapContentInfo()
+ {
+ return _encapContentInfo;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/ContentInfo.cs b/bc-sharp-crypto/src/asn1/cms/ContentInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f130a4bc7cec2e90c496f0c8e75ae1ef831bb4fc
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/ContentInfo.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class ContentInfo
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier contentType;
+ private readonly Asn1Encodable content;
+
+ public static ContentInfo GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is ContentInfo)
+ return (ContentInfo) obj;
+
+ if (obj is Asn1Sequence)
+ return new ContentInfo((Asn1Sequence) obj);
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj));
+ }
+
+ public static ContentInfo GetInstance(Asn1TaggedObject obj, bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ private ContentInfo(
+ Asn1Sequence seq)
+ {
+ if (seq.Count < 1 || seq.Count > 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ contentType = (DerObjectIdentifier) seq[0];
+
+ if (seq.Count > 1)
+ {
+ Asn1TaggedObject tagged = (Asn1TaggedObject) seq[1];
+ if (!tagged.IsExplicit() || tagged.TagNo != 0)
+ throw new ArgumentException("Bad tag for 'content'", "seq");
+
+ content = tagged.GetObject();
+ }
+ }
+
+ public ContentInfo(
+ DerObjectIdentifier contentType,
+ Asn1Encodable content)
+ {
+ this.contentType = contentType;
+ this.content = content;
+ }
+
+ public DerObjectIdentifier ContentType
+ {
+ get { return contentType; }
+ }
+
+ public Asn1Encodable Content
+ {
+ get { return content; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * ContentInfo ::= Sequence {
+ * contentType ContentType,
+ * content
+ * [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(contentType);
+
+ if (content != null)
+ {
+ v.Add(new BerTaggedObject(0, content));
+ }
+
+ return new BerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/ContentInfoParser.cs b/bc-sharp-crypto/src/asn1/cms/ContentInfoParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..541cc0f59bbe420b3c01b77e4d27c172355f765c
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/ContentInfoParser.cs
@@ -0,0 +1,40 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * ContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * content
+ * [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+ *
+ */
+ public class ContentInfoParser
+ {
+ private DerObjectIdentifier contentType;
+ private Asn1TaggedObjectParser content;
+
+ public ContentInfoParser(
+ Asn1SequenceParser seq)
+ {
+ contentType = (DerObjectIdentifier)seq.ReadObject();
+ content = (Asn1TaggedObjectParser)seq.ReadObject();
+ }
+
+ public DerObjectIdentifier ContentType
+ {
+ get { return contentType; }
+ }
+
+ public IAsn1Convertible GetContent(
+ int tag)
+ {
+ if (content == null)
+ return null;
+
+ return content.GetObjectParser(tag, true);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/EncryptedContentInfo.cs b/bc-sharp-crypto/src/asn1/cms/EncryptedContentInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..999f2a01e8b50f3becdf30f4b43455f737f33b22
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/EncryptedContentInfo.cs
@@ -0,0 +1,94 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class EncryptedContentInfo
+ : Asn1Encodable
+ {
+ private DerObjectIdentifier contentType;
+ private AlgorithmIdentifier contentEncryptionAlgorithm;
+ private Asn1OctetString encryptedContent;
+
+ public EncryptedContentInfo(
+ DerObjectIdentifier contentType,
+ AlgorithmIdentifier contentEncryptionAlgorithm,
+ Asn1OctetString encryptedContent)
+ {
+ this.contentType = contentType;
+ this.contentEncryptionAlgorithm = contentEncryptionAlgorithm;
+ this.encryptedContent = encryptedContent;
+ }
+
+ public EncryptedContentInfo(
+ Asn1Sequence seq)
+ {
+ contentType = (DerObjectIdentifier) seq[0];
+ contentEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+
+ if (seq.Count > 2)
+ {
+ encryptedContent = Asn1OctetString.GetInstance(
+ (Asn1TaggedObject) seq[2], false);
+ }
+ }
+
+ /**
+ * return an EncryptedContentInfo object from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static EncryptedContentInfo GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is EncryptedContentInfo)
+ return (EncryptedContentInfo)obj;
+
+ if (obj is Asn1Sequence)
+ return new EncryptedContentInfo((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid EncryptedContentInfo: " + Platform.GetTypeName(obj));
+ }
+
+ public DerObjectIdentifier ContentType
+ {
+ get { return contentType; }
+ }
+
+ public AlgorithmIdentifier ContentEncryptionAlgorithm
+ {
+ get { return contentEncryptionAlgorithm; }
+ }
+
+ public Asn1OctetString EncryptedContent
+ {
+ get { return encryptedContent; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * EncryptedContentInfo ::= Sequence {
+ * contentType ContentType,
+ * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+ * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ contentType, contentEncryptionAlgorithm);
+
+ if (encryptedContent != null)
+ {
+ v.Add(new BerTaggedObject(false, 0, encryptedContent));
+ }
+
+ return new BerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/EncryptedContentInfoParser.cs b/bc-sharp-crypto/src/asn1/cms/EncryptedContentInfoParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..af748b1b3c0afebb86189287356f3df047aadc91
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/EncryptedContentInfoParser.cs
@@ -0,0 +1,46 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ /**
+ *
+ * EncryptedContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+ * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+ * }
+ *
+ */
+ public class EncryptedContentInfoParser
+ {
+ private DerObjectIdentifier _contentType;
+ private AlgorithmIdentifier _contentEncryptionAlgorithm;
+ private Asn1TaggedObjectParser _encryptedContent;
+
+ public EncryptedContentInfoParser(
+ Asn1SequenceParser seq)
+ {
+ _contentType = (DerObjectIdentifier)seq.ReadObject();
+ _contentEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq.ReadObject().ToAsn1Object());
+ _encryptedContent = (Asn1TaggedObjectParser)seq.ReadObject();
+ }
+
+ public DerObjectIdentifier ContentType
+ {
+ get { return _contentType; }
+ }
+
+ public AlgorithmIdentifier ContentEncryptionAlgorithm
+ {
+ get { return _contentEncryptionAlgorithm; }
+ }
+
+ public IAsn1Convertible GetEncryptedContent(
+ int tag)
+ {
+ return _encryptedContent.GetObjectParser(tag, false);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/EncryptedData.cs b/bc-sharp-crypto/src/asn1/cms/EncryptedData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b8492d14bb92bd908ffea5d38fa7c933062795d2
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/EncryptedData.cs
@@ -0,0 +1,97 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class EncryptedData
+ : Asn1Encodable
+ {
+ private readonly DerInteger version;
+ private readonly EncryptedContentInfo encryptedContentInfo;
+ private readonly Asn1Set unprotectedAttrs;
+
+ public static EncryptedData GetInstance(
+ object obj)
+ {
+ if (obj is EncryptedData)
+ return (EncryptedData) obj;
+
+ if (obj is Asn1Sequence)
+ return new EncryptedData((Asn1Sequence) obj);
+
+ throw new ArgumentException("Invalid EncryptedData: " + Platform.GetTypeName(obj));
+ }
+
+ public EncryptedData(
+ EncryptedContentInfo encInfo)
+ : this(encInfo, null)
+ {
+ }
+
+ public EncryptedData(
+ EncryptedContentInfo encInfo,
+ Asn1Set unprotectedAttrs)
+ {
+ if (encInfo == null)
+ throw new ArgumentNullException("encInfo");
+
+ this.version = new DerInteger((unprotectedAttrs == null) ? 0 : 2);
+ this.encryptedContentInfo = encInfo;
+ this.unprotectedAttrs = unprotectedAttrs;
+ }
+
+ private EncryptedData(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+ if (seq.Count < 2 || seq.Count > 3)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ this.version = DerInteger.GetInstance(seq[0]);
+ this.encryptedContentInfo = EncryptedContentInfo.GetInstance(seq[1]);
+
+ if (seq.Count > 2)
+ {
+ this.unprotectedAttrs = Asn1Set.GetInstance((Asn1TaggedObject)seq[2], false);
+ }
+ }
+
+ public virtual DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public virtual EncryptedContentInfo EncryptedContentInfo
+ {
+ get { return encryptedContentInfo; }
+ }
+
+ public virtual Asn1Set UnprotectedAttrs
+ {
+ get { return unprotectedAttrs; }
+ }
+
+ /**
+ *
+ * EncryptedData ::= SEQUENCE {
+ * version CMSVersion,
+ * encryptedContentInfo EncryptedContentInfo,
+ * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(version, encryptedContentInfo);
+
+ if (unprotectedAttrs != null)
+ {
+ v.Add(new BerTaggedObject(false, 1, unprotectedAttrs));
+ }
+
+ return new BerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/EnvelopedData.cs b/bc-sharp-crypto/src/asn1/cms/EnvelopedData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..09f291a93b86098e398a3f8b615bb7d2ccf9d053
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/EnvelopedData.cs
@@ -0,0 +1,176 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class EnvelopedData
+ : Asn1Encodable
+ {
+ private DerInteger version;
+ private OriginatorInfo originatorInfo;
+ private Asn1Set recipientInfos;
+ private EncryptedContentInfo encryptedContentInfo;
+ private Asn1Set unprotectedAttrs;
+
+ public EnvelopedData(
+ OriginatorInfo originatorInfo,
+ Asn1Set recipientInfos,
+ EncryptedContentInfo encryptedContentInfo,
+ Asn1Set unprotectedAttrs)
+ {
+ this.version = new DerInteger(CalculateVersion(originatorInfo, recipientInfos, unprotectedAttrs));
+ this.originatorInfo = originatorInfo;
+ this.recipientInfos = recipientInfos;
+ this.encryptedContentInfo = encryptedContentInfo;
+ this.unprotectedAttrs = unprotectedAttrs;
+ }
+
+ public EnvelopedData(
+ OriginatorInfo originatorInfo,
+ Asn1Set recipientInfos,
+ EncryptedContentInfo encryptedContentInfo,
+ Attributes unprotectedAttrs)
+ {
+ this.version = new DerInteger(CalculateVersion(originatorInfo, recipientInfos, Asn1Set.GetInstance(unprotectedAttrs)));
+ this.originatorInfo = originatorInfo;
+ this.recipientInfos = recipientInfos;
+ this.encryptedContentInfo = encryptedContentInfo;
+ this.unprotectedAttrs = Asn1Set.GetInstance(unprotectedAttrs);
+ }
+
+ [Obsolete("Use 'GetInstance' instead")]
+ public EnvelopedData(
+ Asn1Sequence seq)
+ {
+ int index = 0;
+
+ version = (DerInteger) seq[index++];
+
+ object tmp = seq[index++];
+
+ if (tmp is Asn1TaggedObject)
+ {
+ originatorInfo = OriginatorInfo.GetInstance((Asn1TaggedObject) tmp, false);
+ tmp = seq[index++];
+ }
+
+ recipientInfos = Asn1Set.GetInstance(tmp);
+ encryptedContentInfo = EncryptedContentInfo.GetInstance(seq[index++]);
+
+ if (seq.Count > index)
+ {
+ unprotectedAttrs = Asn1Set.GetInstance((Asn1TaggedObject) seq[index], false);
+ }
+ }
+
+ /**
+ * return an EnvelopedData object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static EnvelopedData GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ /**
+ * return an EnvelopedData object from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static EnvelopedData GetInstance(
+ object obj)
+ {
+ if (obj is EnvelopedData)
+ return (EnvelopedData)obj;
+ if (obj == null)
+ return null;
+ return new EnvelopedData(Asn1Sequence.GetInstance(obj));
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public OriginatorInfo OriginatorInfo
+ {
+ get { return originatorInfo; }
+ }
+
+ public Asn1Set RecipientInfos
+ {
+ get { return recipientInfos; }
+ }
+
+ public EncryptedContentInfo EncryptedContentInfo
+ {
+ get { return encryptedContentInfo; }
+ }
+
+ public Asn1Set UnprotectedAttrs
+ {
+ get { return unprotectedAttrs; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * EnvelopedData ::= Sequence {
+ * version CMSVersion,
+ * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+ * recipientInfos RecipientInfos,
+ * encryptedContentInfo EncryptedContentInfo,
+ * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(version);
+
+ if (originatorInfo != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, originatorInfo));
+ }
+
+ v.Add(recipientInfos, encryptedContentInfo);
+
+ if (unprotectedAttrs != null)
+ {
+ v.Add(new DerTaggedObject(false, 1, unprotectedAttrs));
+ }
+
+ return new BerSequence(v);
+ }
+
+ public static int CalculateVersion(OriginatorInfo originatorInfo, Asn1Set recipientInfos, Asn1Set unprotectedAttrs)
+ {
+ if (originatorInfo != null || unprotectedAttrs != null)
+ {
+ return 2;
+ }
+
+ foreach (object o in recipientInfos)
+ {
+ RecipientInfo ri = RecipientInfo.GetInstance(o);
+
+ if (ri.Version.Value.IntValue != 0)
+ {
+ return 2;
+ }
+ }
+
+ return 0;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/EnvelopedDataParser.cs b/bc-sharp-crypto/src/asn1/cms/EnvelopedDataParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5993537912bb9af91a100cd93eea492439c90bf0
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/EnvelopedDataParser.cs
@@ -0,0 +1,107 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * EnvelopedData ::= SEQUENCE {
+ * version CMSVersion,
+ * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+ * recipientInfos RecipientInfos,
+ * encryptedContentInfo EncryptedContentInfo,
+ * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL
+ * }
+ *
+ */
+ public class EnvelopedDataParser
+ {
+ private Asn1SequenceParser _seq;
+ private DerInteger _version;
+ private IAsn1Convertible _nextObject;
+ private bool _originatorInfoCalled;
+
+ public EnvelopedDataParser(
+ Asn1SequenceParser seq)
+ {
+ this._seq = seq;
+ this._version = (DerInteger)seq.ReadObject();
+ }
+
+ public DerInteger Version
+ {
+ get { return _version; }
+ }
+
+ public OriginatorInfo GetOriginatorInfo()
+ {
+ _originatorInfoCalled = true;
+
+ if (_nextObject == null)
+ {
+ _nextObject = _seq.ReadObject();
+ }
+
+ if (_nextObject is Asn1TaggedObjectParser && ((Asn1TaggedObjectParser)_nextObject).TagNo == 0)
+ {
+ Asn1SequenceParser originatorInfo = (Asn1SequenceParser)
+ ((Asn1TaggedObjectParser)_nextObject).GetObjectParser(Asn1Tags.Sequence, false);
+ _nextObject = null;
+ return OriginatorInfo.GetInstance(originatorInfo.ToAsn1Object());
+ }
+
+ return null;
+ }
+
+ public Asn1SetParser GetRecipientInfos()
+ {
+ if (!_originatorInfoCalled)
+ {
+ GetOriginatorInfo();
+ }
+
+ if (_nextObject == null)
+ {
+ _nextObject = _seq.ReadObject();
+ }
+
+ Asn1SetParser recipientInfos = (Asn1SetParser)_nextObject;
+ _nextObject = null;
+ return recipientInfos;
+ }
+
+ public EncryptedContentInfoParser GetEncryptedContentInfo()
+ {
+ if (_nextObject == null)
+ {
+ _nextObject = _seq.ReadObject();
+ }
+
+ if (_nextObject != null)
+ {
+ Asn1SequenceParser o = (Asn1SequenceParser) _nextObject;
+ _nextObject = null;
+ return new EncryptedContentInfoParser(o);
+ }
+
+ return null;
+ }
+
+ public Asn1SetParser GetUnprotectedAttrs()
+ {
+ if (_nextObject == null)
+ {
+ _nextObject = _seq.ReadObject();
+ }
+
+ if (_nextObject != null)
+ {
+ IAsn1Convertible o = _nextObject;
+ _nextObject = null;
+ return (Asn1SetParser)((Asn1TaggedObjectParser)o).GetObjectParser(Asn1Tags.Set, false);
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/Evidence.cs b/bc-sharp-crypto/src/asn1/cms/Evidence.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8374aed55443a87f4c65ee35f6ab45027b444edd
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/Evidence.cs
@@ -0,0 +1,49 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class Evidence
+ : Asn1Encodable, IAsn1Choice
+ {
+ private TimeStampTokenEvidence tstEvidence;
+
+ public Evidence(TimeStampTokenEvidence tstEvidence)
+ {
+ this.tstEvidence = tstEvidence;
+ }
+
+ private Evidence(Asn1TaggedObject tagged)
+ {
+ if (tagged.TagNo == 0)
+ {
+ this.tstEvidence = TimeStampTokenEvidence.GetInstance(tagged, false);
+ }
+ }
+
+ public static Evidence GetInstance(object obj)
+ {
+ if (obj is Evidence)
+ return (Evidence)obj;
+
+ if (obj is Asn1TaggedObject)
+ return new Evidence(Asn1TaggedObject.GetInstance(obj));
+
+ throw new ArgumentException("Unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public virtual TimeStampTokenEvidence TstEvidence
+ {
+ get { return tstEvidence; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ if (tstEvidence != null)
+ return new DerTaggedObject(false, 0, tstEvidence);
+
+ return null;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/IssuerAndSerialNumber.cs b/bc-sharp-crypto/src/asn1/cms/IssuerAndSerialNumber.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b509e7e19ed469a62b0b30bfd31d57a4987d7f12
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/IssuerAndSerialNumber.cs
@@ -0,0 +1,64 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class IssuerAndSerialNumber
+ : Asn1Encodable
+ {
+ private X509Name name;
+ private DerInteger serialNumber;
+
+ public static IssuerAndSerialNumber GetInstance(object obj)
+ {
+ if (obj == null)
+ return null;
+ IssuerAndSerialNumber existing = obj as IssuerAndSerialNumber;
+ if (existing != null)
+ return existing;
+ return new IssuerAndSerialNumber(Asn1Sequence.GetInstance(obj));
+ }
+
+ [Obsolete("Use GetInstance() instead")]
+ public IssuerAndSerialNumber(
+ Asn1Sequence seq)
+ {
+ this.name = X509Name.GetInstance(seq[0]);
+ this.serialNumber = (DerInteger) seq[1];
+ }
+
+ public IssuerAndSerialNumber(
+ X509Name name,
+ BigInteger serialNumber)
+ {
+ this.name = name;
+ this.serialNumber = new DerInteger(serialNumber);
+ }
+
+ public IssuerAndSerialNumber(
+ X509Name name,
+ DerInteger serialNumber)
+ {
+ this.name = name;
+ this.serialNumber = serialNumber;
+ }
+
+ public X509Name Name
+ {
+ get { return name; }
+ }
+
+ public DerInteger SerialNumber
+ {
+ get { return serialNumber; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(name, serialNumber);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/KEKIdentifier.cs b/bc-sharp-crypto/src/asn1/cms/KEKIdentifier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a422174408843d0e248e3d787130a29799ed2f6f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/KEKIdentifier.cs
@@ -0,0 +1,119 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class KekIdentifier
+ : Asn1Encodable
+ {
+ private Asn1OctetString keyIdentifier;
+ private DerGeneralizedTime date;
+ private OtherKeyAttribute other;
+
+ public KekIdentifier(
+ byte[] keyIdentifier,
+ DerGeneralizedTime date,
+ OtherKeyAttribute other)
+ {
+ this.keyIdentifier = new DerOctetString(keyIdentifier);
+ this.date = date;
+ this.other = other;
+ }
+
+ public KekIdentifier(
+ Asn1Sequence seq)
+ {
+ keyIdentifier = (Asn1OctetString) seq[0];
+
+ switch (seq.Count)
+ {
+ case 1:
+ break;
+ case 2:
+ if (seq[1] is DerGeneralizedTime)
+ {
+ date = (DerGeneralizedTime) seq[1];
+ }
+ else
+ {
+ other = OtherKeyAttribute.GetInstance(seq[2]);
+ }
+ break;
+ case 3:
+ date = (DerGeneralizedTime) seq[1];
+ other = OtherKeyAttribute.GetInstance(seq[2]);
+ break;
+ default:
+ throw new ArgumentException("Invalid KekIdentifier");
+ }
+ }
+
+ /**
+ * return a KekIdentifier object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static KekIdentifier GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ /**
+ * return a KekIdentifier object from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static KekIdentifier GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is KekIdentifier)
+ return (KekIdentifier)obj;
+
+ if (obj is Asn1Sequence)
+ return new KekIdentifier((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid KekIdentifier: " + Platform.GetTypeName(obj));
+ }
+
+ public Asn1OctetString KeyIdentifier
+ {
+ get { return keyIdentifier; }
+ }
+
+ public DerGeneralizedTime Date
+ {
+ get { return date; }
+ }
+
+ public OtherKeyAttribute Other
+ {
+ get { return other; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * KekIdentifier ::= Sequence {
+ * keyIdentifier OCTET STRING,
+ * date GeneralizedTime OPTIONAL,
+ * other OtherKeyAttribute OPTIONAL
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(keyIdentifier);
+ v.AddOptional(date, other);
+ return new DerSequence(v);
+ }
+ }
+}
+
diff --git a/bc-sharp-crypto/src/asn1/cms/KEKRecipientInfo.cs b/bc-sharp-crypto/src/asn1/cms/KEKRecipientInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..810e7fc978d306a7fed62f2a1ea8b669970d05b4
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/KEKRecipientInfo.cs
@@ -0,0 +1,106 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class KekRecipientInfo
+ : Asn1Encodable
+ {
+ private DerInteger version;
+ private KekIdentifier kekID;
+ private AlgorithmIdentifier keyEncryptionAlgorithm;
+ private Asn1OctetString encryptedKey;
+
+ public KekRecipientInfo(
+ KekIdentifier kekID,
+ AlgorithmIdentifier keyEncryptionAlgorithm,
+ Asn1OctetString encryptedKey)
+ {
+ this.version = new DerInteger(4);
+ this.kekID = kekID;
+ this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+ this.encryptedKey = encryptedKey;
+ }
+
+ public KekRecipientInfo(
+ Asn1Sequence seq)
+ {
+ version = (DerInteger) seq[0];
+ kekID = KekIdentifier.GetInstance(seq[1]);
+ keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[2]);
+ encryptedKey = (Asn1OctetString) seq[3];
+ }
+
+ /**
+ * return a KekRecipientInfo object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static KekRecipientInfo GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ /**
+ * return a KekRecipientInfo object from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static KekRecipientInfo GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is KekRecipientInfo)
+ return (KekRecipientInfo)obj;
+
+ if(obj is Asn1Sequence)
+ return new KekRecipientInfo((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid KekRecipientInfo: " + Platform.GetTypeName(obj));
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public KekIdentifier KekID
+ {
+ get { return kekID; }
+ }
+
+ public AlgorithmIdentifier KeyEncryptionAlgorithm
+ {
+ get { return keyEncryptionAlgorithm; }
+ }
+
+ public Asn1OctetString EncryptedKey
+ {
+ get { return encryptedKey; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * KekRecipientInfo ::= Sequence {
+ * version CMSVersion, -- always set to 4
+ * kekID KekIdentifier,
+ * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+ * encryptedKey EncryptedKey
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(version, kekID, keyEncryptionAlgorithm, encryptedKey);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/KeyAgreeRecipientIdentifier.cs b/bc-sharp-crypto/src/asn1/cms/KeyAgreeRecipientIdentifier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0256c2dc209efef1d392e2c9282935c2da03ba16
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/KeyAgreeRecipientIdentifier.cs
@@ -0,0 +1,94 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class KeyAgreeRecipientIdentifier
+ : Asn1Encodable, IAsn1Choice
+ {
+ /**
+ * return an KeyAgreeRecipientIdentifier object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param isExplicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static KeyAgreeRecipientIdentifier GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ /**
+ * return an KeyAgreeRecipientIdentifier object from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static KeyAgreeRecipientIdentifier GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is KeyAgreeRecipientIdentifier)
+ return (KeyAgreeRecipientIdentifier)obj;
+
+ if (obj is Asn1Sequence)
+ return new KeyAgreeRecipientIdentifier(IssuerAndSerialNumber.GetInstance(obj));
+
+ if (obj is Asn1TaggedObject && ((Asn1TaggedObject)obj).TagNo == 0)
+ {
+ return new KeyAgreeRecipientIdentifier(RecipientKeyIdentifier.GetInstance(
+ (Asn1TaggedObject)obj, false));
+ }
+
+ throw new ArgumentException("Invalid KeyAgreeRecipientIdentifier: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private readonly IssuerAndSerialNumber issuerSerial;
+ private readonly RecipientKeyIdentifier rKeyID;
+
+ public KeyAgreeRecipientIdentifier(
+ IssuerAndSerialNumber issuerSerial)
+ {
+ this.issuerSerial = issuerSerial;
+ }
+
+ public KeyAgreeRecipientIdentifier(
+ RecipientKeyIdentifier rKeyID)
+ {
+ this.rKeyID = rKeyID;
+ }
+
+ public IssuerAndSerialNumber IssuerAndSerialNumber
+ {
+ get { return issuerSerial; }
+ }
+
+ public RecipientKeyIdentifier RKeyID
+ {
+ get { return rKeyID; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * KeyAgreeRecipientIdentifier ::= CHOICE {
+ * issuerAndSerialNumber IssuerAndSerialNumber,
+ * rKeyId [0] IMPLICIT RecipientKeyIdentifier
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ if (issuerSerial != null)
+ {
+ return issuerSerial.ToAsn1Object();
+ }
+
+ return new DerTaggedObject(false, 0, rKeyID);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/KeyAgreeRecipientInfo.cs b/bc-sharp-crypto/src/asn1/cms/KeyAgreeRecipientInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..62a38925b928c0a651a6d1e4ddf3e835b96ee335
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/KeyAgreeRecipientInfo.cs
@@ -0,0 +1,141 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class KeyAgreeRecipientInfo
+ : Asn1Encodable
+ {
+ private DerInteger version;
+ private OriginatorIdentifierOrKey originator;
+ private Asn1OctetString ukm;
+ private AlgorithmIdentifier keyEncryptionAlgorithm;
+ private Asn1Sequence recipientEncryptedKeys;
+
+ public KeyAgreeRecipientInfo(
+ OriginatorIdentifierOrKey originator,
+ Asn1OctetString ukm,
+ AlgorithmIdentifier keyEncryptionAlgorithm,
+ Asn1Sequence recipientEncryptedKeys)
+ {
+ this.version = new DerInteger(3);
+ this.originator = originator;
+ this.ukm = ukm;
+ this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+ this.recipientEncryptedKeys = recipientEncryptedKeys;
+ }
+
+ public KeyAgreeRecipientInfo(
+ Asn1Sequence seq)
+ {
+ int index = 0;
+
+ version = (DerInteger) seq[index++];
+ originator = OriginatorIdentifierOrKey.GetInstance(
+ (Asn1TaggedObject) seq[index++], true);
+
+ if (seq[index] is Asn1TaggedObject)
+ {
+ ukm = Asn1OctetString.GetInstance(
+ (Asn1TaggedObject) seq[index++], true);
+ }
+
+ keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(
+ seq[index++]);
+
+ recipientEncryptedKeys = (Asn1Sequence) seq[index++];
+ }
+
+ /**
+ * return a KeyAgreeRecipientInfo object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static KeyAgreeRecipientInfo GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ /**
+ * return a KeyAgreeRecipientInfo object from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static KeyAgreeRecipientInfo GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is KeyAgreeRecipientInfo)
+ return (KeyAgreeRecipientInfo)obj;
+
+ if (obj is Asn1Sequence)
+ return new KeyAgreeRecipientInfo((Asn1Sequence)obj);
+
+ throw new ArgumentException(
+ "Illegal object in KeyAgreeRecipientInfo: " + Platform.GetTypeName(obj));
+
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public OriginatorIdentifierOrKey Originator
+ {
+ get { return originator; }
+ }
+
+ public Asn1OctetString UserKeyingMaterial
+ {
+ get { return ukm; }
+ }
+
+ public AlgorithmIdentifier KeyEncryptionAlgorithm
+ {
+ get { return keyEncryptionAlgorithm; }
+ }
+
+ public Asn1Sequence RecipientEncryptedKeys
+ {
+ get { return recipientEncryptedKeys; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * KeyAgreeRecipientInfo ::= Sequence {
+ * version CMSVersion, -- always set to 3
+ * originator [0] EXPLICIT OriginatorIdentifierOrKey,
+ * ukm [1] EXPLICIT UserKeyingMaterial OPTIONAL,
+ * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+ * recipientEncryptedKeys RecipientEncryptedKeys
+ * }
+ *
+ * UserKeyingMaterial ::= OCTET STRING
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ version, new DerTaggedObject(true, 0, originator));
+
+ if (ukm != null)
+ {
+ v.Add(new DerTaggedObject(true, 1, ukm));
+ }
+
+ v.Add(keyEncryptionAlgorithm, recipientEncryptedKeys);
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/KeyTransRecipientInfo.cs b/bc-sharp-crypto/src/asn1/cms/KeyTransRecipientInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5e4fd22b4c5b6bf77a3636496f34bb8e6ebf1e8f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/KeyTransRecipientInfo.cs
@@ -0,0 +1,99 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class KeyTransRecipientInfo
+ : Asn1Encodable
+ {
+ private DerInteger version;
+ private RecipientIdentifier rid;
+ private AlgorithmIdentifier keyEncryptionAlgorithm;
+ private Asn1OctetString encryptedKey;
+
+ public KeyTransRecipientInfo(
+ RecipientIdentifier rid,
+ AlgorithmIdentifier keyEncryptionAlgorithm,
+ Asn1OctetString encryptedKey)
+ {
+ if (rid.ToAsn1Object() is Asn1TaggedObject)
+ {
+ this.version = new DerInteger(2);
+ }
+ else
+ {
+ this.version = new DerInteger(0);
+ }
+
+ this.rid = rid;
+ this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+ this.encryptedKey = encryptedKey;
+ }
+
+ public KeyTransRecipientInfo(
+ Asn1Sequence seq)
+ {
+ this.version = (DerInteger) seq[0];
+ this.rid = RecipientIdentifier.GetInstance(seq[1]);
+ this.keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[2]);
+ this.encryptedKey = (Asn1OctetString) seq[3];
+ }
+
+ /**
+ * return a KeyTransRecipientInfo object from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static KeyTransRecipientInfo GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is KeyTransRecipientInfo)
+ return (KeyTransRecipientInfo) obj;
+
+ if(obj is Asn1Sequence)
+ return new KeyTransRecipientInfo((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Illegal object in KeyTransRecipientInfo: " + Platform.GetTypeName(obj));
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public RecipientIdentifier RecipientIdentifier
+ {
+ get { return rid; }
+ }
+
+ public AlgorithmIdentifier KeyEncryptionAlgorithm
+ {
+ get { return keyEncryptionAlgorithm; }
+ }
+
+ public Asn1OctetString EncryptedKey
+ {
+ get { return encryptedKey; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * KeyTransRecipientInfo ::= Sequence {
+ * version CMSVersion, -- always set to 0 or 2
+ * rid RecipientIdentifier,
+ * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+ * encryptedKey EncryptedKey
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(version, rid, keyEncryptionAlgorithm, encryptedKey);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/MetaData.cs b/bc-sharp-crypto/src/asn1/cms/MetaData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ad2b5c426f9cfe8443d0973809611b7140727664
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/MetaData.cs
@@ -0,0 +1,94 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class MetaData
+ : Asn1Encodable
+ {
+ private DerBoolean hashProtected;
+ private DerUtf8String fileName;
+ private DerIA5String mediaType;
+ private Attributes otherMetaData;
+
+ public MetaData(
+ DerBoolean hashProtected,
+ DerUtf8String fileName,
+ DerIA5String mediaType,
+ Attributes otherMetaData)
+ {
+ this.hashProtected = hashProtected;
+ this.fileName = fileName;
+ this.mediaType = mediaType;
+ this.otherMetaData = otherMetaData;
+ }
+
+ private MetaData(Asn1Sequence seq)
+ {
+ this.hashProtected = DerBoolean.GetInstance(seq[0]);
+
+ int index = 1;
+
+ if (index < seq.Count && seq[index] is DerUtf8String)
+ {
+ this.fileName = DerUtf8String.GetInstance(seq[index++]);
+ }
+ if (index < seq.Count && seq[index] is DerIA5String)
+ {
+ this.mediaType = DerIA5String.GetInstance(seq[index++]);
+ }
+ if (index < seq.Count)
+ {
+ this.otherMetaData = Attributes.GetInstance(seq[index++]);
+ }
+ }
+
+ public static MetaData GetInstance(object obj)
+ {
+ if (obj is MetaData)
+ return (MetaData)obj;
+
+ if (obj != null)
+ return new MetaData(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ /**
+ *
+ * MetaData ::= SEQUENCE {
+ * hashProtected BOOLEAN,
+ * fileName UTF8String OPTIONAL,
+ * mediaType IA5String OPTIONAL,
+ * otherMetaData Attributes OPTIONAL
+ * }
+ *
+ * @return
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(hashProtected);
+ v.AddOptional(fileName, mediaType, otherMetaData);
+ return new DerSequence(v);
+ }
+
+ public virtual bool IsHashProtected
+ {
+ get { return hashProtected.IsTrue; }
+ }
+
+ public virtual DerUtf8String FileName
+ {
+ get { return fileName; }
+ }
+
+ public virtual DerIA5String MediaType
+ {
+ get { return mediaType; }
+ }
+
+ public virtual Attributes OtherMetaData
+ {
+ get { return otherMetaData; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/OriginatorIdentifierOrKey.cs b/bc-sharp-crypto/src/asn1/cms/OriginatorIdentifierOrKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f197fe965eb4eb46c4fd2f4c81c848569d59c2f7
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/OriginatorIdentifierOrKey.cs
@@ -0,0 +1,168 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class OriginatorIdentifierOrKey
+ : Asn1Encodable, IAsn1Choice
+ {
+ private Asn1Encodable id;
+
+ public OriginatorIdentifierOrKey(
+ IssuerAndSerialNumber id)
+ {
+ this.id = id;
+ }
+
+ [Obsolete("Use version taking a 'SubjectKeyIdentifier'")]
+ public OriginatorIdentifierOrKey(
+ Asn1OctetString id)
+ : this(new SubjectKeyIdentifier(id))
+ {
+ }
+
+ public OriginatorIdentifierOrKey(
+ SubjectKeyIdentifier id)
+ {
+ this.id = new DerTaggedObject(false, 0, id);
+ }
+
+ public OriginatorIdentifierOrKey(
+ OriginatorPublicKey id)
+ {
+ this.id = new DerTaggedObject(false, 1, id);
+ }
+
+ [Obsolete("Use more specific version")]
+ public OriginatorIdentifierOrKey(
+ Asn1Object id)
+ {
+ this.id = id;
+ }
+
+ private OriginatorIdentifierOrKey(
+ Asn1TaggedObject id)
+ {
+ // TODO Add validation
+ this.id = id;
+ }
+
+ /**
+ * return an OriginatorIdentifierOrKey object from a tagged object.
+ *
+ * @param o the tagged object holding the object we want.
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static OriginatorIdentifierOrKey GetInstance(
+ Asn1TaggedObject o,
+ bool explicitly)
+ {
+ if (!explicitly)
+ {
+ throw new ArgumentException(
+ "Can't implicitly tag OriginatorIdentifierOrKey");
+ }
+
+ return GetInstance(o.GetObject());
+ }
+
+ /**
+ * return an OriginatorIdentifierOrKey object from the given object.
+ *
+ * @param o the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static OriginatorIdentifierOrKey GetInstance(
+ object o)
+ {
+ if (o == null || o is OriginatorIdentifierOrKey)
+ return (OriginatorIdentifierOrKey)o;
+
+ if (o is IssuerAndSerialNumber)
+ return new OriginatorIdentifierOrKey((IssuerAndSerialNumber)o);
+
+ if (o is SubjectKeyIdentifier)
+ return new OriginatorIdentifierOrKey((SubjectKeyIdentifier)o);
+
+ if (o is OriginatorPublicKey)
+ return new OriginatorIdentifierOrKey((OriginatorPublicKey)o);
+
+ if (o is Asn1TaggedObject)
+ return new OriginatorIdentifierOrKey((Asn1TaggedObject)o);
+
+ throw new ArgumentException("Invalid OriginatorIdentifierOrKey: " + Platform.GetTypeName(o));
+ }
+
+ public Asn1Encodable ID
+ {
+ get { return id; }
+ }
+
+ public IssuerAndSerialNumber IssuerAndSerialNumber
+ {
+ get
+ {
+ if (id is IssuerAndSerialNumber)
+ {
+ return (IssuerAndSerialNumber)id;
+ }
+
+ return null;
+ }
+ }
+
+ public SubjectKeyIdentifier SubjectKeyIdentifier
+ {
+ get
+ {
+ if (id is Asn1TaggedObject && ((Asn1TaggedObject)id).TagNo == 0)
+ {
+ return SubjectKeyIdentifier.GetInstance((Asn1TaggedObject)id, false);
+ }
+
+ return null;
+ }
+ }
+
+ [Obsolete("Use 'OriginatorPublicKey' property")]
+ public OriginatorPublicKey OriginatorKey
+ {
+ get { return OriginatorPublicKey; }
+ }
+
+ public OriginatorPublicKey OriginatorPublicKey
+ {
+ get
+ {
+ if (id is Asn1TaggedObject && ((Asn1TaggedObject)id).TagNo == 1)
+ {
+ return OriginatorPublicKey.GetInstance((Asn1TaggedObject)id, false);
+ }
+
+ return null;
+ }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * OriginatorIdentifierOrKey ::= CHOICE {
+ * issuerAndSerialNumber IssuerAndSerialNumber,
+ * subjectKeyIdentifier [0] SubjectKeyIdentifier,
+ * originatorKey [1] OriginatorPublicKey
+ * }
+ *
+ * SubjectKeyIdentifier ::= OCTET STRING
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return id.ToAsn1Object();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/OriginatorInfo.cs b/bc-sharp-crypto/src/asn1/cms/OriginatorInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..33b049efad97eed83a7fc206677a379a522ab2c3
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/OriginatorInfo.cs
@@ -0,0 +1,121 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class OriginatorInfo
+ : Asn1Encodable
+ {
+ private Asn1Set certs;
+ private Asn1Set crls;
+
+ public OriginatorInfo(
+ Asn1Set certs,
+ Asn1Set crls)
+ {
+ this.certs = certs;
+ this.crls = crls;
+ }
+
+ public OriginatorInfo(
+ Asn1Sequence seq)
+ {
+ switch (seq.Count)
+ {
+ case 0: // empty
+ break;
+ case 1:
+ Asn1TaggedObject o = (Asn1TaggedObject) seq[0];
+ switch (o.TagNo)
+ {
+ case 0 :
+ certs = Asn1Set.GetInstance(o, false);
+ break;
+ case 1 :
+ crls = Asn1Set.GetInstance(o, false);
+ break;
+ default:
+ throw new ArgumentException("Bad tag in OriginatorInfo: " + o.TagNo);
+ }
+ break;
+ case 2:
+ certs = Asn1Set.GetInstance((Asn1TaggedObject) seq[0], false);
+ crls = Asn1Set.GetInstance((Asn1TaggedObject) seq[1], false);
+ break;
+ default:
+ throw new ArgumentException("OriginatorInfo too big");
+ }
+ }
+
+ /**
+ * return an OriginatorInfo object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static OriginatorInfo GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ /**
+ * return an OriginatorInfo object from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static OriginatorInfo GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is OriginatorInfo)
+ return (OriginatorInfo)obj;
+
+ if (obj is Asn1Sequence)
+ return new OriginatorInfo((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid OriginatorInfo: " + Platform.GetTypeName(obj));
+ }
+
+ public Asn1Set Certificates
+ {
+ get { return certs; }
+ }
+
+ public Asn1Set Crls
+ {
+ get { return crls; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * OriginatorInfo ::= Sequence {
+ * certs [0] IMPLICIT CertificateSet OPTIONAL,
+ * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (certs != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, certs));
+ }
+
+ if (crls != null)
+ {
+ v.Add(new DerTaggedObject(false, 1, crls));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/OriginatorPublicKey.cs b/bc-sharp-crypto/src/asn1/cms/OriginatorPublicKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9f29c624227aafd3fa33a8154c8d003fcba25ed3
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/OriginatorPublicKey.cs
@@ -0,0 +1,88 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class OriginatorPublicKey
+ : Asn1Encodable
+ {
+ private readonly AlgorithmIdentifier mAlgorithm;
+ private readonly DerBitString mPublicKey;
+
+ public OriginatorPublicKey(
+ AlgorithmIdentifier algorithm,
+ byte[] publicKey)
+ {
+ this.mAlgorithm = algorithm;
+ this.mPublicKey = new DerBitString(publicKey);
+ }
+
+ [Obsolete("Use 'GetInstance' instead")]
+ public OriginatorPublicKey(
+ Asn1Sequence seq)
+ {
+ this.mAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]);
+ this.mPublicKey = DerBitString.GetInstance(seq[1]);
+ }
+
+ /**
+ * return an OriginatorPublicKey object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static OriginatorPublicKey GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ /**
+ * return an OriginatorPublicKey object from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static OriginatorPublicKey GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is OriginatorPublicKey)
+ return (OriginatorPublicKey)obj;
+
+ if (obj is Asn1Sequence)
+ return new OriginatorPublicKey(Asn1Sequence.GetInstance(obj));
+
+ throw new ArgumentException("Invalid OriginatorPublicKey: " + Platform.GetTypeName(obj));
+ }
+
+ public AlgorithmIdentifier Algorithm
+ {
+ get { return mAlgorithm; }
+ }
+
+ public DerBitString PublicKey
+ {
+ get { return mPublicKey; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * OriginatorPublicKey ::= Sequence {
+ * algorithm AlgorithmIdentifier,
+ * publicKey BIT STRING
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(mAlgorithm, mPublicKey);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/OtherKeyAttribute.cs b/bc-sharp-crypto/src/asn1/cms/OtherKeyAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..285c8815466caafe33f4f49427ec0af9d67fa14f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/OtherKeyAttribute.cs
@@ -0,0 +1,70 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class OtherKeyAttribute
+ : Asn1Encodable
+ {
+ private DerObjectIdentifier keyAttrId;
+ private Asn1Encodable keyAttr;
+
+ /**
+ * return an OtherKeyAttribute object from the given object.
+ *
+ * @param o the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static OtherKeyAttribute GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is OtherKeyAttribute)
+ return (OtherKeyAttribute) obj;
+
+ if (obj is Asn1Sequence)
+ return new OtherKeyAttribute((Asn1Sequence) obj);
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public OtherKeyAttribute(
+ Asn1Sequence seq)
+ {
+ keyAttrId = (DerObjectIdentifier) seq[0];
+ keyAttr = seq[1];
+ }
+
+ public OtherKeyAttribute(
+ DerObjectIdentifier keyAttrId,
+ Asn1Encodable keyAttr)
+ {
+ this.keyAttrId = keyAttrId;
+ this.keyAttr = keyAttr;
+ }
+
+ public DerObjectIdentifier KeyAttrId
+ {
+ get { return keyAttrId; }
+ }
+
+ public Asn1Encodable KeyAttr
+ {
+ get { return keyAttr; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * OtherKeyAttribute ::= Sequence {
+ * keyAttrId OBJECT IDENTIFIER,
+ * keyAttr ANY DEFINED BY keyAttrId OPTIONAL
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(keyAttrId, keyAttr);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/OtherRecipientInfo.cs b/bc-sharp-crypto/src/asn1/cms/OtherRecipientInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..80dd68e7ccec54957ac57a140b063b35bdcba94f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/OtherRecipientInfo.cs
@@ -0,0 +1,83 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class OtherRecipientInfo
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier oriType;
+ private readonly Asn1Encodable oriValue;
+
+ public OtherRecipientInfo(
+ DerObjectIdentifier oriType,
+ Asn1Encodable oriValue)
+ {
+ this.oriType = oriType;
+ this.oriValue = oriValue;
+ }
+
+ [Obsolete("Use GetInstance() instead")]
+ public OtherRecipientInfo(
+ Asn1Sequence seq)
+ {
+ oriType = DerObjectIdentifier.GetInstance(seq[0]);
+ oriValue = seq[1];
+ }
+
+ /**
+ * return a OtherRecipientInfo object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static OtherRecipientInfo GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ /**
+ * return a OtherRecipientInfo object from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static OtherRecipientInfo GetInstance(
+ object obj)
+ {
+ if (obj == null)
+ return null;
+ OtherRecipientInfo existing = obj as OtherRecipientInfo;
+ if (existing != null)
+ return existing;
+ return new OtherRecipientInfo(Asn1Sequence.GetInstance(obj));
+ }
+
+ public virtual DerObjectIdentifier OriType
+ {
+ get { return oriType; }
+ }
+
+ public virtual Asn1Encodable OriValue
+ {
+ get { return oriValue; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * OtherRecipientInfo ::= Sequence {
+ * oriType OBJECT IDENTIFIER,
+ * oriValue ANY DEFINED BY oriType }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(oriType, oriValue);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/OtherRevocationInfoFormat.cs b/bc-sharp-crypto/src/asn1/cms/OtherRevocationInfoFormat.cs
new file mode 100644
index 0000000000000000000000000000000000000000..78354896f8fc345ba0172c8c30d83a8ff9fbd7b3
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/OtherRevocationInfoFormat.cs
@@ -0,0 +1,77 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class OtherRevocationInfoFormat
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier otherRevInfoFormat;
+ private readonly Asn1Encodable otherRevInfo;
+
+ public OtherRevocationInfoFormat(
+ DerObjectIdentifier otherRevInfoFormat,
+ Asn1Encodable otherRevInfo)
+ {
+ this.otherRevInfoFormat = otherRevInfoFormat;
+ this.otherRevInfo = otherRevInfo;
+ }
+
+ private OtherRevocationInfoFormat(Asn1Sequence seq)
+ {
+ otherRevInfoFormat = DerObjectIdentifier.GetInstance(seq[0]);
+ otherRevInfo = seq[1];
+ }
+
+ /**
+ * return a OtherRevocationInfoFormat object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception IllegalArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static OtherRevocationInfoFormat GetInstance(Asn1TaggedObject obj, bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ /**
+ * return a OtherRevocationInfoFormat object from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static OtherRevocationInfoFormat GetInstance(object obj)
+ {
+ if (obj is OtherRevocationInfoFormat)
+ return (OtherRevocationInfoFormat)obj;
+ if (obj != null)
+ return new OtherRevocationInfoFormat(Asn1Sequence.GetInstance(obj));
+ return null;
+ }
+
+ public virtual DerObjectIdentifier InfoFormat
+ {
+ get { return otherRevInfoFormat; }
+ }
+
+ public virtual Asn1Encodable Info
+ {
+ get { return otherRevInfo; }
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ *
+ * OtherRevocationInfoFormat ::= SEQUENCE {
+ * otherRevInfoFormat OBJECT IDENTIFIER,
+ * otherRevInfo ANY DEFINED BY otherRevInfoFormat }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(otherRevInfoFormat, otherRevInfo);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/PasswordRecipientInfo.cs b/bc-sharp-crypto/src/asn1/cms/PasswordRecipientInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7f275fde7c8c0c412293a82ebe28130aa30622a3
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/PasswordRecipientInfo.cs
@@ -0,0 +1,133 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class PasswordRecipientInfo
+ : Asn1Encodable
+ {
+ private readonly DerInteger version;
+ private readonly AlgorithmIdentifier keyDerivationAlgorithm;
+ private readonly AlgorithmIdentifier keyEncryptionAlgorithm;
+ private readonly Asn1OctetString encryptedKey;
+
+ public PasswordRecipientInfo(
+ AlgorithmIdentifier keyEncryptionAlgorithm,
+ Asn1OctetString encryptedKey)
+ {
+ this.version = new DerInteger(0);
+ this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+ this.encryptedKey = encryptedKey;
+ }
+
+ public PasswordRecipientInfo(
+ AlgorithmIdentifier keyDerivationAlgorithm,
+ AlgorithmIdentifier keyEncryptionAlgorithm,
+ Asn1OctetString encryptedKey)
+ {
+ this.version = new DerInteger(0);
+ this.keyDerivationAlgorithm = keyDerivationAlgorithm;
+ this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+ this.encryptedKey = encryptedKey;
+ }
+
+ public PasswordRecipientInfo(
+ Asn1Sequence seq)
+ {
+ version = (DerInteger) seq[0];
+
+ if (seq[1] is Asn1TaggedObject)
+ {
+ keyDerivationAlgorithm = AlgorithmIdentifier.GetInstance((Asn1TaggedObject) seq[1], false);
+ keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[2]);
+ encryptedKey = (Asn1OctetString) seq[3];
+ }
+ else
+ {
+ keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+ encryptedKey = (Asn1OctetString) seq[2];
+ }
+ }
+
+ /**
+ * return a PasswordRecipientInfo object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicitly true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static PasswordRecipientInfo GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ /**
+ * return a PasswordRecipientInfo object from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static PasswordRecipientInfo GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is PasswordRecipientInfo)
+ return (PasswordRecipientInfo) obj;
+
+ if (obj is Asn1Sequence)
+ return new PasswordRecipientInfo((Asn1Sequence) obj);
+
+ throw new ArgumentException("Invalid PasswordRecipientInfo: " + Platform.GetTypeName(obj));
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public AlgorithmIdentifier KeyDerivationAlgorithm
+ {
+ get { return keyDerivationAlgorithm; }
+ }
+
+ public AlgorithmIdentifier KeyEncryptionAlgorithm
+ {
+ get { return keyEncryptionAlgorithm; }
+ }
+
+ public Asn1OctetString EncryptedKey
+ {
+ get { return encryptedKey; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * PasswordRecipientInfo ::= Sequence {
+ * version CMSVersion, -- Always set to 0
+ * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier
+ * OPTIONAL,
+ * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+ * encryptedKey EncryptedKey }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(version);
+
+ if (keyDerivationAlgorithm != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, keyDerivationAlgorithm));
+ }
+
+ v.Add(keyEncryptionAlgorithm, encryptedKey);
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/RecipientEncryptedKey.cs b/bc-sharp-crypto/src/asn1/cms/RecipientEncryptedKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1afba4ab1e866f4a1cff414f18a1348e4b18aaa0
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/RecipientEncryptedKey.cs
@@ -0,0 +1,90 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class RecipientEncryptedKey
+ : Asn1Encodable
+ {
+ private readonly KeyAgreeRecipientIdentifier identifier;
+ private readonly Asn1OctetString encryptedKey;
+
+ private RecipientEncryptedKey(
+ Asn1Sequence seq)
+ {
+ identifier = KeyAgreeRecipientIdentifier.GetInstance(seq[0]);
+ encryptedKey = (Asn1OctetString) seq[1];
+ }
+
+ /**
+ * return an RecipientEncryptedKey object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param isExplicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static RecipientEncryptedKey GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ /**
+ * return a RecipientEncryptedKey object from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static RecipientEncryptedKey GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is RecipientEncryptedKey)
+ {
+ return (RecipientEncryptedKey) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new RecipientEncryptedKey((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("Invalid RecipientEncryptedKey: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public RecipientEncryptedKey(
+ KeyAgreeRecipientIdentifier id,
+ Asn1OctetString encryptedKey)
+ {
+ this.identifier = id;
+ this.encryptedKey = encryptedKey;
+ }
+
+ public KeyAgreeRecipientIdentifier Identifier
+ {
+ get { return identifier; }
+ }
+
+ public Asn1OctetString EncryptedKey
+ {
+ get { return encryptedKey; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * RecipientEncryptedKey ::= SEQUENCE {
+ * rid KeyAgreeRecipientIdentifier,
+ * encryptedKey EncryptedKey
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(identifier, encryptedKey);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/RecipientIdentifier.cs b/bc-sharp-crypto/src/asn1/cms/RecipientIdentifier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f29fa8d7c7d765c31ba08db914eac1c8cad4a6b9
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/RecipientIdentifier.cs
@@ -0,0 +1,89 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class RecipientIdentifier
+ : Asn1Encodable, IAsn1Choice
+ {
+ private Asn1Encodable id;
+
+ public RecipientIdentifier(
+ IssuerAndSerialNumber id)
+ {
+ this.id = id;
+ }
+
+ public RecipientIdentifier(
+ Asn1OctetString id)
+ {
+ this.id = new DerTaggedObject(false, 0, id);
+ }
+
+ public RecipientIdentifier(
+ Asn1Object id)
+ {
+ this.id = id;
+ }
+
+ /**
+ * return a RecipientIdentifier object from the given object.
+ *
+ * @param o the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static RecipientIdentifier GetInstance(
+ object o)
+ {
+ if (o == null || o is RecipientIdentifier)
+ return (RecipientIdentifier)o;
+
+ if (o is IssuerAndSerialNumber)
+ return new RecipientIdentifier((IssuerAndSerialNumber) o);
+
+ if (o is Asn1OctetString)
+ return new RecipientIdentifier((Asn1OctetString) o);
+
+ if (o is Asn1Object)
+ return new RecipientIdentifier((Asn1Object) o);
+
+ throw new ArgumentException(
+ "Illegal object in RecipientIdentifier: " + Platform.GetTypeName(o));
+ }
+
+ public bool IsTagged
+ {
+ get { return (id is Asn1TaggedObject); }
+ }
+
+ public Asn1Encodable ID
+ {
+ get
+ {
+ if (id is Asn1TaggedObject)
+ {
+ return Asn1OctetString.GetInstance((Asn1TaggedObject) id, false);
+ }
+
+ return IssuerAndSerialNumber.GetInstance(id);
+ }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * RecipientIdentifier ::= CHOICE {
+ * issuerAndSerialNumber IssuerAndSerialNumber,
+ * subjectKeyIdentifier [0] SubjectKeyIdentifier
+ * }
+ *
+ * SubjectKeyIdentifier ::= OCTET STRING
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return id.ToAsn1Object();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/RecipientInfo.cs b/bc-sharp-crypto/src/asn1/cms/RecipientInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c03ad907fd03f86caf360349aa00eec9ffb1f9d9
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/RecipientInfo.cs
@@ -0,0 +1,145 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class RecipientInfo
+ : Asn1Encodable, IAsn1Choice
+ {
+ internal Asn1Encodable info;
+
+ public RecipientInfo(
+ KeyTransRecipientInfo info)
+ {
+ this.info = info;
+ }
+
+ public RecipientInfo(
+ KeyAgreeRecipientInfo info)
+ {
+ this.info = new DerTaggedObject(false, 1, info);
+ }
+
+ public RecipientInfo(
+ KekRecipientInfo info)
+ {
+ this.info = new DerTaggedObject(false, 2, info);
+ }
+
+ public RecipientInfo(
+ PasswordRecipientInfo info)
+ {
+ this.info = new DerTaggedObject(false, 3, info);
+ }
+
+ public RecipientInfo(
+ OtherRecipientInfo info)
+ {
+ this.info = new DerTaggedObject(false, 4, info);
+ }
+
+ public RecipientInfo(
+ Asn1Object info)
+ {
+ this.info = info;
+ }
+
+ public static RecipientInfo GetInstance(
+ object o)
+ {
+ if (o == null || o is RecipientInfo)
+ return (RecipientInfo) o;
+
+ if (o is Asn1Sequence)
+ return new RecipientInfo((Asn1Sequence) o);
+
+ if (o is Asn1TaggedObject)
+ return new RecipientInfo((Asn1TaggedObject) o);
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(o));
+ }
+
+ public DerInteger Version
+ {
+ get
+ {
+ if (info is Asn1TaggedObject)
+ {
+ Asn1TaggedObject o = (Asn1TaggedObject) info;
+
+ switch (o.TagNo)
+ {
+ case 1:
+ return KeyAgreeRecipientInfo.GetInstance(o, false).Version;
+ case 2:
+ return GetKekInfo(o).Version;
+ case 3:
+ return PasswordRecipientInfo.GetInstance(o, false).Version;
+ case 4:
+ return new DerInteger(0); // no syntax version for OtherRecipientInfo
+ default:
+ throw new InvalidOperationException("unknown tag");
+ }
+ }
+
+ return KeyTransRecipientInfo.GetInstance(info).Version;
+ }
+ }
+
+ public bool IsTagged
+ {
+ get { return info is Asn1TaggedObject; }
+ }
+
+ public Asn1Encodable Info
+ {
+ get
+ {
+ if (info is Asn1TaggedObject)
+ {
+ Asn1TaggedObject o = (Asn1TaggedObject) info;
+
+ switch (o.TagNo)
+ {
+ case 1:
+ return KeyAgreeRecipientInfo.GetInstance(o, false);
+ case 2:
+ return GetKekInfo(o);
+ case 3:
+ return PasswordRecipientInfo.GetInstance(o, false);
+ case 4:
+ return OtherRecipientInfo.GetInstance(o, false);
+ default:
+ throw new InvalidOperationException("unknown tag");
+ }
+ }
+
+ return KeyTransRecipientInfo.GetInstance(info);
+ }
+ }
+
+ private KekRecipientInfo GetKekInfo(
+ Asn1TaggedObject o)
+ {
+ // For compatibility with erroneous version, we don't always pass 'false' here
+ return KekRecipientInfo.GetInstance(o, o.IsExplicit());
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * RecipientInfo ::= CHOICE {
+ * ktri KeyTransRecipientInfo,
+ * kari [1] KeyAgreeRecipientInfo,
+ * kekri [2] KekRecipientInfo,
+ * pwri [3] PasswordRecipientInfo,
+ * ori [4] OtherRecipientInfo }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return info.ToAsn1Object();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/RecipientKeyIdentifier.cs b/bc-sharp-crypto/src/asn1/cms/RecipientKeyIdentifier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..995ddab51324b0ce7c51a5bd40f260ec58bfc52b
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/RecipientKeyIdentifier.cs
@@ -0,0 +1,137 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class RecipientKeyIdentifier
+ : Asn1Encodable
+ {
+ private Asn1OctetString subjectKeyIdentifier;
+ private DerGeneralizedTime date;
+ private OtherKeyAttribute other;
+
+ public RecipientKeyIdentifier(
+ Asn1OctetString subjectKeyIdentifier,
+ DerGeneralizedTime date,
+ OtherKeyAttribute other)
+ {
+ this.subjectKeyIdentifier = subjectKeyIdentifier;
+ this.date = date;
+ this.other = other;
+ }
+
+ public RecipientKeyIdentifier(
+ byte[] subjectKeyIdentifier)
+ : this(subjectKeyIdentifier, null, null)
+ {
+ }
+
+ public RecipientKeyIdentifier(
+ byte[] subjectKeyIdentifier,
+ DerGeneralizedTime date,
+ OtherKeyAttribute other)
+ {
+ this.subjectKeyIdentifier = new DerOctetString(subjectKeyIdentifier);
+ this.date = date;
+ this.other = other;
+ }
+
+ public RecipientKeyIdentifier(
+ Asn1Sequence seq)
+ {
+ subjectKeyIdentifier = Asn1OctetString.GetInstance(
+ seq[0]);
+
+ switch(seq.Count)
+ {
+ case 1:
+ break;
+ case 2:
+ if (seq[1] is DerGeneralizedTime)
+ {
+ date = (DerGeneralizedTime) seq[1];
+ }
+ else
+ {
+ other = OtherKeyAttribute.GetInstance(seq[2]);
+ }
+ break;
+ case 3:
+ date = (DerGeneralizedTime) seq[1];
+ other = OtherKeyAttribute.GetInstance(seq[2]);
+ break;
+ default:
+ throw new ArgumentException("Invalid RecipientKeyIdentifier");
+ }
+ }
+
+ /**
+ * return a RecipientKeyIdentifier object from a tagged object.
+ *
+ * @param _ato the tagged object holding the object we want.
+ * @param _explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @exception ArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static RecipientKeyIdentifier GetInstance(
+ Asn1TaggedObject ato,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(ato, explicitly));
+ }
+
+ /**
+ * return a RecipientKeyIdentifier object from the given object.
+ *
+ * @param _obj the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static RecipientKeyIdentifier GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is RecipientKeyIdentifier)
+ return (RecipientKeyIdentifier) obj;
+
+ if (obj is Asn1Sequence)
+ return new RecipientKeyIdentifier((Asn1Sequence) obj);
+
+ throw new ArgumentException("Invalid RecipientKeyIdentifier: " + Platform.GetTypeName(obj));
+ }
+
+ public Asn1OctetString SubjectKeyIdentifier
+ {
+ get { return subjectKeyIdentifier; }
+ }
+
+ public DerGeneralizedTime Date
+ {
+ get { return date; }
+ }
+
+ public OtherKeyAttribute OtherKeyAttribute
+ {
+ get { return other; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * RecipientKeyIdentifier ::= Sequence {
+ * subjectKeyIdentifier SubjectKeyIdentifier,
+ * date GeneralizedTime OPTIONAL,
+ * other OtherKeyAttribute OPTIONAL
+ * }
+ *
+ * SubjectKeyIdentifier ::= OCTET STRING
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(subjectKeyIdentifier);
+ v.AddOptional(date, other);
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/SCVPReqRes.cs b/bc-sharp-crypto/src/asn1/cms/SCVPReqRes.cs
new file mode 100644
index 0000000000000000000000000000000000000000..486979a291dd20ec1d433091b5b5c74c7df471db
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/SCVPReqRes.cs
@@ -0,0 +1,77 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class ScvpReqRes
+ : Asn1Encodable
+ {
+ private readonly ContentInfo request;
+ private readonly ContentInfo response;
+
+ public static ScvpReqRes GetInstance(object obj)
+ {
+ if (obj is ScvpReqRes)
+ return (ScvpReqRes)obj;
+ if (obj != null)
+ return new ScvpReqRes(Asn1Sequence.GetInstance(obj));
+ return null;
+ }
+
+ private ScvpReqRes(Asn1Sequence seq)
+ {
+ if (seq[0] is Asn1TaggedObject)
+ {
+ this.request = ContentInfo.GetInstance(Asn1TaggedObject.GetInstance(seq[0]), true);
+ this.response = ContentInfo.GetInstance(seq[1]);
+ }
+ else
+ {
+ this.request = null;
+ this.response = ContentInfo.GetInstance(seq[0]);
+ }
+ }
+
+ public ScvpReqRes(ContentInfo response)
+ : this(null, response)
+ {
+ }
+
+ public ScvpReqRes(ContentInfo request, ContentInfo response)
+ {
+ this.request = request;
+ this.response = response;
+ }
+
+ public virtual ContentInfo Request
+ {
+ get { return request; }
+ }
+
+ public virtual ContentInfo Response
+ {
+ get { return response; }
+ }
+
+ /**
+ *
+ * ScvpReqRes ::= SEQUENCE {
+ * request [0] EXPLICIT ContentInfo OPTIONAL,
+ * response ContentInfo }
+ *
+ * @return the ASN.1 primitive representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (request != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, request));
+ }
+
+ v.Add(response);
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/SignedData.cs b/bc-sharp-crypto/src/asn1/cms/SignedData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..957b81cd8d1ae3cb9d95943facbbe6063eccd4fe
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/SignedData.cs
@@ -0,0 +1,287 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ /**
+ * a signed data object.
+ */
+ public class SignedData
+ : Asn1Encodable
+ {
+ private static readonly DerInteger Version1 = new DerInteger(1);
+ private static readonly DerInteger Version3 = new DerInteger(3);
+ private static readonly DerInteger Version4 = new DerInteger(4);
+ private static readonly DerInteger Version5 = new DerInteger(5);
+
+ private readonly DerInteger version;
+ private readonly Asn1Set digestAlgorithms;
+ private readonly ContentInfo contentInfo;
+ private readonly Asn1Set certificates;
+ private readonly Asn1Set crls;
+ private readonly Asn1Set signerInfos;
+ private readonly bool certsBer;
+ private readonly bool crlsBer;
+
+ public static SignedData GetInstance(
+ object obj)
+ {
+ if (obj is SignedData)
+ return (SignedData) obj;
+
+ if (obj is Asn1Sequence)
+ return new SignedData((Asn1Sequence) obj);
+
+ throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public SignedData(
+ Asn1Set digestAlgorithms,
+ ContentInfo contentInfo,
+ Asn1Set certificates,
+ Asn1Set crls,
+ Asn1Set signerInfos)
+ {
+ this.version = CalculateVersion(contentInfo.ContentType, certificates, crls, signerInfos);
+ this.digestAlgorithms = digestAlgorithms;
+ this.contentInfo = contentInfo;
+ this.certificates = certificates;
+ this.crls = crls;
+ this.signerInfos = signerInfos;
+ this.crlsBer = crls is BerSet;
+ this.certsBer = certificates is BerSet;
+ }
+
+ // RFC3852, section 5.1:
+ // IF ((certificates is present) AND
+ // (any certificates with a type of other are present)) OR
+ // ((crls is present) AND
+ // (any crls with a type of other are present))
+ // THEN version MUST be 5
+ // ELSE
+ // IF (certificates is present) AND
+ // (any version 2 attribute certificates are present)
+ // THEN version MUST be 4
+ // ELSE
+ // IF ((certificates is present) AND
+ // (any version 1 attribute certificates are present)) OR
+ // (any SignerInfo structures are version 3) OR
+ // (encapContentInfo eContentType is other than id-data)
+ // THEN version MUST be 3
+ // ELSE version MUST be 1
+ //
+ private DerInteger CalculateVersion(
+ DerObjectIdentifier contentOid,
+ Asn1Set certs,
+ Asn1Set crls,
+ Asn1Set signerInfs)
+ {
+ bool otherCert = false;
+ bool otherCrl = false;
+ bool attrCertV1Found = false;
+ bool attrCertV2Found = false;
+
+ if (certs != null)
+ {
+ foreach (object obj in certs)
+ {
+ if (obj is Asn1TaggedObject)
+ {
+ Asn1TaggedObject tagged = (Asn1TaggedObject)obj;
+
+ if (tagged.TagNo == 1)
+ {
+ attrCertV1Found = true;
+ }
+ else if (tagged.TagNo == 2)
+ {
+ attrCertV2Found = true;
+ }
+ else if (tagged.TagNo == 3)
+ {
+ otherCert = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (otherCert)
+ {
+ return Version5;
+ }
+
+ if (crls != null)
+ {
+ foreach (object obj in crls)
+ {
+ if (obj is Asn1TaggedObject)
+ {
+ otherCrl = true;
+ break;
+ }
+ }
+ }
+
+ if (otherCrl)
+ {
+ return Version5;
+ }
+
+ if (attrCertV2Found)
+ {
+ return Version4;
+ }
+
+ if (attrCertV1Found || !CmsObjectIdentifiers.Data.Equals(contentOid) || CheckForVersion3(signerInfs))
+ {
+ return Version3;
+ }
+
+ return Version1;
+ }
+
+ private bool CheckForVersion3(
+ Asn1Set signerInfs)
+ {
+ foreach (object obj in signerInfs)
+ {
+ SignerInfo s = SignerInfo.GetInstance(obj);
+
+ if (s.Version.Value.IntValue == 3)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private SignedData(
+ Asn1Sequence seq)
+ {
+ IEnumerator e = seq.GetEnumerator();
+
+ e.MoveNext();
+ version = (DerInteger)e.Current;
+
+ e.MoveNext();
+ digestAlgorithms = ((Asn1Set)e.Current);
+
+ e.MoveNext();
+ contentInfo = ContentInfo.GetInstance(e.Current);
+
+ while (e.MoveNext())
+ {
+ Asn1Object o = (Asn1Object)e.Current;
+
+ //
+ // an interesting feature of SignedData is that there appear
+ // to be varying implementations...
+ // for the moment we ignore anything which doesn't fit.
+ //
+ if (o is Asn1TaggedObject)
+ {
+ Asn1TaggedObject tagged = (Asn1TaggedObject)o;
+
+ switch (tagged.TagNo)
+ {
+ case 0:
+ certsBer = tagged is BerTaggedObject;
+ certificates = Asn1Set.GetInstance(tagged, false);
+ break;
+ case 1:
+ crlsBer = tagged is BerTaggedObject;
+ crls = Asn1Set.GetInstance(tagged, false);
+ break;
+ default:
+ throw new ArgumentException("unknown tag value " + tagged.TagNo);
+ }
+ }
+ else
+ {
+ signerInfos = (Asn1Set) o;
+ }
+ }
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public Asn1Set DigestAlgorithms
+ {
+ get { return digestAlgorithms; }
+ }
+
+ public ContentInfo EncapContentInfo
+ {
+ get { return contentInfo; }
+ }
+
+ public Asn1Set Certificates
+ {
+ get { return certificates; }
+ }
+
+ public Asn1Set CRLs
+ {
+ get { return crls; }
+ }
+
+ public Asn1Set SignerInfos
+ {
+ get { return signerInfos; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * SignedData ::= Sequence {
+ * version CMSVersion,
+ * digestAlgorithms DigestAlgorithmIdentifiers,
+ * encapContentInfo EncapsulatedContentInfo,
+ * certificates [0] IMPLICIT CertificateSet OPTIONAL,
+ * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+ * signerInfos SignerInfos
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ version, digestAlgorithms, contentInfo);
+
+ if (certificates != null)
+ {
+ if (certsBer)
+ {
+ v.Add(new BerTaggedObject(false, 0, certificates));
+ }
+ else
+ {
+ v.Add(new DerTaggedObject(false, 0, certificates));
+ }
+ }
+
+ if (crls != null)
+ {
+ if (crlsBer)
+ {
+ v.Add(new BerTaggedObject(false, 1, crls));
+ }
+ else
+ {
+ v.Add(new DerTaggedObject(false, 1, crls));
+ }
+ }
+
+ v.Add(signerInfos);
+
+ return new BerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/SignedDataParser.cs b/bc-sharp-crypto/src/asn1/cms/SignedDataParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cd07f4057f26c1af05547c40bdacb2adb078e9cc
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/SignedDataParser.cs
@@ -0,0 +1,114 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ /**
+ *
+ * SignedData ::= SEQUENCE {
+ * version CMSVersion,
+ * digestAlgorithms DigestAlgorithmIdentifiers,
+ * encapContentInfo EncapsulatedContentInfo,
+ * certificates [0] IMPLICIT CertificateSet OPTIONAL,
+ * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+ * signerInfos SignerInfos
+ * }
+ *
+ */
+ public class SignedDataParser
+ {
+ private Asn1SequenceParser _seq;
+ private DerInteger _version;
+ private object _nextObject;
+ private bool _certsCalled;
+ private bool _crlsCalled;
+
+ public static SignedDataParser GetInstance(
+ object o)
+ {
+ if (o is Asn1Sequence)
+ return new SignedDataParser(((Asn1Sequence)o).Parser);
+
+ if (o is Asn1SequenceParser)
+ return new SignedDataParser((Asn1SequenceParser)o);
+
+ throw new IOException("unknown object encountered: " + Platform.GetTypeName(o));
+ }
+
+ public SignedDataParser(
+ Asn1SequenceParser seq)
+ {
+ this._seq = seq;
+ this._version = (DerInteger)seq.ReadObject();
+ }
+
+ public DerInteger Version
+ {
+ get { return _version; }
+ }
+
+ public Asn1SetParser GetDigestAlgorithms()
+ {
+ return (Asn1SetParser)_seq.ReadObject();
+ }
+
+ public ContentInfoParser GetEncapContentInfo()
+ {
+ return new ContentInfoParser((Asn1SequenceParser)_seq.ReadObject());
+ }
+
+ public Asn1SetParser GetCertificates()
+ {
+ _certsCalled = true;
+ _nextObject = _seq.ReadObject();
+
+ if (_nextObject is Asn1TaggedObjectParser && ((Asn1TaggedObjectParser)_nextObject).TagNo == 0)
+ {
+ Asn1SetParser certs = (Asn1SetParser)((Asn1TaggedObjectParser)_nextObject).GetObjectParser(Asn1Tags.Set, false);
+ _nextObject = null;
+
+ return certs;
+ }
+
+ return null;
+ }
+
+ public Asn1SetParser GetCrls()
+ {
+ if (!_certsCalled)
+ throw new IOException("GetCerts() has not been called.");
+
+ _crlsCalled = true;
+
+ if (_nextObject == null)
+ {
+ _nextObject = _seq.ReadObject();
+ }
+
+ if (_nextObject is Asn1TaggedObjectParser && ((Asn1TaggedObjectParser)_nextObject).TagNo == 1)
+ {
+ Asn1SetParser crls = (Asn1SetParser)((Asn1TaggedObjectParser)_nextObject).GetObjectParser(Asn1Tags.Set, false);
+ _nextObject = null;
+
+ return crls;
+ }
+
+ return null;
+ }
+
+ public Asn1SetParser GetSignerInfos()
+ {
+ if (!_certsCalled || !_crlsCalled)
+ throw new IOException("GetCerts() and/or GetCrls() has not been called.");
+
+ if (_nextObject == null)
+ {
+ _nextObject = _seq.ReadObject();
+ }
+
+ return (Asn1SetParser)_nextObject;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/SignerIdentifier.cs b/bc-sharp-crypto/src/asn1/cms/SignerIdentifier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..195ab741f82532513b9090e622e0cab7033fc4a1
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/SignerIdentifier.cs
@@ -0,0 +1,89 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class SignerIdentifier
+ : Asn1Encodable, IAsn1Choice
+ {
+ private Asn1Encodable id;
+
+ public SignerIdentifier(
+ IssuerAndSerialNumber id)
+ {
+ this.id = id;
+ }
+
+ public SignerIdentifier(
+ Asn1OctetString id)
+ {
+ this.id = new DerTaggedObject(false, 0, id);
+ }
+
+ public SignerIdentifier(
+ Asn1Object id)
+ {
+ this.id = id;
+ }
+
+ /**
+ * return a SignerIdentifier object from the given object.
+ *
+ * @param o the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static SignerIdentifier GetInstance(
+ object o)
+ {
+ if (o == null || o is SignerIdentifier)
+ return (SignerIdentifier) o;
+
+ if (o is IssuerAndSerialNumber)
+ return new SignerIdentifier((IssuerAndSerialNumber) o);
+
+ if (o is Asn1OctetString)
+ return new SignerIdentifier((Asn1OctetString) o);
+
+ if (o is Asn1Object)
+ return new SignerIdentifier((Asn1Object) o);
+
+ throw new ArgumentException(
+ "Illegal object in SignerIdentifier: " + Platform.GetTypeName(o));
+ }
+
+ public bool IsTagged
+ {
+ get { return (id is Asn1TaggedObject); }
+ }
+
+ public Asn1Encodable ID
+ {
+ get
+ {
+ if (id is Asn1TaggedObject)
+ {
+ return Asn1OctetString.GetInstance((Asn1TaggedObject)id, false);
+ }
+
+ return id;
+ }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * SignerIdentifier ::= CHOICE {
+ * issuerAndSerialNumber IssuerAndSerialNumber,
+ * subjectKeyIdentifier [0] SubjectKeyIdentifier
+ * }
+ *
+ * SubjectKeyIdentifier ::= OCTET STRING
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return id.ToAsn1Object();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/SignerInfo.cs b/bc-sharp-crypto/src/asn1/cms/SignerInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b6bd319b011f9b7cc263b9f570176a2377a60bd2
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/SignerInfo.cs
@@ -0,0 +1,185 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class SignerInfo
+ : Asn1Encodable
+ {
+ private DerInteger version;
+ private SignerIdentifier sid;
+ private AlgorithmIdentifier digAlgorithm;
+ private Asn1Set authenticatedAttributes;
+ private AlgorithmIdentifier digEncryptionAlgorithm;
+ private Asn1OctetString encryptedDigest;
+ private Asn1Set unauthenticatedAttributes;
+
+ public static SignerInfo GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is SignerInfo)
+ return (SignerInfo) obj;
+
+ if (obj is Asn1Sequence)
+ return new SignerInfo((Asn1Sequence) obj);
+
+ throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public SignerInfo(
+ SignerIdentifier sid,
+ AlgorithmIdentifier digAlgorithm,
+ Asn1Set authenticatedAttributes,
+ AlgorithmIdentifier digEncryptionAlgorithm,
+ Asn1OctetString encryptedDigest,
+ Asn1Set unauthenticatedAttributes)
+ {
+ this.version = new DerInteger(sid.IsTagged ? 3 : 1);
+ this.sid = sid;
+ this.digAlgorithm = digAlgorithm;
+ this.authenticatedAttributes = authenticatedAttributes;
+ this.digEncryptionAlgorithm = digEncryptionAlgorithm;
+ this.encryptedDigest = encryptedDigest;
+ this.unauthenticatedAttributes = unauthenticatedAttributes;
+ }
+
+ public SignerInfo(
+ SignerIdentifier sid,
+ AlgorithmIdentifier digAlgorithm,
+ Attributes authenticatedAttributes,
+ AlgorithmIdentifier digEncryptionAlgorithm,
+ Asn1OctetString encryptedDigest,
+ Attributes unauthenticatedAttributes)
+ {
+ this.version = new DerInteger(sid.IsTagged ? 3 : 1);
+ this.sid = sid;
+ this.digAlgorithm = digAlgorithm;
+ this.authenticatedAttributes = Asn1Set.GetInstance(authenticatedAttributes);
+ this.digEncryptionAlgorithm = digEncryptionAlgorithm;
+ this.encryptedDigest = encryptedDigest;
+ this.unauthenticatedAttributes = Asn1Set.GetInstance(unauthenticatedAttributes);
+ }
+
+ [Obsolete("Use 'GetInstance' instead")]
+ public SignerInfo(
+ Asn1Sequence seq)
+ {
+ IEnumerator e = seq.GetEnumerator();
+
+ e.MoveNext();
+ version = (DerInteger) e.Current;
+
+ e.MoveNext();
+ sid = SignerIdentifier.GetInstance(e.Current);
+
+ e.MoveNext();
+ digAlgorithm = AlgorithmIdentifier.GetInstance(e.Current);
+
+ e.MoveNext();
+ object obj = e.Current;
+
+ if (obj is Asn1TaggedObject)
+ {
+ authenticatedAttributes = Asn1Set.GetInstance((Asn1TaggedObject) obj, false);
+
+ e.MoveNext();
+ digEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(e.Current);
+ }
+ else
+ {
+ authenticatedAttributes = null;
+ digEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(obj);
+ }
+
+ e.MoveNext();
+ encryptedDigest = DerOctetString.GetInstance(e.Current);
+
+ if (e.MoveNext())
+ {
+ unauthenticatedAttributes = Asn1Set.GetInstance((Asn1TaggedObject) e.Current, false);
+ }
+ else
+ {
+ unauthenticatedAttributes = null;
+ }
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public SignerIdentifier SignerID
+ {
+ get { return sid; }
+ }
+
+ public Asn1Set AuthenticatedAttributes
+ {
+ get { return authenticatedAttributes; }
+ }
+
+ public AlgorithmIdentifier DigestAlgorithm
+ {
+ get { return digAlgorithm; }
+ }
+
+ public Asn1OctetString EncryptedDigest
+ {
+ get { return encryptedDigest; }
+ }
+
+ public AlgorithmIdentifier DigestEncryptionAlgorithm
+ {
+ get { return digEncryptionAlgorithm; }
+ }
+
+ public Asn1Set UnauthenticatedAttributes
+ {
+ get { return unauthenticatedAttributes; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * SignerInfo ::= Sequence {
+ * version Version,
+ * SignerIdentifier sid,
+ * digestAlgorithm DigestAlgorithmIdentifier,
+ * authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
+ * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
+ * encryptedDigest EncryptedDigest,
+ * unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
+ * }
+ *
+ * EncryptedDigest ::= OCTET STRING
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ version, sid, digAlgorithm);
+
+ if (authenticatedAttributes != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, authenticatedAttributes));
+ }
+
+ v.Add(digEncryptionAlgorithm, encryptedDigest);
+
+ if (unauthenticatedAttributes != null)
+ {
+ v.Add(new DerTaggedObject(false, 1, unauthenticatedAttributes));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/Time.cs b/bc-sharp-crypto/src/asn1/cms/Time.cs
new file mode 100644
index 0000000000000000000000000000000000000000..52fb4f937fdaa7c6799658d707bce6e6db5182e3
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/Time.cs
@@ -0,0 +1,115 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class Time
+ : Asn1Encodable, IAsn1Choice
+ {
+ private readonly Asn1Object time;
+
+ public static Time GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(obj.GetObject());
+ }
+
+ public Time(
+ Asn1Object time)
+ {
+ if (time == null)
+ throw new ArgumentNullException("time");
+ if (!(time is DerUtcTime) && !(time is DerGeneralizedTime))
+ throw new ArgumentException("unknown object passed to Time");
+
+ this.time = time;
+ }
+
+ /**
+ * creates a time object from a given date - if the date is between 1950
+ * and 2049 a UTCTime object is Generated, otherwise a GeneralizedTime
+ * is used.
+ */
+ public Time(
+ DateTime date)
+ {
+ string d = date.ToString("yyyyMMddHHmmss", CultureInfo.InvariantCulture) + "Z";
+
+ int year = int.Parse(d.Substring(0, 4));
+
+ if (year < 1950 || year > 2049)
+ {
+ time = new DerGeneralizedTime(d);
+ }
+ else
+ {
+ time = new DerUtcTime(d.Substring(2));
+ }
+ }
+
+ public static Time GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is Time)
+ return (Time)obj;
+ if (obj is DerUtcTime)
+ return new Time((DerUtcTime)obj);
+ if (obj is DerGeneralizedTime)
+ return new Time((DerGeneralizedTime)obj);
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public string TimeString
+ {
+ get
+ {
+ if (time is DerUtcTime)
+ {
+ return ((DerUtcTime)time).AdjustedTimeString;
+ }
+ else
+ {
+ return ((DerGeneralizedTime)time).GetTime();
+ }
+ }
+ }
+
+ public DateTime Date
+ {
+ get
+ {
+ try
+ {
+ if (time is DerUtcTime)
+ {
+ return ((DerUtcTime)time).ToAdjustedDateTime();
+ }
+
+ return ((DerGeneralizedTime)time).ToDateTime();
+ }
+ catch (FormatException e)
+ {
+ // this should never happen
+ throw new InvalidOperationException("invalid date string: " + e.Message);
+ }
+ }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Time ::= CHOICE {
+ * utcTime UTCTime,
+ * generalTime GeneralizedTime }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return time;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/TimeStampAndCRL.cs b/bc-sharp-crypto/src/asn1/cms/TimeStampAndCRL.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4cb5f2a52469776a5fa1946ff2908c2d0e584323
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/TimeStampAndCRL.cs
@@ -0,0 +1,62 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class TimeStampAndCrl
+ : Asn1Encodable
+ {
+ private ContentInfo timeStamp;
+ private X509.CertificateList crl;
+
+ public TimeStampAndCrl(ContentInfo timeStamp)
+ {
+ this.timeStamp = timeStamp;
+ }
+
+ private TimeStampAndCrl(Asn1Sequence seq)
+ {
+ this.timeStamp = ContentInfo.GetInstance(seq[0]);
+ if (seq.Count == 2)
+ {
+ this.crl = X509.CertificateList.GetInstance(seq[1]);
+ }
+ }
+
+ public static TimeStampAndCrl GetInstance(object obj)
+ {
+ if (obj is TimeStampAndCrl)
+ return (TimeStampAndCrl)obj;
+
+ if (obj != null)
+ return new TimeStampAndCrl(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ public virtual ContentInfo TimeStampToken
+ {
+ get { return this.timeStamp; }
+ }
+
+ public virtual X509.CertificateList Crl
+ {
+ get { return this.crl; }
+ }
+
+ /**
+ *
+ * TimeStampAndCRL ::= SEQUENCE {
+ * timeStamp TimeStampToken, -- according to RFC 3161
+ * crl CertificateList OPTIONAL -- according to RFC 5280
+ * }
+ *
+ * @return
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(timeStamp);
+ v.AddOptional(crl);
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/TimeStampTokenEvidence.cs b/bc-sharp-crypto/src/asn1/cms/TimeStampTokenEvidence.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8625d058e711c8a7f64d8b753046346d3465eaea
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/TimeStampTokenEvidence.cs
@@ -0,0 +1,65 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class TimeStampTokenEvidence
+ : Asn1Encodable
+ {
+ private TimeStampAndCrl[] timeStampAndCrls;
+
+ public TimeStampTokenEvidence(TimeStampAndCrl[] timeStampAndCrls)
+ {
+ this.timeStampAndCrls = timeStampAndCrls;
+ }
+
+ public TimeStampTokenEvidence(TimeStampAndCrl timeStampAndCrl)
+ {
+ this.timeStampAndCrls = new TimeStampAndCrl[]{ timeStampAndCrl };
+ }
+
+ private TimeStampTokenEvidence(Asn1Sequence seq)
+ {
+ this.timeStampAndCrls = new TimeStampAndCrl[seq.Count];
+
+ int count = 0;
+
+ foreach (Asn1Encodable ae in seq)
+ {
+ this.timeStampAndCrls[count++] = TimeStampAndCrl.GetInstance(ae.ToAsn1Object());
+ }
+ }
+
+ public static TimeStampTokenEvidence GetInstance(Asn1TaggedObject tagged, bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(tagged, isExplicit));
+ }
+
+ public static TimeStampTokenEvidence GetInstance(object obj)
+ {
+ if (obj is TimeStampTokenEvidence)
+ return (TimeStampTokenEvidence)obj;
+
+ if (obj != null)
+ return new TimeStampTokenEvidence(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ public virtual TimeStampAndCrl[] ToTimeStampAndCrlArray()
+ {
+ return (TimeStampAndCrl[])timeStampAndCrls.Clone();
+ }
+
+ /**
+ *
+ * TimeStampTokenEvidence ::=
+ * SEQUENCE SIZE(1..MAX) OF TimeStampAndCrl
+ *
+ * @return
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(timeStampAndCrls);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/TimeStampedData.cs b/bc-sharp-crypto/src/asn1/cms/TimeStampedData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..15448a9237aea1335ce107f680c1884d4c4c4a8e
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/TimeStampedData.cs
@@ -0,0 +1,95 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class TimeStampedData
+ : Asn1Encodable
+ {
+ private DerInteger version;
+ private DerIA5String dataUri;
+ private MetaData metaData;
+ private Asn1OctetString content;
+ private Evidence temporalEvidence;
+
+ public TimeStampedData(DerIA5String dataUri, MetaData metaData, Asn1OctetString content,
+ Evidence temporalEvidence)
+ {
+ this.version = new DerInteger(1);
+ this.dataUri = dataUri;
+ this.metaData = metaData;
+ this.content = content;
+ this.temporalEvidence = temporalEvidence;
+ }
+
+ private TimeStampedData(Asn1Sequence seq)
+ {
+ this.version = DerInteger.GetInstance(seq[0]);
+
+ int index = 1;
+ if (seq[index] is DerIA5String)
+ {
+ this.dataUri = DerIA5String.GetInstance(seq[index++]);
+ }
+ if (seq[index] is MetaData || seq[index] is Asn1Sequence)
+ {
+ this.metaData = MetaData.GetInstance(seq[index++]);
+ }
+ if (seq[index] is Asn1OctetString)
+ {
+ this.content = Asn1OctetString.GetInstance(seq[index++]);
+ }
+ this.temporalEvidence = Evidence.GetInstance(seq[index]);
+ }
+
+ public static TimeStampedData GetInstance(object obj)
+ {
+ if (obj is TimeStampedData)
+ return (TimeStampedData)obj;
+
+ if (obj != null)
+ return new TimeStampedData(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ public virtual DerIA5String DataUri
+ {
+ get { return dataUri; }
+ }
+
+ public MetaData MetaData
+ {
+ get { return metaData; }
+ }
+
+ public Asn1OctetString Content
+ {
+ get { return content; }
+ }
+
+ public Evidence TemporalEvidence
+ {
+ get { return temporalEvidence; }
+ }
+
+ /**
+ *
+ * TimeStampedData ::= SEQUENCE {
+ * version INTEGER { v1(1) },
+ * dataUri IA5String OPTIONAL,
+ * metaData MetaData OPTIONAL,
+ * content OCTET STRING OPTIONAL,
+ * temporalEvidence Evidence
+ * }
+ *
+ * @return
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(version);
+ v.AddOptional(dataUri, metaData, content);
+ v.Add(temporalEvidence);
+ return new BerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/TimeStampedDataParser.cs b/bc-sharp-crypto/src/asn1/cms/TimeStampedDataParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..90307bff9e15a94c56f6cebf36d428680599c4d2
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/TimeStampedDataParser.cs
@@ -0,0 +1,76 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ public class TimeStampedDataParser
+ {
+ private DerInteger version;
+ private DerIA5String dataUri;
+ private MetaData metaData;
+ private Asn1OctetStringParser content;
+ private Evidence temporalEvidence;
+ private Asn1SequenceParser parser;
+
+ private TimeStampedDataParser(Asn1SequenceParser parser)
+ {
+ this.parser = parser;
+ this.version = DerInteger.GetInstance(parser.ReadObject());
+
+ Asn1Object obj = parser.ReadObject().ToAsn1Object();
+
+ if (obj is DerIA5String)
+ {
+ this.dataUri = DerIA5String.GetInstance(obj);
+ obj = parser.ReadObject().ToAsn1Object();
+ }
+
+ if (//obj is MetaData ||
+ obj is Asn1SequenceParser)
+ {
+ this.metaData = MetaData.GetInstance(obj.ToAsn1Object());
+ obj = parser.ReadObject().ToAsn1Object();
+ }
+
+ if (obj is Asn1OctetStringParser)
+ {
+ this.content = (Asn1OctetStringParser)obj;
+ }
+ }
+
+ public static TimeStampedDataParser GetInstance(object obj)
+ {
+ if (obj is Asn1Sequence)
+ return new TimeStampedDataParser(((Asn1Sequence)obj).Parser);
+
+ if (obj is Asn1SequenceParser)
+ return new TimeStampedDataParser((Asn1SequenceParser)obj);
+
+ return null;
+ }
+
+ public virtual DerIA5String DataUri
+ {
+ get { return dataUri; }
+ }
+
+ public virtual MetaData MetaData
+ {
+ get { return metaData; }
+ }
+
+ public virtual Asn1OctetStringParser Content
+ {
+ get { return content; }
+ }
+
+ public virtual Evidence GetTemporalEvidence()
+ {
+ if (temporalEvidence == null)
+ {
+ temporalEvidence = Evidence.GetInstance(parser.ReadObject().ToAsn1Object());
+ }
+
+ return temporalEvidence;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cms/ecc/MQVuserKeyingMaterial.cs b/bc-sharp-crypto/src/asn1/cms/ecc/MQVuserKeyingMaterial.cs
new file mode 100644
index 0000000000000000000000000000000000000000..dc4ac1a4afa4cb6296d27765f4f06248e9ae861f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cms/ecc/MQVuserKeyingMaterial.cs
@@ -0,0 +1,105 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms.Ecc
+{
+ public class MQVuserKeyingMaterial
+ : Asn1Encodable
+ {
+ private OriginatorPublicKey ephemeralPublicKey;
+ private Asn1OctetString addedukm;
+
+ public MQVuserKeyingMaterial(
+ OriginatorPublicKey ephemeralPublicKey,
+ Asn1OctetString addedukm)
+ {
+ // TODO Check ephemeralPublicKey not null
+
+ this.ephemeralPublicKey = ephemeralPublicKey;
+ this.addedukm = addedukm;
+ }
+
+ private MQVuserKeyingMaterial(
+ Asn1Sequence seq)
+ {
+ // TODO Check seq has either 1 or 2 elements
+
+ this.ephemeralPublicKey = OriginatorPublicKey.GetInstance(seq[0]);
+
+ if (seq.Count > 1)
+ {
+ this.addedukm = Asn1OctetString.GetInstance(
+ (Asn1TaggedObject)seq[1], true);
+ }
+ }
+
+ /**
+ * return an AuthEnvelopedData object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param isExplicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws ArgumentException if the object held by the
+ * tagged object cannot be converted.
+ */
+ public static MQVuserKeyingMaterial GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ /**
+ * return an AuthEnvelopedData object from the given object.
+ *
+ * @param obj the object we want converted.
+ * @throws ArgumentException if the object cannot be converted.
+ */
+ public static MQVuserKeyingMaterial GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is MQVuserKeyingMaterial)
+ {
+ return (MQVuserKeyingMaterial)obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new MQVuserKeyingMaterial((Asn1Sequence)obj);
+ }
+
+ throw new ArgumentException("Invalid MQVuserKeyingMaterial: " + Platform.GetTypeName(obj));
+ }
+
+ public OriginatorPublicKey EphemeralPublicKey
+ {
+ get { return ephemeralPublicKey; }
+ }
+
+ public Asn1OctetString AddedUkm
+ {
+ get { return addedukm; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * MQVuserKeyingMaterial ::= SEQUENCE {
+ * ephemeralPublicKey OriginatorPublicKey,
+ * addedukm [0] EXPLICIT UserKeyingMaterial OPTIONAL }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(ephemeralPublicKey);
+
+ if (addedukm != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, addedukm));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/AttributeTypeAndValue.cs b/bc-sharp-crypto/src/asn1/crmf/AttributeTypeAndValue.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0a4b5bdbe7253814cf22507b0760d2d19afed909
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/AttributeTypeAndValue.cs
@@ -0,0 +1,68 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class AttributeTypeAndValue
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier type;
+ private readonly Asn1Encodable value;
+
+ private AttributeTypeAndValue(Asn1Sequence seq)
+ {
+ type = (DerObjectIdentifier)seq[0];
+ value = (Asn1Encodable)seq[1];
+ }
+
+ public static AttributeTypeAndValue GetInstance(object obj)
+ {
+ if (obj is AttributeTypeAndValue)
+ return (AttributeTypeAndValue)obj;
+
+ if (obj is Asn1Sequence)
+ return new AttributeTypeAndValue((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public AttributeTypeAndValue(
+ String oid,
+ Asn1Encodable value)
+ : this(new DerObjectIdentifier(oid), value)
+ {
+ }
+
+ public AttributeTypeAndValue(
+ DerObjectIdentifier type,
+ Asn1Encodable value)
+ {
+ this.type = type;
+ this.value = value;
+ }
+
+ public virtual DerObjectIdentifier Type
+ {
+ get { return type; }
+ }
+
+ public virtual Asn1Encodable Value
+ {
+ get { return value; }
+ }
+
+ /**
+ *
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type OBJECT IDENTIFIER,
+ * value ANY DEFINED BY type }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(type, value);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/CertId.cs b/bc-sharp-crypto/src/asn1/crmf/CertId.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f0cc946913d6222c1bb8efe4fccf50d851eb90dd
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/CertId.cs
@@ -0,0 +1,59 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class CertId
+ : Asn1Encodable
+ {
+ private readonly GeneralName issuer;
+ private readonly DerInteger serialNumber;
+
+ private CertId(Asn1Sequence seq)
+ {
+ issuer = GeneralName.GetInstance(seq[0]);
+ serialNumber = DerInteger.GetInstance(seq[1]);
+ }
+
+ public static CertId GetInstance(object obj)
+ {
+ if (obj is CertId)
+ return (CertId)obj;
+
+ if (obj is Asn1Sequence)
+ return new CertId((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public static CertId GetInstance(Asn1TaggedObject obj, bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ public virtual GeneralName Issuer
+ {
+ get { return issuer; }
+ }
+
+ public virtual DerInteger SerialNumber
+ {
+ get { return serialNumber; }
+ }
+
+ /**
+ *
+ * CertId ::= SEQUENCE {
+ * issuer GeneralName,
+ * serialNumber INTEGER }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(issuer, serialNumber);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/CertReqMessages.cs b/bc-sharp-crypto/src/asn1/crmf/CertReqMessages.cs
new file mode 100644
index 0000000000000000000000000000000000000000..422950b9e49fed87310df83c0d4f23436d9be0f4
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/CertReqMessages.cs
@@ -0,0 +1,54 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class CertReqMessages
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence content;
+
+ private CertReqMessages(Asn1Sequence seq)
+ {
+ content = seq;
+ }
+
+ public static CertReqMessages GetInstance(object obj)
+ {
+ if (obj is CertReqMessages)
+ return (CertReqMessages)obj;
+
+ if (obj is Asn1Sequence)
+ return new CertReqMessages((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public CertReqMessages(params CertReqMsg[] msgs)
+ {
+ content = new DerSequence(msgs);
+ }
+
+ public virtual CertReqMsg[] ToCertReqMsgArray()
+ {
+ CertReqMsg[] result = new CertReqMsg[content.Count];
+ for (int i = 0; i != result.Length; ++i)
+ {
+ result[i] = CertReqMsg.GetInstance(content[i]);
+ }
+ return result;
+ }
+
+ /**
+ *
+ * CertReqMessages ::= SEQUENCE SIZE (1..MAX) OF CertReqMsg
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return content;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/CertReqMsg.cs b/bc-sharp-crypto/src/asn1/crmf/CertReqMsg.cs
new file mode 100644
index 0000000000000000000000000000000000000000..03ce32d99cae9b5b4ebae3dae0c5cb1ceaab4e37
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/CertReqMsg.cs
@@ -0,0 +1,112 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class CertReqMsg
+ : Asn1Encodable
+ {
+ private readonly CertRequest certReq;
+ private readonly ProofOfPossession popo;
+ private readonly Asn1Sequence regInfo;
+
+ private CertReqMsg(Asn1Sequence seq)
+ {
+ certReq = CertRequest.GetInstance(seq[0]);
+
+ for (int pos = 1; pos < seq.Count; ++pos)
+ {
+ object o = seq[pos];
+
+ if (o is Asn1TaggedObject || o is ProofOfPossession)
+ {
+ popo = ProofOfPossession.GetInstance(o);
+ }
+ else
+ {
+ regInfo = Asn1Sequence.GetInstance(o);
+ }
+ }
+ }
+
+ public static CertReqMsg GetInstance(object obj)
+ {
+ if (obj is CertReqMsg)
+ return (CertReqMsg)obj;
+
+ if (obj != null)
+ return new CertReqMsg(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ public static CertReqMsg GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ /**
+ * Creates a new CertReqMsg.
+ * @param certReq CertRequest
+ * @param popo may be null
+ * @param regInfo may be null
+ */
+ public CertReqMsg(
+ CertRequest certReq,
+ ProofOfPossession popo,
+ AttributeTypeAndValue[] regInfo)
+ {
+ if (certReq == null)
+ throw new ArgumentNullException("certReq");
+
+ this.certReq = certReq;
+ this.popo = popo;
+
+ if (regInfo != null)
+ {
+ this.regInfo = new DerSequence(regInfo);
+ }
+ }
+
+ public virtual CertRequest CertReq
+ {
+ get { return certReq; }
+ }
+
+ public virtual ProofOfPossession Popo
+ {
+ get { return popo; }
+ }
+
+ public virtual AttributeTypeAndValue[] GetRegInfo()
+ {
+ if (regInfo == null)
+ return null;
+
+ AttributeTypeAndValue[] results = new AttributeTypeAndValue[regInfo.Count];
+ for (int i = 0; i != results.Length; ++i)
+ {
+ results[i] = AttributeTypeAndValue.GetInstance(regInfo[i]);
+ }
+ return results;
+ }
+
+ /**
+ *
+ * CertReqMsg ::= SEQUENCE {
+ * certReq CertRequest,
+ * pop ProofOfPossession OPTIONAL,
+ * -- content depends upon key type
+ * regInfo SEQUENCE SIZE(1..MAX) OF AttributeTypeAndValue OPTIONAL }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(certReq);
+ v.AddOptional(popo, regInfo);
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/CertRequest.cs b/bc-sharp-crypto/src/asn1/crmf/CertRequest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..625a9b51929fa9164d53f06d3d1d821c49b789fc
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/CertRequest.cs
@@ -0,0 +1,82 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class CertRequest
+ : Asn1Encodable
+ {
+ private readonly DerInteger certReqId;
+ private readonly CertTemplate certTemplate;
+ private readonly Controls controls;
+
+ private CertRequest(Asn1Sequence seq)
+ {
+ certReqId = DerInteger.GetInstance(seq[0]);
+ certTemplate = CertTemplate.GetInstance(seq[1]);
+ if (seq.Count > 2)
+ {
+ controls = Controls.GetInstance(seq[2]);
+ }
+ }
+
+ public static CertRequest GetInstance(object obj)
+ {
+ if (obj is CertRequest)
+ return (CertRequest)obj;
+
+ if (obj != null)
+ return new CertRequest(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ public CertRequest(
+ int certReqId,
+ CertTemplate certTemplate,
+ Controls controls)
+ : this(new DerInteger(certReqId), certTemplate, controls)
+ {
+ }
+
+ public CertRequest(
+ DerInteger certReqId,
+ CertTemplate certTemplate,
+ Controls controls)
+ {
+ this.certReqId = certReqId;
+ this.certTemplate = certTemplate;
+ this.controls = controls;
+ }
+
+ public virtual DerInteger CertReqID
+ {
+ get { return certReqId; }
+ }
+
+ public virtual CertTemplate CertTemplate
+ {
+ get { return certTemplate; }
+ }
+
+ public virtual Controls Controls
+ {
+ get { return controls; }
+ }
+
+ /**
+ *
+ * CertRequest ::= SEQUENCE {
+ * certReqId INTEGER, -- ID for matching request and reply
+ * certTemplate CertTemplate, -- Selected fields of cert to be issued
+ * controls Controls OPTIONAL } -- Attributes affecting issuance
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(certReqId, certTemplate);
+ v.AddOptional(controls);
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/CertTemplate.cs b/bc-sharp-crypto/src/asn1/crmf/CertTemplate.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3de9f1d5afcd5e3f457637d9d2bf2ad44f921fcc
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/CertTemplate.cs
@@ -0,0 +1,149 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class CertTemplate
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence seq;
+
+ private readonly DerInteger version;
+ private readonly DerInteger serialNumber;
+ private readonly AlgorithmIdentifier signingAlg;
+ private readonly X509Name issuer;
+ private readonly OptionalValidity validity;
+ private readonly X509Name subject;
+ private readonly SubjectPublicKeyInfo publicKey;
+ private readonly DerBitString issuerUID;
+ private readonly DerBitString subjectUID;
+ private readonly X509Extensions extensions;
+
+ private CertTemplate(Asn1Sequence seq)
+ {
+ this.seq = seq;
+
+ foreach (Asn1TaggedObject tObj in seq)
+ {
+ switch (tObj.TagNo)
+ {
+ case 0:
+ version = DerInteger.GetInstance(tObj, false);
+ break;
+ case 1:
+ serialNumber = DerInteger.GetInstance(tObj, false);
+ break;
+ case 2:
+ signingAlg = AlgorithmIdentifier.GetInstance(tObj, false);
+ break;
+ case 3:
+ issuer = X509Name.GetInstance(tObj, true); // CHOICE
+ break;
+ case 4:
+ validity = OptionalValidity.GetInstance(Asn1Sequence.GetInstance(tObj, false));
+ break;
+ case 5:
+ subject = X509Name.GetInstance(tObj, true); // CHOICE
+ break;
+ case 6:
+ publicKey = SubjectPublicKeyInfo.GetInstance(tObj, false);
+ break;
+ case 7:
+ issuerUID = DerBitString.GetInstance(tObj, false);
+ break;
+ case 8:
+ subjectUID = DerBitString.GetInstance(tObj, false);
+ break;
+ case 9:
+ extensions = X509Extensions.GetInstance(tObj, false);
+ break;
+ default:
+ throw new ArgumentException("unknown tag: " + tObj.TagNo, "seq");
+ }
+ }
+ }
+
+ public static CertTemplate GetInstance(object obj)
+ {
+ if (obj is CertTemplate)
+ return (CertTemplate)obj;
+
+ if (obj != null)
+ return new CertTemplate(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ public virtual int Version
+ {
+ get { return version.Value.IntValue; }
+ }
+
+ public virtual DerInteger SerialNumber
+ {
+ get { return serialNumber; }
+ }
+
+ public virtual AlgorithmIdentifier SigningAlg
+ {
+ get { return signingAlg; }
+ }
+
+ public virtual X509Name Issuer
+ {
+ get { return issuer; }
+ }
+
+ public virtual OptionalValidity Validity
+ {
+ get { return validity; }
+ }
+
+ public virtual X509Name Subject
+ {
+ get { return subject; }
+ }
+
+ public virtual SubjectPublicKeyInfo PublicKey
+ {
+ get { return publicKey; }
+ }
+
+ public virtual DerBitString IssuerUID
+ {
+ get { return issuerUID; }
+ }
+
+ public virtual DerBitString SubjectUID
+ {
+ get { return subjectUID; }
+ }
+
+ public virtual X509Extensions Extensions
+ {
+ get { return extensions; }
+ }
+
+ /**
+ *
+ * CertTemplate ::= SEQUENCE {
+ * version [0] Version OPTIONAL,
+ * serialNumber [1] INTEGER OPTIONAL,
+ * signingAlg [2] AlgorithmIdentifier OPTIONAL,
+ * issuer [3] Name OPTIONAL,
+ * validity [4] OptionalValidity OPTIONAL,
+ * subject [5] Name OPTIONAL,
+ * publicKey [6] SubjectPublicKeyInfo OPTIONAL,
+ * issuerUID [7] UniqueIdentifier OPTIONAL,
+ * subjectUID [8] UniqueIdentifier OPTIONAL,
+ * extensions [9] Extensions OPTIONAL }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return seq;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/CertTemplateBuilder.cs b/bc-sharp-crypto/src/asn1/crmf/CertTemplateBuilder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..51c73c4e1a616c36868d300175daae96603221bb
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/CertTemplateBuilder.cs
@@ -0,0 +1,125 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class CertTemplateBuilder
+ {
+ private DerInteger version;
+ private DerInteger serialNumber;
+ private AlgorithmIdentifier signingAlg;
+ private X509Name issuer;
+ private OptionalValidity validity;
+ private X509Name subject;
+ private SubjectPublicKeyInfo publicKey;
+ private DerBitString issuerUID;
+ private DerBitString subjectUID;
+ private X509Extensions extensions;
+
+ /** Sets the X.509 version. Note: for X509v3, use 2 here. */
+ public virtual CertTemplateBuilder SetVersion(int ver)
+ {
+ version = new DerInteger(ver);
+ return this;
+ }
+
+ public virtual CertTemplateBuilder SetSerialNumber(DerInteger ser)
+ {
+ serialNumber = ser;
+ return this;
+ }
+
+ public virtual CertTemplateBuilder SetSigningAlg(AlgorithmIdentifier aid)
+ {
+ signingAlg = aid;
+ return this;
+ }
+
+ public virtual CertTemplateBuilder SetIssuer(X509Name name)
+ {
+ issuer = name;
+ return this;
+ }
+
+ public virtual CertTemplateBuilder SetValidity(OptionalValidity v)
+ {
+ validity = v;
+ return this;
+ }
+
+ public virtual CertTemplateBuilder SetSubject(X509Name name)
+ {
+ subject = name;
+ return this;
+ }
+
+ public virtual CertTemplateBuilder SetPublicKey(SubjectPublicKeyInfo spki)
+ {
+ publicKey = spki;
+ return this;
+ }
+
+ /** Sets the issuer unique ID (deprecated in X.509v3) */
+ public virtual CertTemplateBuilder SetIssuerUID(DerBitString uid)
+ {
+ issuerUID = uid;
+ return this;
+ }
+
+ /** Sets the subject unique ID (deprecated in X.509v3) */
+ public virtual CertTemplateBuilder SetSubjectUID(DerBitString uid)
+ {
+ subjectUID = uid;
+ return this;
+ }
+
+ public virtual CertTemplateBuilder SetExtensions(X509Extensions extens)
+ {
+ extensions = extens;
+ return this;
+ }
+
+ /**
+ *
+ * CertTemplate ::= SEQUENCE {
+ * version [0] Version OPTIONAL,
+ * serialNumber [1] INTEGER OPTIONAL,
+ * signingAlg [2] AlgorithmIdentifier OPTIONAL,
+ * issuer [3] Name OPTIONAL,
+ * validity [4] OptionalValidity OPTIONAL,
+ * subject [5] Name OPTIONAL,
+ * publicKey [6] SubjectPublicKeyInfo OPTIONAL,
+ * issuerUID [7] UniqueIdentifier OPTIONAL,
+ * subjectUID [8] UniqueIdentifier OPTIONAL,
+ * extensions [9] Extensions OPTIONAL }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public virtual CertTemplate Build()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ AddOptional(v, 0, false, version);
+ AddOptional(v, 1, false, serialNumber);
+ AddOptional(v, 2, false, signingAlg);
+ AddOptional(v, 3, true, issuer); // CHOICE
+ AddOptional(v, 4, false, validity);
+ AddOptional(v, 5, true, subject); // CHOICE
+ AddOptional(v, 6, false, publicKey);
+ AddOptional(v, 7, false, issuerUID);
+ AddOptional(v, 8, false, subjectUID);
+ AddOptional(v, 9, false, extensions);
+
+ return CertTemplate.GetInstance(new DerSequence(v));
+ }
+
+ private void AddOptional(Asn1EncodableVector v, int tagNo, bool isExplicit, Asn1Encodable obj)
+ {
+ if (obj != null)
+ {
+ v.Add(new DerTaggedObject(isExplicit, tagNo, obj));
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/Controls.cs b/bc-sharp-crypto/src/asn1/crmf/Controls.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e8b9f3db0a729f2a74abfb12516117c0a9fc83cc
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/Controls.cs
@@ -0,0 +1,54 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class Controls
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence content;
+
+ private Controls(Asn1Sequence seq)
+ {
+ content = seq;
+ }
+
+ public static Controls GetInstance(object obj)
+ {
+ if (obj is Controls)
+ return (Controls)obj;
+
+ if (obj is Asn1Sequence)
+ return new Controls((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public Controls(params AttributeTypeAndValue[] atvs)
+ {
+ content = new DerSequence(atvs);
+ }
+
+ public virtual AttributeTypeAndValue[] ToAttributeTypeAndValueArray()
+ {
+ AttributeTypeAndValue[] result = new AttributeTypeAndValue[content.Count];
+ for (int i = 0; i != result.Length; ++i)
+ {
+ result[i] = AttributeTypeAndValue.GetInstance(content[i]);
+ }
+ return result;
+ }
+
+ /**
+ *
+ * Controls ::= SEQUENCE SIZE(1..MAX) OF AttributeTypeAndValue
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return content;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/CrmfObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/crmf/CrmfObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..eaa1f7ba45e8ca2535e664668e709823552c00d4
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/CrmfObjectIdentifiers.cs
@@ -0,0 +1,23 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public abstract class CrmfObjectIdentifiers
+ {
+ public static readonly DerObjectIdentifier id_pkix = new DerObjectIdentifier("1.3.6.1.5.5.7");
+
+ // arc for Internet X.509 PKI protocols and their components
+
+ public static readonly DerObjectIdentifier id_pkip = id_pkix.Branch("5");
+
+ public static readonly DerObjectIdentifier id_regCtrl = id_pkip.Branch("1");
+ public static readonly DerObjectIdentifier id_regCtrl_regToken = id_regCtrl.Branch("1");
+ public static readonly DerObjectIdentifier id_regCtrl_authenticator = id_regCtrl.Branch("2");
+ public static readonly DerObjectIdentifier id_regCtrl_pkiPublicationInfo = id_regCtrl.Branch("3");
+ public static readonly DerObjectIdentifier id_regCtrl_pkiArchiveOptions = id_regCtrl.Branch("4");
+
+ public static readonly DerObjectIdentifier id_ct_encKeyWithID = new DerObjectIdentifier(PkcsObjectIdentifiers.IdCT + ".21");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/EncKeyWithID.cs b/bc-sharp-crypto/src/asn1/crmf/EncKeyWithID.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6de56fa0b67d798f622bd3d991ae7673c1df8cb7
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/EncKeyWithID.cs
@@ -0,0 +1,103 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class EncKeyWithID
+ : Asn1Encodable
+ {
+ private readonly PrivateKeyInfo privKeyInfo;
+ private readonly Asn1Encodable identifier;
+
+ public static EncKeyWithID GetInstance(object obj)
+ {
+ if (obj is EncKeyWithID)
+ return (EncKeyWithID)obj;
+
+ if (obj != null)
+ return new EncKeyWithID(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ private EncKeyWithID(Asn1Sequence seq)
+ {
+ this.privKeyInfo = PrivateKeyInfo.GetInstance(seq[0]);
+
+ if (seq.Count > 1)
+ {
+ if (!(seq[1] is DerUtf8String))
+ {
+ this.identifier = GeneralName.GetInstance(seq[1]);
+ }
+ else
+ {
+ this.identifier = (Asn1Encodable)seq[1];
+ }
+ }
+ else
+ {
+ this.identifier = null;
+ }
+ }
+
+ public EncKeyWithID(PrivateKeyInfo privKeyInfo)
+ {
+ this.privKeyInfo = privKeyInfo;
+ this.identifier = null;
+ }
+
+ public EncKeyWithID(PrivateKeyInfo privKeyInfo, DerUtf8String str)
+ {
+ this.privKeyInfo = privKeyInfo;
+ this.identifier = str;
+ }
+
+ public EncKeyWithID(PrivateKeyInfo privKeyInfo, GeneralName generalName)
+ {
+ this.privKeyInfo = privKeyInfo;
+ this.identifier = generalName;
+ }
+
+ public virtual PrivateKeyInfo PrivateKey
+ {
+ get { return privKeyInfo; }
+ }
+
+ public virtual bool HasIdentifier
+ {
+ get { return identifier != null; }
+ }
+
+ public virtual bool IsIdentifierUtf8String
+ {
+ get { return identifier is DerUtf8String; }
+ }
+
+ public virtual Asn1Encodable Identifier
+ {
+ get { return identifier; }
+ }
+
+ /**
+ *
+ * EncKeyWithID ::= SEQUENCE {
+ * privateKey PrivateKeyInfo,
+ * identifier CHOICE {
+ * string UTF8String,
+ * generalName GeneralName
+ * } OPTIONAL
+ * }
+ *
+ * @return
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(privKeyInfo);
+ v.AddOptional(identifier);
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/EncryptedKey.cs b/bc-sharp-crypto/src/asn1/crmf/EncryptedKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..850fbd21950c3a5572e7bb88d6c0ef33574907c2
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/EncryptedKey.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Cms;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class EncryptedKey
+ : Asn1Encodable, IAsn1Choice
+ {
+ private readonly EnvelopedData envelopedData;
+ private readonly EncryptedValue encryptedValue;
+
+ public static EncryptedKey GetInstance(object o)
+ {
+ if (o is EncryptedKey)
+ {
+ return (EncryptedKey)o;
+ }
+ else if (o is Asn1TaggedObject)
+ {
+ return new EncryptedKey(EnvelopedData.GetInstance((Asn1TaggedObject)o, false));
+ }
+ else if (o is EncryptedValue)
+ {
+ return new EncryptedKey((EncryptedValue)o);
+ }
+ else
+ {
+ return new EncryptedKey(EncryptedValue.GetInstance(o));
+ }
+ }
+
+ public EncryptedKey(EnvelopedData envelopedData)
+ {
+ this.envelopedData = envelopedData;
+ }
+
+ public EncryptedKey(EncryptedValue encryptedValue)
+ {
+ this.encryptedValue = encryptedValue;
+ }
+
+ public virtual bool IsEncryptedValue
+ {
+ get { return encryptedValue != null; }
+ }
+
+ public virtual Asn1Encodable Value
+ {
+ get
+ {
+ if (encryptedValue != null)
+ return encryptedValue;
+
+ return envelopedData;
+ }
+ }
+
+ /**
+ *
+ * EncryptedKey ::= CHOICE {
+ * encryptedValue EncryptedValue, -- deprecated
+ * envelopedData [0] EnvelopedData }
+ * -- The encrypted private key MUST be placed in the envelopedData
+ * -- encryptedContentInfo encryptedContent OCTET STRING.
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ if (encryptedValue != null)
+ {
+ return encryptedValue.ToAsn1Object();
+ }
+
+ return new DerTaggedObject(false, 0, envelopedData);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/EncryptedValue.cs b/bc-sharp-crypto/src/asn1/crmf/EncryptedValue.cs
new file mode 100644
index 0000000000000000000000000000000000000000..83122e220c66af304cc448ccf56e5372d566e1e3
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/EncryptedValue.cs
@@ -0,0 +1,154 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class EncryptedValue
+ : Asn1Encodable
+ {
+ private readonly AlgorithmIdentifier intendedAlg;
+ private readonly AlgorithmIdentifier symmAlg;
+ private readonly DerBitString encSymmKey;
+ private readonly AlgorithmIdentifier keyAlg;
+ private readonly Asn1OctetString valueHint;
+ private readonly DerBitString encValue;
+
+ private EncryptedValue(Asn1Sequence seq)
+ {
+ int index = 0;
+ while (seq[index] is Asn1TaggedObject)
+ {
+ Asn1TaggedObject tObj = (Asn1TaggedObject)seq[index];
+
+ switch (tObj.TagNo)
+ {
+ case 0:
+ intendedAlg = AlgorithmIdentifier.GetInstance(tObj, false);
+ break;
+ case 1:
+ symmAlg = AlgorithmIdentifier.GetInstance(tObj, false);
+ break;
+ case 2:
+ encSymmKey = DerBitString.GetInstance(tObj, false);
+ break;
+ case 3:
+ keyAlg = AlgorithmIdentifier.GetInstance(tObj, false);
+ break;
+ case 4:
+ valueHint = Asn1OctetString.GetInstance(tObj, false);
+ break;
+ }
+ ++index;
+ }
+
+ encValue = DerBitString.GetInstance(seq[index]);
+ }
+
+ public static EncryptedValue GetInstance(object obj)
+ {
+ if (obj is EncryptedValue)
+ return (EncryptedValue)obj;
+
+ if (obj != null)
+ return new EncryptedValue(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ public EncryptedValue(
+ AlgorithmIdentifier intendedAlg,
+ AlgorithmIdentifier symmAlg,
+ DerBitString encSymmKey,
+ AlgorithmIdentifier keyAlg,
+ Asn1OctetString valueHint,
+ DerBitString encValue)
+ {
+ if (encValue == null)
+ {
+ throw new ArgumentNullException("encValue");
+ }
+
+ this.intendedAlg = intendedAlg;
+ this.symmAlg = symmAlg;
+ this.encSymmKey = encSymmKey;
+ this.keyAlg = keyAlg;
+ this.valueHint = valueHint;
+ this.encValue = encValue;
+ }
+
+ public virtual AlgorithmIdentifier IntendedAlg
+ {
+ get { return intendedAlg; }
+ }
+
+ public virtual AlgorithmIdentifier SymmAlg
+ {
+ get { return symmAlg; }
+ }
+
+ public virtual DerBitString EncSymmKey
+ {
+ get { return encSymmKey; }
+ }
+
+ public virtual AlgorithmIdentifier KeyAlg
+ {
+ get { return keyAlg; }
+ }
+
+ public virtual Asn1OctetString ValueHint
+ {
+ get { return valueHint; }
+ }
+
+ public virtual DerBitString EncValue
+ {
+ get { return encValue; }
+ }
+
+ /**
+ *
+ * EncryptedValue ::= SEQUENCE {
+ * intendedAlg [0] AlgorithmIdentifier OPTIONAL,
+ * -- the intended algorithm for which the value will be used
+ * symmAlg [1] AlgorithmIdentifier OPTIONAL,
+ * -- the symmetric algorithm used to encrypt the value
+ * encSymmKey [2] BIT STRING OPTIONAL,
+ * -- the (encrypted) symmetric key used to encrypt the value
+ * keyAlg [3] AlgorithmIdentifier OPTIONAL,
+ * -- algorithm used to encrypt the symmetric key
+ * valueHint [4] OCTET STRING OPTIONAL,
+ * -- a brief description or identifier of the encValue content
+ * -- (may be meaningful only to the sending entity, and used only
+ * -- if EncryptedValue might be re-examined by the sending entity
+ * -- in the future)
+ * encValue BIT STRING }
+ * -- the encrypted value itself
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ AddOptional(v, 0, intendedAlg);
+ AddOptional(v, 1, symmAlg);
+ AddOptional(v, 2, encSymmKey);
+ AddOptional(v, 3, keyAlg);
+ AddOptional(v, 4, valueHint);
+
+ v.Add(encValue);
+
+ return new DerSequence(v);
+ }
+
+ private void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+ {
+ if (obj != null)
+ {
+ v.Add(new DerTaggedObject(false, tagNo, obj));
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/OptionalValidity.cs b/bc-sharp-crypto/src/asn1/crmf/OptionalValidity.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d1a0f7ffbb78a737732c3927d92a775403a2cb46
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/OptionalValidity.cs
@@ -0,0 +1,71 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class OptionalValidity
+ : Asn1Encodable
+ {
+ private readonly Time notBefore;
+ private readonly Time notAfter;
+
+ private OptionalValidity(Asn1Sequence seq)
+ {
+ foreach (Asn1TaggedObject tObj in seq)
+ {
+ if (tObj.TagNo == 0)
+ {
+ notBefore = Time.GetInstance(tObj, true);
+ }
+ else
+ {
+ notAfter = Time.GetInstance(tObj, true);
+ }
+ }
+ }
+
+ public static OptionalValidity GetInstance(object obj)
+ {
+ if (obj == null || obj is OptionalValidity)
+ return (OptionalValidity)obj;
+
+ return new OptionalValidity(Asn1Sequence.GetInstance(obj));
+ }
+
+ public virtual Time NotBefore
+ {
+ get { return notBefore; }
+ }
+
+ public virtual Time NotAfter
+ {
+ get { return notAfter; }
+ }
+
+ /**
+ *
+ * OptionalValidity ::= SEQUENCE {
+ * notBefore [0] Time OPTIONAL,
+ * notAfter [1] Time OPTIONAL } --at least one MUST be present
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (notBefore != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, notBefore));
+ }
+
+ if (notAfter != null)
+ {
+ v.Add(new DerTaggedObject(true, 1, notAfter));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/PKIArchiveOptions.cs b/bc-sharp-crypto/src/asn1/crmf/PKIArchiveOptions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1813d87a7b55451681dc0034700a82e896265e7d
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/PKIArchiveOptions.cs
@@ -0,0 +1,107 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class PkiArchiveOptions
+ : Asn1Encodable, IAsn1Choice
+ {
+ public const int encryptedPrivKey = 0;
+ public const int keyGenParameters = 1;
+ public const int archiveRemGenPrivKey = 2;
+
+ private readonly Asn1Encodable value;
+
+ public static PkiArchiveOptions GetInstance(object obj)
+ {
+ if (obj is PkiArchiveOptions)
+ return (PkiArchiveOptions)obj;
+
+ if (obj is Asn1TaggedObject)
+ return new PkiArchiveOptions((Asn1TaggedObject)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private PkiArchiveOptions(Asn1TaggedObject tagged)
+ {
+ switch (tagged.TagNo)
+ {
+ case encryptedPrivKey:
+ value = EncryptedKey.GetInstance(tagged.GetObject());
+ break;
+ case keyGenParameters:
+ value = Asn1OctetString.GetInstance(tagged, false);
+ break;
+ case archiveRemGenPrivKey:
+ value = DerBoolean.GetInstance(tagged, false);
+ break;
+ default:
+ throw new ArgumentException("unknown tag number: " + tagged.TagNo, "tagged");
+ }
+ }
+
+ public PkiArchiveOptions(EncryptedKey encKey)
+ {
+ this.value = encKey;
+ }
+
+ public PkiArchiveOptions(Asn1OctetString keyGenParameters)
+ {
+ this.value = keyGenParameters;
+ }
+
+ public PkiArchiveOptions(bool archiveRemGenPrivKey)
+ {
+ this.value = DerBoolean.GetInstance(archiveRemGenPrivKey);
+ }
+
+ public virtual int Type
+ {
+ get
+ {
+ if (value is EncryptedKey)
+ return encryptedPrivKey;
+
+ if (value is Asn1OctetString)
+ return keyGenParameters;
+
+ return archiveRemGenPrivKey;
+ }
+ }
+
+ public virtual Asn1Encodable Value
+ {
+ get { return value; }
+ }
+
+ /**
+ *
+ * PkiArchiveOptions ::= CHOICE {
+ * encryptedPrivKey [0] EncryptedKey,
+ * -- the actual value of the private key
+ * keyGenParameters [1] KeyGenParameters,
+ * -- parameters which allow the private key to be re-generated
+ * archiveRemGenPrivKey [2] BOOLEAN }
+ * -- set to TRUE if sender wishes receiver to archive the private
+ * -- key of a key pair that the receiver generates in response to
+ * -- this request; set to FALSE if no archival is desired.
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ if (value is EncryptedKey)
+ {
+ return new DerTaggedObject(true, encryptedPrivKey, value); // choice
+ }
+
+ if (value is Asn1OctetString)
+ {
+ return new DerTaggedObject(false, keyGenParameters, value);
+ }
+
+ return new DerTaggedObject(false, archiveRemGenPrivKey, value);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/PKIPublicationInfo.cs b/bc-sharp-crypto/src/asn1/crmf/PKIPublicationInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a7d2bc603c25a1560f8334ca09c97a8bdcb7ff6a
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/PKIPublicationInfo.cs
@@ -0,0 +1,66 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class PkiPublicationInfo
+ : Asn1Encodable
+ {
+ private readonly DerInteger action;
+ private readonly Asn1Sequence pubInfos;
+
+ private PkiPublicationInfo(Asn1Sequence seq)
+ {
+ action = DerInteger.GetInstance(seq[0]);
+ pubInfos = Asn1Sequence.GetInstance(seq[1]);
+ }
+
+ public static PkiPublicationInfo GetInstance(object obj)
+ {
+ if (obj is PkiPublicationInfo)
+ return (PkiPublicationInfo)obj;
+
+ if (obj is Asn1Sequence)
+ return new PkiPublicationInfo((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public virtual DerInteger Action
+ {
+ get { return action; }
+ }
+
+ public virtual SinglePubInfo[] GetPubInfos()
+ {
+ if (pubInfos == null)
+ return null;
+
+ SinglePubInfo[] results = new SinglePubInfo[pubInfos.Count];
+ for (int i = 0; i != results.Length; ++i)
+ {
+ results[i] = SinglePubInfo.GetInstance(pubInfos[i]);
+ }
+ return results;
+ }
+
+ /**
+ *
+ * PkiPublicationInfo ::= SEQUENCE {
+ * action INTEGER {
+ * dontPublish (0),
+ * pleasePublish (1) },
+ * pubInfos SEQUENCE SIZE (1..MAX) OF SinglePubInfo OPTIONAL }
+ * -- pubInfos MUST NOT be present if action is "dontPublish"
+ * -- (if action is "pleasePublish" and pubInfos is omitted,
+ * -- "dontCare" is assumed)
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(action, pubInfos);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/PKMacValue.cs b/bc-sharp-crypto/src/asn1/crmf/PKMacValue.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e104c08dd852a7080e79508290afc132895cca85
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/PKMacValue.cs
@@ -0,0 +1,90 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ /**
+ * Password-based MAC value for use with POPOSigningKeyInput.
+ */
+ public class PKMacValue
+ : Asn1Encodable
+ {
+ private readonly AlgorithmIdentifier algID;
+ private readonly DerBitString macValue;
+
+ private PKMacValue(Asn1Sequence seq)
+ {
+ this.algID = AlgorithmIdentifier.GetInstance(seq[0]);
+ this.macValue = DerBitString.GetInstance(seq[1]);
+ }
+
+ public static PKMacValue GetInstance(object obj)
+ {
+ if (obj is PKMacValue)
+ return (PKMacValue)obj;
+
+ if (obj is Asn1Sequence)
+ return new PKMacValue((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public static PKMacValue GetInstance(Asn1TaggedObject obj, bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ /**
+ * Creates a new PKMACValue.
+ * @param params parameters for password-based MAC
+ * @param value MAC of the DER-encoded SubjectPublicKeyInfo
+ */
+ public PKMacValue(
+ PbmParameter pbmParams,
+ DerBitString macValue)
+ : this(new AlgorithmIdentifier(CmpObjectIdentifiers.passwordBasedMac, pbmParams), macValue)
+ {
+ }
+
+ /**
+ * Creates a new PKMACValue.
+ * @param aid CMPObjectIdentifiers.passwordBasedMAC, with PBMParameter
+ * @param value MAC of the DER-encoded SubjectPublicKeyInfo
+ */
+ public PKMacValue(
+ AlgorithmIdentifier algID,
+ DerBitString macValue)
+ {
+ this.algID = algID;
+ this.macValue = macValue;
+ }
+
+ public virtual AlgorithmIdentifier AlgID
+ {
+ get { return algID; }
+ }
+
+ public virtual DerBitString MacValue
+ {
+ get { return macValue; }
+ }
+
+ /**
+ *
+ * PKMACValue ::= SEQUENCE {
+ * algId AlgorithmIdentifier,
+ * -- algorithm value shall be PasswordBasedMac 1.2.840.113533.7.66.13
+ * -- parameter value is PBMParameter
+ * value BIT STRING }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(algID, macValue);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/PopoPrivKey.cs b/bc-sharp-crypto/src/asn1/crmf/PopoPrivKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0cedc5127afb60d0ebb5dd7a8be37698c1387938
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/PopoPrivKey.cs
@@ -0,0 +1,84 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Cms;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class PopoPrivKey
+ : Asn1Encodable, IAsn1Choice
+ {
+ public const int thisMessage = 0;
+ public const int subsequentMessage = 1;
+ public const int dhMAC = 2;
+ public const int agreeMAC = 3;
+ public const int encryptedKey = 4;
+
+ private readonly int tagNo;
+ private readonly Asn1Encodable obj;
+
+ private PopoPrivKey(Asn1TaggedObject obj)
+ {
+ this.tagNo = obj.TagNo;
+
+ switch (tagNo)
+ {
+ case thisMessage:
+ this.obj = DerBitString.GetInstance(obj, false);
+ break;
+ case subsequentMessage:
+ this.obj = SubsequentMessage.ValueOf(DerInteger.GetInstance(obj, false).Value.IntValue);
+ break;
+ case dhMAC:
+ this.obj = DerBitString.GetInstance(obj, false);
+ break;
+ case agreeMAC:
+ this.obj = PKMacValue.GetInstance(obj, false);
+ break;
+ case encryptedKey:
+ this.obj = EnvelopedData.GetInstance(obj, false);
+ break;
+ default:
+ throw new ArgumentException("unknown tag in PopoPrivKey", "obj");
+ }
+ }
+
+ public static PopoPrivKey GetInstance(Asn1TaggedObject tagged, bool isExplicit)
+ {
+ return new PopoPrivKey(Asn1TaggedObject.GetInstance(tagged.GetObject()));
+ }
+
+ public PopoPrivKey(SubsequentMessage msg)
+ {
+ this.tagNo = subsequentMessage;
+ this.obj = msg;
+ }
+
+ public virtual int Type
+ {
+ get { return tagNo; }
+ }
+
+ public virtual Asn1Encodable Value
+ {
+ get { return obj; }
+ }
+
+ /**
+ *
+ * PopoPrivKey ::= CHOICE {
+ * thisMessage [0] BIT STRING, -- Deprecated
+ * -- possession is proven in this message (which contains the private
+ * -- key itself (encrypted for the CA))
+ * subsequentMessage [1] SubsequentMessage,
+ * -- possession will be proven in a subsequent message
+ * dhMAC [2] BIT STRING, -- Deprecated
+ * agreeMAC [3] PKMACValue,
+ * encryptedKey [4] EnvelopedData }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerTaggedObject(false, tagNo, obj);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/PopoSigningKey.cs b/bc-sharp-crypto/src/asn1/crmf/PopoSigningKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1c24db8eeaeb16a50ca91027844bec4a9ccf2d7e
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/PopoSigningKey.cs
@@ -0,0 +1,116 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class PopoSigningKey
+ : Asn1Encodable
+ {
+ private readonly PopoSigningKeyInput poposkInput;
+ private readonly AlgorithmIdentifier algorithmIdentifier;
+ private readonly DerBitString signature;
+
+ private PopoSigningKey(Asn1Sequence seq)
+ {
+ int index = 0;
+
+ if (seq[index] is Asn1TaggedObject)
+ {
+ Asn1TaggedObject tagObj
+ = (Asn1TaggedObject) seq[index++];
+ if (tagObj.TagNo != 0)
+ {
+ throw new ArgumentException( "Unknown PopoSigningKeyInput tag: " + tagObj.TagNo, "seq");
+ }
+ poposkInput = PopoSigningKeyInput.GetInstance(tagObj.GetObject());
+ }
+ algorithmIdentifier = AlgorithmIdentifier.GetInstance(seq[index++]);
+ signature = DerBitString.GetInstance(seq[index]);
+ }
+
+ public static PopoSigningKey GetInstance(object obj)
+ {
+ if (obj is PopoSigningKey)
+ return (PopoSigningKey)obj;
+
+ if (obj is Asn1Sequence)
+ return new PopoSigningKey((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public static PopoSigningKey GetInstance(Asn1TaggedObject obj, bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ /**
+ * Creates a new Proof of Possession object for a signing key.
+ * @param poposkIn the PopoSigningKeyInput structure, or null if the
+ * CertTemplate includes both subject and publicKey values.
+ * @param aid the AlgorithmIdentifier used to sign the proof of possession.
+ * @param signature a signature over the DER-encoded value of poposkIn,
+ * or the DER-encoded value of certReq if poposkIn is null.
+ */
+ public PopoSigningKey(
+ PopoSigningKeyInput poposkIn,
+ AlgorithmIdentifier aid,
+ DerBitString signature)
+ {
+ this.poposkInput = poposkIn;
+ this.algorithmIdentifier = aid;
+ this.signature = signature;
+ }
+
+ public virtual PopoSigningKeyInput PoposkInput
+ {
+ get { return poposkInput; }
+ }
+
+ public virtual AlgorithmIdentifier AlgorithmIdentifier
+ {
+ get { return algorithmIdentifier; }
+ }
+
+ public virtual DerBitString Signature
+ {
+ get { return signature; }
+ }
+
+ /**
+ *
+ * PopoSigningKey ::= SEQUENCE {
+ * poposkInput [0] PopoSigningKeyInput OPTIONAL,
+ * algorithmIdentifier AlgorithmIdentifier,
+ * signature BIT STRING }
+ * -- The signature (using "algorithmIdentifier") is on the
+ * -- DER-encoded value of poposkInput. NOTE: If the CertReqMsg
+ * -- certReq CertTemplate contains the subject and publicKey values,
+ * -- then poposkInput MUST be omitted and the signature MUST be
+ * -- computed on the DER-encoded value of CertReqMsg certReq. If
+ * -- the CertReqMsg certReq CertTemplate does not contain the public
+ * -- key and subject values, then poposkInput MUST be present and
+ * -- MUST be signed. This strategy ensures that the public key is
+ * -- not present in both the poposkInput and CertReqMsg certReq
+ * -- CertTemplate fields.
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (poposkInput != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, poposkInput));
+ }
+
+ v.Add(algorithmIdentifier);
+ v.Add(signature);
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/PopoSigningKeyInput.cs b/bc-sharp-crypto/src/asn1/crmf/PopoSigningKeyInput.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e43fa138ee7672bea15c160da7fb93b57f1b3f1b
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/PopoSigningKeyInput.cs
@@ -0,0 +1,116 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class PopoSigningKeyInput
+ : Asn1Encodable
+ {
+ private readonly GeneralName sender;
+ private readonly PKMacValue publicKeyMac;
+ private readonly SubjectPublicKeyInfo publicKey;
+
+ private PopoSigningKeyInput(Asn1Sequence seq)
+ {
+ Asn1Encodable authInfo = (Asn1Encodable)seq[0];
+
+ if (authInfo is Asn1TaggedObject)
+ {
+ Asn1TaggedObject tagObj = (Asn1TaggedObject)authInfo;
+ if (tagObj.TagNo != 0)
+ {
+ throw new ArgumentException("Unknown authInfo tag: " + tagObj.TagNo, "seq");
+ }
+ sender = GeneralName.GetInstance(tagObj.GetObject());
+ }
+ else
+ {
+ publicKeyMac = PKMacValue.GetInstance(authInfo);
+ }
+
+ publicKey = SubjectPublicKeyInfo.GetInstance(seq[1]);
+ }
+
+ public static PopoSigningKeyInput GetInstance(object obj)
+ {
+ if (obj is PopoSigningKeyInput)
+ return (PopoSigningKeyInput)obj;
+
+ if (obj is Asn1Sequence)
+ return new PopoSigningKeyInput((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /** Creates a new PopoSigningKeyInput with sender name as authInfo. */
+ public PopoSigningKeyInput(
+ GeneralName sender,
+ SubjectPublicKeyInfo spki)
+ {
+ this.sender = sender;
+ this.publicKey = spki;
+ }
+
+ /** Creates a new PopoSigningKeyInput using password-based MAC. */
+ public PopoSigningKeyInput(
+ PKMacValue pkmac,
+ SubjectPublicKeyInfo spki)
+ {
+ this.publicKeyMac = pkmac;
+ this.publicKey = spki;
+ }
+
+ /** Returns the sender field, or null if authInfo is publicKeyMac */
+ public virtual GeneralName Sender
+ {
+ get { return sender; }
+ }
+
+ /** Returns the publicKeyMac field, or null if authInfo is sender */
+ public virtual PKMacValue PublicKeyMac
+ {
+ get { return publicKeyMac; }
+ }
+
+ public virtual SubjectPublicKeyInfo PublicKey
+ {
+ get { return publicKey; }
+ }
+
+ /**
+ *
+ * PopoSigningKeyInput ::= SEQUENCE {
+ * authInfo CHOICE {
+ * sender [0] GeneralName,
+ * -- used only if an authenticated identity has been
+ * -- established for the sender (e.g., a DN from a
+ * -- previously-issued and currently-valid certificate
+ * publicKeyMac PKMacValue },
+ * -- used if no authenticated GeneralName currently exists for
+ * -- the sender; publicKeyMac contains a password-based MAC
+ * -- on the DER-encoded value of publicKey
+ * publicKey SubjectPublicKeyInfo } -- from CertTemplate
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (sender != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, sender));
+ }
+ else
+ {
+ v.Add(publicKeyMac);
+ }
+
+ v.Add(publicKey);
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/ProofOfPossession.cs b/bc-sharp-crypto/src/asn1/crmf/ProofOfPossession.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8957169d7702ea7111e031e27fdf87620cd9baea
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/ProofOfPossession.cs
@@ -0,0 +1,100 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class ProofOfPossession
+ : Asn1Encodable, IAsn1Choice
+ {
+ public const int TYPE_RA_VERIFIED = 0;
+ public const int TYPE_SIGNING_KEY = 1;
+ public const int TYPE_KEY_ENCIPHERMENT = 2;
+ public const int TYPE_KEY_AGREEMENT = 3;
+
+ private readonly int tagNo;
+ private readonly Asn1Encodable obj;
+
+ private ProofOfPossession(Asn1TaggedObject tagged)
+ {
+ tagNo = tagged.TagNo;
+ switch (tagNo)
+ {
+ case 0:
+ obj = DerNull.Instance;
+ break;
+ case 1:
+ obj = PopoSigningKey.GetInstance(tagged, false);
+ break;
+ case 2:
+ case 3:
+ obj = PopoPrivKey.GetInstance(tagged, false);
+ break;
+ default:
+ throw new ArgumentException("unknown tag: " + tagNo, "tagged");
+ }
+ }
+
+ public static ProofOfPossession GetInstance(object obj)
+ {
+ if (obj is ProofOfPossession)
+ return (ProofOfPossession)obj;
+
+ if (obj is Asn1TaggedObject)
+ return new ProofOfPossession((Asn1TaggedObject)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /** Creates a ProofOfPossession with type raVerified. */
+ public ProofOfPossession()
+ {
+ tagNo = TYPE_RA_VERIFIED;
+ obj = DerNull.Instance;
+ }
+
+ /** Creates a ProofOfPossession for a signing key. */
+ public ProofOfPossession(PopoSigningKey Poposk)
+ {
+ tagNo = TYPE_SIGNING_KEY;
+ obj = Poposk;
+ }
+
+ /**
+ * Creates a ProofOfPossession for key encipherment or agreement.
+ * @param type one of TYPE_KEY_ENCIPHERMENT or TYPE_KEY_AGREEMENT
+ */
+ public ProofOfPossession(int type, PopoPrivKey privkey)
+ {
+ tagNo = type;
+ obj = privkey;
+ }
+
+ public virtual int Type
+ {
+ get { return tagNo; }
+ }
+
+ public virtual Asn1Encodable Object
+ {
+ get { return obj; }
+ }
+
+ /**
+ *
+ * ProofOfPossession ::= CHOICE {
+ * raVerified [0] NULL,
+ * -- used if the RA has already verified that the requester is in
+ * -- possession of the private key
+ * signature [1] PopoSigningKey,
+ * keyEncipherment [2] PopoPrivKey,
+ * keyAgreement [3] PopoPrivKey }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerTaggedObject(false, tagNo, obj);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/SinglePubInfo.cs b/bc-sharp-crypto/src/asn1/crmf/SinglePubInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5205ce366ca370c2deae392228816f7c9f51d729
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/SinglePubInfo.cs
@@ -0,0 +1,59 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class SinglePubInfo
+ : Asn1Encodable
+ {
+ private readonly DerInteger pubMethod;
+ private readonly GeneralName pubLocation;
+
+ private SinglePubInfo(Asn1Sequence seq)
+ {
+ pubMethod = DerInteger.GetInstance(seq[0]);
+
+ if (seq.Count == 2)
+ {
+ pubLocation = GeneralName.GetInstance(seq[1]);
+ }
+ }
+
+ public static SinglePubInfo GetInstance(object obj)
+ {
+ if (obj is SinglePubInfo)
+ return (SinglePubInfo)obj;
+
+ if (obj is Asn1Sequence)
+ return new SinglePubInfo((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public virtual GeneralName PubLocation
+ {
+ get { return pubLocation; }
+ }
+
+ /**
+ *
+ * SinglePubInfo ::= SEQUENCE {
+ * pubMethod INTEGER {
+ * dontCare (0),
+ * x500 (1),
+ * web (2),
+ * ldap (3) },
+ * pubLocation GeneralName OPTIONAL }
+ *
+ * @return a basic ASN.1 object representation.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(pubMethod);
+ v.AddOptional(pubLocation);
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/crmf/SubsequentMessage.cs b/bc-sharp-crypto/src/asn1/crmf/SubsequentMessage.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cc1c164926965ab1fc2314dfb3991da6c1d94d22
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/crmf/SubsequentMessage.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+ public class SubsequentMessage
+ : DerInteger
+ {
+ public static readonly SubsequentMessage encrCert = new SubsequentMessage(0);
+ public static readonly SubsequentMessage challengeResp = new SubsequentMessage(1);
+
+ private SubsequentMessage(int value)
+ : base(value)
+ {
+ }
+
+ public static SubsequentMessage ValueOf(int value)
+ {
+ if (value == 0)
+ return encrCert;
+
+ if (value == 1)
+ return challengeResp;
+
+ throw new ArgumentException("unknown value: " + value, "value");
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cryptopro/CryptoProObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/cryptopro/CryptoProObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e2f2c18486afb28d349e249d97a3686322a5e10d
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cryptopro/CryptoProObjectIdentifiers.cs
@@ -0,0 +1,51 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+ public abstract class CryptoProObjectIdentifiers
+ {
+ // GOST Algorithms OBJECT IDENTIFIERS :
+ // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2)}
+ public const string GostID = "1.2.643.2.2";
+
+ public static readonly DerObjectIdentifier GostR3411 = new DerObjectIdentifier(GostID + ".9");
+ public static readonly DerObjectIdentifier GostR3411Hmac = new DerObjectIdentifier(GostID + ".10");
+
+ public static readonly DerObjectIdentifier GostR28147Cbc = new DerObjectIdentifier(GostID + ".21");
+
+ public static readonly DerObjectIdentifier ID_Gost28147_89_CryptoPro_A_ParamSet = new DerObjectIdentifier(GostID + ".31.1");
+
+ public static readonly DerObjectIdentifier GostR3410x94 = new DerObjectIdentifier(GostID + ".20");
+ public static readonly DerObjectIdentifier GostR3410x2001 = new DerObjectIdentifier(GostID + ".19");
+ public static readonly DerObjectIdentifier GostR3411x94WithGostR3410x94 = new DerObjectIdentifier(GostID + ".4");
+ public static readonly DerObjectIdentifier GostR3411x94WithGostR3410x2001 = new DerObjectIdentifier(GostID + ".3");
+
+ // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) hashes(30) }
+ public static readonly DerObjectIdentifier GostR3411x94CryptoProParamSet = new DerObjectIdentifier(GostID + ".30.1");
+
+ // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) signs(32) }
+ public static readonly DerObjectIdentifier GostR3410x94CryptoProA = new DerObjectIdentifier(GostID + ".32.2");
+ public static readonly DerObjectIdentifier GostR3410x94CryptoProB = new DerObjectIdentifier(GostID + ".32.3");
+ public static readonly DerObjectIdentifier GostR3410x94CryptoProC = new DerObjectIdentifier(GostID + ".32.4");
+ public static readonly DerObjectIdentifier GostR3410x94CryptoProD = new DerObjectIdentifier(GostID + ".32.5");
+
+ // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) exchanges(33) }
+ public static readonly DerObjectIdentifier GostR3410x94CryptoProXchA = new DerObjectIdentifier(GostID + ".33.1");
+ public static readonly DerObjectIdentifier GostR3410x94CryptoProXchB = new DerObjectIdentifier(GostID + ".33.2");
+ public static readonly DerObjectIdentifier GostR3410x94CryptoProXchC = new DerObjectIdentifier(GostID + ".33.3");
+
+ //{ iso(1) member-body(2)ru(643) rans(2) cryptopro(2) ecc-signs(35) }
+ public static readonly DerObjectIdentifier GostR3410x2001CryptoProA = new DerObjectIdentifier(GostID + ".35.1");
+ public static readonly DerObjectIdentifier GostR3410x2001CryptoProB = new DerObjectIdentifier(GostID + ".35.2");
+ public static readonly DerObjectIdentifier GostR3410x2001CryptoProC = new DerObjectIdentifier(GostID + ".35.3");
+
+ // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) ecc-exchanges(36) }
+ public static readonly DerObjectIdentifier GostR3410x2001CryptoProXchA = new DerObjectIdentifier(GostID + ".36.0");
+ public static readonly DerObjectIdentifier GostR3410x2001CryptoProXchB = new DerObjectIdentifier(GostID + ".36.1");
+
+ public static readonly DerObjectIdentifier GostElSgDH3410Default = new DerObjectIdentifier(GostID + ".36.0");
+ public static readonly DerObjectIdentifier GostElSgDH3410x1 = new DerObjectIdentifier(GostID + ".36.1");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs b/bc-sharp-crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
new file mode 100644
index 0000000000000000000000000000000000000000..32d3103af4346b5b4398f2f14d97510d392d221b
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
@@ -0,0 +1,184 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+ /**
+ * table of the available named parameters for GOST 3410-2001.
+ */
+ public sealed class ECGost3410NamedCurves
+ {
+ private ECGost3410NamedCurves()
+ {
+ }
+
+ internal static readonly IDictionary objIds = Platform.CreateHashtable();
+ internal static readonly IDictionary parameters = Platform.CreateHashtable();
+ internal static readonly IDictionary names = Platform.CreateHashtable();
+
+ static ECGost3410NamedCurves()
+ {
+ BigInteger mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319");
+ BigInteger mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323");
+
+ FpCurve curve = new FpCurve(
+ mod_p, // p
+ new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), // a
+ new BigInteger("166"), // b
+ mod_q,
+ BigInteger.One);
+
+ ECDomainParameters ecParams = new ECDomainParameters(
+ curve,
+ curve.CreatePoint(
+ new BigInteger("1"), // x
+ new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")), // y
+ mod_q);
+
+ parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProA] = ecParams;
+
+ mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319");
+ mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323");
+
+ curve = new FpCurve(
+ mod_p, // p
+ new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"),
+ new BigInteger("166"),
+ mod_q,
+ BigInteger.One);
+
+ ecParams = new ECDomainParameters(
+ curve,
+ curve.CreatePoint(
+ new BigInteger("1"), // x
+ new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")), // y
+ mod_q);
+
+ parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchA] = ecParams;
+
+ mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823193"); //p
+ mod_q = new BigInteger("57896044618658097711785492504343953927102133160255826820068844496087732066703"); //q
+
+ curve = new FpCurve(
+ mod_p, // p
+ new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823190"), // a
+ new BigInteger("28091019353058090096996979000309560759124368558014865957655842872397301267595"), // b
+ mod_q,
+ BigInteger.One);
+
+ ecParams = new ECDomainParameters(
+ curve,
+ curve.CreatePoint(
+ new BigInteger("1"), // x
+ new BigInteger("28792665814854611296992347458380284135028636778229113005756334730996303888124")), // y
+ mod_q); // q
+
+ parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProB] = ecParams;
+
+ mod_p = new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502619");
+ mod_q = new BigInteger("70390085352083305199547718019018437840920882647164081035322601458352298396601");
+
+ curve = new FpCurve(
+ mod_p, // p
+ new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"),
+ new BigInteger("32858"),
+ mod_q,
+ BigInteger.One);
+
+ ecParams = new ECDomainParameters(
+ curve,
+ curve.CreatePoint(
+ new BigInteger("0"),
+ new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247")),
+ mod_q);
+
+ parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchB] = ecParams;
+
+ mod_p = new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502619"); //p
+ mod_q = new BigInteger("70390085352083305199547718019018437840920882647164081035322601458352298396601"); //q
+ curve = new FpCurve(
+ mod_p, // p
+ new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"), // a
+ new BigInteger("32858"), // b
+ mod_q,
+ BigInteger.One);
+
+ ecParams = new ECDomainParameters(
+ curve,
+ curve.CreatePoint(
+ new BigInteger("0"), // x
+ new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247")), // y
+ mod_q); // q
+
+ parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProC] = ecParams;
+
+ objIds["GostR3410-2001-CryptoPro-A"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProA;
+ objIds["GostR3410-2001-CryptoPro-B"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProB;
+ objIds["GostR3410-2001-CryptoPro-C"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProC;
+ objIds["GostR3410-2001-CryptoPro-XchA"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchA;
+ objIds["GostR3410-2001-CryptoPro-XchB"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchB;
+
+ names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProA] = "GostR3410-2001-CryptoPro-A";
+ names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProB] = "GostR3410-2001-CryptoPro-B";
+ names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProC] = "GostR3410-2001-CryptoPro-C";
+ names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchA] = "GostR3410-2001-CryptoPro-XchA";
+ names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchB] = "GostR3410-2001-CryptoPro-XchB";
+ }
+
+ /**
+ * return the ECDomainParameters object for the given OID, null if it
+ * isn't present.
+ *
+ * @param oid an object identifier representing a named parameters, if present.
+ */
+ public static ECDomainParameters GetByOid(
+ DerObjectIdentifier oid)
+ {
+ return (ECDomainParameters) parameters[oid];
+ }
+
+ /**
+ * returns an enumeration containing the name strings for curves
+ * contained in this structure.
+ */
+ public static IEnumerable Names
+ {
+ get { return new EnumerableProxy(names.Values); }
+ }
+
+ public static ECDomainParameters GetByName(
+ string name)
+ {
+ DerObjectIdentifier oid = (DerObjectIdentifier) objIds[name];
+
+ if (oid != null)
+ {
+ return (ECDomainParameters) parameters[oid];
+ }
+
+ return null;
+ }
+
+ /**
+ * return the named curve name represented by the given object identifier.
+ */
+ public static string GetName(
+ DerObjectIdentifier oid)
+ {
+ return (string) names[oid];
+ }
+
+ public static DerObjectIdentifier GetOid(
+ string name)
+ {
+ return (DerObjectIdentifier) objIds[name];
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cryptopro/ECGOST3410ParamSetParameters.cs b/bc-sharp-crypto/src/asn1/cryptopro/ECGOST3410ParamSetParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8e568a229cd86cdd470c819d1ac35a086c32347e
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cryptopro/ECGOST3410ParamSetParameters.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+ public class ECGost3410ParamSetParameters
+ : Asn1Encodable
+ {
+ internal readonly DerInteger p, q, a, b, x, y;
+
+ public static ECGost3410ParamSetParameters GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static ECGost3410ParamSetParameters GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is ECGost3410ParamSetParameters)
+ {
+ return (ECGost3410ParamSetParameters) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new ECGost3410ParamSetParameters((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("Invalid GOST3410Parameter: " + Platform.GetTypeName(obj));
+ }
+
+ public ECGost3410ParamSetParameters(
+ BigInteger a,
+ BigInteger b,
+ BigInteger p,
+ BigInteger q,
+ int x,
+ BigInteger y)
+ {
+ this.a = new DerInteger(a);
+ this.b = new DerInteger(b);
+ this.p = new DerInteger(p);
+ this.q = new DerInteger(q);
+ this.x = new DerInteger(x);
+ this.y = new DerInteger(y);
+ }
+
+ public ECGost3410ParamSetParameters(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 6)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ this.a = DerInteger.GetInstance(seq[0]);
+ this.b = DerInteger.GetInstance(seq[1]);
+ this.p = DerInteger.GetInstance(seq[2]);
+ this.q = DerInteger.GetInstance(seq[3]);
+ this.x = DerInteger.GetInstance(seq[4]);
+ this.y = DerInteger.GetInstance(seq[5]);
+ }
+
+ public BigInteger P
+ {
+ get { return p.PositiveValue; }
+ }
+
+ public BigInteger Q
+ {
+ get { return q.PositiveValue; }
+ }
+
+ public BigInteger A
+ {
+ get { return a.PositiveValue; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(a, b, p, q, x, y);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cryptopro/GOST28147Parameters.cs b/bc-sharp-crypto/src/asn1/cryptopro/GOST28147Parameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fc0d792d1876c3bc1251c5d3a8b9f2724a23946a
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cryptopro/GOST28147Parameters.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+ public class Gost28147Parameters
+ : Asn1Encodable
+ {
+ private readonly Asn1OctetString iv;
+ private readonly DerObjectIdentifier paramSet;
+
+ public static Gost28147Parameters GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static Gost28147Parameters GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is Gost28147Parameters)
+ {
+ return (Gost28147Parameters) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new Gost28147Parameters((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("Invalid GOST3410Parameter: " + Platform.GetTypeName(obj));
+ }
+
+ private Gost28147Parameters(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ this.iv = Asn1OctetString.GetInstance(seq[0]);
+ this.paramSet = DerObjectIdentifier.GetInstance(seq[1]);
+ }
+
+ /**
+ *
+ * Gost28147-89-Parameters ::=
+ * SEQUENCE {
+ * iv Gost28147-89-IV,
+ * encryptionParamSet OBJECT IDENTIFIER
+ * }
+ *
+ * Gost28147-89-IV ::= OCTET STRING (SIZE (8))
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(iv, paramSet);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cryptopro/GOST3410NamedParameters.cs b/bc-sharp-crypto/src/asn1/cryptopro/GOST3410NamedParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..66dba51d73be119d3fe721b22efad847ba030a5e
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cryptopro/GOST3410NamedParameters.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+ /**
+ * table of the available named parameters for GOST 3410-94.
+ */
+ public sealed class Gost3410NamedParameters
+ {
+ private Gost3410NamedParameters()
+ {
+ }
+
+ private static readonly IDictionary objIds = Platform.CreateHashtable();
+ private static readonly IDictionary parameters = Platform.CreateHashtable();
+
+ private static readonly Gost3410ParamSetParameters cryptoProA = new Gost3410ParamSetParameters(
+ 1024,
+ new BigInteger("127021248288932417465907042777176443525787653508916535812817507265705031260985098497423188333483401180925999995120988934130659205614996724254121049274349357074920312769561451689224110579311248812610229678534638401693520013288995000362260684222750813532307004517341633685004541062586971416883686778842537820383"),
+ new BigInteger("68363196144955700784444165611827252895102170888761442055095051287550314083023"),
+ new BigInteger("100997906755055304772081815535925224869841082572053457874823515875577147990529272777244152852699298796483356699682842027972896052747173175480590485607134746852141928680912561502802222185647539190902656116367847270145019066794290930185446216399730872221732889830323194097355403213400972588322876850946740663962")
+ // validationAlgorithm {
+ // algorithm
+ // id-GostR3410-94-bBis,
+ // parameters
+ // GostR3410-94-ValidationBisParameters: {
+ // x0 1376285941,
+ // c 3996757427
+ // }
+ // }
+
+ );
+
+ private static readonly Gost3410ParamSetParameters cryptoProB = new Gost3410ParamSetParameters(
+ 1024,
+ new BigInteger("139454871199115825601409655107690713107041707059928031797758001454375765357722984094124368522288239833039114681648076688236921220737322672160740747771700911134550432053804647694904686120113087816240740184800477047157336662926249423571248823968542221753660143391485680840520336859458494803187341288580489525163"),
+ new BigInteger("79885141663410976897627118935756323747307951916507639758300472692338873533959"),
+ new BigInteger("42941826148615804143873447737955502392672345968607143066798112994089471231420027060385216699563848719957657284814898909770759462613437669456364882730370838934791080835932647976778601915343474400961034231316672578686920482194932878633360203384797092684342247621055760235016132614780652761028509445403338652341")
+ // validationAlgorithm {
+ // algorithm
+ // id-GostR3410-94-bBis,
+ // parameters
+ // GostR3410-94-ValidationBisParameters: {
+ // x0 1536654555,
+ // c 1855361757,
+ // d 14408629386140014567655
+ //4902939282056547857802241461782996702017713059974755104394739915140
+ //6115284791024439062735788342744854120601660303926203867703556828005
+ //8957203818114895398976594425537561271800850306
+ // }
+ // }
+ //}
+ );
+
+ private static readonly Gost3410ParamSetParameters cryptoProXchA = new Gost3410ParamSetParameters(
+ 1024,
+ new BigInteger("142011741597563481196368286022318089743276138395243738762872573441927459393512718973631166078467600360848946623567625795282774719212241929071046134208380636394084512691828894000571524625445295769349356752728956831541775441763139384457191755096847107846595662547942312293338483924514339614727760681880609734239"),
+ new BigInteger("91771529896554605945588149018382750217296858393520724172743325725474374979801"),
+ new BigInteger("133531813272720673433859519948319001217942375967847486899482359599369642528734712461590403327731821410328012529253871914788598993103310567744136196364803064721377826656898686468463277710150809401182608770201615324990468332931294920912776241137878030224355746606283971659376426832674269780880061631528163475887")
+ );
+
+ static Gost3410NamedParameters()
+ {
+ parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProA] = cryptoProA;
+ parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProB] = cryptoProB;
+ //parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProC] = cryptoProC;
+ //parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProD] = cryptoProD;
+ parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProXchA] = cryptoProXchA;
+ //parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProXchB] = cryptoProXchA;
+ //parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProXchC] = cryptoProXchA;
+
+ objIds["GostR3410-94-CryptoPro-A"] = CryptoProObjectIdentifiers.GostR3410x94CryptoProA;
+ objIds["GostR3410-94-CryptoPro-B"] = CryptoProObjectIdentifiers.GostR3410x94CryptoProB;
+ objIds["GostR3410-94-CryptoPro-XchA"] = CryptoProObjectIdentifiers.GostR3410x94CryptoProXchA;
+ }
+
+ /**
+ * return the GOST3410ParamSetParameters object for the given OID, null if it
+ * isn't present.
+ *
+ * @param oid an object identifier representing a named parameters, if present.
+ */
+ public static Gost3410ParamSetParameters GetByOid(
+ DerObjectIdentifier oid)
+ {
+ return (Gost3410ParamSetParameters) parameters[oid];
+ }
+
+ /**
+ * returns an enumeration containing the name strings for parameters
+ * contained in this structure.
+ */
+ public static IEnumerable Names
+ {
+ get { return new EnumerableProxy(objIds.Keys); }
+ }
+
+ public static Gost3410ParamSetParameters GetByName(
+ string name)
+ {
+ DerObjectIdentifier oid = (DerObjectIdentifier) objIds[name];
+
+ if (oid != null)
+ {
+ return (Gost3410ParamSetParameters) parameters[oid];
+ }
+
+ return null;
+ }
+
+ public static DerObjectIdentifier GetOid(
+ string name)
+ {
+ return (DerObjectIdentifier) objIds[name];
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cryptopro/GOST3410ParamSetParameters.cs b/bc-sharp-crypto/src/asn1/cryptopro/GOST3410ParamSetParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b347f8dbd02cbc89871a4f7c65426b15ea99496a
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cryptopro/GOST3410ParamSetParameters.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+ public class Gost3410ParamSetParameters
+ : Asn1Encodable
+ {
+ private readonly int keySize;
+ private readonly DerInteger p, q, a;
+
+ public static Gost3410ParamSetParameters GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static Gost3410ParamSetParameters GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is Gost3410ParamSetParameters)
+ {
+ return (Gost3410ParamSetParameters) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new Gost3410ParamSetParameters((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("Invalid GOST3410Parameter: " + Platform.GetTypeName(obj));
+ }
+
+ public Gost3410ParamSetParameters(
+ int keySize,
+ BigInteger p,
+ BigInteger q,
+ BigInteger a)
+ {
+ this.keySize = keySize;
+ this.p = new DerInteger(p);
+ this.q = new DerInteger(q);
+ this.a = new DerInteger(a);
+ }
+
+ private Gost3410ParamSetParameters(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 4)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ this.keySize = DerInteger.GetInstance(seq[0]).Value.IntValue;
+ this.p = DerInteger.GetInstance(seq[1]);
+ this.q = DerInteger.GetInstance(seq[2]);
+ this.a = DerInteger.GetInstance(seq[3]);
+ }
+
+ public int KeySize
+ {
+ get { return keySize; }
+ }
+
+ public BigInteger P
+ {
+ get { return p.PositiveValue; }
+ }
+
+ public BigInteger Q
+ {
+ get { return q.PositiveValue; }
+ }
+
+ public BigInteger A
+ {
+ get { return a.PositiveValue; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(new DerInteger(keySize), p, q, a);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/cryptopro/GOST3410PublicKeyAlgParameters.cs b/bc-sharp-crypto/src/asn1/cryptopro/GOST3410PublicKeyAlgParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..10c45ba4d5c1727614b8a32a981e2daceff31279
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/cryptopro/GOST3410PublicKeyAlgParameters.cs
@@ -0,0 +1,99 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+ public class Gost3410PublicKeyAlgParameters
+ : Asn1Encodable
+ {
+ private DerObjectIdentifier publicKeyParamSet;
+ private DerObjectIdentifier digestParamSet;
+ private DerObjectIdentifier encryptionParamSet;
+
+ public static Gost3410PublicKeyAlgParameters GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static Gost3410PublicKeyAlgParameters GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is Gost3410PublicKeyAlgParameters)
+ {
+ return (Gost3410PublicKeyAlgParameters) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new Gost3410PublicKeyAlgParameters((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("Invalid GOST3410Parameter: " + Platform.GetTypeName(obj));
+ }
+
+ public Gost3410PublicKeyAlgParameters(
+ DerObjectIdentifier publicKeyParamSet,
+ DerObjectIdentifier digestParamSet)
+ : this (publicKeyParamSet, digestParamSet, null)
+ {
+ }
+
+ public Gost3410PublicKeyAlgParameters(
+ DerObjectIdentifier publicKeyParamSet,
+ DerObjectIdentifier digestParamSet,
+ DerObjectIdentifier encryptionParamSet)
+ {
+ if (publicKeyParamSet == null)
+ throw new ArgumentNullException("publicKeyParamSet");
+ if (digestParamSet == null)
+ throw new ArgumentNullException("digestParamSet");
+
+ this.publicKeyParamSet = publicKeyParamSet;
+ this.digestParamSet = digestParamSet;
+ this.encryptionParamSet = encryptionParamSet;
+ }
+
+ public Gost3410PublicKeyAlgParameters(
+ Asn1Sequence seq)
+ {
+ this.publicKeyParamSet = (DerObjectIdentifier) seq[0];
+ this.digestParamSet = (DerObjectIdentifier) seq[1];
+
+ if (seq.Count > 2)
+ {
+ this.encryptionParamSet = (DerObjectIdentifier) seq[2];
+ }
+ }
+
+ public DerObjectIdentifier PublicKeyParamSet
+ {
+ get { return publicKeyParamSet; }
+ }
+
+ public DerObjectIdentifier DigestParamSet
+ {
+ get { return digestParamSet; }
+ }
+
+ public DerObjectIdentifier EncryptionParamSet
+ {
+ get { return encryptionParamSet; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ publicKeyParamSet, digestParamSet);
+
+ if (encryptionParamSet != null)
+ {
+ v.Add(encryptionParamSet);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/eac/EACObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/eac/EACObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d54ef0ebaf30afad6e105ac90965ce1f5a709c1a
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/eac/EACObjectIdentifiers.cs
@@ -0,0 +1,50 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Eac
+{
+ public abstract class EacObjectIdentifiers
+ {
+ // bsi-de OBJECT IDENTIFIER ::= {
+ // itu-t(0) identified-organization(4) etsi(0)
+ // reserved(127) etsi-identified-organization(0) 7
+ // }
+ public static readonly DerObjectIdentifier bsi_de = new DerObjectIdentifier("0.4.0.127.0.7");
+
+ // id-PK OBJECT IDENTIFIER ::= {
+ // bsi-de protocols(2) smartcard(2) 1
+ // }
+ public static readonly DerObjectIdentifier id_PK = new DerObjectIdentifier(bsi_de + ".2.2.1");
+
+ public static readonly DerObjectIdentifier id_PK_DH = new DerObjectIdentifier(id_PK + ".1");
+ public static readonly DerObjectIdentifier id_PK_ECDH = new DerObjectIdentifier(id_PK + ".2");
+
+ // id-CA OBJECT IDENTIFIER ::= {
+ // bsi-de protocols(2) smartcard(2) 3
+ // }
+ public static readonly DerObjectIdentifier id_CA = new DerObjectIdentifier(bsi_de + ".2.2.3");
+ public static readonly DerObjectIdentifier id_CA_DH = new DerObjectIdentifier(id_CA + ".1");
+ public static readonly DerObjectIdentifier id_CA_DH_3DES_CBC_CBC = new DerObjectIdentifier(id_CA_DH + ".1");
+ public static readonly DerObjectIdentifier id_CA_ECDH = new DerObjectIdentifier(id_CA + ".2");
+ public static readonly DerObjectIdentifier id_CA_ECDH_3DES_CBC_CBC = new DerObjectIdentifier(id_CA_ECDH + ".1");
+
+ //
+ // id-TA OBJECT IDENTIFIER ::= {
+ // bsi-de protocols(2) smartcard(2) 2
+ // }
+ public static readonly DerObjectIdentifier id_TA = new DerObjectIdentifier(bsi_de + ".2.2.2");
+
+ public static readonly DerObjectIdentifier id_TA_RSA = new DerObjectIdentifier(id_TA + ".1");
+ public static readonly DerObjectIdentifier id_TA_RSA_v1_5_SHA_1 = new DerObjectIdentifier(id_TA_RSA + ".1");
+ public static readonly DerObjectIdentifier id_TA_RSA_v1_5_SHA_256 = new DerObjectIdentifier(id_TA_RSA + ".2");
+ public static readonly DerObjectIdentifier id_TA_RSA_PSS_SHA_1 = new DerObjectIdentifier(id_TA_RSA + ".3");
+ public static readonly DerObjectIdentifier id_TA_RSA_PSS_SHA_256 = new DerObjectIdentifier(id_TA_RSA + ".4");
+ public static readonly DerObjectIdentifier id_TA_ECDSA = new DerObjectIdentifier(id_TA + ".2");
+ public static readonly DerObjectIdentifier id_TA_ECDSA_SHA_1 = new DerObjectIdentifier(id_TA_ECDSA + ".1");
+ public static readonly DerObjectIdentifier id_TA_ECDSA_SHA_224 = new DerObjectIdentifier(id_TA_ECDSA + ".2");
+ public static readonly DerObjectIdentifier id_TA_ECDSA_SHA_256 = new DerObjectIdentifier(id_TA_ECDSA + ".3");
+ public static readonly DerObjectIdentifier id_TA_ECDSA_SHA_384 = new DerObjectIdentifier(id_TA_ECDSA + ".4");
+ public static readonly DerObjectIdentifier id_TA_ECDSA_SHA_512 = new DerObjectIdentifier(id_TA_ECDSA + ".5");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/CertificateValues.cs b/bc-sharp-crypto/src/asn1/esf/CertificateValues.cs
new file mode 100644
index 0000000000000000000000000000000000000000..30a719177176fe33eb5f9abc7f1c281b048a1bc5
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/CertificateValues.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ /// RFC 3126: 4.3.1 Certificate Values Attribute Definition
+ ///
+ /// CertificateValues ::= SEQUENCE OF Certificate
+ ///
+ ///
+ public class CertificateValues
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence certificates;
+
+ public static CertificateValues GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is CertificateValues)
+ return (CertificateValues) obj;
+
+ if (obj is Asn1Sequence)
+ return new CertificateValues((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'CertificateValues' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ private CertificateValues(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+
+ foreach (Asn1Encodable ae in seq)
+ {
+ X509CertificateStructure.GetInstance(ae.ToAsn1Object());
+ }
+
+ this.certificates = seq;
+ }
+
+ public CertificateValues(
+ params X509CertificateStructure[] certificates)
+ {
+ if (certificates == null)
+ throw new ArgumentNullException("certificates");
+
+ this.certificates = new DerSequence(certificates);
+ }
+
+ public CertificateValues(
+ IEnumerable certificates)
+ {
+ if (certificates == null)
+ throw new ArgumentNullException("certificates");
+ if (!CollectionUtilities.CheckElementsAreOfType(certificates, typeof(X509CertificateStructure)))
+ throw new ArgumentException("Must contain only 'X509CertificateStructure' objects", "certificates");
+
+ this.certificates = new DerSequence(
+ Asn1EncodableVector.FromEnumerable(certificates));
+ }
+
+ public X509CertificateStructure[] GetCertificates()
+ {
+ X509CertificateStructure[] result = new X509CertificateStructure[certificates.Count];
+ for (int i = 0; i < certificates.Count; ++i)
+ {
+ result[i] = X509CertificateStructure.GetInstance(certificates[i]);
+ }
+ return result;
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return certificates;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/CommitmentTypeIdentifier.cs b/bc-sharp-crypto/src/asn1/esf/CommitmentTypeIdentifier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..65cd45b4af9a05a9659c82aa91678289eca522a1
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/CommitmentTypeIdentifier.cs
@@ -0,0 +1,17 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ public abstract class CommitmentTypeIdentifier
+ {
+ public static readonly DerObjectIdentifier ProofOfOrigin = PkcsObjectIdentifiers.IdCtiEtsProofOfOrigin;
+ public static readonly DerObjectIdentifier ProofOfReceipt = PkcsObjectIdentifiers.IdCtiEtsProofOfReceipt;
+ public static readonly DerObjectIdentifier ProofOfDelivery = PkcsObjectIdentifiers.IdCtiEtsProofOfDelivery;
+ public static readonly DerObjectIdentifier ProofOfSender = PkcsObjectIdentifiers.IdCtiEtsProofOfSender;
+ public static readonly DerObjectIdentifier ProofOfApproval = PkcsObjectIdentifiers.IdCtiEtsProofOfApproval;
+ public static readonly DerObjectIdentifier ProofOfCreation = PkcsObjectIdentifiers.IdCtiEtsProofOfCreation;
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/CommitmentTypeIndication.cs b/bc-sharp-crypto/src/asn1/esf/CommitmentTypeIndication.cs
new file mode 100644
index 0000000000000000000000000000000000000000..196a613a638e060a52adb9753e830e09dc57e126
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/CommitmentTypeIndication.cs
@@ -0,0 +1,95 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ public class CommitmentTypeIndication
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier commitmentTypeId;
+ private readonly Asn1Sequence commitmentTypeQualifier;
+
+ public static CommitmentTypeIndication GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is CommitmentTypeIndication)
+ return (CommitmentTypeIndication) obj;
+
+ if (obj is Asn1Sequence)
+ return new CommitmentTypeIndication((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'CommitmentTypeIndication' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ public CommitmentTypeIndication(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+ if (seq.Count < 1 || seq.Count > 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ this.commitmentTypeId = (DerObjectIdentifier) seq[0].ToAsn1Object();
+
+ if (seq.Count > 1)
+ {
+ this.commitmentTypeQualifier = (Asn1Sequence) seq[1].ToAsn1Object();
+ }
+ }
+
+ public CommitmentTypeIndication(
+ DerObjectIdentifier commitmentTypeId)
+ : this(commitmentTypeId, null)
+ {
+ }
+
+ public CommitmentTypeIndication(
+ DerObjectIdentifier commitmentTypeId,
+ Asn1Sequence commitmentTypeQualifier)
+ {
+ if (commitmentTypeId == null)
+ throw new ArgumentNullException("commitmentTypeId");
+
+ this.commitmentTypeId = commitmentTypeId;
+
+ if (commitmentTypeQualifier != null)
+ {
+ this.commitmentTypeQualifier = commitmentTypeQualifier;
+ }
+ }
+
+ public DerObjectIdentifier CommitmentTypeID
+ {
+ get { return commitmentTypeId; }
+ }
+
+ public Asn1Sequence CommitmentTypeQualifier
+ {
+ get { return commitmentTypeQualifier; }
+ }
+
+ /**
+ *
+ * CommitmentTypeIndication ::= SEQUENCE {
+ * commitmentTypeId CommitmentTypeIdentifier,
+ * commitmentTypeQualifier SEQUENCE SIZE (1..MAX) OF
+ * CommitmentTypeQualifier OPTIONAL }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(commitmentTypeId);
+
+ if (commitmentTypeQualifier != null)
+ {
+ v.Add(commitmentTypeQualifier);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/CommitmentTypeQualifier.cs b/bc-sharp-crypto/src/asn1/esf/CommitmentTypeQualifier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..30bf0edfc56f31a2ced19dce7e5f3365806e9904
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/CommitmentTypeQualifier.cs
@@ -0,0 +1,119 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ /**
+ * Commitment type qualifiers, used in the Commitment-Type-Indication attribute (RFC3126).
+ *
+ *
+ * CommitmentTypeQualifier ::= SEQUENCE {
+ * commitmentTypeIdentifier CommitmentTypeIdentifier,
+ * qualifier ANY DEFINED BY commitmentTypeIdentifier OPTIONAL }
+ *
+ */
+ public class CommitmentTypeQualifier
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier commitmentTypeIdentifier;
+ private readonly Asn1Object qualifier;
+
+ /**
+ * Creates a new CommitmentTypeQualifier
instance.
+ *
+ * @param commitmentTypeIdentifier a CommitmentTypeIdentifier
value
+ */
+ public CommitmentTypeQualifier(
+ DerObjectIdentifier commitmentTypeIdentifier)
+ : this(commitmentTypeIdentifier, null)
+ {
+ }
+
+ /**
+ * Creates a new CommitmentTypeQualifier
instance.
+ *
+ * @param commitmentTypeIdentifier a CommitmentTypeIdentifier
value
+ * @param qualifier the qualifier, defined by the above field.
+ */
+ public CommitmentTypeQualifier(
+ DerObjectIdentifier commitmentTypeIdentifier,
+ Asn1Encodable qualifier)
+ {
+ if (commitmentTypeIdentifier == null)
+ throw new ArgumentNullException("commitmentTypeIdentifier");
+
+ this.commitmentTypeIdentifier = commitmentTypeIdentifier;
+
+ if (qualifier != null)
+ {
+ this.qualifier = qualifier.ToAsn1Object();
+ }
+ }
+
+ /**
+ * Creates a new CommitmentTypeQualifier
instance.
+ *
+ * @param as CommitmentTypeQualifier
structure
+ * encoded as an Asn1Sequence.
+ */
+ public CommitmentTypeQualifier(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+ if (seq.Count < 1 || seq.Count > 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ commitmentTypeIdentifier = (DerObjectIdentifier) seq[0].ToAsn1Object();
+
+ if (seq.Count > 1)
+ {
+ qualifier = seq[1].ToAsn1Object();
+ }
+ }
+
+ public static CommitmentTypeQualifier GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is CommitmentTypeQualifier)
+ return (CommitmentTypeQualifier) obj;
+
+ if (obj is Asn1Sequence)
+ return new CommitmentTypeQualifier((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'CommitmentTypeQualifier' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ public DerObjectIdentifier CommitmentTypeIdentifier
+ {
+ get { return commitmentTypeIdentifier; }
+ }
+
+ public Asn1Object Qualifier
+ {
+ get { return qualifier; }
+ }
+
+ /**
+ * Returns a DER-encodable representation of this instance.
+ *
+ * @return a Asn1Object
value
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ commitmentTypeIdentifier);
+
+ if (qualifier != null)
+ {
+ v.Add(qualifier);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/CompleteCertificateRefs.cs b/bc-sharp-crypto/src/asn1/esf/CompleteCertificateRefs.cs
new file mode 100644
index 0000000000000000000000000000000000000000..af93700be76dbd1b9a6834ce1df549cef5748c8f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/CompleteCertificateRefs.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ /// RFC 3126: 4.2.1 Complete Certificate Refs Attribute Definition
+ ///
+ /// CompleteCertificateRefs ::= SEQUENCE OF OtherCertID
+ ///
+ ///
+ public class CompleteCertificateRefs
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence otherCertIDs;
+
+ public static CompleteCertificateRefs GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is CompleteCertificateRefs)
+ return (CompleteCertificateRefs) obj;
+
+ if (obj is Asn1Sequence)
+ return new CompleteCertificateRefs((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'CompleteCertificateRefs' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ private CompleteCertificateRefs(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+
+ foreach (Asn1Encodable ae in seq)
+ {
+ OtherCertID.GetInstance(ae.ToAsn1Object());
+ }
+
+ this.otherCertIDs = seq;
+ }
+
+ public CompleteCertificateRefs(
+ params OtherCertID[] otherCertIDs)
+ {
+ if (otherCertIDs == null)
+ throw new ArgumentNullException("otherCertIDs");
+
+ this.otherCertIDs = new DerSequence(otherCertIDs);
+ }
+
+ public CompleteCertificateRefs(
+ IEnumerable otherCertIDs)
+ {
+ if (otherCertIDs == null)
+ throw new ArgumentNullException("otherCertIDs");
+ if (!CollectionUtilities.CheckElementsAreOfType(otherCertIDs, typeof(OtherCertID)))
+ throw new ArgumentException("Must contain only 'OtherCertID' objects", "otherCertIDs");
+
+ this.otherCertIDs = new DerSequence(
+ Asn1EncodableVector.FromEnumerable(otherCertIDs));
+ }
+
+ public OtherCertID[] GetOtherCertIDs()
+ {
+ OtherCertID[] result = new OtherCertID[otherCertIDs.Count];
+ for (int i = 0; i < otherCertIDs.Count; ++i)
+ {
+ result[i] = OtherCertID.GetInstance(otherCertIDs[i].ToAsn1Object());
+ }
+ return result;
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return otherCertIDs;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/CompleteRevocationRefs.cs b/bc-sharp-crypto/src/asn1/esf/CompleteRevocationRefs.cs
new file mode 100644
index 0000000000000000000000000000000000000000..348e63fdb8e619f3404e82d8285410e51629cba5
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/CompleteRevocationRefs.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ /// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+ ///
+ /// CompleteRevocationRefs ::= SEQUENCE OF CrlOcspRef
+ ///
+ ///
+ public class CompleteRevocationRefs
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence crlOcspRefs;
+
+ public static CompleteRevocationRefs GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is CompleteRevocationRefs)
+ return (CompleteRevocationRefs) obj;
+
+ if (obj is Asn1Sequence)
+ return new CompleteRevocationRefs((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'CompleteRevocationRefs' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ private CompleteRevocationRefs(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+
+ foreach (Asn1Encodable ae in seq)
+ {
+ CrlOcspRef.GetInstance(ae.ToAsn1Object());
+ }
+
+ this.crlOcspRefs = seq;
+ }
+
+ public CompleteRevocationRefs(
+ params CrlOcspRef[] crlOcspRefs)
+ {
+ if (crlOcspRefs == null)
+ throw new ArgumentNullException("crlOcspRefs");
+
+ this.crlOcspRefs = new DerSequence(crlOcspRefs);
+ }
+
+ public CompleteRevocationRefs(
+ IEnumerable crlOcspRefs)
+ {
+ if (crlOcspRefs == null)
+ throw new ArgumentNullException("crlOcspRefs");
+ if (!CollectionUtilities.CheckElementsAreOfType(crlOcspRefs, typeof(CrlOcspRef)))
+ throw new ArgumentException("Must contain only 'CrlOcspRef' objects", "crlOcspRefs");
+
+ this.crlOcspRefs = new DerSequence(
+ Asn1EncodableVector.FromEnumerable(crlOcspRefs));
+ }
+
+ public CrlOcspRef[] GetCrlOcspRefs()
+ {
+ CrlOcspRef[] result = new CrlOcspRef[crlOcspRefs.Count];
+ for (int i = 0; i < crlOcspRefs.Count; ++i)
+ {
+ result[i] = CrlOcspRef.GetInstance(crlOcspRefs[i].ToAsn1Object());
+ }
+ return result;
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return crlOcspRefs;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/CrlIdentifier.cs b/bc-sharp-crypto/src/asn1/esf/CrlIdentifier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..96b50e211a0e904389cfba731d276d5183898e59
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/CrlIdentifier.cs
@@ -0,0 +1,111 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ /// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+ ///
+ /// CrlIdentifier ::= SEQUENCE
+ /// {
+ /// crlissuer Name,
+ /// crlIssuedTime UTCTime,
+ /// crlNumber INTEGER OPTIONAL
+ /// }
+ ///
+ ///
+ public class CrlIdentifier
+ : Asn1Encodable
+ {
+ private readonly X509Name crlIssuer;
+ private readonly DerUtcTime crlIssuedTime;
+ private readonly DerInteger crlNumber;
+
+ public static CrlIdentifier GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is CrlIdentifier)
+ return (CrlIdentifier) obj;
+
+ if (obj is Asn1Sequence)
+ return new CrlIdentifier((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'CrlIdentifier' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ private CrlIdentifier(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+ if (seq.Count < 2 || seq.Count > 3)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ this.crlIssuer = X509Name.GetInstance(seq[0]);
+ this.crlIssuedTime = DerUtcTime.GetInstance(seq[1]);
+
+ if (seq.Count > 2)
+ {
+ this.crlNumber = DerInteger.GetInstance(seq[2]);
+ }
+ }
+
+ public CrlIdentifier(
+ X509Name crlIssuer,
+ DateTime crlIssuedTime)
+ : this(crlIssuer, crlIssuedTime, null)
+ {
+ }
+
+ public CrlIdentifier(
+ X509Name crlIssuer,
+ DateTime crlIssuedTime,
+ BigInteger crlNumber)
+ {
+ if (crlIssuer == null)
+ throw new ArgumentNullException("crlIssuer");
+
+ this.crlIssuer = crlIssuer;
+ this.crlIssuedTime = new DerUtcTime(crlIssuedTime);
+
+ if (crlNumber != null)
+ {
+ this.crlNumber = new DerInteger(crlNumber);
+ }
+ }
+
+ public X509Name CrlIssuer
+ {
+ get { return crlIssuer; }
+ }
+
+ public DateTime CrlIssuedTime
+ {
+ get { return crlIssuedTime.ToAdjustedDateTime(); }
+ }
+
+ public BigInteger CrlNumber
+ {
+ get { return crlNumber == null ? null : crlNumber.Value; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ crlIssuer.ToAsn1Object(), crlIssuedTime);
+
+ if (crlNumber != null)
+ {
+ v.Add(crlNumber);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/CrlListID.cs b/bc-sharp-crypto/src/asn1/esf/CrlListID.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fbd4fb27cffcd8aa8ac42d266e0c6e7cf5e2b810
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/CrlListID.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ /// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+ ///
+ /// CRLListID ::= SEQUENCE
+ /// {
+ /// crls SEQUENCE OF CrlValidatedID
+ /// }
+ ///
+ ///
+ public class CrlListID
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence crls;
+
+ public static CrlListID GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is CrlListID)
+ return (CrlListID) obj;
+
+ if (obj is Asn1Sequence)
+ return new CrlListID((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'CrlListID' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ private CrlListID(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+ if (seq.Count != 1)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ this.crls = (Asn1Sequence) seq[0].ToAsn1Object();
+
+ foreach (Asn1Encodable ae in this.crls)
+ {
+ CrlValidatedID.GetInstance(ae.ToAsn1Object());
+ }
+ }
+
+ public CrlListID(
+ params CrlValidatedID[] crls)
+ {
+ if (crls == null)
+ throw new ArgumentNullException("crls");
+
+ this.crls = new DerSequence(crls);
+ }
+
+ public CrlListID(
+ IEnumerable crls)
+ {
+ if (crls == null)
+ throw new ArgumentNullException("crls");
+ if (!CollectionUtilities.CheckElementsAreOfType(crls, typeof(CrlValidatedID)))
+ throw new ArgumentException("Must contain only 'CrlValidatedID' objects", "crls");
+
+ this.crls = new DerSequence(
+ Asn1EncodableVector.FromEnumerable(crls));
+ }
+
+ public CrlValidatedID[] GetCrls()
+ {
+ CrlValidatedID[] result = new CrlValidatedID[crls.Count];
+ for (int i = 0; i < crls.Count; ++i)
+ {
+ result[i] = CrlValidatedID.GetInstance(crls[i].ToAsn1Object());
+ }
+ return result;
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(crls);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/CrlOcspRef.cs b/bc-sharp-crypto/src/asn1/esf/CrlOcspRef.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6153e0c5364b24ede56fa18190c5e3aeca3b38dc
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/CrlOcspRef.cs
@@ -0,0 +1,113 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ /// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+ ///
+ /// CrlOcspRef ::= SEQUENCE {
+ /// crlids [0] CRLListID OPTIONAL,
+ /// ocspids [1] OcspListID OPTIONAL,
+ /// otherRev [2] OtherRevRefs OPTIONAL
+ /// }
+ ///
+ ///
+ public class CrlOcspRef
+ : Asn1Encodable
+ {
+ private readonly CrlListID crlids;
+ private readonly OcspListID ocspids;
+ private readonly OtherRevRefs otherRev;
+
+ public static CrlOcspRef GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is CrlOcspRef)
+ return (CrlOcspRef) obj;
+
+ if (obj is Asn1Sequence)
+ return new CrlOcspRef((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'CrlOcspRef' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ private CrlOcspRef(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+
+ foreach (Asn1TaggedObject taggedObj in seq)
+ {
+ Asn1Object asn1Obj = taggedObj.GetObject();
+
+ switch (taggedObj.TagNo)
+ {
+ case 0:
+ this.crlids = CrlListID.GetInstance(asn1Obj);
+ break;
+ case 1:
+ this.ocspids = OcspListID.GetInstance(asn1Obj);
+ break;
+ case 2:
+ this.otherRev = OtherRevRefs.GetInstance(asn1Obj);
+ break;
+ default:
+ throw new ArgumentException("Illegal tag in CrlOcspRef", "seq");
+ }
+ }
+ }
+
+ public CrlOcspRef(
+ CrlListID crlids,
+ OcspListID ocspids,
+ OtherRevRefs otherRev)
+ {
+ this.crlids = crlids;
+ this.ocspids = ocspids;
+ this.otherRev = otherRev;
+ }
+
+ public CrlListID CrlIDs
+ {
+ get { return crlids; }
+ }
+
+ public OcspListID OcspIDs
+ {
+ get { return ocspids; }
+ }
+
+ public OtherRevRefs OtherRev
+ {
+ get { return otherRev; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (crlids != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, crlids.ToAsn1Object()));
+ }
+
+ if (ocspids != null)
+ {
+ v.Add(new DerTaggedObject(true, 1, ocspids.ToAsn1Object()));
+ }
+
+ if (otherRev != null)
+ {
+ v.Add(new DerTaggedObject(true, 2, otherRev.ToAsn1Object()));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/CrlValidatedID.cs b/bc-sharp-crypto/src/asn1/esf/CrlValidatedID.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e8cd17a194349af694bd15229c9e76c89befca44
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/CrlValidatedID.cs
@@ -0,0 +1,91 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ /// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+ ///
+ /// CrlValidatedID ::= SEQUENCE {
+ /// crlHash OtherHash,
+ /// crlIdentifier CrlIdentifier OPTIONAL}
+ ///
+ ///
+ public class CrlValidatedID
+ : Asn1Encodable
+ {
+ private readonly OtherHash crlHash;
+ private readonly CrlIdentifier crlIdentifier;
+
+ public static CrlValidatedID GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is CrlValidatedID)
+ return (CrlValidatedID) obj;
+
+ if (obj is Asn1Sequence)
+ return new CrlValidatedID((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'CrlValidatedID' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ private CrlValidatedID(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+ if (seq.Count < 1 || seq.Count > 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ this.crlHash = OtherHash.GetInstance(seq[0].ToAsn1Object());
+
+ if (seq.Count > 1)
+ {
+ this.crlIdentifier = CrlIdentifier.GetInstance(seq[1].ToAsn1Object());
+ }
+ }
+
+ public CrlValidatedID(
+ OtherHash crlHash)
+ : this(crlHash, null)
+ {
+ }
+
+ public CrlValidatedID(
+ OtherHash crlHash,
+ CrlIdentifier crlIdentifier)
+ {
+ if (crlHash == null)
+ throw new ArgumentNullException("crlHash");
+
+ this.crlHash = crlHash;
+ this.crlIdentifier = crlIdentifier;
+ }
+
+ public OtherHash CrlHash
+ {
+ get { return crlHash; }
+ }
+
+ public CrlIdentifier CrlIdentifier
+ {
+ get { return crlIdentifier; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(crlHash.ToAsn1Object());
+
+ if (crlIdentifier != null)
+ {
+ v.Add(crlIdentifier.ToAsn1Object());
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/ESFAttributes.cs b/bc-sharp-crypto/src/asn1/esf/ESFAttributes.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9401ffb8e2e065d33b1d0838d0c3e667332c1bee
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/ESFAttributes.cs
@@ -0,0 +1,25 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ public abstract class EsfAttributes
+ {
+ public static readonly DerObjectIdentifier SigPolicyId = PkcsObjectIdentifiers.IdAAEtsSigPolicyID;
+ public static readonly DerObjectIdentifier CommitmentType = PkcsObjectIdentifiers.IdAAEtsCommitmentType;
+ public static readonly DerObjectIdentifier SignerLocation = PkcsObjectIdentifiers.IdAAEtsSignerLocation;
+ public static readonly DerObjectIdentifier SignerAttr = PkcsObjectIdentifiers.IdAAEtsSignerAttr;
+ public static readonly DerObjectIdentifier OtherSigCert = PkcsObjectIdentifiers.IdAAEtsOtherSigCert;
+ public static readonly DerObjectIdentifier ContentTimestamp = PkcsObjectIdentifiers.IdAAEtsContentTimestamp;
+ public static readonly DerObjectIdentifier CertificateRefs = PkcsObjectIdentifiers.IdAAEtsCertificateRefs;
+ public static readonly DerObjectIdentifier RevocationRefs = PkcsObjectIdentifiers.IdAAEtsRevocationRefs;
+ public static readonly DerObjectIdentifier CertValues = PkcsObjectIdentifiers.IdAAEtsCertValues;
+ public static readonly DerObjectIdentifier RevocationValues = PkcsObjectIdentifiers.IdAAEtsRevocationValues;
+ public static readonly DerObjectIdentifier EscTimeStamp = PkcsObjectIdentifiers.IdAAEtsEscTimeStamp;
+ public static readonly DerObjectIdentifier CertCrlTimestamp = PkcsObjectIdentifiers.IdAAEtsCertCrlTimestamp;
+ public static readonly DerObjectIdentifier ArchiveTimestamp = PkcsObjectIdentifiers.IdAAEtsArchiveTimestamp;
+ public static readonly DerObjectIdentifier ArchiveTimestampV2 = new DerObjectIdentifier(PkcsObjectIdentifiers.IdAA + ".48");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/OcspIdentifier.cs b/bc-sharp-crypto/src/asn1/esf/OcspIdentifier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e65f1cfe70e53bc7e025fd8e0c5da1d9bd516621
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/OcspIdentifier.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ /// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+ ///
+ /// OcspIdentifier ::= SEQUENCE {
+ /// ocspResponderID ResponderID,
+ /// -- As in OCSP response data
+ /// producedAt GeneralizedTime
+ /// -- As in OCSP response data
+ /// }
+ ///
+ ///
+ public class OcspIdentifier
+ : Asn1Encodable
+ {
+ private readonly ResponderID ocspResponderID;
+ private readonly DerGeneralizedTime producedAt;
+
+ public static OcspIdentifier GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is OcspIdentifier)
+ return (OcspIdentifier) obj;
+
+ if (obj is Asn1Sequence)
+ return new OcspIdentifier((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'OcspIdentifier' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ private OcspIdentifier(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+ if (seq.Count != 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ this.ocspResponderID = ResponderID.GetInstance(seq[0].ToAsn1Object());
+ this.producedAt = (DerGeneralizedTime) seq[1].ToAsn1Object();
+ }
+
+ public OcspIdentifier(
+ ResponderID ocspResponderID,
+ DateTime producedAt)
+ {
+ if (ocspResponderID == null)
+ throw new ArgumentNullException();
+
+ this.ocspResponderID = ocspResponderID;
+ this.producedAt = new DerGeneralizedTime(producedAt);
+ }
+
+ public ResponderID OcspResponderID
+ {
+ get { return ocspResponderID; }
+ }
+
+ public DateTime ProducedAt
+ {
+ get { return producedAt.ToDateTime(); }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(ocspResponderID, producedAt);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/OcspListID.cs b/bc-sharp-crypto/src/asn1/esf/OcspListID.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1c8edb16b8ac971a0743f13c26f1eca90adc8cfe
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/OcspListID.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ /// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+ ///
+ /// OcspListID ::= SEQUENCE {
+ /// ocspResponses SEQUENCE OF OcspResponsesID
+ /// }
+ ///
+ ///
+ public class OcspListID
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence ocspResponses;
+
+ public static OcspListID GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is OcspListID)
+ return (OcspListID) obj;
+
+ if (obj is Asn1Sequence)
+ return new OcspListID((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'OcspListID' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ private OcspListID(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+ if (seq.Count != 1)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ this.ocspResponses = (Asn1Sequence) seq[0].ToAsn1Object();
+
+ foreach (Asn1Encodable ae in this.ocspResponses)
+ {
+ OcspResponsesID.GetInstance(ae.ToAsn1Object());
+ }
+ }
+
+ public OcspListID(
+ params OcspResponsesID[] ocspResponses)
+ {
+ if (ocspResponses == null)
+ throw new ArgumentNullException("ocspResponses");
+
+ this.ocspResponses = new DerSequence(ocspResponses);
+ }
+
+ public OcspListID(
+ IEnumerable ocspResponses)
+ {
+ if (ocspResponses == null)
+ throw new ArgumentNullException("ocspResponses");
+ if (!CollectionUtilities.CheckElementsAreOfType(ocspResponses, typeof(OcspResponsesID)))
+ throw new ArgumentException("Must contain only 'OcspResponsesID' objects", "ocspResponses");
+
+ this.ocspResponses = new DerSequence(
+ Asn1EncodableVector.FromEnumerable(ocspResponses));
+ }
+
+ public OcspResponsesID[] GetOcspResponses()
+ {
+ OcspResponsesID[] result = new OcspResponsesID[ocspResponses.Count];
+ for (int i = 0; i < ocspResponses.Count; ++i)
+ {
+ result[i] = OcspResponsesID.GetInstance(ocspResponses[i].ToAsn1Object());
+ }
+ return result;
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(ocspResponses);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/OcspResponsesID.cs b/bc-sharp-crypto/src/asn1/esf/OcspResponsesID.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8718188fc99d568da6489854f7dee359ab016e7a
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/OcspResponsesID.cs
@@ -0,0 +1,94 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ /// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+ ///
+ /// OcspResponsesID ::= SEQUENCE {
+ /// ocspIdentifier OcspIdentifier,
+ /// ocspRepHash OtherHash OPTIONAL
+ /// }
+ ///
+ ///
+ public class OcspResponsesID
+ : Asn1Encodable
+ {
+ private readonly OcspIdentifier ocspIdentifier;
+ private readonly OtherHash ocspRepHash;
+
+ public static OcspResponsesID GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is OcspResponsesID)
+ return (OcspResponsesID) obj;
+
+ if (obj is Asn1Sequence)
+ return new OcspResponsesID((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'OcspResponsesID' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ private OcspResponsesID(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+ if (seq.Count < 1 || seq.Count > 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ this.ocspIdentifier = OcspIdentifier.GetInstance(seq[0].ToAsn1Object());
+
+ if (seq.Count > 1)
+ {
+ this.ocspRepHash = OtherHash.GetInstance(seq[1].ToAsn1Object());
+ }
+ }
+
+ public OcspResponsesID(
+ OcspIdentifier ocspIdentifier)
+ : this(ocspIdentifier, null)
+ {
+ }
+
+ public OcspResponsesID(
+ OcspIdentifier ocspIdentifier,
+ OtherHash ocspRepHash)
+ {
+ if (ocspIdentifier == null)
+ throw new ArgumentNullException("ocspIdentifier");
+
+ this.ocspIdentifier = ocspIdentifier;
+ this.ocspRepHash = ocspRepHash;
+ }
+
+ public OcspIdentifier OcspIdentifier
+ {
+ get { return ocspIdentifier; }
+ }
+
+ public OtherHash OcspRepHash
+ {
+ get { return ocspRepHash; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ ocspIdentifier.ToAsn1Object());
+
+ if (ocspRepHash != null)
+ {
+ v.Add(ocspRepHash.ToAsn1Object());
+ }
+
+ return new DerSequence(v);
+ }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/OtherCertID.cs b/bc-sharp-crypto/src/asn1/esf/OtherCertID.cs
new file mode 100644
index 0000000000000000000000000000000000000000..19d173aa2523cd5e05cfc6655631e06b1fb13c76
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/OtherCertID.cs
@@ -0,0 +1,94 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ ///
+ /// OtherCertID ::= SEQUENCE {
+ /// otherCertHash OtherHash,
+ /// issuerSerial IssuerSerial OPTIONAL
+ /// }
+ ///
+ ///
+ public class OtherCertID
+ : Asn1Encodable
+ {
+ private readonly OtherHash otherCertHash;
+ private readonly IssuerSerial issuerSerial;
+
+ public static OtherCertID GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is OtherCertID)
+ return (OtherCertID) obj;
+
+ if (obj is Asn1Sequence)
+ return new OtherCertID((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'OtherCertID' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ private OtherCertID(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+ if (seq.Count < 1 || seq.Count > 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ this.otherCertHash = OtherHash.GetInstance(seq[0].ToAsn1Object());
+
+ if (seq.Count > 1)
+ {
+ this.issuerSerial = IssuerSerial.GetInstance(seq[1].ToAsn1Object());
+ }
+ }
+
+ public OtherCertID(
+ OtherHash otherCertHash)
+ : this(otherCertHash, null)
+ {
+ }
+
+ public OtherCertID(
+ OtherHash otherCertHash,
+ IssuerSerial issuerSerial)
+ {
+ if (otherCertHash == null)
+ throw new ArgumentNullException("otherCertHash");
+
+ this.otherCertHash = otherCertHash;
+ this.issuerSerial = issuerSerial;
+ }
+
+ public OtherHash OtherCertHash
+ {
+ get { return otherCertHash; }
+ }
+
+ public IssuerSerial IssuerSerial
+ {
+ get { return issuerSerial; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ otherCertHash.ToAsn1Object());
+
+ if (issuerSerial != null)
+ {
+ v.Add(issuerSerial.ToAsn1Object());
+ }
+
+ return new DerSequence(v);
+ }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/OtherHash.cs b/bc-sharp-crypto/src/asn1/esf/OtherHash.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2ee16247833de98f035fed836a0b33318670ac7b
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/OtherHash.cs
@@ -0,0 +1,88 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ ///
+ /// OtherHash ::= CHOICE {
+ /// sha1Hash OtherHashValue, -- This contains a SHA-1 hash
+ /// otherHash OtherHashAlgAndValue
+ /// }
+ ///
+ /// OtherHashValue ::= OCTET STRING
+ ///
+ ///
+ public class OtherHash
+ : Asn1Encodable, IAsn1Choice
+ {
+ private readonly Asn1OctetString sha1Hash;
+ private readonly OtherHashAlgAndValue otherHash;
+
+ public static OtherHash GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is OtherHash)
+ return (OtherHash) obj;
+
+ if (obj is Asn1OctetString)
+ return new OtherHash((Asn1OctetString) obj);
+
+ return new OtherHash(
+ OtherHashAlgAndValue.GetInstance(obj));
+ }
+
+ public OtherHash(
+ byte[] sha1Hash)
+ {
+ if (sha1Hash == null)
+ throw new ArgumentNullException("sha1Hash");
+
+ this.sha1Hash = new DerOctetString(sha1Hash);
+ }
+
+ public OtherHash(
+ Asn1OctetString sha1Hash)
+ {
+ if (sha1Hash == null)
+ throw new ArgumentNullException("sha1Hash");
+
+ this.sha1Hash = sha1Hash;
+ }
+
+ public OtherHash(
+ OtherHashAlgAndValue otherHash)
+ {
+ if (otherHash == null)
+ throw new ArgumentNullException("otherHash");
+
+ this.otherHash = otherHash;
+ }
+
+ public AlgorithmIdentifier HashAlgorithm
+ {
+ get
+ {
+ return otherHash == null
+ ? new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1)
+ : otherHash.HashAlgorithm;
+ }
+ }
+
+ public byte[] GetHashValue()
+ {
+ return otherHash == null
+ ? sha1Hash.GetOctets()
+ : otherHash.GetHashValue();
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return otherHash == null
+ ? sha1Hash
+ : otherHash.ToAsn1Object();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/OtherHashAlgAndValue.cs b/bc-sharp-crypto/src/asn1/esf/OtherHashAlgAndValue.cs
new file mode 100644
index 0000000000000000000000000000000000000000..00eb24c54a0bcd78cf42f18b3e1d7789ef9d0884
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/OtherHashAlgAndValue.cs
@@ -0,0 +1,95 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ /// Summary description for OtherHashAlgAndValue.
+ ///
+ ///
+ ///
+ /// OtherHashAlgAndValue ::= SEQUENCE {
+ /// hashAlgorithm AlgorithmIdentifier,
+ /// hashValue OtherHashValue
+ /// }
+ ///
+ /// OtherHashValue ::= OCTET STRING
+ ///
+ ///
+ public class OtherHashAlgAndValue
+ : Asn1Encodable
+ {
+ private readonly AlgorithmIdentifier hashAlgorithm;
+ private readonly Asn1OctetString hashValue;
+
+ public static OtherHashAlgAndValue GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is OtherHashAlgAndValue)
+ return (OtherHashAlgAndValue) obj;
+
+ if (obj is Asn1Sequence)
+ return new OtherHashAlgAndValue((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'OtherHashAlgAndValue' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ private OtherHashAlgAndValue(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+ if (seq.Count != 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0].ToAsn1Object());
+ this.hashValue = (Asn1OctetString) seq[1].ToAsn1Object();
+ }
+
+ public OtherHashAlgAndValue(
+ AlgorithmIdentifier hashAlgorithm,
+ byte[] hashValue)
+ {
+ if (hashAlgorithm == null)
+ throw new ArgumentNullException("hashAlgorithm");
+ if (hashValue == null)
+ throw new ArgumentNullException("hashValue");
+
+ this.hashAlgorithm = hashAlgorithm;
+ this.hashValue = new DerOctetString(hashValue);
+ }
+
+ public OtherHashAlgAndValue(
+ AlgorithmIdentifier hashAlgorithm,
+ Asn1OctetString hashValue)
+ {
+ if (hashAlgorithm == null)
+ throw new ArgumentNullException("hashAlgorithm");
+ if (hashValue == null)
+ throw new ArgumentNullException("hashValue");
+
+ this.hashAlgorithm = hashAlgorithm;
+ this.hashValue = hashValue;
+ }
+
+ public AlgorithmIdentifier HashAlgorithm
+ {
+ get { return hashAlgorithm; }
+ }
+
+ public byte[] GetHashValue()
+ {
+ return hashValue.GetOctets();
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(hashAlgorithm, hashValue);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/OtherRevRefs.cs b/bc-sharp-crypto/src/asn1/esf/OtherRevRefs.cs
new file mode 100644
index 0000000000000000000000000000000000000000..446031e5a0ae887a2ed1cd31368007b7f0cab425
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/OtherRevRefs.cs
@@ -0,0 +1,80 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ /// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+ ///
+ /// OtherRevRefs ::= SEQUENCE
+ /// {
+ /// otherRevRefType OtherRevRefType,
+ /// otherRevRefs ANY DEFINED BY otherRevRefType
+ /// }
+ ///
+ /// OtherRevRefType ::= OBJECT IDENTIFIER
+ ///
+ ///
+ public class OtherRevRefs
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier otherRevRefType;
+ private readonly Asn1Object otherRevRefs;
+
+ public static OtherRevRefs GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is OtherRevRefs)
+ return (OtherRevRefs) obj;
+
+ if (obj is Asn1Sequence)
+ return new OtherRevRefs((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'OtherRevRefs' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ private OtherRevRefs(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+ if (seq.Count != 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ this.otherRevRefType = (DerObjectIdentifier) seq[0].ToAsn1Object();
+ this.otherRevRefs = seq[1].ToAsn1Object();
+ }
+
+ public OtherRevRefs(
+ DerObjectIdentifier otherRevRefType,
+ Asn1Encodable otherRevRefs)
+ {
+ if (otherRevRefType == null)
+ throw new ArgumentNullException("otherRevRefType");
+ if (otherRevRefs == null)
+ throw new ArgumentNullException("otherRevRefs");
+
+ this.otherRevRefType = otherRevRefType;
+ this.otherRevRefs = otherRevRefs.ToAsn1Object();
+ }
+
+ public DerObjectIdentifier OtherRevRefType
+ {
+ get { return otherRevRefType; }
+ }
+
+ public Asn1Object OtherRevRefsObject
+ {
+ get { return otherRevRefs; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(otherRevRefType, otherRevRefs);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/OtherRevVals.cs b/bc-sharp-crypto/src/asn1/esf/OtherRevVals.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7b904565aa3e3356bd6f817bc48de829ee9d9a6a
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/OtherRevVals.cs
@@ -0,0 +1,80 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ /// RFC 3126: 4.3.2 Revocation Values Attribute Definition
+ ///
+ /// OtherRevVals ::= SEQUENCE
+ /// {
+ /// otherRevValType OtherRevValType,
+ /// otherRevVals ANY DEFINED BY otherRevValType
+ /// }
+ ///
+ /// OtherRevValType ::= OBJECT IDENTIFIER
+ ///
+ ///
+ public class OtherRevVals
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier otherRevValType;
+ private readonly Asn1Object otherRevVals;
+
+ public static OtherRevVals GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is OtherRevVals)
+ return (OtherRevVals) obj;
+
+ if (obj is Asn1Sequence)
+ return new OtherRevVals((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'OtherRevVals' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ private OtherRevVals(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+ if (seq.Count != 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ this.otherRevValType = (DerObjectIdentifier) seq[0].ToAsn1Object();
+ this.otherRevVals = seq[1].ToAsn1Object();
+ }
+
+ public OtherRevVals(
+ DerObjectIdentifier otherRevValType,
+ Asn1Encodable otherRevVals)
+ {
+ if (otherRevValType == null)
+ throw new ArgumentNullException("otherRevValType");
+ if (otherRevVals == null)
+ throw new ArgumentNullException("otherRevVals");
+
+ this.otherRevValType = otherRevValType;
+ this.otherRevVals = otherRevVals.ToAsn1Object();
+ }
+
+ public DerObjectIdentifier OtherRevValType
+ {
+ get { return otherRevValType; }
+ }
+
+ public Asn1Object OtherRevValsObject
+ {
+ get { return otherRevVals; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(otherRevValType, otherRevVals);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/OtherSigningCertificate.cs b/bc-sharp-crypto/src/asn1/esf/OtherSigningCertificate.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f7b9f5e66a9e2b5be13b749c505150663f205627
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/OtherSigningCertificate.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ ///
+ /// OtherSigningCertificate ::= SEQUENCE {
+ /// certs SEQUENCE OF OtherCertID,
+ /// policies SEQUENCE OF PolicyInformation OPTIONAL
+ /// }
+ ///
+ ///
+ public class OtherSigningCertificate
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence certs;
+ private readonly Asn1Sequence policies;
+
+ public static OtherSigningCertificate GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is OtherSigningCertificate)
+ return (OtherSigningCertificate) obj;
+
+ if (obj is Asn1Sequence)
+ return new OtherSigningCertificate((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'OtherSigningCertificate' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ private OtherSigningCertificate(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+ if (seq.Count < 1 || seq.Count > 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ this.certs = Asn1Sequence.GetInstance(seq[0].ToAsn1Object());
+
+ if (seq.Count > 1)
+ {
+ this.policies = Asn1Sequence.GetInstance(seq[1].ToAsn1Object());
+ }
+ }
+
+ public OtherSigningCertificate(
+ params OtherCertID[] certs)
+ : this(certs, null)
+ {
+ }
+
+ public OtherSigningCertificate(
+ OtherCertID[] certs,
+ params PolicyInformation[] policies)
+ {
+ if (certs == null)
+ throw new ArgumentNullException("certs");
+
+ this.certs = new DerSequence(certs);
+
+ if (policies != null)
+ {
+ this.policies = new DerSequence(policies);
+ }
+ }
+
+ public OtherSigningCertificate(
+ IEnumerable certs)
+ : this(certs, null)
+ {
+ }
+
+ public OtherSigningCertificate(
+ IEnumerable certs,
+ IEnumerable policies)
+ {
+ if (certs == null)
+ throw new ArgumentNullException("certs");
+ if (!CollectionUtilities.CheckElementsAreOfType(certs, typeof(OtherCertID)))
+ throw new ArgumentException("Must contain only 'OtherCertID' objects", "certs");
+
+ this.certs = new DerSequence(
+ Asn1EncodableVector.FromEnumerable(certs));
+
+ if (policies != null)
+ {
+ if (!CollectionUtilities.CheckElementsAreOfType(policies, typeof(PolicyInformation)))
+ throw new ArgumentException("Must contain only 'PolicyInformation' objects", "policies");
+
+ this.policies = new DerSequence(
+ Asn1EncodableVector.FromEnumerable(policies));
+ }
+ }
+
+ public OtherCertID[] GetCerts()
+ {
+ OtherCertID[] cs = new OtherCertID[certs.Count];
+ for (int i = 0; i < certs.Count; ++i)
+ {
+ cs[i] = OtherCertID.GetInstance(certs[i].ToAsn1Object());
+ }
+ return cs;
+ }
+
+ public PolicyInformation[] GetPolicies()
+ {
+ if (policies == null)
+ return null;
+
+ PolicyInformation[] ps = new PolicyInformation[policies.Count];
+ for (int i = 0; i < policies.Count; ++i)
+ {
+ ps[i] = PolicyInformation.GetInstance(policies[i].ToAsn1Object());
+ }
+ return ps;
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(certs);
+
+ if (policies != null)
+ {
+ v.Add(policies);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/RevocationValues.cs b/bc-sharp-crypto/src/asn1/esf/RevocationValues.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a7b47b47a87dd99592ed8620036c3fef83750e31
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/RevocationValues.cs
@@ -0,0 +1,165 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ /// RFC 5126: 6.3.4. revocation-values Attribute Definition
+ ///
+ /// RevocationValues ::= SEQUENCE {
+ /// crlVals [0] SEQUENCE OF CertificateList OPTIONAL,
+ /// ocspVals [1] SEQUENCE OF BasicOCSPResponse OPTIONAL,
+ /// otherRevVals [2] OtherRevVals OPTIONAL
+ /// }
+ ///
+ ///
+ public class RevocationValues
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence crlVals;
+ private readonly Asn1Sequence ocspVals;
+ private readonly OtherRevVals otherRevVals;
+
+ public static RevocationValues GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is RevocationValues)
+ return (RevocationValues) obj;
+
+ return new RevocationValues(Asn1Sequence.GetInstance(obj));
+ }
+
+ private RevocationValues(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+ if (seq.Count > 3)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ foreach (Asn1TaggedObject taggedObj in seq)
+ {
+ Asn1Object asn1Obj = taggedObj.GetObject();
+ switch (taggedObj.TagNo)
+ {
+ case 0:
+ Asn1Sequence crlValsSeq = (Asn1Sequence) asn1Obj;
+ foreach (Asn1Encodable ae in crlValsSeq)
+ {
+ CertificateList.GetInstance(ae.ToAsn1Object());
+ }
+ this.crlVals = crlValsSeq;
+ break;
+ case 1:
+ Asn1Sequence ocspValsSeq = (Asn1Sequence) asn1Obj;
+ foreach (Asn1Encodable ae in ocspValsSeq)
+ {
+ BasicOcspResponse.GetInstance(ae.ToAsn1Object());
+ }
+ this.ocspVals = ocspValsSeq;
+ break;
+ case 2:
+ this.otherRevVals = OtherRevVals.GetInstance(asn1Obj);
+ break;
+ default:
+ throw new ArgumentException("Illegal tag in RevocationValues", "seq");
+ }
+ }
+ }
+
+ public RevocationValues(
+ CertificateList[] crlVals,
+ BasicOcspResponse[] ocspVals,
+ OtherRevVals otherRevVals)
+ {
+ if (crlVals != null)
+ {
+ this.crlVals = new DerSequence(crlVals);
+ }
+
+ if (ocspVals != null)
+ {
+ this.ocspVals = new DerSequence(ocspVals);
+ }
+
+ this.otherRevVals = otherRevVals;
+ }
+
+ public RevocationValues(
+ IEnumerable crlVals,
+ IEnumerable ocspVals,
+ OtherRevVals otherRevVals)
+ {
+ if (crlVals != null)
+ {
+ if (!CollectionUtilities.CheckElementsAreOfType(crlVals, typeof(CertificateList)))
+ throw new ArgumentException("Must contain only 'CertificateList' objects", "crlVals");
+
+ this.crlVals = new DerSequence(
+ Asn1EncodableVector.FromEnumerable(crlVals));
+ }
+
+ if (ocspVals != null)
+ {
+ if (!CollectionUtilities.CheckElementsAreOfType(ocspVals, typeof(BasicOcspResponse)))
+ throw new ArgumentException("Must contain only 'BasicOcspResponse' objects", "ocspVals");
+
+ this.ocspVals = new DerSequence(
+ Asn1EncodableVector.FromEnumerable(ocspVals));
+ }
+
+ this.otherRevVals = otherRevVals;
+ }
+
+ public CertificateList[] GetCrlVals()
+ {
+ CertificateList[] result = new CertificateList[crlVals.Count];
+ for (int i = 0; i < crlVals.Count; ++i)
+ {
+ result[i] = CertificateList.GetInstance(crlVals[i].ToAsn1Object());
+ }
+ return result;
+ }
+
+ public BasicOcspResponse[] GetOcspVals()
+ {
+ BasicOcspResponse[] result = new BasicOcspResponse[ocspVals.Count];
+ for (int i = 0; i < ocspVals.Count; ++i)
+ {
+ result[i] = BasicOcspResponse.GetInstance(ocspVals[i].ToAsn1Object());
+ }
+ return result;
+ }
+
+ public OtherRevVals OtherRevVals
+ {
+ get { return otherRevVals; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (crlVals != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, crlVals));
+ }
+
+ if (ocspVals != null)
+ {
+ v.Add(new DerTaggedObject(true, 1, ocspVals));
+ }
+
+ if (otherRevVals != null)
+ {
+ v.Add(new DerTaggedObject(true, 2, otherRevVals.ToAsn1Object()));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/SigPolicyQualifierInfo.cs b/bc-sharp-crypto/src/asn1/esf/SigPolicyQualifierInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..470c5c873302ed47713fd1297c7d2c9a3220410b
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/SigPolicyQualifierInfo.cs
@@ -0,0 +1,73 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ ///
+ /// SigPolicyQualifierInfo ::= SEQUENCE {
+ /// sigPolicyQualifierId SigPolicyQualifierId,
+ /// sigQualifier ANY DEFINED BY sigPolicyQualifierId
+ /// }
+ ///
+ /// SigPolicyQualifierId ::= OBJECT IDENTIFIER
+ ///
+ ///
+ public class SigPolicyQualifierInfo
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier sigPolicyQualifierId;
+ private readonly Asn1Object sigQualifier;
+
+ public static SigPolicyQualifierInfo GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is SigPolicyQualifierInfo)
+ return (SigPolicyQualifierInfo) obj;
+
+ if (obj is Asn1Sequence)
+ return new SigPolicyQualifierInfo((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'SigPolicyQualifierInfo' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ private SigPolicyQualifierInfo(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+ if (seq.Count != 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ this.sigPolicyQualifierId = (DerObjectIdentifier) seq[0].ToAsn1Object();
+ this.sigQualifier = seq[1].ToAsn1Object();
+ }
+
+ public SigPolicyQualifierInfo(
+ DerObjectIdentifier sigPolicyQualifierId,
+ Asn1Encodable sigQualifier)
+ {
+ this.sigPolicyQualifierId = sigPolicyQualifierId;
+ this.sigQualifier = sigQualifier.ToAsn1Object();
+ }
+
+ public DerObjectIdentifier SigPolicyQualifierId
+ {
+ get { return sigPolicyQualifierId; }
+ }
+
+ public Asn1Object SigQualifier
+ {
+ get { return sigQualifier; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(sigPolicyQualifierId, sigQualifier);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/SignaturePolicyId.cs b/bc-sharp-crypto/src/asn1/esf/SignaturePolicyId.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7146bb4c13e3a3e6d926e497c8cd9709ac6a50b8
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/SignaturePolicyId.cs
@@ -0,0 +1,146 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ ///
+ /// SignaturePolicyId ::= SEQUENCE {
+ /// sigPolicyIdentifier SigPolicyId,
+ /// sigPolicyHash SigPolicyHash,
+ /// sigPolicyQualifiers SEQUENCE SIZE (1..MAX) OF SigPolicyQualifierInfo OPTIONAL
+ /// }
+ ///
+ /// SigPolicyId ::= OBJECT IDENTIFIER
+ ///
+ /// SigPolicyHash ::= OtherHashAlgAndValue
+ ///
+ ///
+ public class SignaturePolicyId
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier sigPolicyIdentifier;
+ private readonly OtherHashAlgAndValue sigPolicyHash;
+ private readonly Asn1Sequence sigPolicyQualifiers;
+
+ public static SignaturePolicyId GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is SignaturePolicyId)
+ return (SignaturePolicyId) obj;
+
+ if (obj is Asn1Sequence)
+ return new SignaturePolicyId((Asn1Sequence) obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'SignaturePolicyId' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ private SignaturePolicyId(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+ if (seq.Count < 2 || seq.Count > 3)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ this.sigPolicyIdentifier = (DerObjectIdentifier) seq[0].ToAsn1Object();
+ this.sigPolicyHash = OtherHashAlgAndValue.GetInstance(seq[1].ToAsn1Object());
+
+ if (seq.Count > 2)
+ {
+ this.sigPolicyQualifiers = (Asn1Sequence) seq[2].ToAsn1Object();
+ }
+ }
+
+ public SignaturePolicyId(
+ DerObjectIdentifier sigPolicyIdentifier,
+ OtherHashAlgAndValue sigPolicyHash)
+ : this(sigPolicyIdentifier, sigPolicyHash, null)
+ {
+ }
+
+ public SignaturePolicyId(
+ DerObjectIdentifier sigPolicyIdentifier,
+ OtherHashAlgAndValue sigPolicyHash,
+ params SigPolicyQualifierInfo[] sigPolicyQualifiers)
+ {
+ if (sigPolicyIdentifier == null)
+ throw new ArgumentNullException("sigPolicyIdentifier");
+ if (sigPolicyHash == null)
+ throw new ArgumentNullException("sigPolicyHash");
+
+ this.sigPolicyIdentifier = sigPolicyIdentifier;
+ this.sigPolicyHash = sigPolicyHash;
+
+ if (sigPolicyQualifiers != null)
+ {
+ this.sigPolicyQualifiers = new DerSequence(sigPolicyQualifiers);
+ }
+ }
+
+ public SignaturePolicyId(
+ DerObjectIdentifier sigPolicyIdentifier,
+ OtherHashAlgAndValue sigPolicyHash,
+ IEnumerable sigPolicyQualifiers)
+ {
+ if (sigPolicyIdentifier == null)
+ throw new ArgumentNullException("sigPolicyIdentifier");
+ if (sigPolicyHash == null)
+ throw new ArgumentNullException("sigPolicyHash");
+
+ this.sigPolicyIdentifier = sigPolicyIdentifier;
+ this.sigPolicyHash = sigPolicyHash;
+
+ if (sigPolicyQualifiers != null)
+ {
+ if (!CollectionUtilities.CheckElementsAreOfType(sigPolicyQualifiers, typeof(SigPolicyQualifierInfo)))
+ throw new ArgumentException("Must contain only 'SigPolicyQualifierInfo' objects", "sigPolicyQualifiers");
+
+ this.sigPolicyQualifiers = new DerSequence(
+ Asn1EncodableVector.FromEnumerable(sigPolicyQualifiers));
+ }
+ }
+
+ public DerObjectIdentifier SigPolicyIdentifier
+ {
+ get { return sigPolicyIdentifier; }
+ }
+
+ public OtherHashAlgAndValue SigPolicyHash
+ {
+ get { return sigPolicyHash; }
+ }
+
+ public SigPolicyQualifierInfo[] GetSigPolicyQualifiers()
+ {
+ if (sigPolicyQualifiers == null)
+ return null;
+
+ SigPolicyQualifierInfo[] infos = new SigPolicyQualifierInfo[sigPolicyQualifiers.Count];
+ for (int i = 0; i < sigPolicyQualifiers.Count; ++i)
+ {
+ infos[i] = SigPolicyQualifierInfo.GetInstance(sigPolicyQualifiers[i]);
+ }
+ return infos;
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ sigPolicyIdentifier, sigPolicyHash.ToAsn1Object());
+
+ if (sigPolicyQualifiers != null)
+ {
+ v.Add(sigPolicyQualifiers.ToAsn1Object());
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/SignaturePolicyIdentifier.cs b/bc-sharp-crypto/src/asn1/esf/SignaturePolicyIdentifier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..12257f2f0cfca2085d1fc3fa37eee1cd18e5c845
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/SignaturePolicyIdentifier.cs
@@ -0,0 +1,66 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ ///
+ ///
+ /// SignaturePolicyIdentifier ::= CHOICE {
+ /// SignaturePolicyId SignaturePolicyId,
+ /// SignaturePolicyImplied SignaturePolicyImplied
+ /// }
+ ///
+ /// SignaturePolicyImplied ::= NULL
+ ///
+ ///
+ public class SignaturePolicyIdentifier
+ : Asn1Encodable, IAsn1Choice
+ {
+ private readonly SignaturePolicyId sigPolicy;
+
+ public static SignaturePolicyIdentifier GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is SignaturePolicyIdentifier)
+ return (SignaturePolicyIdentifier) obj;
+
+ if (obj is SignaturePolicyId)
+ return new SignaturePolicyIdentifier((SignaturePolicyId) obj);
+
+ if (obj is Asn1Null)
+ return new SignaturePolicyIdentifier();
+
+ throw new ArgumentException(
+ "Unknown object in 'SignaturePolicyIdentifier' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ public SignaturePolicyIdentifier()
+ {
+ this.sigPolicy = null;
+ }
+
+ public SignaturePolicyIdentifier(
+ SignaturePolicyId signaturePolicyId)
+ {
+ if (signaturePolicyId == null)
+ throw new ArgumentNullException("signaturePolicyId");
+
+ this.sigPolicy = signaturePolicyId;
+ }
+
+ public SignaturePolicyId SignaturePolicyId
+ {
+ get { return sigPolicy; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return sigPolicy == null
+ ? DerNull.Instance
+ : sigPolicy.ToAsn1Object();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/SignerAttribute.cs b/bc-sharp-crypto/src/asn1/esf/SignerAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..39bd910b290e681494313bb36ced76adc97f51e9
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/SignerAttribute.cs
@@ -0,0 +1,97 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ public class SignerAttribute
+ : Asn1Encodable
+ {
+ private Asn1Sequence claimedAttributes;
+ private AttributeCertificate certifiedAttributes;
+
+ public static SignerAttribute GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is SignerAttribute)
+ return (SignerAttribute) obj;
+
+ if (obj is Asn1Sequence)
+ return new SignerAttribute(obj);
+
+ throw new ArgumentException(
+ "Unknown object in 'SignerAttribute' factory: "
+ + Platform.GetTypeName(obj),
+ "obj");
+ }
+
+ private SignerAttribute(
+ object obj)
+ {
+ Asn1Sequence seq = (Asn1Sequence) obj;
+ DerTaggedObject taggedObject = (DerTaggedObject) seq[0];
+ if (taggedObject.TagNo == 0)
+ {
+ claimedAttributes = Asn1Sequence.GetInstance(taggedObject, true);
+ }
+ else if (taggedObject.TagNo == 1)
+ {
+ certifiedAttributes = AttributeCertificate.GetInstance(taggedObject);
+ }
+ else
+ {
+ throw new ArgumentException("illegal tag.", "obj");
+ }
+ }
+
+ public SignerAttribute(
+ Asn1Sequence claimedAttributes)
+ {
+ this.claimedAttributes = claimedAttributes;
+ }
+
+ public SignerAttribute(
+ AttributeCertificate certifiedAttributes)
+ {
+ this.certifiedAttributes = certifiedAttributes;
+ }
+
+ public virtual Asn1Sequence ClaimedAttributes
+ {
+ get { return claimedAttributes; }
+ }
+
+ public virtual AttributeCertificate CertifiedAttributes
+ {
+ get { return certifiedAttributes; }
+ }
+
+ /**
+ *
+ *
+ * SignerAttribute ::= SEQUENCE OF CHOICE {
+ * claimedAttributes [0] ClaimedAttributes,
+ * certifiedAttributes [1] CertifiedAttributes }
+ *
+ * ClaimedAttributes ::= SEQUENCE OF Attribute
+ * CertifiedAttributes ::= AttributeCertificate -- as defined in RFC 3281: see clause 4.1.
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (claimedAttributes != null)
+ {
+ v.Add(new DerTaggedObject(0, claimedAttributes));
+ }
+ else
+ {
+ v.Add(new DerTaggedObject(1, certifiedAttributes));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/esf/SignerLocation.cs b/bc-sharp-crypto/src/asn1/esf/SignerLocation.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d2cef51bb3de9242d45ca08c8a5140fb02720dec
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/esf/SignerLocation.cs
@@ -0,0 +1,144 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+ /**
+ * Signer-Location attribute (RFC3126).
+ *
+ *
+ * SignerLocation ::= SEQUENCE {
+ * countryName [0] DirectoryString OPTIONAL,
+ * localityName [1] DirectoryString OPTIONAL,
+ * postalAddress [2] PostalAddress OPTIONAL }
+ *
+ * PostalAddress ::= SEQUENCE SIZE(1..6) OF DirectoryString
+ *
+ */
+ public class SignerLocation
+ : Asn1Encodable
+ {
+ // TODO Should these be using DirectoryString?
+ private DerUtf8String countryName;
+ private DerUtf8String localityName;
+ private Asn1Sequence postalAddress;
+
+ public SignerLocation(
+ Asn1Sequence seq)
+ {
+ foreach (Asn1TaggedObject obj in seq)
+ {
+ switch (obj.TagNo)
+ {
+ case 0:
+ this.countryName = DerUtf8String.GetInstance(obj, true);
+ break;
+ case 1:
+ this.localityName = DerUtf8String.GetInstance(obj, true);
+ break;
+ case 2:
+ bool isExplicit = obj.IsExplicit(); // handle erroneous implicitly tagged sequences
+ this.postalAddress = Asn1Sequence.GetInstance(obj, isExplicit);
+ if (postalAddress != null && postalAddress.Count > 6)
+ throw new ArgumentException("postal address must contain less than 6 strings");
+ break;
+ default:
+ throw new ArgumentException("illegal tag");
+ }
+ }
+ }
+
+ public SignerLocation(
+ DerUtf8String countryName,
+ DerUtf8String localityName,
+ Asn1Sequence postalAddress)
+ {
+ if (postalAddress != null && postalAddress.Count > 6)
+ {
+ throw new ArgumentException("postal address must contain less than 6 strings");
+ }
+
+ if (countryName != null)
+ {
+ this.countryName = DerUtf8String.GetInstance(countryName.ToAsn1Object());
+ }
+
+ if (localityName != null)
+ {
+ this.localityName = DerUtf8String.GetInstance(localityName.ToAsn1Object());
+ }
+
+ if (postalAddress != null)
+ {
+ this.postalAddress = (Asn1Sequence) postalAddress.ToAsn1Object();
+ }
+ }
+
+ public static SignerLocation GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is SignerLocation)
+ {
+ return (SignerLocation) obj;
+ }
+
+ return new SignerLocation(Asn1Sequence.GetInstance(obj));
+ }
+
+ public DerUtf8String CountryName
+ {
+ get { return countryName; }
+ }
+
+ public DerUtf8String LocalityName
+ {
+ get { return localityName; }
+ }
+
+ public Asn1Sequence PostalAddress
+ {
+ get { return postalAddress; }
+ }
+
+ /**
+ *
+ * SignerLocation ::= SEQUENCE {
+ * countryName [0] DirectoryString OPTIONAL,
+ * localityName [1] DirectoryString OPTIONAL,
+ * postalAddress [2] PostalAddress OPTIONAL }
+ *
+ * PostalAddress ::= SEQUENCE SIZE(1..6) OF DirectoryString
+ *
+ * DirectoryString ::= CHOICE {
+ * teletexString TeletexString (SIZE (1..MAX)),
+ * printableString PrintableString (SIZE (1..MAX)),
+ * universalString UniversalString (SIZE (1..MAX)),
+ * utf8String UTF8String (SIZE (1.. MAX)),
+ * bmpString BMPString (SIZE (1..MAX)) }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (countryName != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, countryName));
+ }
+
+ if (localityName != null)
+ {
+ v.Add(new DerTaggedObject(true, 1, localityName));
+ }
+
+ if (postalAddress != null)
+ {
+ v.Add(new DerTaggedObject(true, 2, postalAddress));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ess/ContentHints.cs b/bc-sharp-crypto/src/asn1/ess/ContentHints.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cfd174b3a9fe89932c70277d35ded2766ab9d9b9
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ess/ContentHints.cs
@@ -0,0 +1,94 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+ public class ContentHints
+ : Asn1Encodable
+ {
+ private readonly DerUtf8String contentDescription;
+ private readonly DerObjectIdentifier contentType;
+
+ public static ContentHints GetInstance(
+ object o)
+ {
+ if (o == null || o is ContentHints)
+ {
+ return (ContentHints)o;
+ }
+
+ if (o is Asn1Sequence)
+ {
+ return new ContentHints((Asn1Sequence)o);
+ }
+
+ throw new ArgumentException("unknown object in 'ContentHints' factory : "
+ + Platform.GetTypeName(o) + ".");
+ }
+
+ /**
+ * constructor
+ */
+ private ContentHints(
+ Asn1Sequence seq)
+ {
+ IAsn1Convertible field = seq[0];
+ if (field.ToAsn1Object() is DerUtf8String)
+ {
+ contentDescription = DerUtf8String.GetInstance(field);
+ contentType = DerObjectIdentifier.GetInstance(seq[1]);
+ }
+ else
+ {
+ contentType = DerObjectIdentifier.GetInstance(seq[0]);
+ }
+ }
+
+ public ContentHints(
+ DerObjectIdentifier contentType)
+ {
+ this.contentType = contentType;
+ this.contentDescription = null;
+ }
+
+ public ContentHints(
+ DerObjectIdentifier contentType,
+ DerUtf8String contentDescription)
+ {
+ this.contentType = contentType;
+ this.contentDescription = contentDescription;
+ }
+
+ public DerObjectIdentifier ContentType
+ {
+ get { return contentType; }
+ }
+
+ public DerUtf8String ContentDescription
+ {
+ get { return contentDescription; }
+ }
+
+ /**
+ *
+ * ContentHints ::= SEQUENCE {
+ * contentDescription UTF8String (SIZE (1..MAX)) OPTIONAL,
+ * contentType ContentType }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (contentDescription != null)
+ {
+ v.Add(contentDescription);
+ }
+
+ v.Add(contentType);
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ess/ContentIdentifier.cs b/bc-sharp-crypto/src/asn1/ess/ContentIdentifier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..430185e1129460f97960f36477f73bd50efd2a23
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ess/ContentIdentifier.cs
@@ -0,0 +1,67 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+ public class ContentIdentifier
+ : Asn1Encodable
+ {
+ private Asn1OctetString value;
+
+ public static ContentIdentifier GetInstance(
+ object o)
+ {
+ if (o == null || o is ContentIdentifier)
+ {
+ return (ContentIdentifier) o;
+ }
+
+ if (o is Asn1OctetString)
+ {
+ return new ContentIdentifier((Asn1OctetString) o);
+ }
+
+ throw new ArgumentException(
+ "unknown object in 'ContentIdentifier' factory : "
+ + Platform.GetTypeName(o) + ".");
+ }
+
+ /**
+ * Create from OCTET STRING whose octets represent the identifier.
+ */
+ public ContentIdentifier(
+ Asn1OctetString value)
+ {
+ this.value = value;
+ }
+
+ /**
+ * Create from byte array representing the identifier.
+ */
+ public ContentIdentifier(
+ byte[] value)
+ : this(new DerOctetString(value))
+ {
+ }
+
+ public Asn1OctetString Value
+ {
+ get { return value; }
+ }
+
+ /**
+ * The definition of ContentIdentifier is
+ *
+ * ContentIdentifier ::= OCTET STRING
+ *
+ * id-aa-contentIdentifier OBJECT IDENTIFIER ::= { iso(1)
+ * member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
+ * smime(16) id-aa(2) 7 }
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return value;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ess/ESSCertID.cs b/bc-sharp-crypto/src/asn1/ess/ESSCertID.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b4465ea4f51a48e0280cea0e069ab9994617e7b7
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ess/ESSCertID.cs
@@ -0,0 +1,94 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+ public class EssCertID
+ : Asn1Encodable
+ {
+ private Asn1OctetString certHash;
+ private IssuerSerial issuerSerial;
+
+ public static EssCertID GetInstance(
+ object o)
+ {
+ if (o == null || o is EssCertID)
+ {
+ return (EssCertID) o;
+ }
+
+ if (o is Asn1Sequence)
+ {
+ return new EssCertID((Asn1Sequence) o);
+ }
+
+ throw new ArgumentException(
+ "unknown object in 'EssCertID' factory : "
+ + Platform.GetTypeName(o) + ".");
+ }
+
+ /**
+ * constructor
+ */
+ public EssCertID(
+ Asn1Sequence seq)
+ {
+ if (seq.Count < 1 || seq.Count > 2)
+ {
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+ }
+
+ this.certHash = Asn1OctetString.GetInstance(seq[0]);
+
+ if (seq.Count > 1)
+ {
+ issuerSerial = IssuerSerial.GetInstance(seq[1]);
+ }
+ }
+
+ public EssCertID(
+ byte[] hash)
+ {
+ certHash = new DerOctetString(hash);
+ }
+
+ public EssCertID(
+ byte[] hash,
+ IssuerSerial issuerSerial)
+ {
+ this.certHash = new DerOctetString(hash);
+ this.issuerSerial = issuerSerial;
+ }
+
+ public byte[] GetCertHash()
+ {
+ return certHash.GetOctets();
+ }
+
+ public IssuerSerial IssuerSerial
+ {
+ get { return issuerSerial; }
+ }
+
+ /**
+ *
+ * EssCertID ::= SEQUENCE {
+ * certHash Hash,
+ * issuerSerial IssuerSerial OPTIONAL }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(certHash);
+
+ if (issuerSerial != null)
+ {
+ v.Add(issuerSerial);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ess/ESSCertIDv2.cs b/bc-sharp-crypto/src/asn1/ess/ESSCertIDv2.cs
new file mode 100644
index 0000000000000000000000000000000000000000..35ce699e8889b914790dc5d8df7f9838a48c665d
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ess/ESSCertIDv2.cs
@@ -0,0 +1,146 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+ public class EssCertIDv2
+ : Asn1Encodable
+ {
+ private readonly AlgorithmIdentifier hashAlgorithm;
+ private readonly byte[] certHash;
+ private readonly IssuerSerial issuerSerial;
+
+ private static readonly AlgorithmIdentifier DefaultAlgID = new AlgorithmIdentifier(
+ NistObjectIdentifiers.IdSha256);
+
+ public static EssCertIDv2 GetInstance(object obj)
+ {
+ if (obj == null)
+ return null;
+ EssCertIDv2 existing = obj as EssCertIDv2;
+ if (existing != null)
+ return existing;
+ return new EssCertIDv2(Asn1Sequence.GetInstance(obj));
+ }
+
+ private EssCertIDv2(
+ Asn1Sequence seq)
+ {
+ if (seq.Count > 3)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ int count = 0;
+
+ if (seq[0] is Asn1OctetString)
+ {
+ // Default value
+ this.hashAlgorithm = DefaultAlgID;
+ }
+ else
+ {
+ this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[count++].ToAsn1Object());
+ }
+
+ this.certHash = Asn1OctetString.GetInstance(seq[count++].ToAsn1Object()).GetOctets();
+
+ if (seq.Count > count)
+ {
+ this.issuerSerial = IssuerSerial.GetInstance(
+ Asn1Sequence.GetInstance(seq[count].ToAsn1Object()));
+ }
+ }
+
+ public EssCertIDv2(byte[] certHash)
+ : this(null, certHash, null)
+ {
+ }
+
+ public EssCertIDv2(
+ AlgorithmIdentifier algId,
+ byte[] certHash)
+ : this(algId, certHash, null)
+ {
+ }
+
+ public EssCertIDv2(
+ byte[] certHash,
+ IssuerSerial issuerSerial)
+ : this(null, certHash, issuerSerial)
+ {
+ }
+
+ public EssCertIDv2(
+ AlgorithmIdentifier algId,
+ byte[] certHash,
+ IssuerSerial issuerSerial)
+ {
+ if (algId == null)
+ {
+ // Default value
+ this.hashAlgorithm = DefaultAlgID;
+ }
+ else
+ {
+ this.hashAlgorithm = algId;
+ }
+
+ this.certHash = certHash;
+ this.issuerSerial = issuerSerial;
+ }
+
+ public AlgorithmIdentifier HashAlgorithm
+ {
+ get { return this.hashAlgorithm; }
+ }
+
+ public byte[] GetCertHash()
+ {
+ return Arrays.Clone(certHash);
+ }
+
+ public IssuerSerial IssuerSerial
+ {
+ get { return issuerSerial; }
+ }
+
+ /**
+ *
+ * EssCertIDv2 ::= SEQUENCE {
+ * hashAlgorithm AlgorithmIdentifier
+ * DEFAULT {algorithm id-sha256},
+ * certHash Hash,
+ * issuerSerial IssuerSerial OPTIONAL
+ * }
+ *
+ * Hash ::= OCTET STRING
+ *
+ * IssuerSerial ::= SEQUENCE {
+ * issuer GeneralNames,
+ * serialNumber CertificateSerialNumber
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (!hashAlgorithm.Equals(DefaultAlgID))
+ {
+ v.Add(hashAlgorithm);
+ }
+
+ v.Add(new DerOctetString(certHash).ToAsn1Object());
+
+ if (issuerSerial != null)
+ {
+ v.Add(issuerSerial);
+ }
+
+ return new DerSequence(v);
+ }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ess/OtherCertID.cs b/bc-sharp-crypto/src/asn1/ess/OtherCertID.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7794c81faca5b570f4b59468be47ade2891d3b07
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ess/OtherCertID.cs
@@ -0,0 +1,134 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+ [Obsolete("Use version in Asn1.Esf instead")]
+ public class OtherCertID
+ : Asn1Encodable
+ {
+ private Asn1Encodable otherCertHash;
+ private IssuerSerial issuerSerial;
+
+ public static OtherCertID GetInstance(
+ object o)
+ {
+ if (o == null || o is OtherCertID)
+ {
+ return (OtherCertID) o;
+ }
+
+ if (o is Asn1Sequence)
+ {
+ return new OtherCertID((Asn1Sequence) o);
+ }
+
+ throw new ArgumentException(
+ "unknown object in 'OtherCertID' factory : "
+ + Platform.GetTypeName(o) + ".");
+ }
+
+ /**
+ * constructor
+ */
+ public OtherCertID(
+ Asn1Sequence seq)
+ {
+ if (seq.Count < 1 || seq.Count > 2)
+ {
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+ }
+
+ if (seq[0].ToAsn1Object() is Asn1OctetString)
+ {
+ otherCertHash = Asn1OctetString.GetInstance(seq[0]);
+ }
+ else
+ {
+ otherCertHash = DigestInfo.GetInstance(seq[0]);
+ }
+
+ if (seq.Count > 1)
+ {
+ issuerSerial = IssuerSerial.GetInstance(Asn1Sequence.GetInstance(seq[1]));
+ }
+ }
+
+ public OtherCertID(
+ AlgorithmIdentifier algId,
+ byte[] digest)
+ {
+ this.otherCertHash = new DigestInfo(algId, digest);
+ }
+
+ public OtherCertID(
+ AlgorithmIdentifier algId,
+ byte[] digest,
+ IssuerSerial issuerSerial)
+ {
+ this.otherCertHash = new DigestInfo(algId, digest);
+ this.issuerSerial = issuerSerial;
+ }
+
+ public AlgorithmIdentifier AlgorithmHash
+ {
+ get
+ {
+ if (otherCertHash.ToAsn1Object() is Asn1OctetString)
+ {
+ // SHA-1
+ return new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1);
+ }
+
+ return DigestInfo.GetInstance(otherCertHash).AlgorithmID;
+ }
+ }
+
+ public byte[] GetCertHash()
+ {
+ if (otherCertHash.ToAsn1Object() is Asn1OctetString)
+ {
+ // SHA-1
+ return ((Asn1OctetString) otherCertHash.ToAsn1Object()).GetOctets();
+ }
+
+ return DigestInfo.GetInstance(otherCertHash).GetDigest();
+ }
+
+ public IssuerSerial IssuerSerial
+ {
+ get { return issuerSerial; }
+ }
+
+ /**
+ *
+ * OtherCertID ::= SEQUENCE {
+ * otherCertHash OtherHash,
+ * issuerSerial IssuerSerial OPTIONAL }
+ *
+ * OtherHash ::= CHOICE {
+ * sha1Hash OCTET STRING,
+ * otherHash OtherHashAlgAndValue }
+ *
+ * OtherHashAlgAndValue ::= SEQUENCE {
+ * hashAlgorithm AlgorithmIdentifier,
+ * hashValue OCTET STRING }
+ *
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(otherCertHash);
+
+ if (issuerSerial != null)
+ {
+ v.Add(issuerSerial);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ess/OtherSigningCertificate.cs b/bc-sharp-crypto/src/asn1/ess/OtherSigningCertificate.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6cef92b6204069d9b82a64b126714de9b54060d1
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ess/OtherSigningCertificate.cs
@@ -0,0 +1,110 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+ [Obsolete("Use version in Asn1.Esf instead")]
+ public class OtherSigningCertificate
+ : Asn1Encodable
+ {
+ private Asn1Sequence certs, policies;
+
+ public static OtherSigningCertificate GetInstance(
+ object o)
+ {
+ if (o == null || o is OtherSigningCertificate)
+ {
+ return (OtherSigningCertificate) o;
+ }
+
+ if (o is Asn1Sequence)
+ {
+ return new OtherSigningCertificate((Asn1Sequence) o);
+ }
+
+ throw new ArgumentException(
+ "unknown object in 'OtherSigningCertificate' factory : "
+ + Platform.GetTypeName(o) + ".");
+ }
+
+ /**
+ * constructors
+ */
+ public OtherSigningCertificate(
+ Asn1Sequence seq)
+ {
+ if (seq.Count < 1 || seq.Count > 2)
+ {
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+ }
+
+ this.certs = Asn1Sequence.GetInstance(seq[0]);
+
+ if (seq.Count > 1)
+ {
+ this.policies = Asn1Sequence.GetInstance(seq[1]);
+ }
+ }
+
+ public OtherSigningCertificate(
+ OtherCertID otherCertID)
+ {
+ certs = new DerSequence(otherCertID);
+ }
+
+ public OtherCertID[] GetCerts()
+ {
+ OtherCertID[] cs = new OtherCertID[certs.Count];
+
+ for (int i = 0; i != certs.Count; ++i)
+ {
+ cs[i] = OtherCertID.GetInstance(certs[i]);
+ }
+
+ return cs;
+ }
+
+ public PolicyInformation[] GetPolicies()
+ {
+ if (policies == null)
+ {
+ return null;
+ }
+
+ PolicyInformation[] ps = new PolicyInformation[policies.Count];
+
+ for (int i = 0; i != policies.Count; i++)
+ {
+ ps[i] = PolicyInformation.GetInstance(policies[i]);
+ }
+
+ return ps;
+ }
+
+ /**
+ * The definition of OtherSigningCertificate is
+ *
+ * OtherSigningCertificate ::= SEQUENCE {
+ * certs SEQUENCE OF OtherCertID,
+ * policies SEQUENCE OF PolicyInformation OPTIONAL
+ * }
+ *
+ * id-aa-ets-otherSigCert OBJECT IDENTIFIER ::= { iso(1)
+ * member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
+ * smime(16) id-aa(2) 19 }
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(certs);
+
+ if (policies != null)
+ {
+ v.Add(policies);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ess/SigningCertificate.cs b/bc-sharp-crypto/src/asn1/ess/SigningCertificate.cs
new file mode 100644
index 0000000000000000000000000000000000000000..51f67c1ffb4b8dff58f089dda9cd5e9823e757cd
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ess/SigningCertificate.cs
@@ -0,0 +1,109 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+ public class SigningCertificate
+ : Asn1Encodable
+ {
+ private Asn1Sequence certs, policies;
+
+ public static SigningCertificate GetInstance(
+ object o)
+ {
+ if (o == null || o is SigningCertificate)
+ {
+ return (SigningCertificate) o;
+ }
+
+ if (o is Asn1Sequence)
+ {
+ return new SigningCertificate((Asn1Sequence) o);
+ }
+
+ throw new ArgumentException(
+ "unknown object in 'SigningCertificate' factory : "
+ + Platform.GetTypeName(o) + ".");
+ }
+
+ /**
+ * constructors
+ */
+ public SigningCertificate(
+ Asn1Sequence seq)
+ {
+ if (seq.Count < 1 || seq.Count > 2)
+ {
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+ }
+
+ this.certs = Asn1Sequence.GetInstance(seq[0]);
+
+ if (seq.Count > 1)
+ {
+ this.policies = Asn1Sequence.GetInstance(seq[1]);
+ }
+ }
+
+ public SigningCertificate(
+ EssCertID essCertID)
+ {
+ certs = new DerSequence(essCertID);
+ }
+
+ public EssCertID[] GetCerts()
+ {
+ EssCertID[] cs = new EssCertID[certs.Count];
+
+ for (int i = 0; i != certs.Count; i++)
+ {
+ cs[i] = EssCertID.GetInstance(certs[i]);
+ }
+
+ return cs;
+ }
+
+ public PolicyInformation[] GetPolicies()
+ {
+ if (policies == null)
+ {
+ return null;
+ }
+
+ PolicyInformation[] ps = new PolicyInformation[policies.Count];
+
+ for (int i = 0; i != policies.Count; i++)
+ {
+ ps[i] = PolicyInformation.GetInstance(policies[i]);
+ }
+
+ return ps;
+ }
+
+ /**
+ * The definition of SigningCertificate is
+ *
+ * SigningCertificate ::= SEQUENCE {
+ * certs SEQUENCE OF EssCertID,
+ * policies SEQUENCE OF PolicyInformation OPTIONAL
+ * }
+ *
+ * id-aa-signingCertificate OBJECT IDENTIFIER ::= { iso(1)
+ * member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
+ * smime(16) id-aa(2) 12 }
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(certs);
+
+ if (policies != null)
+ {
+ v.Add(policies);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ess/SigningCertificateV2.cs b/bc-sharp-crypto/src/asn1/ess/SigningCertificateV2.cs
new file mode 100644
index 0000000000000000000000000000000000000000..91eda9e33d6143eaea6c8b1594af2662772ca9bc
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ess/SigningCertificateV2.cs
@@ -0,0 +1,113 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+ public class SigningCertificateV2
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence certs;
+ private readonly Asn1Sequence policies;
+
+ public static SigningCertificateV2 GetInstance(
+ object o)
+ {
+ if (o == null || o is SigningCertificateV2)
+ return (SigningCertificateV2) o;
+
+ if (o is Asn1Sequence)
+ return new SigningCertificateV2((Asn1Sequence) o);
+
+ throw new ArgumentException(
+ "unknown object in 'SigningCertificateV2' factory : "
+ + Platform.GetTypeName(o) + ".");
+ }
+
+ private SigningCertificateV2(
+ Asn1Sequence seq)
+ {
+ if (seq.Count < 1 || seq.Count > 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ this.certs = Asn1Sequence.GetInstance(seq[0].ToAsn1Object());
+
+ if (seq.Count > 1)
+ {
+ this.policies = Asn1Sequence.GetInstance(seq[1].ToAsn1Object());
+ }
+ }
+
+ public SigningCertificateV2(
+ EssCertIDv2 cert)
+ {
+ this.certs = new DerSequence(cert);
+ }
+
+ public SigningCertificateV2(
+ EssCertIDv2[] certs)
+ {
+ this.certs = new DerSequence(certs);
+ }
+
+ public SigningCertificateV2(
+ EssCertIDv2[] certs,
+ PolicyInformation[] policies)
+ {
+ this.certs = new DerSequence(certs);
+
+ if (policies != null)
+ {
+ this.policies = new DerSequence(policies);
+ }
+ }
+
+ public EssCertIDv2[] GetCerts()
+ {
+ EssCertIDv2[] certIds = new EssCertIDv2[certs.Count];
+ for (int i = 0; i != certs.Count; i++)
+ {
+ certIds[i] = EssCertIDv2.GetInstance(certs[i]);
+ }
+ return certIds;
+ }
+
+ public PolicyInformation[] GetPolicies()
+ {
+ if (policies == null)
+ return null;
+
+ PolicyInformation[] policyInformations = new PolicyInformation[policies.Count];
+ for (int i = 0; i != policies.Count; i++)
+ {
+ policyInformations[i] = PolicyInformation.GetInstance(policies[i]);
+ }
+ return policyInformations;
+ }
+
+ /**
+ * The definition of SigningCertificateV2 is
+ *
+ * SigningCertificateV2 ::= SEQUENCE {
+ * certs SEQUENCE OF EssCertIDv2,
+ * policies SEQUENCE OF PolicyInformation OPTIONAL
+ * }
+ *
+ * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::= { iso(1)
+ * member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
+ * smime(16) id-aa(2) 47 }
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(certs);
+
+ if (policies != null)
+ {
+ v.Add(policies);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/gm/GMNamedCurves.cs b/bc-sharp-crypto/src/asn1/gm/GMNamedCurves.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e2ec6d854169e7b0ab53f8b8061394419c49ffa9
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/gm/GMNamedCurves.cs
@@ -0,0 +1,157 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.EC.Endo;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.GM
+{
+ public sealed class GMNamedCurves
+ {
+ private GMNamedCurves()
+ {
+ }
+
+ private static ECCurve ConfigureCurve(ECCurve curve)
+ {
+ return curve;
+ }
+
+ private static BigInteger FromHex(string hex)
+ {
+ return new BigInteger(1, Hex.Decode(hex));
+ }
+
+ /*
+ * sm2p256v1
+ */
+ internal class SM2P256V1Holder
+ : X9ECParametersHolder
+ {
+ private SM2P256V1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new SM2P256V1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger p = FromHex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF");
+ BigInteger a = FromHex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC");
+ BigInteger b = FromHex("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93");
+ byte[] S = null;
+ BigInteger n = FromHex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123");
+ BigInteger h = BigInteger.One;
+
+ ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7"
+ + "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * wapip192v1
+ */
+ internal class WapiP192V1Holder
+ : X9ECParametersHolder
+ {
+ private WapiP192V1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new WapiP192V1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger p = FromHex("BDB6F4FE3E8B1D9E0DA8C0D46F4C318CEFE4AFE3B6B8551F");
+ BigInteger a = FromHex("BB8E5E8FBC115E139FE6A814FE48AAA6F0ADA1AA5DF91985");
+ BigInteger b = FromHex("1854BEBDC31B21B7AEFC80AB0ECD10D5B1B3308E6DBF11C1");
+ byte[] S = null;
+ BigInteger n = FromHex("BDB6F4FE3E8B1D9E0DA8C0D40FC962195DFAE76F56564677");
+ BigInteger h = BigInteger.One;
+
+ ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "4AD5F7048DE709AD51236DE6" + "5E4D4B482C836DC6E4106640"
+ + "02BB3A02D4AAADACAE24817A" + "4CA3A1B014B5270432DB27D2"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+
+ private static readonly IDictionary objIds = Platform.CreateHashtable();
+ private static readonly IDictionary curves = Platform.CreateHashtable();
+ private static readonly IDictionary names = Platform.CreateHashtable();
+
+ private static void DefineCurve(
+ string name,
+ DerObjectIdentifier oid,
+ X9ECParametersHolder holder)
+ {
+ objIds.Add(Platform.ToUpperInvariant(name), oid);
+ names.Add(oid, name);
+ curves.Add(oid, holder);
+ }
+
+ static GMNamedCurves()
+ {
+ DefineCurve("wapip192v1", GMObjectIdentifiers.wapip192v1, WapiP192V1Holder.Instance);
+ DefineCurve("sm2p256v1", GMObjectIdentifiers.sm2p256v1, SM2P256V1Holder.Instance);
+ }
+
+ public static X9ECParameters GetByName(
+ string name)
+ {
+ DerObjectIdentifier oid = GetOid(name);
+ return oid == null ? null : GetByOid(oid);
+ }
+
+ /**
+ * return the X9ECParameters object for the named curve represented by
+ * the passed in object identifier. Null if the curve isn't present.
+ *
+ * @param oid an object identifier representing a named curve, if present.
+ */
+ public static X9ECParameters GetByOid(
+ DerObjectIdentifier oid)
+ {
+ X9ECParametersHolder holder = (X9ECParametersHolder)curves[oid];
+ return holder == null ? null : holder.Parameters;
+ }
+
+ /**
+ * return the object identifier signified by the passed in name. Null
+ * if there is no object identifier associated with name.
+ *
+ * @return the object identifier associated with name, if present.
+ */
+ public static DerObjectIdentifier GetOid(
+ string name)
+ {
+ return (DerObjectIdentifier)objIds[Platform.ToUpperInvariant(name)];
+ }
+
+ /**
+ * return the named curve name represented by the given object identifier.
+ */
+ public static string GetName(
+ DerObjectIdentifier oid)
+ {
+ return (string)names[oid];
+ }
+
+ /**
+ * returns an enumeration containing the name strings for curves
+ * contained in this structure.
+ */
+ public static IEnumerable Names
+ {
+ get { return new EnumerableProxy(names.Values); }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/gm/GMObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/gm/GMObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..edb3a41c579f8d230daf1152c26d840ef94f3b47
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/gm/GMObjectIdentifiers.cs
@@ -0,0 +1,85 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.GM
+{
+ public abstract class GMObjectIdentifiers
+ {
+ public static readonly DerObjectIdentifier sm_scheme = new DerObjectIdentifier("1.2.156.10197.1");
+
+ public static readonly DerObjectIdentifier sm6_ecb = sm_scheme.Branch("101.1");
+ public static readonly DerObjectIdentifier sm6_cbc = sm_scheme.Branch("101.2");
+ public static readonly DerObjectIdentifier sm6_ofb128 = sm_scheme.Branch("101.3");
+ public static readonly DerObjectIdentifier sm6_cfb128 = sm_scheme.Branch("101.4");
+
+ public static readonly DerObjectIdentifier sm1_ecb = sm_scheme.Branch("102.1");
+ public static readonly DerObjectIdentifier sm1_cbc = sm_scheme.Branch("102.2");
+ public static readonly DerObjectIdentifier sm1_ofb128 = sm_scheme.Branch("102.3");
+ public static readonly DerObjectIdentifier sm1_cfb128 = sm_scheme.Branch("102.4");
+ public static readonly DerObjectIdentifier sm1_cfb1 = sm_scheme.Branch("102.5");
+ public static readonly DerObjectIdentifier sm1_cfb8 = sm_scheme.Branch("102.6");
+
+ public static readonly DerObjectIdentifier ssf33_ecb = sm_scheme.Branch("103.1");
+ public static readonly DerObjectIdentifier ssf33_cbc = sm_scheme.Branch("103.2");
+ public static readonly DerObjectIdentifier ssf33_ofb128 = sm_scheme.Branch("103.3");
+ public static readonly DerObjectIdentifier ssf33_cfb128 = sm_scheme.Branch("103.4");
+ public static readonly DerObjectIdentifier ssf33_cfb1 = sm_scheme.Branch("103.5");
+ public static readonly DerObjectIdentifier ssf33_cfb8 = sm_scheme.Branch("103.6");
+
+ public static readonly DerObjectIdentifier sms4_ecb = sm_scheme.Branch("104.1");
+ public static readonly DerObjectIdentifier sms4_cbc = sm_scheme.Branch("104.2");
+ public static readonly DerObjectIdentifier sms4_ofb128 = sm_scheme.Branch("104.3");
+ public static readonly DerObjectIdentifier sms4_cfb128 = sm_scheme.Branch("104.4");
+ public static readonly DerObjectIdentifier sms4_cfb1 = sm_scheme.Branch("104.5");
+ public static readonly DerObjectIdentifier sms4_cfb8 = sm_scheme.Branch("104.6");
+ public static readonly DerObjectIdentifier sms4_ctr = sm_scheme.Branch("104.7");
+ public static readonly DerObjectIdentifier sms4_gcm = sm_scheme.Branch("104.8");
+ public static readonly DerObjectIdentifier sms4_ccm = sm_scheme.Branch("104.9");
+ public static readonly DerObjectIdentifier sms4_xts = sm_scheme.Branch("104.10");
+ public static readonly DerObjectIdentifier sms4_wrap = sm_scheme.Branch("104.11");
+ public static readonly DerObjectIdentifier sms4_wrap_pad = sm_scheme.Branch("104.12");
+ public static readonly DerObjectIdentifier sms4_ocb = sm_scheme.Branch("104.100");
+
+ public static readonly DerObjectIdentifier sm5 = sm_scheme.Branch("201");
+
+ public static readonly DerObjectIdentifier sm2p256v1 = sm_scheme.Branch("301");
+ public static readonly DerObjectIdentifier sm2sign = sm_scheme.Branch("301.1");
+ public static readonly DerObjectIdentifier sm2exchange = sm_scheme.Branch("301.2");
+ public static readonly DerObjectIdentifier sm2encrypt = sm_scheme.Branch("301.3");
+
+ public static readonly DerObjectIdentifier wapip192v1 = sm_scheme.Branch("301.101");
+
+ public static readonly DerObjectIdentifier sm2encrypt_recommendedParameters = sm2encrypt.Branch("1");
+ public static readonly DerObjectIdentifier sm2encrypt_specifiedParameters = sm2encrypt.Branch("2");
+ public static readonly DerObjectIdentifier sm2encrypt_with_sm3 = sm2encrypt.Branch("2.1");
+ public static readonly DerObjectIdentifier sm2encrypt_with_sha1 = sm2encrypt.Branch("2.2");
+ public static readonly DerObjectIdentifier sm2encrypt_with_sha224 = sm2encrypt.Branch("2.3");
+ public static readonly DerObjectIdentifier sm2encrypt_with_sha256 = sm2encrypt.Branch("2.4");
+ public static readonly DerObjectIdentifier sm2encrypt_with_sha384 = sm2encrypt.Branch("2.5");
+ public static readonly DerObjectIdentifier sm2encrypt_with_sha512 = sm2encrypt.Branch("2.6");
+ public static readonly DerObjectIdentifier sm2encrypt_with_rmd160 = sm2encrypt.Branch("2.7");
+ public static readonly DerObjectIdentifier sm2encrypt_with_whirlpool = sm2encrypt.Branch("2.8");
+ public static readonly DerObjectIdentifier sm2encrypt_with_blake2b512 = sm2encrypt.Branch("2.9");
+ public static readonly DerObjectIdentifier sm2encrypt_with_blake2s256 = sm2encrypt.Branch("2.10");
+ public static readonly DerObjectIdentifier sm2encrypt_with_md5 = sm2encrypt.Branch("2.11");
+
+ public static readonly DerObjectIdentifier id_sm9PublicKey = sm_scheme.Branch("302");
+ public static readonly DerObjectIdentifier sm9sign = sm_scheme.Branch("302.1");
+ public static readonly DerObjectIdentifier sm9keyagreement = sm_scheme.Branch("302.2");
+ public static readonly DerObjectIdentifier sm9encrypt = sm_scheme.Branch("302.3");
+
+ public static readonly DerObjectIdentifier sm3 = sm_scheme.Branch("401");
+
+ public static readonly DerObjectIdentifier hmac_sm3 = sm3.Branch("2");
+
+ public static readonly DerObjectIdentifier sm2sign_with_sm3 = sm_scheme.Branch("501");
+ public static readonly DerObjectIdentifier sm2sign_with_sha1 = sm_scheme.Branch("502");
+ public static readonly DerObjectIdentifier sm2sign_with_sha256 = sm_scheme.Branch("503");
+ public static readonly DerObjectIdentifier sm2sign_with_sha512 = sm_scheme.Branch("504");
+ public static readonly DerObjectIdentifier sm2sign_with_sha224 = sm_scheme.Branch("505");
+ public static readonly DerObjectIdentifier sm2sign_with_sha384 = sm_scheme.Branch("506");
+ public static readonly DerObjectIdentifier sm2sign_with_rmd160 = sm_scheme.Branch("507");
+ public static readonly DerObjectIdentifier sm2sign_with_whirlpool = sm_scheme.Branch("520");
+ public static readonly DerObjectIdentifier sm2sign_with_blake2b512 = sm_scheme.Branch("521");
+ public static readonly DerObjectIdentifier sm2sign_with_blake2s256 = sm_scheme.Branch("522");
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/asn1/gnu/GNUObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/gnu/GNUObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b322ef233b4e652e3e9cb5c8d5ec2680a9a43086
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/gnu/GNUObjectIdentifiers.cs
@@ -0,0 +1,36 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Gnu
+{
+ public abstract class GnuObjectIdentifiers
+ {
+ public static readonly DerObjectIdentifier Gnu = new DerObjectIdentifier("1.3.6.1.4.1.11591.1"); // GNU Radius
+ public static readonly DerObjectIdentifier GnuPG = new DerObjectIdentifier("1.3.6.1.4.1.11591.2"); // GnuPG (Ägypten)
+ public static readonly DerObjectIdentifier Notation = new DerObjectIdentifier("1.3.6.1.4.1.11591.2.1"); // notation
+ public static readonly DerObjectIdentifier PkaAddress = new DerObjectIdentifier("1.3.6.1.4.1.11591.2.1.1"); // pkaAddress
+ public static readonly DerObjectIdentifier GnuRadar = new DerObjectIdentifier("1.3.6.1.4.1.11591.3"); // GNU Radar
+ public static readonly DerObjectIdentifier DigestAlgorithm = new DerObjectIdentifier("1.3.6.1.4.1.11591.12"); // digestAlgorithm
+ public static readonly DerObjectIdentifier Tiger192 = new DerObjectIdentifier("1.3.6.1.4.1.11591.12.2"); // TIGER/192
+ public static readonly DerObjectIdentifier EncryptionAlgorithm = new DerObjectIdentifier("1.3.6.1.4.1.11591.13"); // encryptionAlgorithm
+ public static readonly DerObjectIdentifier Serpent = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2"); // Serpent
+ public static readonly DerObjectIdentifier Serpent128Ecb = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.1"); // Serpent-128-ECB
+ public static readonly DerObjectIdentifier Serpent128Cbc = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.2"); // Serpent-128-CBC
+ public static readonly DerObjectIdentifier Serpent128Ofb = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.3"); // Serpent-128-OFB
+ public static readonly DerObjectIdentifier Serpent128Cfb = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.4"); // Serpent-128-CFB
+ public static readonly DerObjectIdentifier Serpent192Ecb = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.21"); // Serpent-192-ECB
+ public static readonly DerObjectIdentifier Serpent192Cbc = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.22"); // Serpent-192-CBC
+ public static readonly DerObjectIdentifier Serpent192Ofb = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.23"); // Serpent-192-OFB
+ public static readonly DerObjectIdentifier Serpent192Cfb = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.24"); // Serpent-192-CFB
+ public static readonly DerObjectIdentifier Serpent256Ecb = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.41"); // Serpent-256-ECB
+ public static readonly DerObjectIdentifier Serpent256Cbc = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.42"); // Serpent-256-CBC
+ public static readonly DerObjectIdentifier Serpent256Ofb = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.43"); // Serpent-256-OFB
+ public static readonly DerObjectIdentifier Serpent256Cfb = new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.44"); // Serpent-256-CFB
+ public static readonly DerObjectIdentifier Crc = new DerObjectIdentifier("1.3.6.1.4.1.11591.14"); // CRC algorithms
+ public static readonly DerObjectIdentifier Crc32 = new DerObjectIdentifier("1.3.6.1.4.1.11591.14.1"); // CRC 32
+
+ /** 1.3.6.1.4.1.11591.15 - ellipticCurve */
+ public static readonly DerObjectIdentifier EllipticCurve = new DerObjectIdentifier("1.3.6.1.4.1.11591.15");
+
+ public static readonly DerObjectIdentifier Ed25519 = EllipticCurve.Branch("1");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/iana/IANAObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/iana/IANAObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..63343f5ce2c904a71ccc1240faccb03b65ec24c1
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/iana/IANAObjectIdentifiers.cs
@@ -0,0 +1,18 @@
+namespace Org.BouncyCastle.Asn1.Iana
+{
+ public abstract class IanaObjectIdentifiers
+ {
+ // id-SHA1 OBJECT IDENTIFIER ::=
+ // {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) ipsec(8) isakmpOakley(1)}
+ //
+
+ public static readonly DerObjectIdentifier IsakmpOakley = new DerObjectIdentifier("1.3.6.1.5.5.8.1");
+
+ public static readonly DerObjectIdentifier HmacMD5 = new DerObjectIdentifier(IsakmpOakley + ".1");
+ public static readonly DerObjectIdentifier HmacSha1 = new DerObjectIdentifier(IsakmpOakley + ".2");
+
+ public static readonly DerObjectIdentifier HmacTiger = new DerObjectIdentifier(IsakmpOakley + ".3");
+
+ public static readonly DerObjectIdentifier HmacRipeMD160 = new DerObjectIdentifier(IsakmpOakley + ".4");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/icao/CscaMasterList.cs b/bc-sharp-crypto/src/asn1/icao/CscaMasterList.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6890d8a2e5479c68e705ee135fff4a20ec31d995
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/icao/CscaMasterList.cs
@@ -0,0 +1,83 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+ /**
+ * The CscaMasterList object. This object can be wrapped in a
+ * CMSSignedData to be published in LDAP.
+ *
+ *
+ * CscaMasterList ::= SEQUENCE {
+ * version CscaMasterListVersion,
+ * certList SET OF Certificate }
+ *
+ * CscaMasterListVersion :: INTEGER {v0(0)}
+ *
+ */
+ public class CscaMasterList
+ : Asn1Encodable
+ {
+ private DerInteger version = new DerInteger(0);
+ private X509CertificateStructure[] certList;
+
+ public static CscaMasterList GetInstance(
+ object obj)
+ {
+ if (obj is CscaMasterList)
+ return (CscaMasterList)obj;
+
+ if (obj != null)
+ return new CscaMasterList(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ private CscaMasterList(
+ Asn1Sequence seq)
+ {
+ if (seq == null || seq.Count == 0)
+ throw new ArgumentException("null or empty sequence passed.");
+
+ if (seq.Count != 2)
+ throw new ArgumentException("Incorrect sequence size: " + seq.Count);
+
+ this.version = DerInteger.GetInstance(seq[0]);
+
+ Asn1Set certSet = Asn1Set.GetInstance(seq[1]);
+
+ this.certList = new X509CertificateStructure[certSet.Count];
+ for (int i = 0; i < certList.Length; i++)
+ {
+ certList[i] = X509CertificateStructure.GetInstance(certSet[i]);
+ }
+ }
+
+ public CscaMasterList(
+ X509CertificateStructure[] certStructs)
+ {
+ certList = CopyCertList(certStructs);
+ }
+
+ public virtual int Version
+ {
+ get { return version.Value.IntValue; }
+ }
+
+ public X509CertificateStructure[] GetCertStructs()
+ {
+ return CopyCertList(certList);
+ }
+
+ private static X509CertificateStructure[] CopyCertList(X509CertificateStructure[] orig)
+ {
+ return (X509CertificateStructure[])orig.Clone();
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(version, new DerSet(certList));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/icao/DataGroupHash.cs b/bc-sharp-crypto/src/asn1/icao/DataGroupHash.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e0d7eee7b581b39d24f95d2717165f9b4a5bc6c3
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/icao/DataGroupHash.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+ /**
+ * The DataGroupHash object.
+ *
+ * DataGroupHash ::= SEQUENCE {
+ * dataGroupNumber DataGroupNumber,
+ * dataGroupHashValue OCTET STRING }
+ *
+ * DataGroupNumber ::= INTEGER {
+ * dataGroup1 (1),
+ * dataGroup1 (2),
+ * dataGroup1 (3),
+ * dataGroup1 (4),
+ * dataGroup1 (5),
+ * dataGroup1 (6),
+ * dataGroup1 (7),
+ * dataGroup1 (8),
+ * dataGroup1 (9),
+ * dataGroup1 (10),
+ * dataGroup1 (11),
+ * dataGroup1 (12),
+ * dataGroup1 (13),
+ * dataGroup1 (14),
+ * dataGroup1 (15),
+ * dataGroup1 (16) }
+ *
+ *
+ */
+ public class DataGroupHash
+ : Asn1Encodable
+ {
+ private readonly DerInteger dataGroupNumber;
+ private readonly Asn1OctetString dataGroupHashValue;
+
+ public static DataGroupHash GetInstance(
+ object obj)
+ {
+ if (obj is DataGroupHash)
+ return (DataGroupHash)obj;
+
+ if (obj != null)
+ return new DataGroupHash(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ private DataGroupHash(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ this.dataGroupNumber = DerInteger.GetInstance(seq[0]);
+ this.dataGroupHashValue = Asn1OctetString.GetInstance(seq[1]);
+ }
+
+ public DataGroupHash(
+ int dataGroupNumber,
+ Asn1OctetString dataGroupHashValue)
+ {
+ this.dataGroupNumber = new DerInteger(dataGroupNumber);
+ this.dataGroupHashValue = dataGroupHashValue;
+ }
+
+ public int DataGroupNumber
+ {
+ get { return dataGroupNumber.Value.IntValue; }
+ }
+
+ public Asn1OctetString DataGroupHashValue
+ {
+ get { return dataGroupHashValue; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(dataGroupNumber, dataGroupHashValue);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/icao/ICAOObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/icao/ICAOObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..389d4dacd9ca12460dc910f27431bee63b7b12b5
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/icao/ICAOObjectIdentifiers.cs
@@ -0,0 +1,34 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+ public abstract class IcaoObjectIdentifiers
+ {
+ //
+ // base id
+ //
+ public static readonly DerObjectIdentifier IdIcao = new DerObjectIdentifier("2.23.136");
+
+ public static readonly DerObjectIdentifier IdIcaoMrtd = IdIcao.Branch("1");
+ public static readonly DerObjectIdentifier IdIcaoMrtdSecurity = IdIcaoMrtd.Branch("1");
+
+ // LDS security object, see ICAO Doc 9303-Volume 2-Section IV-A3.2
+ public static readonly DerObjectIdentifier IdIcaoLdsSecurityObject = IdIcaoMrtdSecurity.Branch("1");
+
+ // CSCA master list, see TR CSCA Countersigning and Master List issuance
+ public static readonly DerObjectIdentifier IdIcaoCscaMasterList = IdIcaoMrtdSecurity.Branch("2");
+ public static readonly DerObjectIdentifier IdIcaoCscaMasterListSigningKey = IdIcaoMrtdSecurity.Branch("3");
+
+ // document type list, see draft TR LDS and PKI Maintenance, par. 3.2.1
+ public static readonly DerObjectIdentifier IdIcaoDocumentTypeList = IdIcaoMrtdSecurity.Branch("4");
+
+ // Active Authentication protocol, see draft TR LDS and PKI Maintenance,
+ // par. 5.2.2
+ public static readonly DerObjectIdentifier IdIcaoAAProtocolObject = IdIcaoMrtdSecurity.Branch("5");
+
+ // CSCA name change and key reoll-over, see draft TR LDS and PKI
+ // Maintenance, par. 3.2.1
+ public static readonly DerObjectIdentifier IdIcaoExtensions = IdIcaoMrtdSecurity.Branch("6");
+ public static readonly DerObjectIdentifier IdIcaoExtensionsNamechangekeyrollover = IdIcaoExtensions.Branch("1");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/icao/LDSSecurityObject.cs b/bc-sharp-crypto/src/asn1/icao/LDSSecurityObject.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c33ca68772502cf0016e894c458e015dc6fb52da
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/icao/LDSSecurityObject.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+ /**
+ * The LDSSecurityObject object (V1.8).
+ *
+ * LDSSecurityObject ::= SEQUENCE {
+ * version LDSSecurityObjectVersion,
+ * hashAlgorithm DigestAlgorithmIdentifier,
+ * dataGroupHashValues SEQUENCE SIZE (2..ub-DataGroups) OF DataHashGroup,
+ * ldsVersionInfo LDSVersionInfo OPTIONAL
+ * -- if present, version MUST be v1 }
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier,
+ *
+ * LDSSecurityObjectVersion :: INTEGER {V0(0)}
+ *
+ */
+ public class LdsSecurityObject
+ : Asn1Encodable
+ {
+ public const int UBDataGroups = 16;
+
+ private DerInteger version = new DerInteger(0);
+ private AlgorithmIdentifier digestAlgorithmIdentifier;
+ private DataGroupHash[] datagroupHash;
+ private LdsVersionInfo versionInfo;
+
+ public static LdsSecurityObject GetInstance(
+ object obj)
+ {
+ if (obj is LdsSecurityObject)
+ return (LdsSecurityObject)obj;
+
+ if (obj != null)
+ return new LdsSecurityObject(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ private LdsSecurityObject(
+ Asn1Sequence seq)
+ {
+ if (seq == null || seq.Count == 0)
+ throw new ArgumentException("null or empty sequence passed.");
+
+ IEnumerator e = seq.GetEnumerator();
+
+ // version
+ e.MoveNext();
+ version = DerInteger.GetInstance(e.Current);
+ // digestAlgorithmIdentifier
+ e.MoveNext();
+ digestAlgorithmIdentifier = AlgorithmIdentifier.GetInstance(e.Current);
+
+ e.MoveNext();
+ Asn1Sequence datagroupHashSeq = Asn1Sequence.GetInstance(e.Current);
+
+ if (version.Value.Equals(BigInteger.One))
+ {
+ e.MoveNext();
+ versionInfo = LdsVersionInfo.GetInstance(e.Current);
+ }
+
+ CheckDatagroupHashSeqSize(datagroupHashSeq.Count);
+
+ datagroupHash = new DataGroupHash[datagroupHashSeq.Count];
+ for (int i= 0; i< datagroupHashSeq.Count; i++)
+ {
+ datagroupHash[i] = DataGroupHash.GetInstance(datagroupHashSeq[i]);
+ }
+ }
+
+ public LdsSecurityObject(
+ AlgorithmIdentifier digestAlgorithmIdentifier,
+ DataGroupHash[] datagroupHash)
+ {
+ this.version = new DerInteger(0);
+ this.digestAlgorithmIdentifier = digestAlgorithmIdentifier;
+ this.datagroupHash = datagroupHash;
+
+ CheckDatagroupHashSeqSize(datagroupHash.Length);
+ }
+
+
+ public LdsSecurityObject(
+ AlgorithmIdentifier digestAlgorithmIdentifier,
+ DataGroupHash[] datagroupHash,
+ LdsVersionInfo versionInfo)
+ {
+ this.version = new DerInteger(1);
+ this.digestAlgorithmIdentifier = digestAlgorithmIdentifier;
+ this.datagroupHash = datagroupHash;
+ this.versionInfo = versionInfo;
+
+ CheckDatagroupHashSeqSize(datagroupHash.Length);
+ }
+
+ private void CheckDatagroupHashSeqSize(int size)
+ {
+ if (size < 2 || size > UBDataGroups)
+ throw new ArgumentException("wrong size in DataGroupHashValues : not in (2.."+ UBDataGroups +")");
+ }
+
+ public BigInteger Version
+ {
+ get { return version.Value; }
+ }
+
+ public AlgorithmIdentifier DigestAlgorithmIdentifier
+ {
+ get { return digestAlgorithmIdentifier; }
+ }
+
+ public DataGroupHash[] GetDatagroupHash()
+ {
+ return datagroupHash;
+ }
+
+ public LdsVersionInfo VersionInfo
+ {
+ get { return versionInfo; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ DerSequence hashSeq = new DerSequence(datagroupHash);
+
+ Asn1EncodableVector v = new Asn1EncodableVector(version, digestAlgorithmIdentifier, hashSeq);
+
+ if (versionInfo != null)
+ {
+ v.Add(versionInfo);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/icao/LDSVersionInfo.cs b/bc-sharp-crypto/src/asn1/icao/LDSVersionInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2cdcad2dbabe2381b201c36d38ccf2e96f0f635c
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/icao/LDSVersionInfo.cs
@@ -0,0 +1,61 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+ public class LdsVersionInfo
+ : Asn1Encodable
+ {
+ private DerPrintableString ldsVersion;
+ private DerPrintableString unicodeVersion;
+
+ public LdsVersionInfo(string ldsVersion, string unicodeVersion)
+ {
+ this.ldsVersion = new DerPrintableString(ldsVersion);
+ this.unicodeVersion = new DerPrintableString(unicodeVersion);
+ }
+
+ private LdsVersionInfo(Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("sequence wrong size for LDSVersionInfo", "seq");
+
+ this.ldsVersion = DerPrintableString.GetInstance(seq[0]);
+ this.unicodeVersion = DerPrintableString.GetInstance(seq[1]);
+ }
+
+ public static LdsVersionInfo GetInstance(object obj)
+ {
+ if (obj is LdsVersionInfo)
+ return (LdsVersionInfo)obj;
+
+ if (obj != null)
+ return new LdsVersionInfo(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ public virtual string GetLdsVersion()
+ {
+ return ldsVersion.GetString();
+ }
+
+ public virtual string GetUnicodeVersion()
+ {
+ return unicodeVersion.GetString();
+ }
+
+ /**
+ *
+ * LDSVersionInfo ::= SEQUENCE {
+ * ldsVersion PRINTABLE STRING
+ * unicodeVersion PRINTABLE STRING
+ * }
+ *
+ * @return
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(ldsVersion, unicodeVersion);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/isismtt/ISISMTTObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/isismtt/ISISMTTObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..af60b030a0e916efdcc95729b95a85e344b615de
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/isismtt/ISISMTTObjectIdentifiers.cs
@@ -0,0 +1,177 @@
+namespace Org.BouncyCastle.Asn1.IsisMtt
+{
+ public abstract class IsisMttObjectIdentifiers
+ {
+ public static readonly DerObjectIdentifier IdIsisMtt = new DerObjectIdentifier("1.3.36.8");
+
+ public static readonly DerObjectIdentifier IdIsisMttCP = new DerObjectIdentifier(IdIsisMtt + ".1");
+
+ /**
+ * The id-isismtt-cp-accredited OID indicates that the certificate is a
+ * qualified certificate according to Directive 1999/93/EC of the European
+ * Parliament and of the Council of 13 December 1999 on a Community
+ * Framework for Electronic Signatures, which additionally conforms the
+ * special requirements of the SigG and has been issued by an accredited CA.
+ */
+ public static readonly DerObjectIdentifier IdIsisMttCPAccredited = new DerObjectIdentifier(IdIsisMttCP + ".1");
+
+ public static readonly DerObjectIdentifier IdIsisMttAT = new DerObjectIdentifier(IdIsisMtt + ".3");
+
+ /**
+ * Certificate extensionDate of certificate generation
+ *
+ *
+ * DateOfCertGenSyntax ::= GeneralizedTime
+ *
+ */
+ public static readonly DerObjectIdentifier IdIsisMttATDateOfCertGen = new DerObjectIdentifier(IdIsisMttAT + ".1");
+
+ /**
+ * Attribute to indicate that the certificate holder may sign in the name of
+ * a third person. May also be used as extension in a certificate.
+ */
+ public static readonly DerObjectIdentifier IdIsisMttATProcuration = new DerObjectIdentifier(IdIsisMttAT + ".2");
+
+ /**
+ * Attribute to indicate admissions to certain professions. May be used as
+ * attribute in attribute certificate or as extension in a certificate
+ */
+ public static readonly DerObjectIdentifier IdIsisMttATAdmission = new DerObjectIdentifier(IdIsisMttAT + ".3");
+
+ /**
+ * Monetary limit for transactions. The QcEuMonetaryLimit QC statement MUST
+ * be used in new certificates in place of the extension/attribute
+ * MonetaryLimit since January 1, 2004. For the sake of backward
+ * compatibility with certificates already in use, SigG conforming
+ * components MUST support MonetaryLimit (as well as QcEuLimitValue).
+ */
+ public static readonly DerObjectIdentifier IdIsisMttATMonetaryLimit = new DerObjectIdentifier(IdIsisMttAT + ".4");
+
+ /**
+ * A declaration of majority. May be used as attribute in attribute
+ * certificate or as extension in a certificate
+ */
+ public static readonly DerObjectIdentifier IdIsisMttATDeclarationOfMajority = new DerObjectIdentifier(IdIsisMttAT + ".5");
+
+ /**
+ *
+ * Serial number of the smart card containing the corresponding private key
+ *
+ *
+ * ICCSNSyntax ::= OCTET STRING (SIZE(8..20))
+ *
+ */
+ public static readonly DerObjectIdentifier IdIsisMttATIccsn = new DerObjectIdentifier(IdIsisMttAT + ".6");
+
+ /**
+ *
+ * Reference for a file of a smartcard that stores the public key of this
+ * certificate and that is used as �security anchor�.
+ *
+ *
+ * PKReferenceSyntax ::= OCTET STRING (SIZE(20))
+ *
+ */
+ public static readonly DerObjectIdentifier IdIsisMttATPKReference = new DerObjectIdentifier(IdIsisMttAT + ".7");
+
+ /**
+ * Some other restriction regarding the usage of this certificate. May be
+ * used as attribute in attribute certificate or as extension in a
+ * certificate.
+ *
+ *
+ * RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+ *
+ *
+ * @see Org.BouncyCastle.Asn1.IsisMtt.X509.Restriction
+ */
+ public static readonly DerObjectIdentifier IdIsisMttATRestriction = new DerObjectIdentifier(IdIsisMttAT + ".8");
+
+ /**
+ *
+ * (Single)Request extension: Clients may include this extension in a
+ * (single) Request to request the responder to send the certificate in the
+ * response message along with the status information. Besides the LDAP
+ * service, this extension provides another mechanism for the distribution
+ * of certificates, which MAY optionally be provided by certificate
+ * repositories.
+ *
+ *
+ * RetrieveIfAllowed ::= BOOLEAN
+ *
+ */
+ public static readonly DerObjectIdentifier IdIsisMttATRetrieveIfAllowed = new DerObjectIdentifier(IdIsisMttAT + ".9");
+
+ /**
+ * SingleOCSPResponse extension: The certificate requested by the client by
+ * inserting the RetrieveIfAllowed extension in the request, will be
+ * returned in this extension.
+ *
+ * @see Org.BouncyCastle.Asn1.IsisMtt.Ocsp.RequestedCertificate
+ */
+ public static readonly DerObjectIdentifier IdIsisMttATRequestedCertificate = new DerObjectIdentifier(IdIsisMttAT + ".10");
+
+ /**
+ * Base ObjectIdentifier for naming authorities
+ */
+ public static readonly DerObjectIdentifier IdIsisMttATNamingAuthorities = new DerObjectIdentifier(IdIsisMttAT + ".11");
+
+ /**
+ * SingleOCSPResponse extension: Date, when certificate has been published
+ * in the directory and status information has become available. Currently,
+ * accrediting authorities enforce that SigG-conforming OCSP servers include
+ * this extension in the responses.
+ *
+ *
+ * CertInDirSince ::= GeneralizedTime
+ *
+ */
+ public static readonly DerObjectIdentifier IdIsisMttATCertInDirSince = new DerObjectIdentifier(IdIsisMttAT + ".12");
+
+ /**
+ * Hash of a certificate in OCSP.
+ *
+ * @see Org.BouncyCastle.Asn1.IsisMtt.Ocsp.CertHash
+ */
+ public static readonly DerObjectIdentifier IdIsisMttATCertHash = new DerObjectIdentifier(IdIsisMttAT + ".13");
+
+ /**
+ *
+ * NameAtBirth ::= DirectoryString(SIZE(1..64)
+ *
+ *
+ * Used in
+ * {@link Org.BouncyCastle.Asn1.X509.SubjectDirectoryAttributes SubjectDirectoryAttributes}
+ */
+ public static readonly DerObjectIdentifier IdIsisMttATNameAtBirth = new DerObjectIdentifier(IdIsisMttAT + ".14");
+
+ /**
+ * Some other information of non-restrictive nature regarding the usage of
+ * this certificate. May be used as attribute in atribute certificate or as
+ * extension in a certificate.
+ *
+ *
+ * AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
+ *
+ *
+ * @see Org.BouncyCastle.Asn1.IsisMtt.X509.AdditionalInformationSyntax
+ */
+ public static readonly DerObjectIdentifier IdIsisMttATAdditionalInformation = new DerObjectIdentifier(IdIsisMttAT + ".15");
+
+ /**
+ * Indicates that an attribute certificate exists, which limits the
+ * usability of this public key certificate. Whenever verifying a signature
+ * with the help of this certificate, the content of the corresponding
+ * attribute certificate should be concerned. This extension MUST be
+ * included in a PKC, if a corresponding attribute certificate (having the
+ * PKC as base certificate) contains some attribute that restricts the
+ * usability of the PKC too. Attribute certificates with restricting content
+ * MUST always be included in the signed document.
+ *
+ *
+ * LiabilityLimitationFlagSyntax ::= BOOLEAN
+ *
+ */
+ public static readonly DerObjectIdentifier IdIsisMttATLiabilityLimitationFlag = new DerObjectIdentifier("0.2.262.1.10.12.0");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/isismtt/ocsp/CertHash.cs b/bc-sharp-crypto/src/asn1/isismtt/ocsp/CertHash.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5773e1c565c017c5d1d46f21b9c0ef8df1df22d3
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/isismtt/ocsp/CertHash.cs
@@ -0,0 +1,122 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp
+{
+ /**
+ * ISIS-MTT PROFILE: The responder may include this extension in a response to
+ * send the hash of the requested certificate to the responder. This hash is
+ * cryptographically bound to the certificate and serves as evidence that the
+ * certificate is known to the responder (i.e. it has been issued and is present
+ * in the directory). Hence, this extension is a means to provide a positive
+ * statement of availability as described in T8.[8]. As explained in T13.[1],
+ * clients may rely on this information to be able to validate signatures after
+ * the expiry of the corresponding certificate. Hence, clients MUST support this
+ * extension. If a positive statement of availability is to be delivered, this
+ * extension syntax and OID MUST be used.
+ *
+ *
+ *
+ * CertHash ::= SEQUENCE {
+ * hashAlgorithm AlgorithmIdentifier,
+ * certificateHash OCTET STRING
+ * }
+ *
+ */
+ public class CertHash
+ : Asn1Encodable
+ {
+ private readonly AlgorithmIdentifier hashAlgorithm;
+ private readonly byte[] certificateHash;
+
+ public static CertHash GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is CertHash)
+ {
+ return (CertHash) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new CertHash((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * Constructor from Asn1Sequence.
+ *
+ * The sequence is of type CertHash:
+ *
+ *
+ * CertHash ::= SEQUENCE {
+ * hashAlgorithm AlgorithmIdentifier,
+ * certificateHash OCTET STRING
+ * }
+ *
+ *
+ * @param seq The ASN.1 sequence.
+ */
+ private CertHash(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+ this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]);
+ this.certificateHash = DerOctetString.GetInstance(seq[1]).GetOctets();
+ }
+
+ /**
+ * Constructor from a given details.
+ *
+ * @param hashAlgorithm The hash algorithm identifier.
+ * @param certificateHash The hash of the whole DER encoding of the certificate.
+ */
+ public CertHash(
+ AlgorithmIdentifier hashAlgorithm,
+ byte[] certificateHash)
+ {
+ if (hashAlgorithm == null)
+ throw new ArgumentNullException("hashAlgorithm");
+ if (certificateHash == null)
+ throw new ArgumentNullException("certificateHash");
+
+ this.hashAlgorithm = hashAlgorithm;
+ this.certificateHash = (byte[]) certificateHash.Clone();
+ }
+
+ public AlgorithmIdentifier HashAlgorithm
+ {
+ get { return hashAlgorithm; }
+ }
+
+ public byte[] CertificateHash
+ {
+ get { return (byte[]) certificateHash.Clone(); }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * CertHash ::= SEQUENCE {
+ * hashAlgorithm AlgorithmIdentifier,
+ * certificateHash OCTET STRING
+ * }
+ *
+ *
+ * @return an Asn1Object
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(hashAlgorithm, new DerOctetString(certificateHash));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/isismtt/ocsp/RequestedCertificate.cs b/bc-sharp-crypto/src/asn1/isismtt/ocsp/RequestedCertificate.cs
new file mode 100644
index 0000000000000000000000000000000000000000..413b3bd7fc99d953b4d96d7b80a58bcf13554712
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/isismtt/ocsp/RequestedCertificate.cs
@@ -0,0 +1,188 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp
+{
+ /**
+ * ISIS-MTT-Optional: The certificate requested by the client by inserting the
+ * RetrieveIfAllowed extension in the request, will be returned in this
+ * extension.
+ *
+ * ISIS-MTT-SigG: The signature act allows publishing certificates only then,
+ * when the certificate owner gives his isExplicit permission. Accordingly, there
+ * may be �nondownloadable� certificates, about which the responder must provide
+ * status information, but MUST NOT include them in the response. Clients may
+ * get therefore the following three kind of answers on a single request
+ * including the RetrieveIfAllowed extension:
+ *
+ * a) the responder supports the extension and is allowed to publish the
+ * certificate: RequestedCertificate returned including the requested
+ * certificate
+ * b) the responder supports the extension but is NOT allowed to publish
+ * the certificate: RequestedCertificate returned including an empty OCTET
+ * STRING
+ * c) the responder does not support the extension: RequestedCertificate is
+ * not included in the response
+ *
+ * Clients requesting RetrieveIfAllowed MUST be able to handle these cases. If
+ * any of the OCTET STRING options is used, it MUST contain the DER encoding of
+ * the requested certificate.
+ *
+ *
+ * RequestedCertificate ::= CHOICE {
+ * Certificate Certificate,
+ * publicKeyCertificate [0] EXPLICIT OCTET STRING,
+ * attributeCertificate [1] EXPLICIT OCTET STRING
+ * }
+ *
+ */
+ public class RequestedCertificate
+ : Asn1Encodable, IAsn1Choice
+ {
+ public enum Choice
+ {
+ Certificate = -1,
+ PublicKeyCertificate = 0,
+ AttributeCertificate = 1
+ }
+
+ private readonly X509CertificateStructure cert;
+ private readonly byte[] publicKeyCert;
+ private readonly byte[] attributeCert;
+
+ public static RequestedCertificate GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is RequestedCertificate)
+ {
+ return (RequestedCertificate) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new RequestedCertificate(X509CertificateStructure.GetInstance(obj));
+ }
+
+ if (obj is Asn1TaggedObject)
+ {
+ return new RequestedCertificate((Asn1TaggedObject) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public static RequestedCertificate GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ if (!isExplicit)
+ throw new ArgumentException("choice item must be explicitly tagged");
+
+ return GetInstance(obj.GetObject());
+ }
+
+ private RequestedCertificate(
+ Asn1TaggedObject tagged)
+ {
+ switch ((Choice) tagged.TagNo)
+ {
+ case Choice.AttributeCertificate:
+ this.attributeCert = Asn1OctetString.GetInstance(tagged, true).GetOctets();
+ break;
+ case Choice.PublicKeyCertificate:
+ this.publicKeyCert = Asn1OctetString.GetInstance(tagged, true).GetOctets();
+ break;
+ default:
+ throw new ArgumentException("unknown tag number: " + tagged.TagNo);
+ }
+ }
+
+ /**
+ * Constructor from a given details.
+ *
+ * Only one parameter can be given. All other must be null
.
+ *
+ * @param certificate Given as Certificate
+ */
+ public RequestedCertificate(
+ X509CertificateStructure certificate)
+ {
+ this.cert = certificate;
+ }
+
+ public RequestedCertificate(
+ Choice type,
+ byte[] certificateOctets)
+ : this(new DerTaggedObject((int) type, new DerOctetString(certificateOctets)))
+ {
+ }
+
+ public Choice Type
+ {
+ get
+ {
+ if (cert != null)
+ return Choice.Certificate;
+
+ if (publicKeyCert != null)
+ return Choice.PublicKeyCertificate;
+
+ return Choice.AttributeCertificate;
+ }
+ }
+
+ public byte[] GetCertificateBytes()
+ {
+ if (cert != null)
+ {
+ try
+ {
+ return cert.GetEncoded();
+ }
+ catch (IOException e)
+ {
+ throw new InvalidOperationException("can't decode certificate: " + e);
+ }
+ }
+
+ if (publicKeyCert != null)
+ return publicKeyCert;
+
+ return attributeCert;
+ }
+
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * RequestedCertificate ::= CHOICE {
+ * Certificate Certificate,
+ * publicKeyCertificate [0] EXPLICIT OCTET STRING,
+ * attributeCertificate [1] EXPLICIT OCTET STRING
+ * }
+ *
+ *
+ * @return an Asn1Object
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ if (publicKeyCert != null)
+ {
+ return new DerTaggedObject(0, new DerOctetString(publicKeyCert));
+ }
+
+ if (attributeCert != null)
+ {
+ return new DerTaggedObject(1, new DerOctetString(attributeCert));
+ }
+
+ return cert.ToAsn1Object();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/isismtt/x509/AdditionalInformationSyntax.cs b/bc-sharp-crypto/src/asn1/isismtt/x509/AdditionalInformationSyntax.cs
new file mode 100644
index 0000000000000000000000000000000000000000..53a8e98a72c034fa4ff9711254fdbb471cbbac62
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/isismtt/x509/AdditionalInformationSyntax.cs
@@ -0,0 +1,71 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+ /**
+ * Some other information of non-restrictive nature regarding the usage of this
+ * certificate.
+ *
+ *
+ * AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
+ *
+ */
+ public class AdditionalInformationSyntax
+ : Asn1Encodable
+ {
+ private readonly DirectoryString information;
+
+ public static AdditionalInformationSyntax GetInstance(
+ object obj)
+ {
+ if (obj is AdditionalInformationSyntax)
+ return (AdditionalInformationSyntax) obj;
+
+ if (obj is IAsn1String)
+ return new AdditionalInformationSyntax(DirectoryString.GetInstance(obj));
+
+ throw new ArgumentException("Unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private AdditionalInformationSyntax(
+ DirectoryString information)
+ {
+ this.information = information;
+ }
+
+ /**
+ * Constructor from a given details.
+ *
+ * @param information The describtion of the information.
+ */
+ public AdditionalInformationSyntax(
+ string information)
+ {
+ this.information = new DirectoryString(information);
+ }
+
+ public virtual DirectoryString Information
+ {
+ get { return information; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
+ *
+ *
+ * @return an Asn1Object
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return information.ToAsn1Object();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/isismtt/x509/AdmissionSyntax.cs b/bc-sharp-crypto/src/asn1/isismtt/x509/AdmissionSyntax.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4b6264ae08759dbe4b2ff65cc8bac0af2f8acaed
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/isismtt/x509/AdmissionSyntax.cs
@@ -0,0 +1,278 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+ /**
+ * Attribute to indicate admissions to certain professions.
+ *
+ *
+ * AdmissionSyntax ::= SEQUENCE
+ * {
+ * admissionAuthority GeneralName OPTIONAL,
+ * contentsOfAdmissions SEQUENCE OF Admissions
+ * }
+ *
+ * Admissions ::= SEQUENCE
+ * {
+ * admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
+ * namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
+ * professionInfos SEQUENCE OF ProfessionInfo
+ * }
+ *
+ * NamingAuthority ::= SEQUENCE
+ * {
+ * namingAuthorityId OBJECT IDENTIFIER OPTIONAL,
+ * namingAuthorityUrl IA5String OPTIONAL,
+ * namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
+ * }
+ *
+ * ProfessionInfo ::= SEQUENCE
+ * {
+ * namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL,
+ * professionItems SEQUENCE OF DirectoryString (SIZE(1..128)),
+ * professionOIDs SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
+ * registrationNumber PrintableString(SIZE(1..128)) OPTIONAL,
+ * addProfessionInfo OCTET STRING OPTIONAL
+ * }
+ *
+ *
+ *
+ * ISIS-MTT PROFILE: The relatively complex structure of AdmissionSyntax
+ * supports the following concepts and requirements:
+ *
+ * External institutions (e.g. professional associations, chambers, unions,
+ * administrative bodies, companies, etc.), which are responsible for granting
+ * and verifying professional admissions, are indicated by means of the data
+ * field admissionAuthority. An admission authority is indicated by a
+ * GeneralName object. Here an X.501 directory name (distinguished name) can be
+ * indicated in the field directoryName, a URL address can be indicated in the
+ * field uniformResourceIdentifier, and an object identifier can be indicated in
+ * the field registeredId.
+ * The names of authorities which are responsible for the administration of
+ * title registers are indicated in the data field namingAuthority. The name of
+ * the authority can be identified by an object identifier in the field
+ * namingAuthorityId, by means of a text string in the field
+ * namingAuthorityText, by means of a URL address in the field
+ * namingAuthorityUrl, or by a combination of them. For example, the text string
+ * can contain the name of the authority, the country and the name of the title
+ * register. The URL-option refers to a web page which contains lists with
+ * officially registered professions (text and possibly OID) as well as
+ * further information on these professions. Object identifiers for the
+ * component namingAuthorityId are grouped under the OID-branch
+ * id-isis-at-namingAuthorities and must be applied for.
+ * See http://www.teletrust.de/anwend.asp?Id=30200&Sprache=E_&HomePG=0
+ * for an application form and http://www.teletrust.de/links.asp?id=30220,11
+ * for an overview of registered naming authorities.
+ * By means of the data type ProfessionInfo certain professions,
+ * specializations, disciplines, fields of activity, etc. are identified. A
+ * profession is represented by one or more text strings, resp. profession OIDs
+ * in the fields professionItems and professionOIDs and by a registration number
+ * in the field registrationNumber. An indication in text form must always be
+ * present, whereas the other indications are optional. The component
+ * addProfessionInfo may contain additional applicationspecific information in
+ * DER-encoded form.
+ *
+ *
+ * By means of different namingAuthority-OIDs or profession OIDs hierarchies of
+ * professions, specializations, disciplines, fields of activity, etc. can be
+ * expressed. The issuing admission authority should always be indicated (field
+ * admissionAuthority), whenever a registration number is presented. Still,
+ * information on admissions can be given without indicating an admission or a
+ * naming authority by the exclusive use of the component professionItems. In
+ * this case the certification authority is responsible for the verification of
+ * the admission information.
+ *
+ *
+ *
+ * This attribute is single-valued. Still, several admissions can be captured in
+ * the sequence structure of the component contentsOfAdmissions of
+ * AdmissionSyntax or in the component professionInfos of Admissions. The
+ * component admissionAuthority of AdmissionSyntax serves as default value for
+ * the component admissionAuthority of Admissions. Within the latter component
+ * the default value can be overwritten, in case that another authority is
+ * responsible. The component namingAuthority of Admissions serves as a default
+ * value for the component namingAuthority of ProfessionInfo. Within the latter
+ * component the default value can be overwritten, in case that another naming
+ * authority needs to be recorded.
+ *
+ * The length of the string objects is limited to 128 characters. It is
+ * recommended to indicate a namingAuthorityURL in all issued attribute
+ * certificates. If a namingAuthorityURL is indicated, the field professionItems
+ * of ProfessionInfo should contain only registered titles. If the field
+ * professionOIDs exists, it has to contain the OIDs of the professions listed
+ * in professionItems in the same order. In general, the field professionInfos
+ * should contain only one entry, unless the admissions that are to be listed
+ * are logically connected (e.g. they have been issued under the same admission
+ * number).
+ *
+ * @see Org.BouncyCastle.Asn1.IsisMtt.X509.Admissions
+ * @see Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo
+ * @see Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority
+ */
+ public class AdmissionSyntax
+ : Asn1Encodable
+ {
+ private readonly GeneralName admissionAuthority;
+ private readonly Asn1Sequence contentsOfAdmissions;
+
+ public static AdmissionSyntax GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is AdmissionSyntax)
+ {
+ return (AdmissionSyntax)obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new AdmissionSyntax((Asn1Sequence)obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * Constructor from Asn1Sequence.
+ *
+ * The sequence is of type ProcurationSyntax:
+ *
+ *
+ * AdmissionSyntax ::= SEQUENCE
+ * {
+ * admissionAuthority GeneralName OPTIONAL,
+ * contentsOfAdmissions SEQUENCE OF Admissions
+ * }
+ *
+ * Admissions ::= SEQUENCE
+ * {
+ * admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
+ * namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
+ * professionInfos SEQUENCE OF ProfessionInfo
+ * }
+ *
+ * NamingAuthority ::= SEQUENCE
+ * {
+ * namingAuthorityId OBJECT IDENTIFIER OPTIONAL,
+ * namingAuthorityUrl IA5String OPTIONAL,
+ * namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
+ * }
+ *
+ * ProfessionInfo ::= SEQUENCE
+ * {
+ * namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL,
+ * professionItems SEQUENCE OF DirectoryString (SIZE(1..128)),
+ * professionOIDs SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
+ * registrationNumber PrintableString(SIZE(1..128)) OPTIONAL,
+ * addProfessionInfo OCTET STRING OPTIONAL
+ * }
+ *
+ *
+ * @param seq The ASN.1 sequence.
+ */
+ private AdmissionSyntax(
+ Asn1Sequence seq)
+ {
+ switch (seq.Count)
+ {
+ case 1:
+ this.contentsOfAdmissions = DerSequence.GetInstance(seq[0]);
+ break;
+ case 2:
+ admissionAuthority = GeneralName.GetInstance(seq[0]);
+ contentsOfAdmissions = DerSequence.GetInstance(seq[1]);
+ break;
+ default:
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+ }
+ }
+
+ /**
+ * Constructor from given details.
+ *
+ * @param admissionAuthority The admission authority.
+ * @param contentsOfAdmissions The admissions.
+ */
+ public AdmissionSyntax(
+ GeneralName admissionAuthority,
+ Asn1Sequence contentsOfAdmissions)
+ {
+ this.admissionAuthority = admissionAuthority;
+ this.contentsOfAdmissions = contentsOfAdmissions;
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * AdmissionSyntax ::= SEQUENCE
+ * {
+ * admissionAuthority GeneralName OPTIONAL,
+ * contentsOfAdmissions SEQUENCE OF Admissions
+ * }
+ *
+ * Admissions ::= SEQUENCE
+ * {
+ * admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
+ * namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
+ * professionInfos SEQUENCE OF ProfessionInfo
+ * }
+ *
+ * NamingAuthority ::= SEQUENCE
+ * {
+ * namingAuthorityId OBJECT IDENTIFIER OPTIONAL,
+ * namingAuthorityUrl IA5String OPTIONAL,
+ * namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
+ * }
+ *
+ * ProfessionInfo ::= SEQUENCE
+ * {
+ * namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL,
+ * professionItems SEQUENCE OF DirectoryString (SIZE(1..128)),
+ * professionOIDs SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
+ * registrationNumber PrintableString(SIZE(1..128)) OPTIONAL,
+ * addProfessionInfo OCTET STRING OPTIONAL
+ * }
+ *
+ *
+ * @return an Asn1Object
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector vec = new Asn1EncodableVector();
+ if (admissionAuthority != null)
+ {
+ vec.Add(admissionAuthority);
+ }
+ vec.Add(contentsOfAdmissions);
+ return new DerSequence(vec);
+ }
+
+ /**
+ * @return Returns the admissionAuthority if present, null otherwise.
+ */
+ public virtual GeneralName AdmissionAuthority
+ {
+ get { return admissionAuthority; }
+ }
+
+ /**
+ * @return Returns the contentsOfAdmissions.
+ */
+ public virtual Admissions[] GetContentsOfAdmissions()
+ {
+ Admissions[] result = new Admissions[contentsOfAdmissions.Count];
+
+ for (int i = 0; i < contentsOfAdmissions.Count; ++i)
+ {
+ result[i] = Admissions.GetInstance(contentsOfAdmissions[i]);
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/isismtt/x509/Admissions.cs b/bc-sharp-crypto/src/asn1/isismtt/x509/Admissions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e914db0b5e8e28ad7bca9de0274881de965d45e7
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/isismtt/x509/Admissions.cs
@@ -0,0 +1,187 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+ /**
+ * An Admissions structure.
+ *
+ *
+ * Admissions ::= SEQUENCE
+ * {
+ * admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
+ * namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
+ * professionInfos SEQUENCE OF ProfessionInfo
+ * }
+ *
+ *
+ *
+ * @see Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax
+ * @see Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo
+ * @see Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority
+ */
+ public class Admissions
+ : Asn1Encodable
+ {
+ private readonly GeneralName admissionAuthority;
+ private readonly NamingAuthority namingAuthority;
+ private readonly Asn1Sequence professionInfos;
+
+ public static Admissions GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is Admissions)
+ {
+ return (Admissions) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new Admissions((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * Constructor from Asn1Sequence.
+ *
+ * The sequence is of type ProcurationSyntax:
+ *
+ *
+ * Admissions ::= SEQUENCE
+ * {
+ * admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
+ * namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
+ * professionInfos SEQUENCE OF ProfessionInfo
+ * }
+ *
+ *
+ * @param seq The ASN.1 sequence.
+ */
+ private Admissions(
+ Asn1Sequence seq)
+ {
+ if (seq.Count > 3)
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+ IEnumerator e = seq.GetEnumerator();
+
+ e.MoveNext();
+ Asn1Encodable o = (Asn1Encodable) e.Current;
+ if (o is Asn1TaggedObject)
+ {
+ switch (((Asn1TaggedObject)o).TagNo)
+ {
+ case 0:
+ admissionAuthority = GeneralName.GetInstance((Asn1TaggedObject)o, true);
+ break;
+ case 1:
+ namingAuthority = NamingAuthority.GetInstance((Asn1TaggedObject)o, true);
+ break;
+ default:
+ throw new ArgumentException("Bad tag number: " + ((Asn1TaggedObject)o).TagNo);
+ }
+ e.MoveNext();
+ o = (Asn1Encodable) e.Current;
+ }
+ if (o is Asn1TaggedObject)
+ {
+ switch (((Asn1TaggedObject)o).TagNo)
+ {
+ case 1:
+ namingAuthority = NamingAuthority.GetInstance((Asn1TaggedObject)o, true);
+ break;
+ default:
+ throw new ArgumentException("Bad tag number: " + ((Asn1TaggedObject)o).TagNo);
+ }
+ e.MoveNext();
+ o = (Asn1Encodable) e.Current;
+ }
+ professionInfos = Asn1Sequence.GetInstance(o);
+ if (e.MoveNext())
+ {
+ throw new ArgumentException("Bad object encountered: " + Platform.GetTypeName(e.Current));
+ }
+ }
+
+ /**
+ * Constructor from a given details.
+ *
+ * Parameter professionInfos
is mandatory.
+ *
+ * @param admissionAuthority The admission authority.
+ * @param namingAuthority The naming authority.
+ * @param professionInfos The profession infos.
+ */
+ public Admissions(
+ GeneralName admissionAuthority,
+ NamingAuthority namingAuthority,
+ ProfessionInfo[] professionInfos)
+ {
+ this.admissionAuthority = admissionAuthority;
+ this.namingAuthority = namingAuthority;
+ this.professionInfos = new DerSequence(professionInfos);
+ }
+
+ public virtual GeneralName AdmissionAuthority
+ {
+ get { return admissionAuthority; }
+ }
+
+ public virtual NamingAuthority NamingAuthority
+ {
+ get { return namingAuthority; }
+ }
+
+ public ProfessionInfo[] GetProfessionInfos()
+ {
+ ProfessionInfo[] infos = new ProfessionInfo[professionInfos.Count];
+ int count = 0;
+ foreach (Asn1Encodable ae in professionInfos)
+ {
+ infos[count++] = ProfessionInfo.GetInstance(ae);
+ }
+ return infos;
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * Admissions ::= SEQUENCE
+ * {
+ * admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
+ * namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
+ * professionInfos SEQUENCE OF ProfessionInfo
+ * }
+ *
+ *
+ *
+ * @return an Asn1Object
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector vec = new Asn1EncodableVector();
+
+ if (admissionAuthority != null)
+ {
+ vec.Add(new DerTaggedObject(true, 0, admissionAuthority));
+ }
+
+ if (namingAuthority != null)
+ {
+ vec.Add(new DerTaggedObject(true, 1, namingAuthority));
+ }
+
+ vec.Add(professionInfos);
+
+ return new DerSequence(vec);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs b/bc-sharp-crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c4ebb2b72b990f4fdbe370a6ca940237289ad141
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs
@@ -0,0 +1,172 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+ /**
+ * A declaration of majority.
+ *
+ *
+ * DeclarationOfMajoritySyntax ::= CHOICE
+ * {
+ * notYoungerThan [0] IMPLICIT INTEGER,
+ * fullAgeAtCountry [1] IMPLICIT SEQUENCE
+ * {
+ * fullAge BOOLEAN DEFAULT TRUE,
+ * country PrintableString (SIZE(2))
+ * }
+ * dateOfBirth [2] IMPLICIT GeneralizedTime
+ * }
+ *
+ *
+ * fullAgeAtCountry indicates the majority of the owner with respect to the laws
+ * of a specific country.
+ */
+ public class DeclarationOfMajority
+ : Asn1Encodable, IAsn1Choice
+ {
+ public enum Choice
+ {
+ NotYoungerThan = 0,
+ FullAgeAtCountry = 1,
+ DateOfBirth = 2
+ };
+
+ private readonly Asn1TaggedObject declaration;
+
+ public DeclarationOfMajority(
+ int notYoungerThan)
+ {
+ declaration = new DerTaggedObject(false, 0, new DerInteger(notYoungerThan));
+ }
+
+ public DeclarationOfMajority(
+ bool fullAge,
+ string country)
+ {
+ if (country.Length > 2)
+ throw new ArgumentException("country can only be 2 characters");
+
+ DerPrintableString countryString = new DerPrintableString(country, true);
+
+ DerSequence seq;
+ if (fullAge)
+ {
+ seq = new DerSequence(countryString);
+ }
+ else
+ {
+ seq = new DerSequence(DerBoolean.False, countryString);
+ }
+
+ this.declaration = new DerTaggedObject(false, 1, seq);
+ }
+
+ public DeclarationOfMajority(
+ DerGeneralizedTime dateOfBirth)
+ {
+ this.declaration = new DerTaggedObject(false, 2, dateOfBirth);
+ }
+
+ public static DeclarationOfMajority GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is DeclarationOfMajority)
+ {
+ return (DeclarationOfMajority) obj;
+ }
+
+ if (obj is Asn1TaggedObject)
+ {
+ return new DeclarationOfMajority((Asn1TaggedObject) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private DeclarationOfMajority(
+ Asn1TaggedObject o)
+ {
+ if (o.TagNo > 2)
+ throw new ArgumentException("Bad tag number: " + o.TagNo);
+
+ this.declaration = o;
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * DeclarationOfMajoritySyntax ::= CHOICE
+ * {
+ * notYoungerThan [0] IMPLICIT INTEGER,
+ * fullAgeAtCountry [1] IMPLICIT SEQUENCE
+ * {
+ * fullAge BOOLEAN DEFAULT TRUE,
+ * country PrintableString (SIZE(2))
+ * }
+ * dateOfBirth [2] IMPLICIT GeneralizedTime
+ * }
+ *
+ *
+ * @return an Asn1Object
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return declaration;
+ }
+
+ public Choice Type
+ {
+ get { return (Choice) declaration.TagNo; }
+ }
+
+ /**
+ * @return notYoungerThan if that's what we are, -1 otherwise
+ */
+ public virtual int NotYoungerThan
+ {
+ get
+ {
+ switch ((Choice) declaration.TagNo)
+ {
+ case Choice.NotYoungerThan:
+ return DerInteger.GetInstance(declaration, false).Value.IntValue;
+ default:
+ return -1;
+ }
+ }
+ }
+
+ public virtual Asn1Sequence FullAgeAtCountry
+ {
+ get
+ {
+ switch ((Choice) declaration.TagNo)
+ {
+ case Choice.FullAgeAtCountry:
+ return Asn1Sequence.GetInstance(declaration, false);
+ default:
+ return null;
+ }
+ }
+ }
+
+ public virtual DerGeneralizedTime DateOfBirth
+ {
+ get
+ {
+ switch ((Choice) declaration.TagNo)
+ {
+ case Choice.DateOfBirth:
+ return DerGeneralizedTime.GetInstance(declaration, false);
+ default:
+ return null;
+ }
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/isismtt/x509/MonetaryLimit.cs b/bc-sharp-crypto/src/asn1/isismtt/x509/MonetaryLimit.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b792fffdaafe420eb4575347bde451104584c04f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/isismtt/x509/MonetaryLimit.cs
@@ -0,0 +1,122 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+ /**
+ * Monetary limit for transactions. The QcEuMonetaryLimit QC statement MUST be
+ * used in new certificates in place of the extension/attribute MonetaryLimit
+ * since January 1, 2004. For the sake of backward compatibility with
+ * certificates already in use, components SHOULD support MonetaryLimit (as well
+ * as QcEuLimitValue).
+ *
+ * Indicates a monetary limit within which the certificate holder is authorized
+ * to act. (This value DOES NOT express a limit on the liability of the
+ * certification authority).
+ *
+ *
+ * MonetaryLimitSyntax ::= SEQUENCE
+ * {
+ * currency PrintableString (SIZE(3)),
+ * amount INTEGER,
+ * exponent INTEGER
+ * }
+ *
+ *
+ * currency must be the ISO code.
+ *
+ * value = amount�10*exponent
+ */
+ public class MonetaryLimit
+ : Asn1Encodable
+ {
+ private readonly DerPrintableString currency;
+ private readonly DerInteger amount;
+ private readonly DerInteger exponent;
+
+ public static MonetaryLimit GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is MonetaryLimit)
+ {
+ return (MonetaryLimit) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new MonetaryLimit(Asn1Sequence.GetInstance(obj));
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private MonetaryLimit(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 3)
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+ currency = DerPrintableString.GetInstance(seq[0]);
+ amount = DerInteger.GetInstance(seq[1]);
+ exponent = DerInteger.GetInstance(seq[2]);
+ }
+
+ /**
+ * Constructor from a given details.
+ *
+ *
+ * value = amount�10^exponent
+ *
+ * @param currency The currency. Must be the ISO code.
+ * @param amount The amount
+ * @param exponent The exponent
+ */
+ public MonetaryLimit(
+ string currency,
+ int amount,
+ int exponent)
+ {
+ this.currency = new DerPrintableString(currency, true);
+ this.amount = new DerInteger(amount);
+ this.exponent = new DerInteger(exponent);
+ }
+
+ public virtual string Currency
+ {
+ get { return currency.GetString(); }
+ }
+
+ public virtual BigInteger Amount
+ {
+ get { return amount.Value; }
+ }
+
+ public virtual BigInteger Exponent
+ {
+ get { return exponent.Value; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * MonetaryLimitSyntax ::= SEQUENCE
+ * {
+ * currency PrintableString (SIZE(3)),
+ * amount INTEGER,
+ * exponent INTEGER
+ * }
+ *
+ *
+ * @return an Asn1Object
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(currency, amount, exponent);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/isismtt/x509/NamingAuthority.cs b/bc-sharp-crypto/src/asn1/isismtt/x509/NamingAuthority.cs
new file mode 100644
index 0000000000000000000000000000000000000000..35539f488ccba2d344d4aeccf77e5795bd270432
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/isismtt/x509/NamingAuthority.cs
@@ -0,0 +1,215 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+ /**
+ * Names of authorities which are responsible for the administration of title
+ * registers.
+ *
+ *
+ * NamingAuthority ::= SEQUENCE
+ * {
+ * namingAuthorityID OBJECT IDENTIFIER OPTIONAL,
+ * namingAuthorityUrl IA5String OPTIONAL,
+ * namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
+ * }
+ *
+ * @see Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax
+ *
+ */
+ public class NamingAuthority
+ : Asn1Encodable
+ {
+ /**
+ * Profession OIDs should always be defined under the OID branch of the
+ * responsible naming authority. At the time of this writing, the work group
+ * �Recht, Wirtschaft, Steuern� (�Law, Economy, Taxes�) is registered as the
+ * first naming authority under the OID id-isismtt-at-namingAuthorities.
+ */
+ public static readonly DerObjectIdentifier IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern
+ = new DerObjectIdentifier(IsisMttObjectIdentifiers.IdIsisMttATNamingAuthorities + ".1");
+
+ private readonly DerObjectIdentifier namingAuthorityID;
+ private readonly string namingAuthorityUrl;
+ private readonly DirectoryString namingAuthorityText;
+
+ public static NamingAuthority GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is NamingAuthority)
+ {
+ return (NamingAuthority) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new NamingAuthority((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public static NamingAuthority GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ /**
+ * Constructor from Asn1Sequence.
+ *
+ *
+ *
+ * NamingAuthority ::= SEQUENCE
+ * {
+ * namingAuthorityID OBJECT IDENTIFIER OPTIONAL,
+ * namingAuthorityUrl IA5String OPTIONAL,
+ * namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
+ * }
+ *
+ *
+ * @param seq The ASN.1 sequence.
+ */
+ private NamingAuthority(
+ Asn1Sequence seq)
+ {
+ if (seq.Count > 3)
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+ IEnumerator e = seq.GetEnumerator();
+
+ if (e.MoveNext())
+ {
+ Asn1Encodable o = (Asn1Encodable) e.Current;
+ if (o is DerObjectIdentifier)
+ {
+ namingAuthorityID = (DerObjectIdentifier) o;
+ }
+ else if (o is DerIA5String)
+ {
+ namingAuthorityUrl = DerIA5String.GetInstance(o).GetString();
+ }
+ else if (o is IAsn1String)
+ {
+ namingAuthorityText = DirectoryString.GetInstance(o);
+ }
+ else
+ {
+ throw new ArgumentException("Bad object encountered: " + Platform.GetTypeName(o));
+ }
+ }
+
+ if (e.MoveNext())
+ {
+ Asn1Encodable o = (Asn1Encodable) e.Current;
+ if (o is DerIA5String)
+ {
+ namingAuthorityUrl = DerIA5String.GetInstance(o).GetString();
+ }
+ else if (o is IAsn1String)
+ {
+ namingAuthorityText = DirectoryString.GetInstance(o);
+ }
+ else
+ {
+ throw new ArgumentException("Bad object encountered: " + Platform.GetTypeName(o));
+ }
+ }
+
+ if (e.MoveNext())
+ {
+ Asn1Encodable o = (Asn1Encodable) e.Current;
+ if (o is IAsn1String)
+ {
+ namingAuthorityText = DirectoryString.GetInstance(o);
+ }
+ else
+ {
+ throw new ArgumentException("Bad object encountered: " + Platform.GetTypeName(o));
+ }
+ }
+ }
+
+ /**
+ * @return Returns the namingAuthorityID.
+ */
+ public virtual DerObjectIdentifier NamingAuthorityID
+ {
+ get { return namingAuthorityID; }
+ }
+
+ /**
+ * @return Returns the namingAuthorityText.
+ */
+ public virtual DirectoryString NamingAuthorityText
+ {
+ get { return namingAuthorityText; }
+ }
+
+ /**
+ * @return Returns the namingAuthorityUrl.
+ */
+ public virtual string NamingAuthorityUrl
+ {
+ get { return namingAuthorityUrl; }
+ }
+
+ /**
+ * Constructor from given details.
+ *
+ * All parameters can be combined.
+ *
+ * @param namingAuthorityID ObjectIdentifier for naming authority.
+ * @param namingAuthorityUrl URL for naming authority.
+ * @param namingAuthorityText Textual representation of naming authority.
+ */
+ public NamingAuthority(
+ DerObjectIdentifier namingAuthorityID,
+ string namingAuthorityUrl,
+ DirectoryString namingAuthorityText)
+ {
+ this.namingAuthorityID = namingAuthorityID;
+ this.namingAuthorityUrl = namingAuthorityUrl;
+ this.namingAuthorityText = namingAuthorityText;
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * NamingAuthority ::= SEQUENCE
+ * {
+ * namingAuthorityID OBJECT IDENTIFIER OPTIONAL,
+ * namingAuthorityUrl IA5String OPTIONAL,
+ * namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
+ * }
+ *
+ *
+ * @return an Asn1Object
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector vec = new Asn1EncodableVector();
+ if (namingAuthorityID != null)
+ {
+ vec.Add(namingAuthorityID);
+ }
+ if (namingAuthorityUrl != null)
+ {
+ vec.Add(new DerIA5String(namingAuthorityUrl, true));
+ }
+ if (namingAuthorityText != null)
+ {
+ vec.Add(namingAuthorityText);
+ }
+ return new DerSequence(vec);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/isismtt/x509/ProcurationSyntax.cs b/bc-sharp-crypto/src/asn1/isismtt/x509/ProcurationSyntax.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f423646991ef7f723b65e70eb986a9bd418a11d1
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/isismtt/x509/ProcurationSyntax.cs
@@ -0,0 +1,233 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+ /**
+ * Attribute to indicate that the certificate holder may sign in the name of a
+ * third person.
+ *
+ * ISIS-MTT PROFILE: The corresponding ProcurationSyntax contains either the
+ * name of the person who is represented (subcomponent thirdPerson) or a
+ * reference to his/her base certificate (in the component signingFor,
+ * subcomponent certRef), furthermore the optional components country and
+ * typeSubstitution to indicate the country whose laws apply, and respectively
+ * the type of procuration (e.g. manager, procuration, custody).
+ *
+ *
+ * ISIS-MTT PROFILE: The GeneralName MUST be of type directoryName and MAY only
+ * contain: - RFC3039 attributes, except pseudonym (countryName, commonName,
+ * surname, givenName, serialNumber, organizationName, organizationalUnitName,
+ * stateOrProvincename, localityName, postalAddress) and - SubjectDirectoryName
+ * attributes (title, dateOfBirth, placeOfBirth, gender, countryOfCitizenship,
+ * countryOfResidence and NameAtBirth).
+ *
+ *
+ * ProcurationSyntax ::= SEQUENCE {
+ * country [1] EXPLICIT PrintableString(SIZE(2)) OPTIONAL,
+ * typeOfSubstitution [2] EXPLICIT DirectoryString (SIZE(1..128)) OPTIONAL,
+ * signingFor [3] EXPLICIT SigningFor
+ * }
+ *
+ * SigningFor ::= CHOICE
+ * {
+ * thirdPerson GeneralName,
+ * certRef IssuerSerial
+ * }
+ *
+ *
+ */
+ public class ProcurationSyntax
+ : Asn1Encodable
+ {
+ private readonly string country;
+ private readonly DirectoryString typeOfSubstitution;
+ private readonly GeneralName thirdPerson;
+ private readonly IssuerSerial certRef;
+
+ public static ProcurationSyntax GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is ProcurationSyntax)
+ {
+ return (ProcurationSyntax) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new ProcurationSyntax((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * Constructor from Asn1Sequence.
+ *
+ * The sequence is of type ProcurationSyntax:
+ *
+ *
+ * ProcurationSyntax ::= SEQUENCE {
+ * country [1] EXPLICIT PrintableString(SIZE(2)) OPTIONAL,
+ * typeOfSubstitution [2] EXPLICIT DirectoryString (SIZE(1..128)) OPTIONAL,
+ * signingFor [3] EXPLICIT SigningFor
+ * }
+ *
+ * SigningFor ::= CHOICE
+ * {
+ * thirdPerson GeneralName,
+ * certRef IssuerSerial
+ * }
+ *
+ *
+ * @param seq The ASN.1 sequence.
+ */
+ private ProcurationSyntax(
+ Asn1Sequence seq)
+ {
+ if (seq.Count < 1 || seq.Count > 3)
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+ IEnumerator e = seq.GetEnumerator();
+
+ while (e.MoveNext())
+ {
+ Asn1TaggedObject o = Asn1TaggedObject.GetInstance(e.Current);
+ switch (o.TagNo)
+ {
+ case 1:
+ country = DerPrintableString.GetInstance(o, true).GetString();
+ break;
+ case 2:
+ typeOfSubstitution = DirectoryString.GetInstance(o, true);
+ break;
+ case 3:
+ Asn1Object signingFor = o.GetObject();
+ if (signingFor is Asn1TaggedObject)
+ {
+ thirdPerson = GeneralName.GetInstance(signingFor);
+ }
+ else
+ {
+ certRef = IssuerSerial.GetInstance(signingFor);
+ }
+ break;
+ default:
+ throw new ArgumentException("Bad tag number: " + o.TagNo);
+ }
+ }
+ }
+
+ /**
+ * Constructor from a given details.
+ *
+ *
+ * Either generalName
or certRef
MUST be
+ * null
.
+ *
+ * @param country The country code whose laws apply.
+ * @param typeOfSubstitution The type of procuration.
+ * @param certRef Reference to certificate of the person who is represented.
+ */
+ public ProcurationSyntax(
+ string country,
+ DirectoryString typeOfSubstitution,
+ IssuerSerial certRef)
+ {
+ this.country = country;
+ this.typeOfSubstitution = typeOfSubstitution;
+ this.thirdPerson = null;
+ this.certRef = certRef;
+ }
+
+ /**
+ * Constructor from a given details.
+ *
+ *
+ * Either generalName
or certRef
MUST be
+ * null
.
+ *
+ * @param country The country code whose laws apply.
+ * @param typeOfSubstitution The type of procuration.
+ * @param thirdPerson The GeneralName of the person who is represented.
+ */
+ public ProcurationSyntax(
+ string country,
+ DirectoryString typeOfSubstitution,
+ GeneralName thirdPerson)
+ {
+ this.country = country;
+ this.typeOfSubstitution = typeOfSubstitution;
+ this.thirdPerson = thirdPerson;
+ this.certRef = null;
+ }
+
+ public virtual string Country
+ {
+ get { return country; }
+ }
+
+ public virtual DirectoryString TypeOfSubstitution
+ {
+ get { return typeOfSubstitution; }
+ }
+
+ public virtual GeneralName ThirdPerson
+ {
+ get { return thirdPerson; }
+ }
+
+ public virtual IssuerSerial CertRef
+ {
+ get { return certRef; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * ProcurationSyntax ::= SEQUENCE {
+ * country [1] EXPLICIT PrintableString(SIZE(2)) OPTIONAL,
+ * typeOfSubstitution [2] EXPLICIT DirectoryString (SIZE(1..128)) OPTIONAL,
+ * signingFor [3] EXPLICIT SigningFor
+ * }
+ *
+ * SigningFor ::= CHOICE
+ * {
+ * thirdPerson GeneralName,
+ * certRef IssuerSerial
+ * }
+ *
+ *
+ * @return an Asn1Object
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector vec = new Asn1EncodableVector();
+ if (country != null)
+ {
+ vec.Add(new DerTaggedObject(true, 1, new DerPrintableString(country, true)));
+ }
+ if (typeOfSubstitution != null)
+ {
+ vec.Add(new DerTaggedObject(true, 2, typeOfSubstitution));
+ }
+ if (thirdPerson != null)
+ {
+ vec.Add(new DerTaggedObject(true, 3, thirdPerson));
+ }
+ else
+ {
+ vec.Add(new DerTaggedObject(true, 3, certRef));
+ }
+
+ return new DerSequence(vec);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/isismtt/x509/ProfessionInfo.cs b/bc-sharp-crypto/src/asn1/isismtt/x509/ProfessionInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..671a465af8c44588699c6b74a3bcae1346304276
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/isismtt/x509/ProfessionInfo.cs
@@ -0,0 +1,387 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+ /**
+ * Professions, specializations, disciplines, fields of activity, etc.
+ *
+ *
+ * ProfessionInfo ::= SEQUENCE
+ * {
+ * namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL,
+ * professionItems SEQUENCE OF DirectoryString (SIZE(1..128)),
+ * professionOids SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
+ * registrationNumber PrintableString(SIZE(1..128)) OPTIONAL,
+ * addProfessionInfo OCTET STRING OPTIONAL
+ * }
+ *
+ *
+ * @see Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax
+ */
+ public class ProfessionInfo
+ : Asn1Encodable
+ {
+ /**
+ * Rechtsanw�ltin
+ */
+ public static readonly DerObjectIdentifier Rechtsanwltin = new DerObjectIdentifier(
+ NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".1");
+
+ /**
+ * Rechtsanwalt
+ */
+ public static readonly DerObjectIdentifier Rechtsanwalt = new DerObjectIdentifier(
+ NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".2");
+
+ /**
+ * Rechtsbeistand
+ */
+ public static readonly DerObjectIdentifier Rechtsbeistand = new DerObjectIdentifier(
+ NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".3");
+
+ /**
+ * Steuerberaterin
+ */
+ public static readonly DerObjectIdentifier Steuerberaterin = new DerObjectIdentifier(
+ NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".4");
+
+ /**
+ * Steuerberater
+ */
+ public static readonly DerObjectIdentifier Steuerberater = new DerObjectIdentifier(
+ NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".5");
+
+ /**
+ * Steuerbevollm�chtigte
+ */
+ public static readonly DerObjectIdentifier Steuerbevollmchtigte = new DerObjectIdentifier(
+ NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".6");
+
+ /**
+ * Steuerbevollm�chtigter
+ */
+ public static readonly DerObjectIdentifier Steuerbevollmchtigter = new DerObjectIdentifier(
+ NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".7");
+
+ /**
+ * Notarin
+ */
+ public static readonly DerObjectIdentifier Notarin = new DerObjectIdentifier(
+ NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".8");
+
+ /**
+ * Notar
+ */
+ public static readonly DerObjectIdentifier Notar = new DerObjectIdentifier(
+ NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".9");
+
+ /**
+ * Notarvertreterin
+ */
+ public static readonly DerObjectIdentifier Notarvertreterin = new DerObjectIdentifier(
+ NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".10");
+
+ /**
+ * Notarvertreter
+ */
+ public static readonly DerObjectIdentifier Notarvertreter = new DerObjectIdentifier(
+ NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".11");
+
+ /**
+ * Notariatsverwalterin
+ */
+ public static readonly DerObjectIdentifier Notariatsverwalterin = new DerObjectIdentifier(
+ NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".12");
+
+ /**
+ * Notariatsverwalter
+ */
+ public static readonly DerObjectIdentifier Notariatsverwalter = new DerObjectIdentifier(
+ NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".13");
+
+ /**
+ * Wirtschaftspr�ferin
+ */
+ public static readonly DerObjectIdentifier Wirtschaftsprferin = new DerObjectIdentifier(
+ NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".14");
+
+ /**
+ * Wirtschaftspr�fer
+ */
+ public static readonly DerObjectIdentifier Wirtschaftsprfer = new DerObjectIdentifier(
+ NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".15");
+
+ /**
+ * Vereidigte Buchpr�ferin
+ */
+ public static readonly DerObjectIdentifier VereidigteBuchprferin = new DerObjectIdentifier(
+ NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".16");
+
+ /**
+ * Vereidigter Buchpr�fer
+ */
+ public static readonly DerObjectIdentifier VereidigterBuchprfer = new DerObjectIdentifier(
+ NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".17");
+
+ /**
+ * Patentanw�ltin
+ */
+ public static readonly DerObjectIdentifier Patentanwltin = new DerObjectIdentifier(
+ NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".18");
+
+ /**
+ * Patentanwalt
+ */
+ public static readonly DerObjectIdentifier Patentanwalt = new DerObjectIdentifier(
+ NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".19");
+
+ private readonly NamingAuthority namingAuthority;
+ private readonly Asn1Sequence professionItems;
+ private readonly Asn1Sequence professionOids;
+ private readonly string registrationNumber;
+ private readonly Asn1OctetString addProfessionInfo;
+
+ public static ProfessionInfo GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is ProfessionInfo)
+ {
+ return (ProfessionInfo) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new ProfessionInfo((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * Constructor from Asn1Sequence.
+ *
+ *
+ *
+ * ProfessionInfo ::= SEQUENCE
+ * {
+ * namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL,
+ * professionItems SEQUENCE OF DirectoryString (SIZE(1..128)),
+ * professionOids SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
+ * registrationNumber PrintableString(SIZE(1..128)) OPTIONAL,
+ * addProfessionInfo OCTET STRING OPTIONAL
+ * }
+ *
+ *
+ * @param seq The ASN.1 sequence.
+ */
+ private ProfessionInfo(
+ Asn1Sequence seq)
+ {
+ if (seq.Count > 5)
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+ IEnumerator e = seq.GetEnumerator();
+
+ e.MoveNext();
+ Asn1Encodable o = (Asn1Encodable) e.Current;
+
+ if (o is Asn1TaggedObject)
+ {
+ Asn1TaggedObject ato = (Asn1TaggedObject) o;
+ if (ato.TagNo != 0)
+ throw new ArgumentException("Bad tag number: " + ato.TagNo);
+
+ namingAuthority = NamingAuthority.GetInstance(ato, true);
+ e.MoveNext();
+ o = (Asn1Encodable) e.Current;
+ }
+
+ professionItems = Asn1Sequence.GetInstance(o);
+
+ if (e.MoveNext())
+ {
+ o = (Asn1Encodable) e.Current;
+ if (o is Asn1Sequence)
+ {
+ professionOids = Asn1Sequence.GetInstance(o);
+ }
+ else if (o is DerPrintableString)
+ {
+ registrationNumber = DerPrintableString.GetInstance(o).GetString();
+ }
+ else if (o is Asn1OctetString)
+ {
+ addProfessionInfo = Asn1OctetString.GetInstance(o);
+ }
+ else
+ {
+ throw new ArgumentException("Bad object encountered: " + Platform.GetTypeName(o));
+ }
+ }
+
+ if (e.MoveNext())
+ {
+ o = (Asn1Encodable) e.Current;
+ if (o is DerPrintableString)
+ {
+ registrationNumber = DerPrintableString.GetInstance(o).GetString();
+ }
+ else if (o is DerOctetString)
+ {
+ addProfessionInfo = (DerOctetString) o;
+ }
+ else
+ {
+ throw new ArgumentException("Bad object encountered: " + Platform.GetTypeName(o));
+ }
+ }
+
+ if (e.MoveNext())
+ {
+ o = (Asn1Encodable) e.Current;
+ if (o is DerOctetString)
+ {
+ addProfessionInfo = (DerOctetString) o;
+ }
+ else
+ {
+ throw new ArgumentException("Bad object encountered: " + Platform.GetTypeName(o));
+ }
+ }
+ }
+
+ /**
+ * Constructor from given details.
+ *
+ * professionItems
is mandatory, all other parameters are
+ * optional.
+ *
+ * @param namingAuthority The naming authority.
+ * @param professionItems Directory strings of the profession.
+ * @param professionOids DERObjectIdentfier objects for the
+ * profession.
+ * @param registrationNumber Registration number.
+ * @param addProfessionInfo Additional infos in encoded form.
+ */
+ public ProfessionInfo(
+ NamingAuthority namingAuthority,
+ DirectoryString[] professionItems,
+ DerObjectIdentifier[] professionOids,
+ string registrationNumber,
+ Asn1OctetString addProfessionInfo)
+ {
+ this.namingAuthority = namingAuthority;
+ this.professionItems = new DerSequence(professionItems);
+ if (professionOids != null)
+ {
+ this.professionOids = new DerSequence(professionOids);
+ }
+ this.registrationNumber = registrationNumber;
+ this.addProfessionInfo = addProfessionInfo;
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * ProfessionInfo ::= SEQUENCE
+ * {
+ * namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL,
+ * professionItems SEQUENCE OF DirectoryString (SIZE(1..128)),
+ * professionOids SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
+ * registrationNumber PrintableString(SIZE(1..128)) OPTIONAL,
+ * addProfessionInfo OCTET STRING OPTIONAL
+ * }
+ *
+ *
+ * @return an Asn1Object
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector vec = new Asn1EncodableVector();
+ if (namingAuthority != null)
+ {
+ vec.Add(new DerTaggedObject(true, 0, namingAuthority));
+ }
+ vec.Add(professionItems);
+ if (professionOids != null)
+ {
+ vec.Add(professionOids);
+ }
+ if (registrationNumber != null)
+ {
+ vec.Add(new DerPrintableString(registrationNumber, true));
+ }
+ if (addProfessionInfo != null)
+ {
+ vec.Add(addProfessionInfo);
+ }
+ return new DerSequence(vec);
+ }
+
+ /**
+ * @return Returns the addProfessionInfo.
+ */
+ public virtual Asn1OctetString AddProfessionInfo
+ {
+ get { return addProfessionInfo; }
+ }
+
+ /**
+ * @return Returns the namingAuthority.
+ */
+ public virtual NamingAuthority NamingAuthority
+ {
+ get { return namingAuthority; }
+ }
+
+ /**
+ * @return Returns the professionItems.
+ */
+ public virtual DirectoryString[] GetProfessionItems()
+ {
+ DirectoryString[] result = new DirectoryString[professionItems.Count];
+
+ for (int i = 0; i < professionItems.Count; ++i)
+ {
+ result[i] = DirectoryString.GetInstance(professionItems[i]);
+ }
+
+ return result;
+ }
+
+ /**
+ * @return Returns the professionOids.
+ */
+ public virtual DerObjectIdentifier[] GetProfessionOids()
+ {
+ if (professionOids == null)
+ {
+ return new DerObjectIdentifier[0];
+ }
+
+ DerObjectIdentifier[] result = new DerObjectIdentifier[professionOids.Count];
+
+ for (int i = 0; i < professionOids.Count; ++i)
+ {
+ result[i] = DerObjectIdentifier.GetInstance(professionOids[i]);
+ }
+
+ return result;
+ }
+
+ /**
+ * @return Returns the registrationNumber.
+ */
+ public virtual string RegistrationNumber
+ {
+ get { return registrationNumber; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/isismtt/x509/Restriction.cs b/bc-sharp-crypto/src/asn1/isismtt/x509/Restriction.cs
new file mode 100644
index 0000000000000000000000000000000000000000..75df252011e3d8362dc8b63521d7e2f592b79946
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/isismtt/x509/Restriction.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+ /**
+ * Some other restriction regarding the usage of this certificate.
+ *
+ *
+ * RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+ *
+ */
+ public class Restriction
+ : Asn1Encodable
+ {
+ private readonly DirectoryString restriction;
+
+ public static Restriction GetInstance(
+ object obj)
+ {
+ if (obj is Restriction)
+ return (Restriction) obj;
+
+ if (obj is IAsn1String)
+ return new Restriction(DirectoryString.GetInstance(obj));
+
+ throw new ArgumentException("Unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * Constructor from DirectoryString.
+ *
+ * The DirectoryString is of type RestrictionSyntax:
+ *
+ *
+ * RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+ *
+ *
+ * @param restriction A IAsn1String.
+ */
+ private Restriction(
+ DirectoryString restriction)
+ {
+ this.restriction = restriction;
+ }
+
+ /**
+ * Constructor from a given details.
+ *
+ * @param restriction The description of the restriction.
+ */
+ public Restriction(
+ string restriction)
+ {
+ this.restriction = new DirectoryString(restriction);
+ }
+
+ public virtual DirectoryString RestrictionString
+ {
+ get { return restriction; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+ *
+ *
+ *
+ * @return an Asn1Object
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return restriction.ToAsn1Object();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/kisa/KISAObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/kisa/KISAObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..05351ec75eb452f9f127d54fed7e853bbace4e5f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/kisa/KISAObjectIdentifiers.cs
@@ -0,0 +1,8 @@
+namespace Org.BouncyCastle.Asn1.Kisa
+{
+ public abstract class KisaObjectIdentifiers
+ {
+ public static readonly DerObjectIdentifier IdSeedCbc = new DerObjectIdentifier("1.2.410.200004.1.4");
+ public static readonly DerObjectIdentifier IdNpkiAppCmsSeedWrap = new DerObjectIdentifier("1.2.410.200004.7.1.1.1");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/microsoft/MicrosoftObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/microsoft/MicrosoftObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bc48c3fa24a06d2d2540954d5aa0ef9d1123ca83
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/microsoft/MicrosoftObjectIdentifiers.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Microsoft
+{
+ public abstract class MicrosoftObjectIdentifiers
+ {
+ //
+ // Microsoft
+ // iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprise(1) Microsoft(311)
+ //
+ public static readonly DerObjectIdentifier Microsoft = new DerObjectIdentifier("1.3.6.1.4.1.311");
+ public static readonly DerObjectIdentifier MicrosoftCertTemplateV1 = Microsoft.Branch("20.2");
+ public static readonly DerObjectIdentifier MicrosoftCAVersion = Microsoft.Branch("21.1");
+ public static readonly DerObjectIdentifier MicrosoftPrevCACertHash = Microsoft.Branch("21.2");
+ public static readonly DerObjectIdentifier MicrosoftCrlNextPublish = Microsoft.Branch("21.4");
+ public static readonly DerObjectIdentifier MicrosoftCertTemplateV2 = Microsoft.Branch("21.7");
+ public static readonly DerObjectIdentifier MicrosoftAppPolicies = Microsoft.Branch("21.10");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/misc/CAST5CBCParameters.cs b/bc-sharp-crypto/src/asn1/misc/CAST5CBCParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..51fd6607abd5c1e5014dc8f7c4ca796aed622663
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/misc/CAST5CBCParameters.cs
@@ -0,0 +1,74 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Misc
+{
+ public class Cast5CbcParameters
+ : Asn1Encodable
+ {
+ private readonly DerInteger keyLength;
+ private readonly Asn1OctetString iv;
+
+ public static Cast5CbcParameters GetInstance(
+ object o)
+ {
+ if (o is Cast5CbcParameters)
+ {
+ return (Cast5CbcParameters) o;
+ }
+
+ if (o is Asn1Sequence)
+ {
+ return new Cast5CbcParameters((Asn1Sequence) o);
+ }
+
+ throw new ArgumentException("unknown object in Cast5CbcParameters factory");
+ }
+
+ public Cast5CbcParameters(
+ byte[] iv,
+ int keyLength)
+ {
+ this.iv = new DerOctetString(iv);
+ this.keyLength = new DerInteger(keyLength);
+ }
+
+ private Cast5CbcParameters(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ iv = (Asn1OctetString) seq[0];
+ keyLength = (DerInteger) seq[1];
+ }
+
+ public byte[] GetIV()
+ {
+ return Arrays.Clone(iv.GetOctets());
+ }
+
+ public int KeyLength
+ {
+ get { return keyLength.Value.IntValue; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * cast5CBCParameters ::= Sequence {
+ * iv OCTET STRING DEFAULT 0,
+ * -- Initialization vector
+ * keyLength Integer
+ * -- Key length, in bits
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(iv, keyLength);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/misc/IDEACBCPar.cs b/bc-sharp-crypto/src/asn1/misc/IDEACBCPar.cs
new file mode 100644
index 0000000000000000000000000000000000000000..72a60b9dcc3754e594d5247404a05ecf32727134
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/misc/IDEACBCPar.cs
@@ -0,0 +1,68 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Misc
+{
+ public class IdeaCbcPar
+ : Asn1Encodable
+ {
+ internal Asn1OctetString iv;
+
+ public static IdeaCbcPar GetInstance(
+ object o)
+ {
+ if (o is IdeaCbcPar)
+ {
+ return (IdeaCbcPar) o;
+ }
+
+ if (o is Asn1Sequence)
+ {
+ return new IdeaCbcPar((Asn1Sequence) o);
+ }
+
+ throw new ArgumentException("unknown object in IDEACBCPar factory");
+ }
+
+ public IdeaCbcPar(
+ byte[] iv)
+ {
+ this.iv = new DerOctetString(iv);
+ }
+
+ private IdeaCbcPar(
+ Asn1Sequence seq)
+ {
+ if (seq.Count == 1)
+ {
+ iv = (Asn1OctetString) seq[0];
+ }
+ }
+
+ public byte[] GetIV()
+ {
+ return iv == null ? null : iv.GetOctets();
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * IDEA-CBCPar ::= Sequence {
+ * iv OCTET STRING OPTIONAL -- exactly 8 octets
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (iv != null)
+ {
+ v.Add(iv);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/misc/MiscObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/misc/MiscObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8128b695244c2bad4313b47cced08e620d9b8af5
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/misc/MiscObjectIdentifiers.cs
@@ -0,0 +1,79 @@
+namespace Org.BouncyCastle.Asn1.Misc
+{
+ public abstract class MiscObjectIdentifiers
+ {
+ //
+ // Netscape
+ // iso/itu(2) joint-assign(16) us(840) uscompany(1) Netscape(113730) cert-extensions(1) }
+ //
+ public static readonly DerObjectIdentifier Netscape = new DerObjectIdentifier("2.16.840.1.113730.1");
+ public static readonly DerObjectIdentifier NetscapeCertType = Netscape.Branch("1");
+ public static readonly DerObjectIdentifier NetscapeBaseUrl = Netscape.Branch("2");
+ public static readonly DerObjectIdentifier NetscapeRevocationUrl = Netscape.Branch("3");
+ public static readonly DerObjectIdentifier NetscapeCARevocationUrl = Netscape.Branch("4");
+ public static readonly DerObjectIdentifier NetscapeRenewalUrl = Netscape.Branch("7");
+ public static readonly DerObjectIdentifier NetscapeCAPolicyUrl = Netscape.Branch("8");
+ public static readonly DerObjectIdentifier NetscapeSslServerName = Netscape.Branch("12");
+ public static readonly DerObjectIdentifier NetscapeCertComment = Netscape.Branch("13");
+
+ //
+ // Verisign
+ // iso/itu(2) joint-assign(16) us(840) uscompany(1) verisign(113733) cert-extensions(1) }
+ //
+ public static readonly DerObjectIdentifier Verisign = new DerObjectIdentifier("2.16.840.1.113733.1");
+
+ //
+ // CZAG - country, zip, age, and gender
+ //
+ public static readonly DerObjectIdentifier VerisignCzagExtension = Verisign.Branch("6.3");
+
+ public static readonly DerObjectIdentifier VerisignPrivate_6_9 = Verisign.Branch("6.9");
+ public static readonly DerObjectIdentifier VerisignOnSiteJurisdictionHash = Verisign.Branch("6.11");
+ public static readonly DerObjectIdentifier VerisignBitString_6_13 = Verisign.Branch("6.13");
+
+ // D&B D-U-N-S number
+ public static readonly DerObjectIdentifier VerisignDnbDunsNumber = Verisign.Branch("6.15");
+
+ public static readonly DerObjectIdentifier VerisignIssStrongCrypto = Verisign.Branch("8.1");
+
+ //
+ // Novell
+ // iso/itu(2) country(16) us(840) organization(1) novell(113719)
+ //
+ public static readonly string Novell = "2.16.840.1.113719";
+ public static readonly DerObjectIdentifier NovellSecurityAttribs = new DerObjectIdentifier(Novell + ".1.9.4.1");
+
+ //
+ // Entrust
+ // iso(1) member-body(16) us(840) nortelnetworks(113533) entrust(7)
+ //
+ public static readonly string Entrust = "1.2.840.113533.7";
+ public static readonly DerObjectIdentifier EntrustVersionExtension = new DerObjectIdentifier(Entrust + ".65.0");
+
+ //
+ // Ascom
+ //
+ public static readonly DerObjectIdentifier as_sys_sec_alg_ideaCBC = new DerObjectIdentifier("1.3.6.1.4.1.188.7.1.1.2");
+
+ //
+ // Peter Gutmann's Cryptlib
+ //
+ public static readonly DerObjectIdentifier cryptlib = new DerObjectIdentifier("1.3.6.1.4.1.3029");
+
+ public static readonly DerObjectIdentifier cryptlib_algorithm = cryptlib.Branch("1");
+ public static readonly DerObjectIdentifier cryptlib_algorithm_blowfish_ECB = cryptlib_algorithm.Branch("1.1");
+ public static readonly DerObjectIdentifier cryptlib_algorithm_blowfish_CBC = cryptlib_algorithm.Branch("1.2");
+ public static readonly DerObjectIdentifier cryptlib_algorithm_blowfish_CFB = cryptlib_algorithm.Branch("1.3");
+ public static readonly DerObjectIdentifier cryptlib_algorithm_blowfish_OFB = cryptlib_algorithm.Branch("1.4");
+
+ //
+ // Blake2b
+ //
+ public static readonly DerObjectIdentifier blake2 = new DerObjectIdentifier("1.3.6.1.4.1.1722.12.2");
+
+ public static readonly DerObjectIdentifier id_blake2b160 = blake2.Branch("1.5");
+ public static readonly DerObjectIdentifier id_blake2b256 = blake2.Branch("1.8");
+ public static readonly DerObjectIdentifier id_blake2b384 = blake2.Branch("1.12");
+ public static readonly DerObjectIdentifier id_blake2b512 = blake2.Branch("1.16");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/misc/NetscapeCertType.cs b/bc-sharp-crypto/src/asn1/misc/NetscapeCertType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d809eae663c97e24f018a6caac0a85a5e10b1ede
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/misc/NetscapeCertType.cs
@@ -0,0 +1,54 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Misc
+{
+ /**
+ * The NetscapeCertType object.
+ *
+ * NetscapeCertType ::= BIT STRING {
+ * SSLClient (0),
+ * SSLServer (1),
+ * S/MIME (2),
+ * Object Signing (3),
+ * Reserved (4),
+ * SSL CA (5),
+ * S/MIME CA (6),
+ * Object Signing CA (7) }
+ *
+ */
+ public class NetscapeCertType
+ : DerBitString
+ {
+ public const int SslClient = (1 << 7);
+ public const int SslServer = (1 << 6);
+ public const int Smime = (1 << 5);
+ public const int ObjectSigning = (1 << 4);
+ public const int Reserved = (1 << 3);
+ public const int SslCA = (1 << 2);
+ public const int SmimeCA = (1 << 1);
+ public const int ObjectSigningCA = (1 << 0);
+
+ /**
+ * Basic constructor.
+ *
+ * @param usage - the bitwise OR of the Key Usage flags giving the
+ * allowed uses for the key.
+ * e.g. (X509NetscapeCertType.sslCA | X509NetscapeCertType.smimeCA)
+ */
+ public NetscapeCertType(int usage)
+ : base(usage)
+ {
+ }
+
+ public NetscapeCertType(DerBitString usage)
+ : base(usage.GetBytes(), usage.PadBits)
+ {
+ }
+
+ public override string ToString()
+ {
+ byte[] data = GetBytes();
+ return "NetscapeCertType: 0x" + (data[0] & 0xff).ToString("X");
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/misc/NetscapeRevocationURL.cs b/bc-sharp-crypto/src/asn1/misc/NetscapeRevocationURL.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6cac031f20a3386b3e72bf572d97969c4012c5fb
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/misc/NetscapeRevocationURL.cs
@@ -0,0 +1,18 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Misc
+{
+ public class NetscapeRevocationUrl
+ : DerIA5String
+ {
+ public NetscapeRevocationUrl(DerIA5String str)
+ : base(str.GetString())
+ {
+ }
+
+ public override string ToString()
+ {
+ return "NetscapeRevocationUrl: " + this.GetString();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/misc/VerisignCzagExtension.cs b/bc-sharp-crypto/src/asn1/misc/VerisignCzagExtension.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1c3054b32cc91ef7ef59d4f723b98bfdd6a90c2a
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/misc/VerisignCzagExtension.cs
@@ -0,0 +1,18 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Misc
+{
+ public class VerisignCzagExtension
+ : DerIA5String
+ {
+ public VerisignCzagExtension(DerIA5String str)
+ : base(str.GetString())
+ {
+ }
+
+ public override string ToString()
+ {
+ return "VerisignCzagExtension: " + this.GetString();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/mozilla/PublicKeyAndChallenge.cs b/bc-sharp-crypto/src/asn1/mozilla/PublicKeyAndChallenge.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ff2a1199fe7a98eeccb8c3e19b47acf5639d4551
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/mozilla/PublicKeyAndChallenge.cs
@@ -0,0 +1,68 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Mozilla
+{
+ /**
+ * This is designed to parse
+ * the PublicKeyAndChallenge created by the KEYGEN tag included by
+ * Mozilla based browsers.
+ *
+ * PublicKeyAndChallenge ::= SEQUENCE {
+ * spki SubjectPublicKeyInfo,
+ * challenge IA5STRING
+ * }
+ *
+ *
+ */
+ public class PublicKeyAndChallenge
+ : Asn1Encodable
+ {
+ private Asn1Sequence pkacSeq;
+ private SubjectPublicKeyInfo spki;
+ private DerIA5String challenge;
+
+ public static PublicKeyAndChallenge GetInstance(
+ object obj)
+ {
+ if (obj is PublicKeyAndChallenge)
+ {
+ return (PublicKeyAndChallenge) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new PublicKeyAndChallenge((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException(
+ "unknown object in 'PublicKeyAndChallenge' factory : "
+ + Platform.GetTypeName(obj) + ".");
+ }
+
+ public PublicKeyAndChallenge(
+ Asn1Sequence seq)
+ {
+ pkacSeq = seq;
+ spki = SubjectPublicKeyInfo.GetInstance(seq[0]);
+ challenge = DerIA5String.GetInstance(seq[1]);
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return pkacSeq;
+ }
+
+ public SubjectPublicKeyInfo SubjectPublicKeyInfo
+ {
+ get { return spki; }
+ }
+
+ public DerIA5String Challenge
+ {
+ get { return challenge; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/nist/NISTNamedCurves.cs b/bc-sharp-crypto/src/asn1/nist/NISTNamedCurves.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f6c1598c67f559440bd85929708ba155b14827b5
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/nist/NISTNamedCurves.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Nist
+{
+ /**
+ * Utility class for fetching curves using their NIST names as published in FIPS-PUB 186-3
+ */
+ public sealed class NistNamedCurves
+ {
+ private NistNamedCurves()
+ {
+ }
+
+ private static readonly IDictionary objIds = Platform.CreateHashtable();
+ private static readonly IDictionary names = Platform.CreateHashtable();
+
+ private static void DefineCurveAlias(
+ string name,
+ DerObjectIdentifier oid)
+ {
+ objIds.Add(Platform.ToUpperInvariant(name), oid);
+ names.Add(oid, name);
+ }
+
+ static NistNamedCurves()
+ {
+ DefineCurveAlias("B-163", SecObjectIdentifiers.SecT163r2);
+ DefineCurveAlias("B-233", SecObjectIdentifiers.SecT233r1);
+ DefineCurveAlias("B-283", SecObjectIdentifiers.SecT283r1);
+ DefineCurveAlias("B-409", SecObjectIdentifiers.SecT409r1);
+ DefineCurveAlias("B-571", SecObjectIdentifiers.SecT571r1);
+
+ DefineCurveAlias("K-163", SecObjectIdentifiers.SecT163k1);
+ DefineCurveAlias("K-233", SecObjectIdentifiers.SecT233k1);
+ DefineCurveAlias("K-283", SecObjectIdentifiers.SecT283k1);
+ DefineCurveAlias("K-409", SecObjectIdentifiers.SecT409k1);
+ DefineCurveAlias("K-571", SecObjectIdentifiers.SecT571k1);
+
+ DefineCurveAlias("P-192", SecObjectIdentifiers.SecP192r1);
+ DefineCurveAlias("P-224", SecObjectIdentifiers.SecP224r1);
+ DefineCurveAlias("P-256", SecObjectIdentifiers.SecP256r1);
+ DefineCurveAlias("P-384", SecObjectIdentifiers.SecP384r1);
+ DefineCurveAlias("P-521", SecObjectIdentifiers.SecP521r1);
+ }
+
+ public static X9ECParameters GetByName(
+ string name)
+ {
+ DerObjectIdentifier oid = GetOid(name);
+ return oid == null ? null : GetByOid(oid);
+ }
+
+ /**
+ * return the X9ECParameters object for the named curve represented by
+ * the passed in object identifier. Null if the curve isn't present.
+ *
+ * @param oid an object identifier representing a named curve, if present.
+ */
+ public static X9ECParameters GetByOid(
+ DerObjectIdentifier oid)
+ {
+ return SecNamedCurves.GetByOid(oid);
+ }
+
+ /**
+ * return the object identifier signified by the passed in name. Null
+ * if there is no object identifier associated with name.
+ *
+ * @return the object identifier associated with name, if present.
+ */
+ public static DerObjectIdentifier GetOid(
+ string name)
+ {
+ return (DerObjectIdentifier) objIds[Platform.ToUpperInvariant(name)];
+ }
+
+ /**
+ * return the named curve name represented by the given object identifier.
+ */
+ public static string GetName(
+ DerObjectIdentifier oid)
+ {
+ return (string) names[oid];
+ }
+
+ /**
+ * returns an enumeration containing the name strings for curves
+ * contained in this structure.
+ */
+ public static IEnumerable Names
+ {
+ get { return new EnumerableProxy(names.Values); }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/nist/NISTObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/nist/NISTObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..55b9d8e68306e3a7be6ab62624470039f1b54860
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/nist/NISTObjectIdentifiers.cs
@@ -0,0 +1,71 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Nist
+{
+ public sealed class NistObjectIdentifiers
+ {
+ private NistObjectIdentifiers()
+ {
+ }
+
+ //
+ // NIST
+ // iso/itu(2) joint-assign(16) us(840) organization(1) gov(101) csor(3)
+
+ //
+ // nistalgorithms(4)
+ //
+ public static readonly DerObjectIdentifier NistAlgorithm = new DerObjectIdentifier("2.16.840.1.101.3.4");
+
+ public static readonly DerObjectIdentifier HashAlgs = NistAlgorithm.Branch("2");
+
+ public static readonly DerObjectIdentifier IdSha256 = HashAlgs.Branch("1");
+ public static readonly DerObjectIdentifier IdSha384 = HashAlgs.Branch("2");
+ public static readonly DerObjectIdentifier IdSha512 = HashAlgs.Branch("3");
+ public static readonly DerObjectIdentifier IdSha224 = HashAlgs.Branch("4");
+ public static readonly DerObjectIdentifier IdSha512_224 = HashAlgs.Branch("5");
+ public static readonly DerObjectIdentifier IdSha512_256 = HashAlgs.Branch("6");
+ public static readonly DerObjectIdentifier IdSha3_224 = HashAlgs.Branch("7");
+ public static readonly DerObjectIdentifier IdSha3_256 = HashAlgs.Branch("8");
+ public static readonly DerObjectIdentifier IdSha3_384 = HashAlgs.Branch("9");
+ public static readonly DerObjectIdentifier IdSha3_512 = HashAlgs.Branch("10");
+ public static readonly DerObjectIdentifier IdShake128 = HashAlgs.Branch("11");
+ public static readonly DerObjectIdentifier IdShake256 = HashAlgs.Branch("12");
+
+ public static readonly DerObjectIdentifier Aes = new DerObjectIdentifier(NistAlgorithm + ".1");
+
+ public static readonly DerObjectIdentifier IdAes128Ecb = new DerObjectIdentifier(Aes + ".1");
+ public static readonly DerObjectIdentifier IdAes128Cbc = new DerObjectIdentifier(Aes + ".2");
+ public static readonly DerObjectIdentifier IdAes128Ofb = new DerObjectIdentifier(Aes + ".3");
+ public static readonly DerObjectIdentifier IdAes128Cfb = new DerObjectIdentifier(Aes + ".4");
+ public static readonly DerObjectIdentifier IdAes128Wrap = new DerObjectIdentifier(Aes + ".5");
+ public static readonly DerObjectIdentifier IdAes128Gcm = new DerObjectIdentifier(Aes + ".6");
+ public static readonly DerObjectIdentifier IdAes128Ccm = new DerObjectIdentifier(Aes + ".7");
+
+ public static readonly DerObjectIdentifier IdAes192Ecb = new DerObjectIdentifier(Aes + ".21");
+ public static readonly DerObjectIdentifier IdAes192Cbc = new DerObjectIdentifier(Aes + ".22");
+ public static readonly DerObjectIdentifier IdAes192Ofb = new DerObjectIdentifier(Aes + ".23");
+ public static readonly DerObjectIdentifier IdAes192Cfb = new DerObjectIdentifier(Aes + ".24");
+ public static readonly DerObjectIdentifier IdAes192Wrap = new DerObjectIdentifier(Aes + ".25");
+ public static readonly DerObjectIdentifier IdAes192Gcm = new DerObjectIdentifier(Aes + ".26");
+ public static readonly DerObjectIdentifier IdAes192Ccm = new DerObjectIdentifier(Aes + ".27");
+
+ public static readonly DerObjectIdentifier IdAes256Ecb = new DerObjectIdentifier(Aes + ".41");
+ public static readonly DerObjectIdentifier IdAes256Cbc = new DerObjectIdentifier(Aes + ".42");
+ public static readonly DerObjectIdentifier IdAes256Ofb = new DerObjectIdentifier(Aes + ".43");
+ public static readonly DerObjectIdentifier IdAes256Cfb = new DerObjectIdentifier(Aes + ".44");
+ public static readonly DerObjectIdentifier IdAes256Wrap = new DerObjectIdentifier(Aes + ".45");
+ public static readonly DerObjectIdentifier IdAes256Gcm = new DerObjectIdentifier(Aes + ".46");
+ public static readonly DerObjectIdentifier IdAes256Ccm = new DerObjectIdentifier(Aes + ".47");
+
+ //
+ // signatures
+ //
+ public static readonly DerObjectIdentifier IdDsaWithSha2 = new DerObjectIdentifier(NistAlgorithm + ".3");
+
+ public static readonly DerObjectIdentifier DsaWithSha224 = new DerObjectIdentifier(IdDsaWithSha2 + ".1");
+ public static readonly DerObjectIdentifier DsaWithSha256 = new DerObjectIdentifier(IdDsaWithSha2 + ".2");
+ public static readonly DerObjectIdentifier DsaWithSha384 = new DerObjectIdentifier(IdDsaWithSha2 + ".3");
+ public static readonly DerObjectIdentifier DsaWithSha512 = new DerObjectIdentifier(IdDsaWithSha2 + ".4");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ntt/NTTObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/ntt/NTTObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cd25956006f2cb90820051e5e071dfe9bb136bb5
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ntt/NTTObjectIdentifiers.cs
@@ -0,0 +1,14 @@
+namespace Org.BouncyCastle.Asn1.Ntt
+{
+ /// From RFC 3657
+ public abstract class NttObjectIdentifiers
+ {
+ public static readonly DerObjectIdentifier IdCamellia128Cbc = new DerObjectIdentifier("1.2.392.200011.61.1.1.1.2");
+ public static readonly DerObjectIdentifier IdCamellia192Cbc = new DerObjectIdentifier("1.2.392.200011.61.1.1.1.3");
+ public static readonly DerObjectIdentifier IdCamellia256Cbc = new DerObjectIdentifier("1.2.392.200011.61.1.1.1.4");
+
+ public static readonly DerObjectIdentifier IdCamellia128Wrap = new DerObjectIdentifier("1.2.392.200011.61.1.1.3.2");
+ public static readonly DerObjectIdentifier IdCamellia192Wrap = new DerObjectIdentifier("1.2.392.200011.61.1.1.3.3");
+ public static readonly DerObjectIdentifier IdCamellia256Wrap = new DerObjectIdentifier("1.2.392.200011.61.1.1.3.4");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ocsp/BasicOCSPResponse.cs b/bc-sharp-crypto/src/asn1/ocsp/BasicOCSPResponse.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e6aa1f86bfb35c5c08e15215136b81ecc1dde918
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ocsp/BasicOCSPResponse.cs
@@ -0,0 +1,137 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+ public class BasicOcspResponse
+ : Asn1Encodable
+ {
+ private readonly ResponseData tbsResponseData;
+ private readonly AlgorithmIdentifier signatureAlgorithm;
+ private readonly DerBitString signature;
+ private readonly Asn1Sequence certs;
+
+ public static BasicOcspResponse GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static BasicOcspResponse GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is BasicOcspResponse)
+ {
+ return (BasicOcspResponse)obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new BasicOcspResponse((Asn1Sequence)obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public BasicOcspResponse(
+ ResponseData tbsResponseData,
+ AlgorithmIdentifier signatureAlgorithm,
+ DerBitString signature,
+ Asn1Sequence certs)
+ {
+ this.tbsResponseData = tbsResponseData;
+ this.signatureAlgorithm = signatureAlgorithm;
+ this.signature = signature;
+ this.certs = certs;
+ }
+
+ private BasicOcspResponse(
+ Asn1Sequence seq)
+ {
+ this.tbsResponseData = ResponseData.GetInstance(seq[0]);
+ this.signatureAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+ this.signature = (DerBitString)seq[2];
+
+ if (seq.Count > 3)
+ {
+ this.certs = Asn1Sequence.GetInstance((Asn1TaggedObject)seq[3], true);
+ }
+ }
+
+ [Obsolete("Use TbsResponseData property instead")]
+ public ResponseData GetTbsResponseData()
+ {
+ return tbsResponseData;
+ }
+
+ public ResponseData TbsResponseData
+ {
+ get { return tbsResponseData; }
+ }
+
+ [Obsolete("Use SignatureAlgorithm property instead")]
+ public AlgorithmIdentifier GetSignatureAlgorithm()
+ {
+ return signatureAlgorithm;
+ }
+
+ public AlgorithmIdentifier SignatureAlgorithm
+ {
+ get { return signatureAlgorithm; }
+ }
+
+ [Obsolete("Use Signature property instead")]
+ public DerBitString GetSignature()
+ {
+ return signature;
+ }
+
+ public DerBitString Signature
+ {
+ get { return signature; }
+ }
+
+ public byte[] GetSignatureOctets()
+ {
+ return signature.GetOctets();
+ }
+
+ [Obsolete("Use Certs property instead")]
+ public Asn1Sequence GetCerts()
+ {
+ return certs;
+ }
+
+ public Asn1Sequence Certs
+ {
+ get { return certs; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * BasicOcspResponse ::= Sequence {
+ * tbsResponseData ResponseData,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT Sequence OF Certificate OPTIONAL }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ tbsResponseData, signatureAlgorithm, signature);
+
+ if (certs != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, certs));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ocsp/CertID.cs b/bc-sharp-crypto/src/asn1/ocsp/CertID.cs
new file mode 100644
index 0000000000000000000000000000000000000000..523f6b87c3fc9e599b9d90591057ed527cc6b41d
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ocsp/CertID.cs
@@ -0,0 +1,99 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+ public class CertID
+ : Asn1Encodable
+ {
+ private readonly AlgorithmIdentifier hashAlgorithm;
+ private readonly Asn1OctetString issuerNameHash;
+ private readonly Asn1OctetString issuerKeyHash;
+ private readonly DerInteger serialNumber;
+
+ public static CertID GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static CertID GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is CertID)
+ {
+ return (CertID)obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new CertID((Asn1Sequence)obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public CertID(
+ AlgorithmIdentifier hashAlgorithm,
+ Asn1OctetString issuerNameHash,
+ Asn1OctetString issuerKeyHash,
+ DerInteger serialNumber)
+ {
+ this.hashAlgorithm = hashAlgorithm;
+ this.issuerNameHash = issuerNameHash;
+ this.issuerKeyHash = issuerKeyHash;
+ this.serialNumber = serialNumber;
+ }
+
+ private CertID(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 4)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]);
+ this.issuerNameHash = Asn1OctetString.GetInstance(seq[1]);
+ this.issuerKeyHash = Asn1OctetString.GetInstance(seq[2]);
+ this.serialNumber = DerInteger.GetInstance(seq[3]);
+ }
+
+ public AlgorithmIdentifier HashAlgorithm
+ {
+ get { return hashAlgorithm; }
+ }
+
+ public Asn1OctetString IssuerNameHash
+ {
+ get { return issuerNameHash; }
+ }
+
+ public Asn1OctetString IssuerKeyHash
+ {
+ get { return issuerKeyHash; }
+ }
+
+ public DerInteger SerialNumber
+ {
+ get { return serialNumber; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * CertID ::= Sequence {
+ * hashAlgorithm AlgorithmIdentifier,
+ * issuerNameHash OCTET STRING, -- Hash of Issuer's DN
+ * issuerKeyHash OCTET STRING, -- Hash of Issuers public key
+ * serialNumber CertificateSerialNumber }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(hashAlgorithm, issuerNameHash, issuerKeyHash, serialNumber);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ocsp/CertStatus.cs b/bc-sharp-crypto/src/asn1/ocsp/CertStatus.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7dd99b8447921d11bc686351a7eec516f554ec6c
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ocsp/CertStatus.cs
@@ -0,0 +1,96 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+ public class CertStatus
+ : Asn1Encodable, IAsn1Choice
+ {
+ private readonly int tagNo;
+ private readonly Asn1Encodable value;
+
+ /**
+ * create a CertStatus object with a tag of zero.
+ */
+ public CertStatus()
+ {
+ tagNo = 0;
+ value = DerNull.Instance;
+ }
+
+ public CertStatus(
+ RevokedInfo info)
+ {
+ tagNo = 1;
+ value = info;
+ }
+
+ public CertStatus(
+ int tagNo,
+ Asn1Encodable value)
+ {
+ this.tagNo = tagNo;
+ this.value = value;
+ }
+
+ public CertStatus(
+ Asn1TaggedObject choice)
+ {
+ this.tagNo = choice.TagNo;
+
+ switch (choice.TagNo)
+ {
+ case 1:
+ value = RevokedInfo.GetInstance(choice, false);
+ break;
+ case 0:
+ case 2:
+ value = DerNull.Instance;
+ break;
+ default:
+ throw new ArgumentException("Unknown tag encountered: " + choice.TagNo);
+ }
+ }
+
+ public static CertStatus GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is CertStatus)
+ {
+ return (CertStatus)obj;
+ }
+
+ if (obj is Asn1TaggedObject)
+ {
+ return new CertStatus((Asn1TaggedObject)obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public int TagNo
+ {
+ get { return tagNo; }
+ }
+
+ public Asn1Encodable Status
+ {
+ get { return value; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * CertStatus ::= CHOICE {
+ * good [0] IMPLICIT Null,
+ * revoked [1] IMPLICIT RevokedInfo,
+ * unknown [2] IMPLICIT UnknownInfo }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerTaggedObject(false, tagNo, value);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ocsp/CrlID.cs b/bc-sharp-crypto/src/asn1/ocsp/CrlID.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cfb3d6fcbfb45fa0b59c9285bc99ac4c7888e0d2
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ocsp/CrlID.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+ public class CrlID
+ : Asn1Encodable
+ {
+ private readonly DerIA5String crlUrl;
+ private readonly DerInteger crlNum;
+ private readonly DerGeneralizedTime crlTime;
+
+ // TODO Add GetInstance method(s) and amke this private?
+ public CrlID(
+ Asn1Sequence seq)
+ {
+ foreach (Asn1TaggedObject o in seq)
+ {
+ switch (o.TagNo)
+ {
+ case 0:
+ crlUrl = DerIA5String.GetInstance(o, true);
+ break;
+ case 1:
+ crlNum = DerInteger.GetInstance(o, true);
+ break;
+ case 2:
+ crlTime = DerGeneralizedTime.GetInstance(o, true);
+ break;
+ default:
+ throw new ArgumentException("unknown tag number: " + o.TagNo);
+ }
+ }
+ }
+
+ public DerIA5String CrlUrl
+ {
+ get { return crlUrl; }
+ }
+
+ public DerInteger CrlNum
+ {
+ get { return crlNum; }
+ }
+
+ public DerGeneralizedTime CrlTime
+ {
+ get { return crlTime; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * CrlID ::= Sequence {
+ * crlUrl [0] EXPLICIT IA5String OPTIONAL,
+ * crlNum [1] EXPLICIT Integer OPTIONAL,
+ * crlTime [2] EXPLICIT GeneralizedTime OPTIONAL }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (crlUrl != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, crlUrl));
+ }
+
+ if (crlNum != null)
+ {
+ v.Add(new DerTaggedObject(true, 1, crlNum));
+ }
+
+ if (crlTime != null)
+ {
+ v.Add(new DerTaggedObject(true, 2, crlTime));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ocsp/OCSPObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/ocsp/OCSPObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a37c8552dc560f934fc4a67241f8dbdc5b7cf4a4
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ocsp/OCSPObjectIdentifiers.cs
@@ -0,0 +1,23 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+ public abstract class OcspObjectIdentifiers
+ {
+ internal const string PkixOcspId = "1.3.6.1.5.5.7.48.1";
+
+ public static readonly DerObjectIdentifier PkixOcsp = new DerObjectIdentifier(PkixOcspId);
+ public static readonly DerObjectIdentifier PkixOcspBasic = new DerObjectIdentifier(PkixOcspId + ".1");
+
+ //
+ // extensions
+ //
+ public static readonly DerObjectIdentifier PkixOcspNonce = new DerObjectIdentifier(PkixOcsp + ".2");
+ public static readonly DerObjectIdentifier PkixOcspCrl = new DerObjectIdentifier(PkixOcsp + ".3");
+
+ public static readonly DerObjectIdentifier PkixOcspResponse = new DerObjectIdentifier(PkixOcsp + ".4");
+ public static readonly DerObjectIdentifier PkixOcspNocheck = new DerObjectIdentifier(PkixOcsp + ".5");
+ public static readonly DerObjectIdentifier PkixOcspArchiveCutoff = new DerObjectIdentifier(PkixOcsp + ".6");
+ public static readonly DerObjectIdentifier PkixOcspServiceLocator = new DerObjectIdentifier(PkixOcsp + ".7");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ocsp/OCSPRequest.cs b/bc-sharp-crypto/src/asn1/ocsp/OCSPRequest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2407678b411254d1aac1a5d79f0cf47ca6f4d8d2
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ocsp/OCSPRequest.cs
@@ -0,0 +1,89 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+ public class OcspRequest
+ : Asn1Encodable
+ {
+ private readonly TbsRequest tbsRequest;
+ private readonly Signature optionalSignature;
+
+ public static OcspRequest GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static OcspRequest GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is OcspRequest)
+ {
+ return (OcspRequest)obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new OcspRequest((Asn1Sequence)obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public OcspRequest(
+ TbsRequest tbsRequest,
+ Signature optionalSignature)
+ {
+ if (tbsRequest == null)
+ throw new ArgumentNullException("tbsRequest");
+
+ this.tbsRequest = tbsRequest;
+ this.optionalSignature = optionalSignature;
+ }
+
+ private OcspRequest(
+ Asn1Sequence seq)
+ {
+ tbsRequest = TbsRequest.GetInstance(seq[0]);
+
+ if (seq.Count == 2)
+ {
+ optionalSignature = Signature.GetInstance(
+ (Asn1TaggedObject)seq[1], true);
+ }
+ }
+
+ public TbsRequest TbsRequest
+ {
+ get { return tbsRequest; }
+ }
+
+ public Signature OptionalSignature
+ {
+ get { return optionalSignature; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * OcspRequest ::= Sequence {
+ * tbsRequest TBSRequest,
+ * optionalSignature [0] EXPLICIT Signature OPTIONAL }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(tbsRequest);
+
+ if (optionalSignature != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, optionalSignature));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ocsp/OCSPResponse.cs b/bc-sharp-crypto/src/asn1/ocsp/OCSPResponse.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9477b61c035cbb99645ebaeffe7604e2f5d0529d
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ocsp/OCSPResponse.cs
@@ -0,0 +1,90 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+ public class OcspResponse
+ : Asn1Encodable
+ {
+ private readonly OcspResponseStatus responseStatus;
+ private readonly ResponseBytes responseBytes;
+
+ public static OcspResponse GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static OcspResponse GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is OcspResponse)
+ {
+ return (OcspResponse)obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new OcspResponse((Asn1Sequence)obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public OcspResponse(
+ OcspResponseStatus responseStatus,
+ ResponseBytes responseBytes)
+ {
+ if (responseStatus == null)
+ throw new ArgumentNullException("responseStatus");
+
+ this.responseStatus = responseStatus;
+ this.responseBytes = responseBytes;
+ }
+
+ private OcspResponse(
+ Asn1Sequence seq)
+ {
+ responseStatus = new OcspResponseStatus(
+ DerEnumerated.GetInstance(seq[0]));
+
+ if (seq.Count == 2)
+ {
+ responseBytes = ResponseBytes.GetInstance(
+ (Asn1TaggedObject)seq[1], true);
+ }
+ }
+
+ public OcspResponseStatus ResponseStatus
+ {
+ get { return responseStatus; }
+ }
+
+ public ResponseBytes ResponseBytes
+ {
+ get { return responseBytes; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * OcspResponse ::= Sequence {
+ * responseStatus OcspResponseStatus,
+ * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(responseStatus);
+
+ if (responseBytes != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, responseBytes));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ocsp/OCSPResponseStatus.cs b/bc-sharp-crypto/src/asn1/ocsp/OCSPResponseStatus.cs
new file mode 100644
index 0000000000000000000000000000000000000000..653317e33e8146904ab18476f73c9a777c787c3b
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ocsp/OCSPResponseStatus.cs
@@ -0,0 +1,41 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+ public class OcspResponseStatus
+ : DerEnumerated
+ {
+ public const int Successful = 0;
+ public const int MalformedRequest = 1;
+ public const int InternalError = 2;
+ public const int TryLater = 3;
+ public const int SignatureRequired = 5;
+ public const int Unauthorized = 6;
+
+ /**
+ * The OcspResponseStatus enumeration.
+ *
+ * OcspResponseStatus ::= Enumerated {
+ * successful (0), --Response has valid confirmations
+ * malformedRequest (1), --Illegal confirmation request
+ * internalError (2), --Internal error in issuer
+ * tryLater (3), --Try again later
+ * --(4) is not used
+ * sigRequired (5), --Must sign the request
+ * unauthorized (6) --Request unauthorized
+ * }
+ *
+ */
+ public OcspResponseStatus(int value)
+ : base(value)
+ {
+ }
+
+ public OcspResponseStatus(DerEnumerated value)
+ : base(value.Value.IntValue)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ocsp/Request.cs b/bc-sharp-crypto/src/asn1/ocsp/Request.cs
new file mode 100644
index 0000000000000000000000000000000000000000..26e81ba70123dd23e20f46aa58a6a85daae7b165
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ocsp/Request.cs
@@ -0,0 +1,91 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+ public class Request
+ : Asn1Encodable
+ {
+ private readonly CertID reqCert;
+ private readonly X509Extensions singleRequestExtensions;
+
+ public static Request GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static Request GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is Request)
+ {
+ return (Request)obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new Request((Asn1Sequence)obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public Request(
+ CertID reqCert,
+ X509Extensions singleRequestExtensions)
+ {
+ if (reqCert == null)
+ throw new ArgumentNullException("reqCert");
+
+ this.reqCert = reqCert;
+ this.singleRequestExtensions = singleRequestExtensions;
+ }
+
+ private Request(
+ Asn1Sequence seq)
+ {
+ reqCert = CertID.GetInstance(seq[0]);
+
+ if (seq.Count == 2)
+ {
+ singleRequestExtensions = X509Extensions.GetInstance(
+ (Asn1TaggedObject)seq[1], true);
+ }
+ }
+
+ public CertID ReqCert
+ {
+ get { return reqCert; }
+ }
+
+ public X509Extensions SingleRequestExtensions
+ {
+ get { return singleRequestExtensions; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Request ::= Sequence {
+ * reqCert CertID,
+ * singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(reqCert);
+
+ if (singleRequestExtensions != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, singleRequestExtensions));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ocsp/ResponderID.cs b/bc-sharp-crypto/src/asn1/ocsp/ResponderID.cs
new file mode 100644
index 0000000000000000000000000000000000000000..143b17339b708b06cb5fc5ae0e3739f8934acc1f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ocsp/ResponderID.cs
@@ -0,0 +1,107 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+ public class ResponderID
+ : Asn1Encodable, IAsn1Choice
+ {
+ private readonly Asn1Encodable id;
+
+ public static ResponderID GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is ResponderID)
+ {
+ return (ResponderID)obj;
+ }
+
+ if (obj is DerOctetString)
+ {
+ return new ResponderID((DerOctetString)obj);
+ }
+
+ if (obj is Asn1TaggedObject)
+ {
+ Asn1TaggedObject o = (Asn1TaggedObject)obj;
+
+ if (o.TagNo == 1)
+ {
+ return new ResponderID(X509Name.GetInstance(o, true));
+ }
+
+ return new ResponderID(Asn1OctetString.GetInstance(o, true));
+ }
+
+ return new ResponderID(X509Name.GetInstance(obj));
+ }
+
+ public ResponderID(
+ Asn1OctetString id)
+ {
+ if (id == null)
+ throw new ArgumentNullException("id");
+
+ this.id = id;
+ }
+
+ public ResponderID(
+ X509Name id)
+ {
+ if (id == null)
+ throw new ArgumentNullException("id");
+
+ this.id = id;
+ }
+
+ public static ResponderID GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ return GetInstance(obj.GetObject()); // must be explicitly tagged
+ }
+
+ public virtual byte[] GetKeyHash()
+ {
+ if (id is Asn1OctetString)
+ {
+ return ((Asn1OctetString)id).GetOctets();
+ }
+
+ return null;
+ }
+
+ public virtual X509Name Name
+ {
+ get
+ {
+ if (id is Asn1OctetString)
+ {
+ return null;
+ }
+
+ return X509Name.GetInstance(id);
+ }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * ResponderID ::= CHOICE {
+ * byName [1] Name,
+ * byKey [2] KeyHash }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ if (id is Asn1OctetString)
+ {
+ return new DerTaggedObject(true, 2, id);
+ }
+
+ return new DerTaggedObject(true, 1, id);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ocsp/ResponseBytes.cs b/bc-sharp-crypto/src/asn1/ocsp/ResponseBytes.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d3ea044bfc31c9603ce720d622195730d391d06a
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ocsp/ResponseBytes.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+ public class ResponseBytes
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier responseType;
+ private readonly Asn1OctetString response;
+
+ public static ResponseBytes GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static ResponseBytes GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is ResponseBytes)
+ {
+ return (ResponseBytes)obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new ResponseBytes((Asn1Sequence)obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public ResponseBytes(
+ DerObjectIdentifier responseType,
+ Asn1OctetString response)
+ {
+ if (responseType == null)
+ throw new ArgumentNullException("responseType");
+ if (response == null)
+ throw new ArgumentNullException("response");
+
+ this.responseType = responseType;
+ this.response = response;
+ }
+
+ private ResponseBytes(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ this.responseType = DerObjectIdentifier.GetInstance(seq[0]);
+ this.response = Asn1OctetString.GetInstance(seq[1]);
+ }
+
+ public DerObjectIdentifier ResponseType
+ {
+ get { return responseType; }
+ }
+
+ public Asn1OctetString Response
+ {
+ get { return response; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * ResponseBytes ::= Sequence {
+ * responseType OBJECT IDENTIFIER,
+ * response OCTET STRING }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(responseType, response);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ocsp/ResponseData.cs b/bc-sharp-crypto/src/asn1/ocsp/ResponseData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..70620cbc3d9c5f17a8f4e0148bebaad0d3c536d7
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ocsp/ResponseData.cs
@@ -0,0 +1,158 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+ public class ResponseData
+ : Asn1Encodable
+ {
+ private static readonly DerInteger V1 = new DerInteger(0);
+
+ private readonly bool versionPresent;
+ private readonly DerInteger version;
+ private readonly ResponderID responderID;
+ private readonly DerGeneralizedTime producedAt;
+ private readonly Asn1Sequence responses;
+ private readonly X509Extensions responseExtensions;
+
+ public static ResponseData GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static ResponseData GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is ResponseData)
+ {
+ return (ResponseData)obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new ResponseData((Asn1Sequence)obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public ResponseData(
+ DerInteger version,
+ ResponderID responderID,
+ DerGeneralizedTime producedAt,
+ Asn1Sequence responses,
+ X509Extensions responseExtensions)
+ {
+ this.version = version;
+ this.responderID = responderID;
+ this.producedAt = producedAt;
+ this.responses = responses;
+ this.responseExtensions = responseExtensions;
+ }
+
+ public ResponseData(
+ ResponderID responderID,
+ DerGeneralizedTime producedAt,
+ Asn1Sequence responses,
+ X509Extensions responseExtensions)
+ : this(V1, responderID, producedAt, responses, responseExtensions)
+ {
+ }
+
+ private ResponseData(
+ Asn1Sequence seq)
+ {
+ int index = 0;
+
+ Asn1Encodable enc = seq[0];
+ if (enc is Asn1TaggedObject)
+ {
+ Asn1TaggedObject o = (Asn1TaggedObject)enc;
+
+ if (o.TagNo == 0)
+ {
+ this.versionPresent = true;
+ this.version = DerInteger.GetInstance(o, true);
+ index++;
+ }
+ else
+ {
+ this.version = V1;
+ }
+ }
+ else
+ {
+ this.version = V1;
+ }
+
+ this.responderID = ResponderID.GetInstance(seq[index++]);
+ this.producedAt = (DerGeneralizedTime)seq[index++];
+ this.responses = (Asn1Sequence)seq[index++];
+
+ if (seq.Count > index)
+ {
+ this.responseExtensions = X509Extensions.GetInstance(
+ (Asn1TaggedObject)seq[index], true);
+ }
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public ResponderID ResponderID
+ {
+ get { return responderID; }
+ }
+
+ public DerGeneralizedTime ProducedAt
+ {
+ get { return producedAt; }
+ }
+
+ public Asn1Sequence Responses
+ {
+ get { return responses; }
+ }
+
+ public X509Extensions ResponseExtensions
+ {
+ get { return responseExtensions; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * ResponseData ::= Sequence {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * responderID ResponderID,
+ * producedAt GeneralizedTime,
+ * responses Sequence OF SingleResponse,
+ * responseExtensions [1] EXPLICIT Extensions OPTIONAL }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (versionPresent || !version.Equals(V1))
+ {
+ v.Add(new DerTaggedObject(true, 0, version));
+ }
+
+ v.Add(responderID, producedAt, responses);
+
+ if (responseExtensions != null)
+ {
+ v.Add(new DerTaggedObject(true, 1, responseExtensions));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ocsp/RevokedInfo.cs b/bc-sharp-crypto/src/asn1/ocsp/RevokedInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ee9e554299e66f62278c545dbab7d7496b62d795
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ocsp/RevokedInfo.cs
@@ -0,0 +1,96 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+ public class RevokedInfo
+ : Asn1Encodable
+ {
+ private readonly DerGeneralizedTime revocationTime;
+ private readonly CrlReason revocationReason;
+
+ public static RevokedInfo GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static RevokedInfo GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is RevokedInfo)
+ {
+ return (RevokedInfo) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new RevokedInfo((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public RevokedInfo(
+ DerGeneralizedTime revocationTime)
+ : this(revocationTime, null)
+ {
+ }
+
+ public RevokedInfo(
+ DerGeneralizedTime revocationTime,
+ CrlReason revocationReason)
+ {
+ if (revocationTime == null)
+ throw new ArgumentNullException("revocationTime");
+
+ this.revocationTime = revocationTime;
+ this.revocationReason = revocationReason;
+ }
+
+ private RevokedInfo(
+ Asn1Sequence seq)
+ {
+ this.revocationTime = (DerGeneralizedTime) seq[0];
+
+ if (seq.Count > 1)
+ {
+ this.revocationReason = new CrlReason(
+ DerEnumerated.GetInstance((Asn1TaggedObject) seq[1], true));
+ }
+ }
+
+ public DerGeneralizedTime RevocationTime
+ {
+ get { return revocationTime; }
+ }
+
+ public CrlReason RevocationReason
+ {
+ get { return revocationReason; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * RevokedInfo ::= Sequence {
+ * revocationTime GeneralizedTime,
+ * revocationReason [0] EXPLICIT CRLReason OPTIONAL }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(revocationTime);
+
+ if (revocationReason != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, revocationReason));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ocsp/ServiceLocator.cs b/bc-sharp-crypto/src/asn1/ocsp/ServiceLocator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4ba252be33de3d58a7b24caced6b3f9df36e915e
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ocsp/ServiceLocator.cs
@@ -0,0 +1,95 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+ public class ServiceLocator
+ : Asn1Encodable
+ {
+ private readonly X509Name issuer;
+ private readonly Asn1Object locator;
+
+ public static ServiceLocator GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static ServiceLocator GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is ServiceLocator)
+ {
+ return (ServiceLocator) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new ServiceLocator((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public ServiceLocator(
+ X509Name issuer)
+ : this(issuer, null)
+ {
+ }
+
+ public ServiceLocator(
+ X509Name issuer,
+ Asn1Object locator)
+ {
+ if (issuer == null)
+ throw new ArgumentNullException("issuer");
+
+ this.issuer = issuer;
+ this.locator = locator;
+ }
+
+ private ServiceLocator(
+ Asn1Sequence seq)
+ {
+ this.issuer = X509Name.GetInstance(seq[0]);
+
+ if (seq.Count > 1)
+ {
+ this.locator = seq[1].ToAsn1Object();
+ }
+ }
+
+ public X509Name Issuer
+ {
+ get { return issuer; }
+ }
+
+ public Asn1Object Locator
+ {
+ get { return locator; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * ServiceLocator ::= Sequence {
+ * issuer Name,
+ * locator AuthorityInfoAccessSyntax OPTIONAL }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(issuer);
+
+ if (locator != null)
+ {
+ v.Add(locator);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ocsp/Signature.cs b/bc-sharp-crypto/src/asn1/ocsp/Signature.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d6b4ccfbf63f79bd2c816ec361de6849c3adcd47
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ocsp/Signature.cs
@@ -0,0 +1,115 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+ public class Signature
+ : Asn1Encodable
+ {
+ internal AlgorithmIdentifier signatureAlgorithm;
+ internal DerBitString signatureValue;
+ internal Asn1Sequence certs;
+
+ public static Signature GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static Signature GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is Signature)
+ {
+ return (Signature)obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new Signature((Asn1Sequence)obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public Signature(
+ AlgorithmIdentifier signatureAlgorithm,
+ DerBitString signatureValue)
+ : this(signatureAlgorithm, signatureValue, null)
+ {
+ }
+
+ public Signature(
+ AlgorithmIdentifier signatureAlgorithm,
+ DerBitString signatureValue,
+ Asn1Sequence certs)
+ {
+ if (signatureAlgorithm == null)
+ throw new ArgumentException("signatureAlgorithm");
+ if (signatureValue == null)
+ throw new ArgumentException("signatureValue");
+
+ this.signatureAlgorithm = signatureAlgorithm;
+ this.signatureValue = signatureValue;
+ this.certs = certs;
+ }
+
+ private Signature(
+ Asn1Sequence seq)
+ {
+ signatureAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]);
+ signatureValue = (DerBitString)seq[1];
+
+ if (seq.Count == 3)
+ {
+ certs = Asn1Sequence.GetInstance(
+ (Asn1TaggedObject)seq[2], true);
+ }
+ }
+
+ public AlgorithmIdentifier SignatureAlgorithm
+ {
+ get { return signatureAlgorithm; }
+ }
+
+ public DerBitString SignatureValue
+ {
+ get { return signatureValue; }
+ }
+
+ public byte[] GetSignatureOctets()
+ {
+ return signatureValue.GetOctets();
+ }
+
+ public Asn1Sequence Certs
+ {
+ get { return certs; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Signature ::= Sequence {
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT Sequence OF Certificate OPTIONAL}
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ signatureAlgorithm, signatureValue);
+
+ if (certs != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, certs));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ocsp/SingleResponse.cs b/bc-sharp-crypto/src/asn1/ocsp/SingleResponse.cs
new file mode 100644
index 0000000000000000000000000000000000000000..544232abe82a7ce65c9bad1c79a48ce86b61b3ff
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ocsp/SingleResponse.cs
@@ -0,0 +1,137 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+ public class SingleResponse
+ : Asn1Encodable
+ {
+ private readonly CertID certID;
+ private readonly CertStatus certStatus;
+ private readonly DerGeneralizedTime thisUpdate;
+ private readonly DerGeneralizedTime nextUpdate;
+ private readonly X509Extensions singleExtensions;
+
+ public SingleResponse(
+ CertID certID,
+ CertStatus certStatus,
+ DerGeneralizedTime thisUpdate,
+ DerGeneralizedTime nextUpdate,
+ X509Extensions singleExtensions)
+ {
+ this.certID = certID;
+ this.certStatus = certStatus;
+ this.thisUpdate = thisUpdate;
+ this.nextUpdate = nextUpdate;
+ this.singleExtensions = singleExtensions;
+ }
+
+ public SingleResponse(
+ Asn1Sequence seq)
+ {
+ this.certID = CertID.GetInstance(seq[0]);
+ this.certStatus = CertStatus.GetInstance(seq[1]);
+ this.thisUpdate = (DerGeneralizedTime)seq[2];
+
+ if (seq.Count > 4)
+ {
+ this.nextUpdate = DerGeneralizedTime.GetInstance(
+ (Asn1TaggedObject) seq[3], true);
+ this.singleExtensions = X509Extensions.GetInstance(
+ (Asn1TaggedObject) seq[4], true);
+ }
+ else if (seq.Count > 3)
+ {
+ Asn1TaggedObject o = (Asn1TaggedObject) seq[3];
+
+ if (o.TagNo == 0)
+ {
+ this.nextUpdate = DerGeneralizedTime.GetInstance(o, true);
+ }
+ else
+ {
+ this.singleExtensions = X509Extensions.GetInstance(o, true);
+ }
+ }
+ }
+
+ public static SingleResponse GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static SingleResponse GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is SingleResponse)
+ {
+ return (SingleResponse)obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new SingleResponse((Asn1Sequence)obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public CertID CertId
+ {
+ get { return certID; }
+ }
+
+ public CertStatus CertStatus
+ {
+ get { return certStatus; }
+ }
+
+ public DerGeneralizedTime ThisUpdate
+ {
+ get { return thisUpdate; }
+ }
+
+ public DerGeneralizedTime NextUpdate
+ {
+ get { return nextUpdate; }
+ }
+
+ public X509Extensions SingleExtensions
+ {
+ get { return singleExtensions; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * SingleResponse ::= Sequence {
+ * certID CertID,
+ * certStatus CertStatus,
+ * thisUpdate GeneralizedTime,
+ * nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
+ * singleExtensions [1] EXPLICIT Extensions OPTIONAL }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ certID, certStatus, thisUpdate);
+
+ if (nextUpdate != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, nextUpdate));
+ }
+
+ if (singleExtensions != null)
+ {
+ v.Add(new DerTaggedObject(true, 1, singleExtensions));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/ocsp/TBSRequest.cs b/bc-sharp-crypto/src/asn1/ocsp/TBSRequest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1ad8649f8ffd6105319eefba1ff94612ec33a520
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/ocsp/TBSRequest.cs
@@ -0,0 +1,151 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+ public class TbsRequest
+ : Asn1Encodable
+ {
+ private static readonly DerInteger V1 = new DerInteger(0);
+
+ private readonly DerInteger version;
+ private readonly GeneralName requestorName;
+ private readonly Asn1Sequence requestList;
+ private readonly X509Extensions requestExtensions;
+
+ private bool versionSet;
+
+ public static TbsRequest GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static TbsRequest GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is TbsRequest)
+ {
+ return (TbsRequest)obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new TbsRequest((Asn1Sequence)obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public TbsRequest(
+ GeneralName requestorName,
+ Asn1Sequence requestList,
+ X509Extensions requestExtensions)
+ {
+ this.version = V1;
+ this.requestorName = requestorName;
+ this.requestList = requestList;
+ this.requestExtensions = requestExtensions;
+ }
+
+ private TbsRequest(
+ Asn1Sequence seq)
+ {
+ int index = 0;
+
+ Asn1Encodable enc = seq[0];
+ if (enc is Asn1TaggedObject)
+ {
+ Asn1TaggedObject o = (Asn1TaggedObject) enc;
+
+ if (o.TagNo == 0)
+ {
+ versionSet = true;
+ version = DerInteger.GetInstance(o, true);
+ index++;
+ }
+ else
+ {
+ version = V1;
+ }
+ }
+ else
+ {
+ version = V1;
+ }
+
+ if (seq[index] is Asn1TaggedObject)
+ {
+ requestorName = GeneralName.GetInstance((Asn1TaggedObject) seq[index++], true);
+ }
+
+ requestList = (Asn1Sequence) seq[index++];
+
+ if (seq.Count == (index + 1))
+ {
+ requestExtensions = X509Extensions.GetInstance((Asn1TaggedObject) seq[index], true);
+ }
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public GeneralName RequestorName
+ {
+ get { return requestorName; }
+ }
+
+ public Asn1Sequence RequestList
+ {
+ get { return requestList; }
+ }
+
+ public X509Extensions RequestExtensions
+ {
+ get { return requestExtensions; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * TBSRequest ::= Sequence {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * requestorName [1] EXPLICIT GeneralName OPTIONAL,
+ * requestList Sequence OF Request,
+ * requestExtensions [2] EXPLICIT Extensions OPTIONAL }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ //
+ // if default don't include - unless explicitly provided. Not strictly correct
+ // but required for some requests
+ //
+ if (!version.Equals(V1) || versionSet)
+ {
+ v.Add(new DerTaggedObject(true, 0, version));
+ }
+
+ if (requestorName != null)
+ {
+ v.Add(new DerTaggedObject(true, 1, requestorName));
+ }
+
+ v.Add(requestList);
+
+ if (requestExtensions != null)
+ {
+ v.Add(new DerTaggedObject(true, 2, requestExtensions));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/oiw/ElGamalParameter.cs b/bc-sharp-crypto/src/asn1/oiw/ElGamalParameter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3e020f0598aad57e3e7989a7447610ef2c9d0248
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/oiw/ElGamalParameter.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Oiw
+{
+ public class ElGamalParameter
+ : Asn1Encodable
+ {
+ internal DerInteger p, g;
+
+ public ElGamalParameter(
+ BigInteger p,
+ BigInteger g)
+ {
+ this.p = new DerInteger(p);
+ this.g = new DerInteger(g);
+ }
+
+ public ElGamalParameter(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ p = DerInteger.GetInstance(seq[0]);
+ g = DerInteger.GetInstance(seq[1]);
+ }
+
+ public BigInteger P
+ {
+ get { return p.PositiveValue; }
+ }
+
+ public BigInteger G
+ {
+ get { return g.PositiveValue; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(p, g);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/oiw/OIWObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/oiw/OIWObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3da2263012a6f3ce56de18d520a6548922e00b6b
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/oiw/OIWObjectIdentifiers.cs
@@ -0,0 +1,29 @@
+namespace Org.BouncyCastle.Asn1.Oiw
+{
+ public abstract class OiwObjectIdentifiers
+ {
+ public static readonly DerObjectIdentifier MD4WithRsa = new DerObjectIdentifier("1.3.14.3.2.2");
+ public static readonly DerObjectIdentifier MD5WithRsa = new DerObjectIdentifier("1.3.14.3.2.3");
+ public static readonly DerObjectIdentifier MD4WithRsaEncryption = new DerObjectIdentifier("1.3.14.3.2.4");
+
+ public static readonly DerObjectIdentifier DesEcb = new DerObjectIdentifier("1.3.14.3.2.6");
+ public static readonly DerObjectIdentifier DesCbc = new DerObjectIdentifier("1.3.14.3.2.7");
+ public static readonly DerObjectIdentifier DesOfb = new DerObjectIdentifier("1.3.14.3.2.8");
+ public static readonly DerObjectIdentifier DesCfb = new DerObjectIdentifier("1.3.14.3.2.9");
+
+ public static readonly DerObjectIdentifier DesEde = new DerObjectIdentifier("1.3.14.3.2.17");
+
+ // id-SHA1 OBJECT IDENTIFIER ::=
+ // {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } //
+ public static readonly DerObjectIdentifier IdSha1 = new DerObjectIdentifier("1.3.14.3.2.26");
+
+ public static readonly DerObjectIdentifier DsaWithSha1 = new DerObjectIdentifier("1.3.14.3.2.27");
+
+ public static readonly DerObjectIdentifier Sha1WithRsa = new DerObjectIdentifier("1.3.14.3.2.29");
+
+ // ElGamal Algorithm OBJECT IDENTIFIER ::=
+ // {iso(1) identified-organization(3) oiw(14) dirservsig(7) algorithm(2) encryption(1) 1 }
+ //
+ public static readonly DerObjectIdentifier ElGamalAlgorithm = new DerObjectIdentifier("1.3.14.7.2.1.1");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/Attribute.cs b/bc-sharp-crypto/src/asn1/pkcs/Attribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1858285964e53624f9a5b9b16e70f5e2c2520665
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/Attribute.cs
@@ -0,0 +1,79 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class AttributePkcs
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier attrType;
+ private readonly Asn1Set attrValues;
+
+ /**
+ * return an Attribute object from the given object.
+ *
+ * @param o the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static AttributePkcs GetInstance(
+ object obj)
+ {
+ AttributePkcs attr = obj as AttributePkcs;
+ if (obj == null || attr != null)
+ {
+ return attr;
+ }
+
+ Asn1Sequence seq = obj as Asn1Sequence;
+ if (seq != null)
+ {
+ return new AttributePkcs(seq);
+ }
+
+ throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private AttributePkcs(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ attrType = DerObjectIdentifier.GetInstance(seq[0]);
+ attrValues = Asn1Set.GetInstance(seq[1]);
+ }
+
+ public AttributePkcs(
+ DerObjectIdentifier attrType,
+ Asn1Set attrValues)
+ {
+ this.attrType = attrType;
+ this.attrValues = attrValues;
+ }
+
+ public DerObjectIdentifier AttrType
+ {
+ get { return attrType; }
+ }
+
+ public Asn1Set AttrValues
+ {
+ get { return attrValues; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Attr ::= Sequence {
+ * attrType OBJECT IDENTIFIER,
+ * attrValues Set OF AttributeValue
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(attrType, attrValues);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/AuthenticatedSafe.cs b/bc-sharp-crypto/src/asn1/pkcs/AuthenticatedSafe.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f3dabb89c0424d703db208ca5983282d93c5d335
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/AuthenticatedSafe.cs
@@ -0,0 +1,37 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class AuthenticatedSafe
+ : Asn1Encodable
+ {
+ private readonly ContentInfo[] info;
+
+ public AuthenticatedSafe(
+ Asn1Sequence seq)
+ {
+ info = new ContentInfo[seq.Count];
+
+ for (int i = 0; i != info.Length; i++)
+ {
+ info[i] = ContentInfo.GetInstance(seq[i]);
+ }
+ }
+
+ public AuthenticatedSafe(
+ ContentInfo[] info)
+ {
+ this.info = (ContentInfo[]) info.Clone();
+ }
+
+ public ContentInfo[] GetContentInfo()
+ {
+ return (ContentInfo[]) info.Clone();
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new BerSequence(info);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/CertBag.cs b/bc-sharp-crypto/src/asn1/pkcs/CertBag.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b6f4c8a307f206d9a1c2df43803ca463022f5024
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/CertBag.cs
@@ -0,0 +1,46 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class CertBag
+ : Asn1Encodable
+ {
+// private readonly Asn1Sequence seq;
+ private readonly DerObjectIdentifier certID;
+ private readonly Asn1Object certValue;
+
+ public CertBag(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+// this.seq = seq;
+ this.certID = DerObjectIdentifier.GetInstance(seq[0]);
+ this.certValue = DerTaggedObject.GetInstance(seq[1]).GetObject();
+ }
+
+ public CertBag(
+ DerObjectIdentifier certID,
+ Asn1Object certValue)
+ {
+ this.certID = certID;
+ this.certValue = certValue;
+ }
+
+ public DerObjectIdentifier CertID
+ {
+ get { return certID; }
+ }
+
+ public Asn1Object CertValue
+ {
+ get { return certValue; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(certID, new DerTaggedObject(0, certValue));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/CertificationRequest.cs b/bc-sharp-crypto/src/asn1/pkcs/CertificationRequest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..98caa2268f4ae50a72eda8d4d5e070f93456ff54
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/CertificationRequest.cs
@@ -0,0 +1,87 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ /**
+ * Pkcs10 Certfication request object.
+ *
+ * CertificationRequest ::= Sequence {
+ * certificationRequestInfo CertificationRequestInfo,
+ * signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
+ * signature BIT STRING
+ * }
+ *
+ */
+ public class CertificationRequest
+ : Asn1Encodable
+ {
+ protected CertificationRequestInfo reqInfo;
+ protected AlgorithmIdentifier sigAlgId;
+ protected DerBitString sigBits;
+
+ public static CertificationRequest GetInstance(
+ object obj)
+ {
+ if (obj is CertificationRequest)
+ return (CertificationRequest)obj;
+
+ if (obj != null)
+ return new CertificationRequest((Asn1Sequence)obj);
+
+ return null;
+ }
+
+ protected CertificationRequest()
+ {
+ }
+
+ public CertificationRequest(
+ CertificationRequestInfo requestInfo,
+ AlgorithmIdentifier algorithm,
+ DerBitString signature)
+ {
+ this.reqInfo = requestInfo;
+ this.sigAlgId = algorithm;
+ this.sigBits = signature;
+ }
+
+ [Obsolete("Use 'GetInstance' instead")]
+ public CertificationRequest(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 3)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ reqInfo = CertificationRequestInfo.GetInstance(seq[0]);
+ sigAlgId = AlgorithmIdentifier.GetInstance(seq[1]);
+ sigBits = DerBitString.GetInstance(seq[2]);
+ }
+
+ public CertificationRequestInfo GetCertificationRequestInfo()
+ {
+ return reqInfo;
+ }
+
+ public AlgorithmIdentifier SignatureAlgorithm
+ {
+ get { return sigAlgId; }
+ }
+
+ public DerBitString Signature
+ {
+ get { return sigBits; }
+ }
+
+ public byte[] GetSignatureOctets()
+ {
+ return sigBits.GetOctets();
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(reqInfo, sigAlgId, sigBits);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/CertificationRequestInfo.cs b/bc-sharp-crypto/src/asn1/pkcs/CertificationRequestInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6d980131e126824a473877da387dca2d17b56d52
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/CertificationRequestInfo.cs
@@ -0,0 +1,137 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ /**
+ * Pkcs10 CertificationRequestInfo object.
+ *
+ * CertificationRequestInfo ::= Sequence {
+ * version Integer { v1(0) } (v1,...),
+ * subject Name,
+ * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+ * attributes [0] Attributes{{ CRIAttributes }}
+ * }
+ *
+ * Attributes { ATTRIBUTE:IOSet } ::= Set OF Attr{{ IOSet }}
+ *
+ * Attr { ATTRIBUTE:IOSet } ::= Sequence {
+ * type ATTRIBUTE.&id({IOSet}),
+ * values Set SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type})
+ * }
+ *
+ */
+ public class CertificationRequestInfo
+ : Asn1Encodable
+ {
+ internal DerInteger version = new DerInteger(0);
+ internal X509Name subject;
+ internal SubjectPublicKeyInfo subjectPKInfo;
+ internal Asn1Set attributes;
+
+ public static CertificationRequestInfo GetInstance(object obj)
+ {
+ if (obj is CertificationRequestInfo)
+ return (CertificationRequestInfo)obj;
+ if (obj != null)
+ return new CertificationRequestInfo(Asn1Sequence.GetInstance(obj));
+ return null;
+ }
+
+ public CertificationRequestInfo(
+ X509Name subject,
+ SubjectPublicKeyInfo pkInfo,
+ Asn1Set attributes)
+ {
+ this.subject = subject;
+ this.subjectPKInfo = pkInfo;
+ this.attributes = attributes;
+
+ ValidateAttributes(attributes);
+
+ if (subject == null || version == null || subjectPKInfo == null)
+ {
+ throw new ArgumentException(
+ "Not all mandatory fields set in CertificationRequestInfo generator.");
+ }
+ }
+
+ private CertificationRequestInfo(
+ Asn1Sequence seq)
+ {
+ version = (DerInteger) seq[0];
+
+ subject = X509Name.GetInstance(seq[1]);
+ subjectPKInfo = SubjectPublicKeyInfo.GetInstance(seq[2]);
+
+ //
+ // some CertificationRequestInfo objects seem to treat this field
+ // as optional.
+ //
+ if (seq.Count > 3)
+ {
+ DerTaggedObject tagobj = (DerTaggedObject) seq[3];
+ attributes = Asn1Set.GetInstance(tagobj, false);
+ }
+
+ ValidateAttributes(attributes);
+
+ if (subject == null || version == null || subjectPKInfo == null)
+ {
+ throw new ArgumentException(
+ "Not all mandatory fields set in CertificationRequestInfo generator.");
+ }
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public X509Name Subject
+ {
+ get { return subject; }
+ }
+
+ public SubjectPublicKeyInfo SubjectPublicKeyInfo
+ {
+ get { return subjectPKInfo; }
+ }
+
+ public Asn1Set Attributes
+ {
+ get { return attributes; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ version, subject, subjectPKInfo);
+
+ if (attributes != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, attributes));
+ }
+
+ return new DerSequence(v);
+ }
+
+ private static void ValidateAttributes(Asn1Set attributes)
+ {
+ if (attributes == null)
+ return;
+
+ foreach (Asn1Encodable ae in attributes)
+ {
+ Asn1Object obj = ae.ToAsn1Object();
+ AttributePkcs attr = AttributePkcs.GetInstance(obj);
+ if (attr.AttrType.Equals(PkcsObjectIdentifiers.Pkcs9AtChallengePassword))
+ {
+ if (attr.AttrValues.Count != 1)
+ throw new ArgumentException("challengePassword attribute must have one value");
+ }
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/ContentInfo.cs b/bc-sharp-crypto/src/asn1/pkcs/ContentInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..526a3c48e1fe3f2e1c979c04f83c25bffa2dddd5
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/ContentInfo.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class ContentInfo
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier contentType;
+ private readonly Asn1Encodable content;
+
+ public static ContentInfo GetInstance(object obj)
+ {
+ if (obj == null)
+ return null;
+ ContentInfo existing = obj as ContentInfo;
+ if (existing != null)
+ return existing;
+ return new ContentInfo(Asn1Sequence.GetInstance(obj));
+ }
+
+ private ContentInfo(
+ Asn1Sequence seq)
+ {
+ contentType = (DerObjectIdentifier) seq[0];
+
+ if (seq.Count > 1)
+ {
+ content = ((Asn1TaggedObject) seq[1]).GetObject();
+ }
+ }
+
+ public ContentInfo(
+ DerObjectIdentifier contentType,
+ Asn1Encodable content)
+ {
+ this.contentType = contentType;
+ this.content = content;
+ }
+
+ public DerObjectIdentifier ContentType
+ {
+ get { return contentType; }
+ }
+
+ public Asn1Encodable Content
+ {
+ get { return content; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * ContentInfo ::= Sequence {
+ * contentType ContentType,
+ * content
+ * [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(contentType);
+
+ if (content != null)
+ {
+ v.Add(new BerTaggedObject(0, content));
+ }
+
+ return new BerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/DHParameter.cs b/bc-sharp-crypto/src/asn1/pkcs/DHParameter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..25a091a9772fb9b63457d91f6bde7805a41d145a
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/DHParameter.cs
@@ -0,0 +1,72 @@
+using Org.BouncyCastle.Asn1;
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class DHParameter
+ : Asn1Encodable
+ {
+ internal DerInteger p, g, l;
+
+ public DHParameter(
+ BigInteger p,
+ BigInteger g,
+ int l)
+ {
+ this.p = new DerInteger(p);
+ this.g = new DerInteger(g);
+
+ if (l != 0)
+ {
+ this.l = new DerInteger(l);
+ }
+ }
+
+ public DHParameter(
+ Asn1Sequence seq)
+ {
+ IEnumerator e = seq.GetEnumerator();
+
+ e.MoveNext();
+ p = (DerInteger)e.Current;
+
+ e.MoveNext();
+ g = (DerInteger)e.Current;
+
+ if (e.MoveNext())
+ {
+ l = (DerInteger) e.Current;
+ }
+ }
+
+ public BigInteger P
+ {
+ get { return p.PositiveValue; }
+ }
+
+ public BigInteger G
+ {
+ get { return g.PositiveValue; }
+ }
+
+ public BigInteger L
+ {
+ get { return l == null ? null : l.PositiveValue; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(p, g);
+
+ if (this.l != null)
+ {
+ v.Add(l);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/EncryptedData.cs b/bc-sharp-crypto/src/asn1/pkcs/EncryptedData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7e95eb586374c3b4654ef02c0b182fc7230181e3
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/EncryptedData.cs
@@ -0,0 +1,105 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ /**
+ * The EncryptedData object.
+ *
+ * EncryptedData ::= Sequence {
+ * version Version,
+ * encryptedContentInfo EncryptedContentInfo
+ * }
+ *
+ *
+ * EncryptedContentInfo ::= Sequence {
+ * contentType ContentType,
+ * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+ * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+ * }
+ *
+ * EncryptedContent ::= OCTET STRING
+ *
+ */
+ public class EncryptedData
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence data;
+// private readonly DerObjectIdentifier bagId;
+// private readonly Asn1Object bagValue;
+
+ public static EncryptedData GetInstance(
+ object obj)
+ {
+ if (obj is EncryptedData)
+ {
+ return (EncryptedData) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new EncryptedData((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private EncryptedData(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ int version = ((DerInteger) seq[0]).Value.IntValue;
+ if (version != 0)
+ {
+ throw new ArgumentException("sequence not version 0");
+ }
+
+ this.data = (Asn1Sequence) seq[1];
+ }
+
+ public EncryptedData(
+ DerObjectIdentifier contentType,
+ AlgorithmIdentifier encryptionAlgorithm,
+ Asn1Encodable content)
+ {
+ data = new BerSequence(
+ contentType,
+ encryptionAlgorithm.ToAsn1Object(),
+ new BerTaggedObject(false, 0, content));
+ }
+
+ public DerObjectIdentifier ContentType
+ {
+ get { return (DerObjectIdentifier) data[0]; }
+ }
+
+ public AlgorithmIdentifier EncryptionAlgorithm
+ {
+ get { return AlgorithmIdentifier.GetInstance(data[1]); }
+ }
+
+ public Asn1OctetString Content
+ {
+ get
+ {
+ if (data.Count == 3)
+ {
+ DerTaggedObject o = (DerTaggedObject) data[2];
+
+ return Asn1OctetString.GetInstance(o, false);
+ }
+
+ return null;
+ }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new BerSequence(new DerInteger(0), data);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/EncryptedPrivateKeyInfo.cs b/bc-sharp-crypto/src/asn1/pkcs/EncryptedPrivateKeyInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..987027009919393f7fa646fd804e67eca9574ce3
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/EncryptedPrivateKeyInfo.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class EncryptedPrivateKeyInfo
+ : Asn1Encodable
+ {
+ private readonly AlgorithmIdentifier algId;
+ private readonly Asn1OctetString data;
+
+ private EncryptedPrivateKeyInfo(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ algId = AlgorithmIdentifier.GetInstance(seq[0]);
+ data = Asn1OctetString.GetInstance(seq[1]);
+ }
+
+ public EncryptedPrivateKeyInfo(
+ AlgorithmIdentifier algId,
+ byte[] encoding)
+ {
+ this.algId = algId;
+ this.data = new DerOctetString(encoding);
+ }
+
+ public static EncryptedPrivateKeyInfo GetInstance(
+ object obj)
+ {
+ if (obj is EncryptedPrivateKeyInfo)
+ {
+ return (EncryptedPrivateKeyInfo) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new EncryptedPrivateKeyInfo((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public AlgorithmIdentifier EncryptionAlgorithm
+ {
+ get { return algId; }
+ }
+
+ public byte[] GetEncryptedData()
+ {
+ return data.GetOctets();
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * EncryptedPrivateKeyInfo ::= Sequence {
+ * encryptionAlgorithm AlgorithmIdentifier {{KeyEncryptionAlgorithms}},
+ * encryptedData EncryptedData
+ * }
+ *
+ * EncryptedData ::= OCTET STRING
+ *
+ * KeyEncryptionAlgorithms ALGORITHM-IDENTIFIER ::= {
+ * ... -- For local profiles
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(algId, data);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/EncryptionScheme.cs b/bc-sharp-crypto/src/asn1/pkcs/EncryptionScheme.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7b90ece531aafeadaba3095daf2cb2faf73af944
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/EncryptionScheme.cs
@@ -0,0 +1,49 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class EncryptionScheme
+ : AlgorithmIdentifier
+ {
+ public EncryptionScheme(
+ DerObjectIdentifier objectID,
+ Asn1Encodable parameters)
+ : base(objectID, parameters)
+ {
+ }
+
+ internal EncryptionScheme(
+ Asn1Sequence seq)
+ : this((DerObjectIdentifier)seq[0], seq[1])
+ {
+ }
+
+ public new static EncryptionScheme GetInstance(object obj)
+ {
+ if (obj is EncryptionScheme)
+ {
+ return (EncryptionScheme)obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new EncryptionScheme((Asn1Sequence)obj);
+ }
+
+ throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public Asn1Object Asn1Object
+ {
+ get { return Parameters.ToAsn1Object(); }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(Algorithm, Parameters);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/IssuerAndSerialNumber.cs b/bc-sharp-crypto/src/asn1/pkcs/IssuerAndSerialNumber.cs
new file mode 100644
index 0000000000000000000000000000000000000000..da863cb6200b769e7ca99dc7d099ad09e9343d99
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/IssuerAndSerialNumber.cs
@@ -0,0 +1,72 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class IssuerAndSerialNumber
+ : Asn1Encodable
+ {
+ private readonly X509Name name;
+ private readonly DerInteger certSerialNumber;
+
+ public static IssuerAndSerialNumber GetInstance(
+ object obj)
+ {
+ if (obj is IssuerAndSerialNumber)
+ {
+ return (IssuerAndSerialNumber) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new IssuerAndSerialNumber((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private IssuerAndSerialNumber(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ this.name = X509Name.GetInstance(seq[0]);
+ this.certSerialNumber = DerInteger.GetInstance(seq[1]);
+ }
+
+ public IssuerAndSerialNumber(
+ X509Name name,
+ BigInteger certSerialNumber)
+ {
+ this.name = name;
+ this.certSerialNumber = new DerInteger(certSerialNumber);
+ }
+
+ public IssuerAndSerialNumber(
+ X509Name name,
+ DerInteger certSerialNumber)
+ {
+ this.name = name;
+ this.certSerialNumber = certSerialNumber;
+ }
+
+ public X509Name Name
+ {
+ get { return name; }
+ }
+
+ public DerInteger CertificateSerialNumber
+ {
+ get { return certSerialNumber; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(name, certSerialNumber);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/KeyDerivationFunc.cs b/bc-sharp-crypto/src/asn1/pkcs/KeyDerivationFunc.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9fc89853bf15cc7435e99a90f89801e09cfed492
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/KeyDerivationFunc.cs
@@ -0,0 +1,21 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class KeyDerivationFunc
+ : AlgorithmIdentifier
+ {
+ internal KeyDerivationFunc(Asn1Sequence seq)
+ : base(seq)
+ {
+ }
+
+ public KeyDerivationFunc(
+ DerObjectIdentifier id,
+ Asn1Encodable parameters)
+ : base(id, parameters)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/asn1/pkcs/MacData.cs b/bc-sharp-crypto/src/asn1/pkcs/MacData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c4b7df17669da8f211c1239453b2f799cb20534d
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/MacData.cs
@@ -0,0 +1,96 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class MacData
+ : Asn1Encodable
+ {
+ internal DigestInfo digInfo;
+ internal byte[] salt;
+ internal BigInteger iterationCount;
+
+ public static MacData GetInstance(
+ object obj)
+ {
+ if (obj is MacData)
+ {
+ return (MacData) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new MacData((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private MacData(
+ Asn1Sequence seq)
+ {
+ this.digInfo = DigestInfo.GetInstance(seq[0]);
+ this.salt = ((Asn1OctetString) seq[1]).GetOctets();
+
+ if (seq.Count == 3)
+ {
+ this.iterationCount = ((DerInteger) seq[2]).Value;
+ }
+ else
+ {
+ this.iterationCount = BigInteger.One;
+ }
+ }
+
+ public MacData(
+ DigestInfo digInfo,
+ byte[] salt,
+ int iterationCount)
+ {
+ this.digInfo = digInfo;
+ this.salt = (byte[]) salt.Clone();
+ this.iterationCount = BigInteger.ValueOf(iterationCount);
+ }
+
+ public DigestInfo Mac
+ {
+ get { return digInfo; }
+ }
+
+ public byte[] GetSalt()
+ {
+ return (byte[]) salt.Clone();
+ }
+
+ public BigInteger IterationCount
+ {
+ get { return iterationCount; }
+ }
+
+ /**
+ *
+ * MacData ::= SEQUENCE {
+ * mac DigestInfo,
+ * macSalt OCTET STRING,
+ * iterations INTEGER DEFAULT 1
+ * -- Note: The default is for historic reasons and its use is deprecated. A
+ * -- higher value, like 1024 is recommended.
+ *
+ * @return the basic DERObject construction.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(digInfo, new DerOctetString(salt));
+
+ if (!iterationCount.Equals(BigInteger.One))
+ {
+ v.Add(new DerInteger(iterationCount));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/PBEParameter.cs b/bc-sharp-crypto/src/asn1/pkcs/PBEParameter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..56cea5fb77f07f7d3d961eff25a4cbfa8d577832
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/PBEParameter.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class PbeParameter
+ : Asn1Encodable
+ {
+ private readonly Asn1OctetString salt;
+ private readonly DerInteger iterationCount;
+
+ public static PbeParameter GetInstance(object obj)
+ {
+ if (obj is PbeParameter || obj == null)
+ {
+ return (PbeParameter) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new PbeParameter((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private PbeParameter(Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ salt = Asn1OctetString.GetInstance(seq[0]);
+ iterationCount = DerInteger.GetInstance(seq[1]);
+ }
+
+ public PbeParameter(byte[] salt, int iterationCount)
+ {
+ this.salt = new DerOctetString(salt);
+ this.iterationCount = new DerInteger(iterationCount);
+ }
+
+ public byte[] GetSalt()
+ {
+ return salt.GetOctets();
+ }
+
+ public BigInteger IterationCount
+ {
+ get { return iterationCount.Value; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(salt, iterationCount);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/PBES2Parameters.cs b/bc-sharp-crypto/src/asn1/pkcs/PBES2Parameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fc6904eed0f64b6ee57b54fbf7fcd51a020318b9
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/PBES2Parameters.cs
@@ -0,0 +1,65 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class PbeS2Parameters
+ : Asn1Encodable
+ {
+ private readonly KeyDerivationFunc func;
+ private readonly EncryptionScheme scheme;
+
+ public static PbeS2Parameters GetInstance(object obj)
+ {
+ if (obj == null)
+ return null;
+ PbeS2Parameters existing = obj as PbeS2Parameters;
+ if (existing != null)
+ return existing;
+ return new PbeS2Parameters(Asn1Sequence.GetInstance(obj));
+ }
+
+ public PbeS2Parameters(KeyDerivationFunc keyDevFunc, EncryptionScheme encScheme)
+ {
+ this.func = keyDevFunc;
+ this.scheme = encScheme;
+ }
+
+ [Obsolete("Use GetInstance() instead")]
+ public PbeS2Parameters(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ Asn1Sequence funcSeq = (Asn1Sequence)seq[0].ToAsn1Object();
+
+ // TODO Not sure if this special case is really necessary/appropriate
+ if (funcSeq[0].Equals(PkcsObjectIdentifiers.IdPbkdf2))
+ {
+ func = new KeyDerivationFunc(PkcsObjectIdentifiers.IdPbkdf2,
+ Pbkdf2Params.GetInstance(funcSeq[1]));
+ }
+ else
+ {
+ func = new KeyDerivationFunc(funcSeq);
+ }
+
+ scheme = EncryptionScheme.GetInstance(seq[1].ToAsn1Object());
+ }
+
+ public KeyDerivationFunc KeyDerivationFunc
+ {
+ get { return func; }
+ }
+
+ public EncryptionScheme EncryptionScheme
+ {
+ get { return scheme; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(func, scheme);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/PBKDF2Params.cs b/bc-sharp-crypto/src/asn1/pkcs/PBKDF2Params.cs
new file mode 100644
index 0000000000000000000000000000000000000000..279f30de889f178cad994f85ef1df43920a62491
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/PBKDF2Params.cs
@@ -0,0 +1,144 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class Pbkdf2Params
+ : Asn1Encodable
+ {
+ private static AlgorithmIdentifier algid_hmacWithSHA1 = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdHmacWithSha1, DerNull.Instance);
+
+ private readonly Asn1OctetString octStr;
+ private readonly DerInteger iterationCount, keyLength;
+ private readonly AlgorithmIdentifier prf;
+
+ public static Pbkdf2Params GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is Pbkdf2Params)
+ return (Pbkdf2Params)obj;
+
+ if (obj is Asn1Sequence)
+ return new Pbkdf2Params((Asn1Sequence)obj);
+
+ throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public Pbkdf2Params(
+ Asn1Sequence seq)
+ {
+ if (seq.Count < 2 || seq.Count > 4)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ this.octStr = (Asn1OctetString)seq[0];
+ this.iterationCount = (DerInteger)seq[1];
+
+ Asn1Encodable kl = null, d = null;
+ if (seq.Count > 3)
+ {
+ kl = seq[2];
+ d = seq[3];
+ }
+ else if (seq.Count > 2)
+ {
+ if (seq[2] is DerInteger)
+ {
+ kl = seq[2];
+ }
+ else
+ {
+ d = seq[2];
+ }
+ }
+ if (kl != null)
+ {
+ keyLength = (DerInteger)kl;
+ }
+ if (d != null)
+ {
+ prf = AlgorithmIdentifier.GetInstance(d);
+ }
+ }
+
+ public Pbkdf2Params(
+ byte[] salt,
+ int iterationCount)
+ {
+ this.octStr = new DerOctetString(salt);
+ this.iterationCount = new DerInteger(iterationCount);
+ }
+
+ public Pbkdf2Params(
+ byte[] salt,
+ int iterationCount,
+ int keyLength)
+ : this(salt, iterationCount)
+ {
+ this.keyLength = new DerInteger(keyLength);
+ }
+
+ public Pbkdf2Params(
+ byte[] salt,
+ int iterationCount,
+ int keyLength,
+ AlgorithmIdentifier prf)
+ : this(salt, iterationCount, keyLength)
+ {
+ this.prf = prf;
+ }
+
+ public Pbkdf2Params(
+ byte[] salt,
+ int iterationCount,
+ AlgorithmIdentifier prf)
+ : this(salt, iterationCount)
+ {
+ this.prf = prf;
+ }
+
+ public byte[] GetSalt()
+ {
+ return octStr.GetOctets();
+ }
+
+ public BigInteger IterationCount
+ {
+ get { return iterationCount.Value; }
+ }
+
+ public BigInteger KeyLength
+ {
+ get { return keyLength == null ? null : keyLength.Value; }
+ }
+
+ public bool IsDefaultPrf
+ {
+ get { return prf == null || prf.Equals(algid_hmacWithSHA1); }
+ }
+
+ public AlgorithmIdentifier Prf
+ {
+ get { return prf != null ? prf : algid_hmacWithSHA1; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ octStr, iterationCount);
+
+ if (keyLength != null)
+ {
+ v.Add(keyLength);
+ }
+ if (!IsDefaultPrf)
+ {
+ v.Add(prf);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/PKCS12PBEParams.cs b/bc-sharp-crypto/src/asn1/pkcs/PKCS12PBEParams.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b41c289d847cf11719d13d31777c2e248f770bbb
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/PKCS12PBEParams.cs
@@ -0,0 +1,63 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class Pkcs12PbeParams
+ : Asn1Encodable
+ {
+ private readonly DerInteger iterations;
+ private readonly Asn1OctetString iv;
+
+ public Pkcs12PbeParams(
+ byte[] salt,
+ int iterations)
+ {
+ this.iv = new DerOctetString(salt);
+ this.iterations = new DerInteger(iterations);
+ }
+
+ private Pkcs12PbeParams(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ iv = Asn1OctetString.GetInstance(seq[0]);
+ iterations = DerInteger.GetInstance(seq[1]);
+ }
+
+ public static Pkcs12PbeParams GetInstance(
+ object obj)
+ {
+ if (obj is Pkcs12PbeParams)
+ {
+ return (Pkcs12PbeParams) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new Pkcs12PbeParams((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public BigInteger Iterations
+ {
+ get { return iterations.Value; }
+ }
+
+ public byte[] GetIV()
+ {
+ return iv.GetOctets();
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(iv, iterations);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1a9a03e9f98b062a84ec26a3ee89cd860d431873
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs
@@ -0,0 +1,293 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public abstract class PkcsObjectIdentifiers
+ {
+ //
+ // pkcs-1 OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
+ //
+ public const string Pkcs1 = "1.2.840.113549.1.1";
+ internal static readonly DerObjectIdentifier Pkcs1Oid = new DerObjectIdentifier(Pkcs1);
+
+ public static readonly DerObjectIdentifier RsaEncryption = Pkcs1Oid.Branch("1");
+ public static readonly DerObjectIdentifier MD2WithRsaEncryption = Pkcs1Oid.Branch("2");
+ public static readonly DerObjectIdentifier MD4WithRsaEncryption = Pkcs1Oid.Branch("3");
+ public static readonly DerObjectIdentifier MD5WithRsaEncryption = Pkcs1Oid.Branch("4");
+ public static readonly DerObjectIdentifier Sha1WithRsaEncryption = Pkcs1Oid.Branch("5");
+ public static readonly DerObjectIdentifier SrsaOaepEncryptionSet = Pkcs1Oid.Branch("6");
+ public static readonly DerObjectIdentifier IdRsaesOaep = Pkcs1Oid.Branch("7");
+ public static readonly DerObjectIdentifier IdMgf1 = Pkcs1Oid.Branch("8");
+ public static readonly DerObjectIdentifier IdPSpecified = Pkcs1Oid.Branch("9");
+ public static readonly DerObjectIdentifier IdRsassaPss = Pkcs1Oid.Branch("10");
+ public static readonly DerObjectIdentifier Sha256WithRsaEncryption = Pkcs1Oid.Branch("11");
+ public static readonly DerObjectIdentifier Sha384WithRsaEncryption = Pkcs1Oid.Branch("12");
+ public static readonly DerObjectIdentifier Sha512WithRsaEncryption = Pkcs1Oid.Branch("13");
+ public static readonly DerObjectIdentifier Sha224WithRsaEncryption = Pkcs1Oid.Branch("14");
+ /** PKCS#1: 1.2.840.113549.1.1.15 */
+ public static readonly DerObjectIdentifier Sha512_224WithRSAEncryption = Pkcs1Oid.Branch("15");
+ /** PKCS#1: 1.2.840.113549.1.1.16 */
+ public static readonly DerObjectIdentifier Sha512_256WithRSAEncryption = Pkcs1Oid.Branch("16");
+
+ //
+ // pkcs-3 OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 3 }
+ //
+ public const string Pkcs3 = "1.2.840.113549.1.3";
+
+ public static readonly DerObjectIdentifier DhKeyAgreement = new DerObjectIdentifier(Pkcs3 + ".1");
+
+ //
+ // pkcs-5 OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 }
+ //
+ public const string Pkcs5 = "1.2.840.113549.1.5";
+
+ public static readonly DerObjectIdentifier PbeWithMD2AndDesCbc = new DerObjectIdentifier(Pkcs5 + ".1");
+ public static readonly DerObjectIdentifier PbeWithMD2AndRC2Cbc = new DerObjectIdentifier(Pkcs5 + ".4");
+ public static readonly DerObjectIdentifier PbeWithMD5AndDesCbc = new DerObjectIdentifier(Pkcs5 + ".3");
+ public static readonly DerObjectIdentifier PbeWithMD5AndRC2Cbc = new DerObjectIdentifier(Pkcs5 + ".6");
+ public static readonly DerObjectIdentifier PbeWithSha1AndDesCbc = new DerObjectIdentifier(Pkcs5 + ".10");
+ public static readonly DerObjectIdentifier PbeWithSha1AndRC2Cbc = new DerObjectIdentifier(Pkcs5 + ".11");
+
+ public static readonly DerObjectIdentifier IdPbeS2 = new DerObjectIdentifier(Pkcs5 + ".13");
+ public static readonly DerObjectIdentifier IdPbkdf2 = new DerObjectIdentifier(Pkcs5 + ".12");
+
+ //
+ // encryptionAlgorithm OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) 3 }
+ //
+ public const string EncryptionAlgorithm = "1.2.840.113549.3";
+
+ public static readonly DerObjectIdentifier DesEde3Cbc = new DerObjectIdentifier(EncryptionAlgorithm + ".7");
+ public static readonly DerObjectIdentifier RC2Cbc = new DerObjectIdentifier(EncryptionAlgorithm + ".2");
+
+ //
+ // object identifiers for digests
+ //
+ public const string DigestAlgorithm = "1.2.840.113549.2";
+
+ //
+ // md2 OBJECT IDENTIFIER ::=
+ // {iso(1) member-body(2) US(840) rsadsi(113549) DigestAlgorithm(2) 2}
+ //
+ public static readonly DerObjectIdentifier MD2 = new DerObjectIdentifier(DigestAlgorithm + ".2");
+
+ //
+ // md4 OBJECT IDENTIFIER ::=
+ // {iso(1) member-body(2) US(840) rsadsi(113549) DigestAlgorithm(2) 4}
+ //
+ public static readonly DerObjectIdentifier MD4 = new DerObjectIdentifier(DigestAlgorithm + ".4");
+
+ //
+ // md5 OBJECT IDENTIFIER ::=
+ // {iso(1) member-body(2) US(840) rsadsi(113549) DigestAlgorithm(2) 5}
+ //
+ public static readonly DerObjectIdentifier MD5 = new DerObjectIdentifier(DigestAlgorithm + ".5");
+
+ public static readonly DerObjectIdentifier IdHmacWithSha1 = new DerObjectIdentifier(DigestAlgorithm + ".7");
+ public static readonly DerObjectIdentifier IdHmacWithSha224 = new DerObjectIdentifier(DigestAlgorithm + ".8");
+ public static readonly DerObjectIdentifier IdHmacWithSha256 = new DerObjectIdentifier(DigestAlgorithm + ".9");
+ public static readonly DerObjectIdentifier IdHmacWithSha384 = new DerObjectIdentifier(DigestAlgorithm + ".10");
+ public static readonly DerObjectIdentifier IdHmacWithSha512 = new DerObjectIdentifier(DigestAlgorithm + ".11");
+
+ //
+ // pkcs-7 OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 7 }
+ //
+ public const string Pkcs7 = "1.2.840.113549.1.7";
+
+ public static readonly DerObjectIdentifier Data = new DerObjectIdentifier(Pkcs7 + ".1");
+ public static readonly DerObjectIdentifier SignedData = new DerObjectIdentifier(Pkcs7 + ".2");
+ public static readonly DerObjectIdentifier EnvelopedData = new DerObjectIdentifier(Pkcs7 + ".3");
+ public static readonly DerObjectIdentifier SignedAndEnvelopedData = new DerObjectIdentifier(Pkcs7 + ".4");
+ public static readonly DerObjectIdentifier DigestedData = new DerObjectIdentifier(Pkcs7 + ".5");
+ public static readonly DerObjectIdentifier EncryptedData = new DerObjectIdentifier(Pkcs7 + ".6");
+
+ //
+ // pkcs-9 OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 }
+ //
+ public const string Pkcs9 = "1.2.840.113549.1.9";
+
+ public static readonly DerObjectIdentifier Pkcs9AtEmailAddress = new DerObjectIdentifier(Pkcs9 + ".1");
+ public static readonly DerObjectIdentifier Pkcs9AtUnstructuredName = new DerObjectIdentifier(Pkcs9 + ".2");
+ public static readonly DerObjectIdentifier Pkcs9AtContentType = new DerObjectIdentifier(Pkcs9 + ".3");
+ public static readonly DerObjectIdentifier Pkcs9AtMessageDigest = new DerObjectIdentifier(Pkcs9 + ".4");
+ public static readonly DerObjectIdentifier Pkcs9AtSigningTime = new DerObjectIdentifier(Pkcs9 + ".5");
+ public static readonly DerObjectIdentifier Pkcs9AtCounterSignature = new DerObjectIdentifier(Pkcs9 + ".6");
+ public static readonly DerObjectIdentifier Pkcs9AtChallengePassword = new DerObjectIdentifier(Pkcs9 + ".7");
+ public static readonly DerObjectIdentifier Pkcs9AtUnstructuredAddress = new DerObjectIdentifier(Pkcs9 + ".8");
+ public static readonly DerObjectIdentifier Pkcs9AtExtendedCertificateAttributes = new DerObjectIdentifier(Pkcs9 + ".9");
+ public static readonly DerObjectIdentifier Pkcs9AtSigningDescription = new DerObjectIdentifier(Pkcs9 + ".13");
+ public static readonly DerObjectIdentifier Pkcs9AtExtensionRequest = new DerObjectIdentifier(Pkcs9 + ".14");
+ public static readonly DerObjectIdentifier Pkcs9AtSmimeCapabilities = new DerObjectIdentifier(Pkcs9 + ".15");
+ public static readonly DerObjectIdentifier IdSmime = new DerObjectIdentifier(Pkcs9 + ".16");
+
+ public static readonly DerObjectIdentifier Pkcs9AtFriendlyName = new DerObjectIdentifier(Pkcs9 + ".20");
+ public static readonly DerObjectIdentifier Pkcs9AtLocalKeyID = new DerObjectIdentifier(Pkcs9 + ".21");
+
+ [Obsolete("Use X509Certificate instead")]
+ public static readonly DerObjectIdentifier X509CertType = new DerObjectIdentifier(Pkcs9 + ".22.1");
+
+ public const string CertTypes = Pkcs9 + ".22";
+ public static readonly DerObjectIdentifier X509Certificate = new DerObjectIdentifier(CertTypes + ".1");
+ public static readonly DerObjectIdentifier SdsiCertificate = new DerObjectIdentifier(CertTypes + ".2");
+
+ public const string CrlTypes = Pkcs9 + ".23";
+ public static readonly DerObjectIdentifier X509Crl = new DerObjectIdentifier(CrlTypes + ".1");
+
+ public static readonly DerObjectIdentifier IdAlg = IdSmime.Branch("3");
+
+ public static readonly DerObjectIdentifier IdAlgEsdh = IdAlg.Branch("5");
+ public static readonly DerObjectIdentifier IdAlgCms3DesWrap = IdAlg.Branch("6");
+ public static readonly DerObjectIdentifier IdAlgCmsRC2Wrap = IdAlg.Branch("7");
+ public static readonly DerObjectIdentifier IdAlgPwriKek = IdAlg.Branch("9");
+ public static readonly DerObjectIdentifier IdAlgSsdh = IdAlg.Branch("10");
+
+ /*
+ *
+ * -- RSA-KEM Key Transport Algorithm
+ *
+ * id-rsa-kem OID ::= {
+ * iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
+ * pkcs-9(9) smime(16) alg(3) 14
+ * }
+ *
+ */
+ public static readonly DerObjectIdentifier IdRsaKem = IdAlg.Branch("14");
+
+ //
+ // SMIME capability sub oids.
+ //
+ public static readonly DerObjectIdentifier PreferSignedData = Pkcs9AtSmimeCapabilities.Branch("1");
+ public static readonly DerObjectIdentifier CannotDecryptAny = Pkcs9AtSmimeCapabilities.Branch("2");
+ public static readonly DerObjectIdentifier SmimeCapabilitiesVersions = Pkcs9AtSmimeCapabilities.Branch("3");
+
+ //
+ // other SMIME attributes
+ //
+ public static readonly DerObjectIdentifier IdAAReceiptRequest = IdSmime.Branch("2.1");
+
+ //
+ // id-ct OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+ // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) ct(1)}
+ //
+ public const string IdCT = "1.2.840.113549.1.9.16.1";
+
+ public static readonly DerObjectIdentifier IdCTAuthData = new DerObjectIdentifier(IdCT + ".2");
+ public static readonly DerObjectIdentifier IdCTTstInfo = new DerObjectIdentifier(IdCT + ".4");
+ public static readonly DerObjectIdentifier IdCTCompressedData = new DerObjectIdentifier(IdCT + ".9");
+ public static readonly DerObjectIdentifier IdCTAuthEnvelopedData = new DerObjectIdentifier(IdCT + ".23");
+ public static readonly DerObjectIdentifier IdCTTimestampedData = new DerObjectIdentifier(IdCT + ".31");
+
+ //
+ // id-cti OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+ // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) cti(6)}
+ //
+ public const string IdCti = "1.2.840.113549.1.9.16.6";
+
+ public static readonly DerObjectIdentifier IdCtiEtsProofOfOrigin = new DerObjectIdentifier(IdCti + ".1");
+ public static readonly DerObjectIdentifier IdCtiEtsProofOfReceipt = new DerObjectIdentifier(IdCti + ".2");
+ public static readonly DerObjectIdentifier IdCtiEtsProofOfDelivery = new DerObjectIdentifier(IdCti + ".3");
+ public static readonly DerObjectIdentifier IdCtiEtsProofOfSender = new DerObjectIdentifier(IdCti + ".4");
+ public static readonly DerObjectIdentifier IdCtiEtsProofOfApproval = new DerObjectIdentifier(IdCti + ".5");
+ public static readonly DerObjectIdentifier IdCtiEtsProofOfCreation = new DerObjectIdentifier(IdCti + ".6");
+
+ //
+ // id-aa OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+ // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) attributes(2)}
+ //
+ public const string IdAA = "1.2.840.113549.1.9.16.2";
+ public static readonly DerObjectIdentifier IdAAOid = new DerObjectIdentifier(IdAA);
+
+ public static readonly DerObjectIdentifier IdAAContentHint = new DerObjectIdentifier(IdAA + ".4"); // See RFC 2634
+ public static readonly DerObjectIdentifier IdAAMsgSigDigest = new DerObjectIdentifier(IdAA + ".5");
+ public static readonly DerObjectIdentifier IdAAContentReference = new DerObjectIdentifier(IdAA + ".10");
+
+ /*
+ * id-aa-encrypKeyPref OBJECT IDENTIFIER ::= {id-aa 11}
+ *
+ */
+ public static readonly DerObjectIdentifier IdAAEncrypKeyPref = new DerObjectIdentifier(IdAA + ".11");
+ public static readonly DerObjectIdentifier IdAASigningCertificate = new DerObjectIdentifier(IdAA + ".12");
+ public static readonly DerObjectIdentifier IdAASigningCertificateV2 = new DerObjectIdentifier(IdAA + ".47");
+
+ public static readonly DerObjectIdentifier IdAAContentIdentifier = new DerObjectIdentifier(IdAA + ".7"); // See RFC 2634
+
+ /*
+ * RFC 3126
+ */
+ public static readonly DerObjectIdentifier IdAASignatureTimeStampToken = new DerObjectIdentifier(IdAA + ".14");
+
+ public static readonly DerObjectIdentifier IdAAEtsSigPolicyID = new DerObjectIdentifier(IdAA + ".15");
+ public static readonly DerObjectIdentifier IdAAEtsCommitmentType = new DerObjectIdentifier(IdAA + ".16");
+ public static readonly DerObjectIdentifier IdAAEtsSignerLocation = new DerObjectIdentifier(IdAA + ".17");
+ public static readonly DerObjectIdentifier IdAAEtsSignerAttr = new DerObjectIdentifier(IdAA + ".18");
+ public static readonly DerObjectIdentifier IdAAEtsOtherSigCert = new DerObjectIdentifier(IdAA + ".19");
+ public static readonly DerObjectIdentifier IdAAEtsContentTimestamp = new DerObjectIdentifier(IdAA + ".20");
+ public static readonly DerObjectIdentifier IdAAEtsCertificateRefs = new DerObjectIdentifier(IdAA + ".21");
+ public static readonly DerObjectIdentifier IdAAEtsRevocationRefs = new DerObjectIdentifier(IdAA + ".22");
+ public static readonly DerObjectIdentifier IdAAEtsCertValues = new DerObjectIdentifier(IdAA + ".23");
+ public static readonly DerObjectIdentifier IdAAEtsRevocationValues = new DerObjectIdentifier(IdAA + ".24");
+ public static readonly DerObjectIdentifier IdAAEtsEscTimeStamp = new DerObjectIdentifier(IdAA + ".25");
+ public static readonly DerObjectIdentifier IdAAEtsCertCrlTimestamp = new DerObjectIdentifier(IdAA + ".26");
+ public static readonly DerObjectIdentifier IdAAEtsArchiveTimestamp = new DerObjectIdentifier(IdAA + ".27");
+
+ /** PKCS#9: 1.2.840.113549.1.9.16.6.2.37 - RFC 4108 */
+ public static readonly DerObjectIdentifier IdAADecryptKeyID = IdAAOid.Branch("37");
+
+ /** PKCS#9: 1.2.840.113549.1.9.16.6.2.38 - RFC 4108 */
+ public static readonly DerObjectIdentifier IdAAImplCryptoAlgs = IdAAOid.Branch("38");
+
+ /** PKCS#9: 1.2.840.113549.1.9.16.2.54 RFC7030 */
+ public static readonly DerObjectIdentifier IdAAAsymmDecryptKeyID = IdAAOid.Branch("54");
+
+ /** PKCS#9: 1.2.840.113549.1.9.16.2.43 RFC7030 */
+ public static readonly DerObjectIdentifier IdAAImplCompressAlgs = IdAAOid.Branch("43");
+ /** PKCS#9: 1.2.840.113549.1.9.16.2.40 RFC7030 */
+ public static readonly DerObjectIdentifier IdAACommunityIdentifiers = IdAAOid.Branch("40");
+
+ [Obsolete("Use 'IdAAEtsSigPolicyID' instead")]
+ public static readonly DerObjectIdentifier IdAASigPolicyID = IdAAEtsSigPolicyID;
+ [Obsolete("Use 'IdAAEtsCommitmentType' instead")]
+ public static readonly DerObjectIdentifier IdAACommitmentType = IdAAEtsCommitmentType;
+ [Obsolete("Use 'IdAAEtsSignerLocation' instead")]
+ public static readonly DerObjectIdentifier IdAASignerLocation = IdAAEtsSignerLocation;
+ [Obsolete("Use 'IdAAEtsOtherSigCert' instead")]
+ public static readonly DerObjectIdentifier IdAAOtherSigCert = IdAAEtsOtherSigCert;
+
+ //
+ // id-spq OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+ // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-spq(5)}
+ //
+ public const string IdSpq = "1.2.840.113549.1.9.16.5";
+
+ public static readonly DerObjectIdentifier IdSpqEtsUri = new DerObjectIdentifier(IdSpq + ".1");
+ public static readonly DerObjectIdentifier IdSpqEtsUNotice = new DerObjectIdentifier(IdSpq + ".2");
+
+ //
+ // pkcs-12 OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 }
+ //
+ public const string Pkcs12 = "1.2.840.113549.1.12";
+ public const string BagTypes = Pkcs12 + ".10.1";
+
+ public static readonly DerObjectIdentifier KeyBag = new DerObjectIdentifier(BagTypes + ".1");
+ public static readonly DerObjectIdentifier Pkcs8ShroudedKeyBag = new DerObjectIdentifier(BagTypes + ".2");
+ public static readonly DerObjectIdentifier CertBag = new DerObjectIdentifier(BagTypes + ".3");
+ public static readonly DerObjectIdentifier CrlBag = new DerObjectIdentifier(BagTypes + ".4");
+ public static readonly DerObjectIdentifier SecretBag = new DerObjectIdentifier(BagTypes + ".5");
+ public static readonly DerObjectIdentifier SafeContentsBag = new DerObjectIdentifier(BagTypes + ".6");
+
+ public const string Pkcs12PbeIds = Pkcs12 + ".1";
+
+ public static readonly DerObjectIdentifier PbeWithShaAnd128BitRC4 = new DerObjectIdentifier(Pkcs12PbeIds + ".1");
+ public static readonly DerObjectIdentifier PbeWithShaAnd40BitRC4 = new DerObjectIdentifier(Pkcs12PbeIds + ".2");
+ public static readonly DerObjectIdentifier PbeWithShaAnd3KeyTripleDesCbc = new DerObjectIdentifier(Pkcs12PbeIds + ".3");
+ public static readonly DerObjectIdentifier PbeWithShaAnd2KeyTripleDesCbc = new DerObjectIdentifier(Pkcs12PbeIds + ".4");
+ public static readonly DerObjectIdentifier PbeWithShaAnd128BitRC2Cbc = new DerObjectIdentifier(Pkcs12PbeIds + ".5");
+ public static readonly DerObjectIdentifier PbewithShaAnd40BitRC2Cbc = new DerObjectIdentifier(Pkcs12PbeIds + ".6");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/Pfx.cs b/bc-sharp-crypto/src/asn1/pkcs/Pfx.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9676f64fc889a290e4a0bda7ba141239292fbe6f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/Pfx.cs
@@ -0,0 +1,65 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ /**
+ * the infamous Pfx from Pkcs12
+ */
+ public class Pfx
+ : Asn1Encodable
+ {
+ private ContentInfo contentInfo;
+ private MacData macData;
+
+ public Pfx(
+ Asn1Sequence seq)
+ {
+ BigInteger version = ((DerInteger) seq[0]).Value;
+ if (version.IntValue != 3)
+ {
+ throw new ArgumentException("wrong version for PFX PDU");
+ }
+
+ contentInfo = ContentInfo.GetInstance(seq[1]);
+
+ if (seq.Count == 3)
+ {
+ macData = MacData.GetInstance(seq[2]);
+ }
+ }
+
+ public Pfx(
+ ContentInfo contentInfo,
+ MacData macData)
+ {
+ this.contentInfo = contentInfo;
+ this.macData = macData;
+ }
+
+ public ContentInfo AuthSafe
+ {
+ get { return contentInfo; }
+ }
+
+ public MacData MacData
+ {
+ get { return macData; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ new DerInteger(3), contentInfo);
+
+ if (macData != null)
+ {
+ v.Add(macData);
+ }
+
+ return new BerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/PrivateKeyInfo.cs b/bc-sharp-crypto/src/asn1/pkcs/PrivateKeyInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c5be7a315389bafb9bdfc01231d81b6b27066dbe
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/PrivateKeyInfo.cs
@@ -0,0 +1,135 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class PrivateKeyInfo
+ : Asn1Encodable
+ {
+ private readonly Asn1OctetString privKey;
+ private readonly AlgorithmIdentifier algID;
+ private readonly Asn1Set attributes;
+
+ public static PrivateKeyInfo GetInstance(Asn1TaggedObject obj, bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static PrivateKeyInfo GetInstance(
+ object obj)
+ {
+ if (obj == null)
+ return null;
+ if (obj is PrivateKeyInfo)
+ return (PrivateKeyInfo) obj;
+ return new PrivateKeyInfo(Asn1Sequence.GetInstance(obj));
+ }
+
+ public PrivateKeyInfo(AlgorithmIdentifier algID, Asn1Encodable privateKey)
+ : this(algID, privateKey, null)
+ {
+ }
+
+ public PrivateKeyInfo(
+ AlgorithmIdentifier algID,
+ Asn1Encodable privateKey,
+ Asn1Set attributes)
+ {
+ this.algID = algID;
+ this.privKey = new DerOctetString(privateKey.GetEncoded(Asn1Encodable.Der));
+ this.attributes = attributes;
+ }
+
+ private PrivateKeyInfo(Asn1Sequence seq)
+ {
+ IEnumerator e = seq.GetEnumerator();
+
+ e.MoveNext();
+ BigInteger version = ((DerInteger)e.Current).Value;
+ if (version.IntValue != 0)
+ {
+ throw new ArgumentException("wrong version for private key info: " + version.IntValue);
+ }
+
+ e.MoveNext();
+ algID = AlgorithmIdentifier.GetInstance(e.Current);
+ e.MoveNext();
+ privKey = Asn1OctetString.GetInstance(e.Current);
+
+ if (e.MoveNext())
+ {
+ attributes = Asn1Set.GetInstance((Asn1TaggedObject)e.Current, false);
+ }
+ }
+
+ public virtual AlgorithmIdentifier PrivateKeyAlgorithm
+ {
+ get { return algID; }
+ }
+
+ [Obsolete("Use 'PrivateKeyAlgorithm' property instead")]
+ public virtual AlgorithmIdentifier AlgorithmID
+ {
+ get { return algID; }
+ }
+
+ public virtual Asn1Object ParsePrivateKey()
+ {
+ return Asn1Object.FromByteArray(privKey.GetOctets());
+ }
+
+ [Obsolete("Use 'ParsePrivateKey' instead")]
+ public virtual Asn1Object PrivateKey
+ {
+ get
+ {
+ try
+ {
+ return ParsePrivateKey();
+ }
+ catch (IOException)
+ {
+ throw new InvalidOperationException("unable to parse private key");
+ }
+ }
+ }
+
+ public virtual Asn1Set Attributes
+ {
+ get { return attributes; }
+ }
+
+ /**
+ * write out an RSA private key with its associated information
+ * as described in Pkcs8.
+ *
+ * PrivateKeyInfo ::= Sequence {
+ * version Version,
+ * privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
+ * privateKey PrivateKey,
+ * attributes [0] IMPLICIT Attributes OPTIONAL
+ * }
+ * Version ::= Integer {v1(0)} (v1,...)
+ *
+ * PrivateKey ::= OCTET STRING
+ *
+ * Attributes ::= Set OF Attr
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(new DerInteger(0), algID, privKey);
+
+ if (attributes != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, attributes));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/RC2CBCParameter.cs b/bc-sharp-crypto/src/asn1/pkcs/RC2CBCParameter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..880ca7443b67da3291e8b1cd739754c3dc3e3528
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/RC2CBCParameter.cs
@@ -0,0 +1,80 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class RC2CbcParameter
+ : Asn1Encodable
+ {
+ internal DerInteger version;
+ internal Asn1OctetString iv;
+
+ public static RC2CbcParameter GetInstance(
+ object obj)
+ {
+ if (obj is Asn1Sequence)
+ {
+ return new RC2CbcParameter((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public RC2CbcParameter(
+ byte[] iv)
+ {
+ this.iv = new DerOctetString(iv);
+ }
+
+ public RC2CbcParameter(
+ int parameterVersion,
+ byte[] iv)
+ {
+ this.version = new DerInteger(parameterVersion);
+ this.iv = new DerOctetString(iv);
+ }
+
+ private RC2CbcParameter(
+ Asn1Sequence seq)
+ {
+ if (seq.Count == 1)
+ {
+ iv = (Asn1OctetString)seq[0];
+ }
+ else
+ {
+ version = (DerInteger)seq[0];
+ iv = (Asn1OctetString)seq[1];
+ }
+ }
+
+ public BigInteger RC2ParameterVersion
+ {
+ get
+ {
+ return version == null ? null : version.Value;
+ }
+ }
+
+ public byte[] GetIV()
+ {
+ return Arrays.Clone(iv.GetOctets());
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (version != null)
+ {
+ v.Add(version);
+ }
+
+ v.Add(iv);
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/RSAESOAEPparams.cs b/bc-sharp-crypto/src/asn1/pkcs/RSAESOAEPparams.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0cf22f8601aee0cf5cd67750871db222677dd911
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/RSAESOAEPparams.cs
@@ -0,0 +1,146 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class RsaesOaepParameters
+ : Asn1Encodable
+ {
+ private AlgorithmIdentifier hashAlgorithm;
+ private AlgorithmIdentifier maskGenAlgorithm;
+ private AlgorithmIdentifier pSourceAlgorithm;
+
+ public readonly static AlgorithmIdentifier DefaultHashAlgorithm = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+ public readonly static AlgorithmIdentifier DefaultMaskGenFunction = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, DefaultHashAlgorithm);
+ public readonly static AlgorithmIdentifier DefaultPSourceAlgorithm = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdPSpecified, new DerOctetString(new byte[0]));
+
+ public static RsaesOaepParameters GetInstance(
+ object obj)
+ {
+ if (obj is RsaesOaepParameters)
+ {
+ return (RsaesOaepParameters)obj;
+ }
+ else if (obj is Asn1Sequence)
+ {
+ return new RsaesOaepParameters((Asn1Sequence)obj);
+ }
+
+ throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * The default version
+ */
+ public RsaesOaepParameters()
+ {
+ hashAlgorithm = DefaultHashAlgorithm;
+ maskGenAlgorithm = DefaultMaskGenFunction;
+ pSourceAlgorithm = DefaultPSourceAlgorithm;
+ }
+
+ public RsaesOaepParameters(
+ AlgorithmIdentifier hashAlgorithm,
+ AlgorithmIdentifier maskGenAlgorithm,
+ AlgorithmIdentifier pSourceAlgorithm)
+ {
+ this.hashAlgorithm = hashAlgorithm;
+ this.maskGenAlgorithm = maskGenAlgorithm;
+ this.pSourceAlgorithm = pSourceAlgorithm;
+ }
+
+ public RsaesOaepParameters(
+ Asn1Sequence seq)
+ {
+ hashAlgorithm = DefaultHashAlgorithm;
+ maskGenAlgorithm = DefaultMaskGenFunction;
+ pSourceAlgorithm = DefaultPSourceAlgorithm;
+
+ for (int i = 0; i != seq.Count; i++)
+ {
+ Asn1TaggedObject o = (Asn1TaggedObject)seq[i];
+
+ switch (o.TagNo)
+ {
+ case 0:
+ hashAlgorithm = AlgorithmIdentifier.GetInstance(o, true);
+ break;
+ case 1:
+ maskGenAlgorithm = AlgorithmIdentifier.GetInstance(o, true);
+ break;
+ case 2:
+ pSourceAlgorithm = AlgorithmIdentifier.GetInstance(o, true);
+ break;
+ default:
+ throw new ArgumentException("unknown tag");
+ }
+ }
+ }
+
+ public AlgorithmIdentifier HashAlgorithm
+ {
+ get { return hashAlgorithm; }
+ }
+
+ public AlgorithmIdentifier MaskGenAlgorithm
+ {
+ get { return maskGenAlgorithm; }
+ }
+
+ public AlgorithmIdentifier PSourceAlgorithm
+ {
+ get { return pSourceAlgorithm; }
+ }
+
+ /**
+ *
+ * RSAES-OAEP-params ::= SEQUENCE {
+ * hashAlgorithm [0] OAEP-PSSDigestAlgorithms DEFAULT sha1,
+ * maskGenAlgorithm [1] PKCS1MGFAlgorithms DEFAULT mgf1SHA1,
+ * pSourceAlgorithm [2] PKCS1PSourceAlgorithms DEFAULT pSpecifiedEmpty
+ * }
+ *
+ * OAEP-PSSDigestAlgorithms ALGORITHM-IDENTIFIER ::= {
+ * { OID id-sha1 PARAMETERS NULL }|
+ * { OID id-sha256 PARAMETERS NULL }|
+ * { OID id-sha384 PARAMETERS NULL }|
+ * { OID id-sha512 PARAMETERS NULL },
+ * ... -- Allows for future expansion --
+ * }
+ * PKCS1MGFAlgorithms ALGORITHM-IDENTIFIER ::= {
+ * { OID id-mgf1 PARAMETERS OAEP-PSSDigestAlgorithms },
+ * ... -- Allows for future expansion --
+ * }
+ * PKCS1PSourceAlgorithms ALGORITHM-IDENTIFIER ::= {
+ * { OID id-pSpecified PARAMETERS OCTET STRING },
+ * ... -- Allows for future expansion --
+ * }
+ *
+ * @return the asn1 primitive representing the parameters.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (!hashAlgorithm.Equals(DefaultHashAlgorithm))
+ {
+ v.Add(new DerTaggedObject(true, 0, hashAlgorithm));
+ }
+
+ if (!maskGenAlgorithm.Equals(DefaultMaskGenFunction))
+ {
+ v.Add(new DerTaggedObject(true, 1, maskGenAlgorithm));
+ }
+
+ if (!pSourceAlgorithm.Equals(DefaultPSourceAlgorithm))
+ {
+ v.Add(new DerTaggedObject(true, 2, pSourceAlgorithm));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs b/bc-sharp-crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7212991056bfb60c846b5b9b1f329edca745991f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs
@@ -0,0 +1,146 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class RsaPrivateKeyStructure
+ : Asn1Encodable
+ {
+ private readonly BigInteger modulus;
+ private readonly BigInteger publicExponent;
+ private readonly BigInteger privateExponent;
+ private readonly BigInteger prime1;
+ private readonly BigInteger prime2;
+ private readonly BigInteger exponent1;
+ private readonly BigInteger exponent2;
+ private readonly BigInteger coefficient;
+
+ public static RsaPrivateKeyStructure GetInstance(Asn1TaggedObject obj, bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ public static RsaPrivateKeyStructure GetInstance(object obj)
+ {
+ if (obj == null)
+ return null;
+ if (obj is RsaPrivateKeyStructure)
+ return (RsaPrivateKeyStructure)obj;
+ return new RsaPrivateKeyStructure(Asn1Sequence.GetInstance(obj));
+ }
+
+ public RsaPrivateKeyStructure(
+ BigInteger modulus,
+ BigInteger publicExponent,
+ BigInteger privateExponent,
+ BigInteger prime1,
+ BigInteger prime2,
+ BigInteger exponent1,
+ BigInteger exponent2,
+ BigInteger coefficient)
+ {
+ this.modulus = modulus;
+ this.publicExponent = publicExponent;
+ this.privateExponent = privateExponent;
+ this.prime1 = prime1;
+ this.prime2 = prime2;
+ this.exponent1 = exponent1;
+ this.exponent2 = exponent2;
+ this.coefficient = coefficient;
+ }
+
+ [Obsolete("Use 'GetInstance' method(s) instead")]
+ public RsaPrivateKeyStructure(
+ Asn1Sequence seq)
+ {
+ BigInteger version = ((DerInteger) seq[0]).Value;
+ if (version.IntValue != 0)
+ throw new ArgumentException("wrong version for RSA private key");
+
+ modulus = ((DerInteger) seq[1]).Value;
+ publicExponent = ((DerInteger) seq[2]).Value;
+ privateExponent = ((DerInteger) seq[3]).Value;
+ prime1 = ((DerInteger) seq[4]).Value;
+ prime2 = ((DerInteger) seq[5]).Value;
+ exponent1 = ((DerInteger) seq[6]).Value;
+ exponent2 = ((DerInteger) seq[7]).Value;
+ coefficient = ((DerInteger) seq[8]).Value;
+ }
+
+ public BigInteger Modulus
+ {
+ get { return modulus; }
+ }
+
+ public BigInteger PublicExponent
+ {
+ get { return publicExponent; }
+ }
+
+ public BigInteger PrivateExponent
+ {
+ get { return privateExponent; }
+ }
+
+ public BigInteger Prime1
+ {
+ get { return prime1; }
+ }
+
+ public BigInteger Prime2
+ {
+ get { return prime2; }
+ }
+
+ public BigInteger Exponent1
+ {
+ get { return exponent1; }
+ }
+
+ public BigInteger Exponent2
+ {
+ get { return exponent2; }
+ }
+
+ public BigInteger Coefficient
+ {
+ get { return coefficient; }
+ }
+
+ /**
+ * This outputs the key in Pkcs1v2 format.
+ *
+ * RsaPrivateKey ::= Sequence {
+ * version Version,
+ * modulus Integer, -- n
+ * publicExponent Integer, -- e
+ * privateExponent Integer, -- d
+ * prime1 Integer, -- p
+ * prime2 Integer, -- q
+ * exponent1 Integer, -- d mod (p-1)
+ * exponent2 Integer, -- d mod (q-1)
+ * coefficient Integer -- (inverse of q) mod p
+ * }
+ *
+ * Version ::= Integer
+ *
+ * This routine is written to output Pkcs1 version 0, private keys.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(
+ new DerInteger(0), // version
+ new DerInteger(Modulus),
+ new DerInteger(PublicExponent),
+ new DerInteger(PrivateExponent),
+ new DerInteger(Prime1),
+ new DerInteger(Prime2),
+ new DerInteger(Exponent1),
+ new DerInteger(Exponent2),
+ new DerInteger(Coefficient));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/RSASSAPSSparams.cs b/bc-sharp-crypto/src/asn1/pkcs/RSASSAPSSparams.cs
new file mode 100644
index 0000000000000000000000000000000000000000..85849c3624efd088d194870786711ef25cebf4d1
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/RSASSAPSSparams.cs
@@ -0,0 +1,166 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class RsassaPssParameters
+ : Asn1Encodable
+ {
+ private AlgorithmIdentifier hashAlgorithm;
+ private AlgorithmIdentifier maskGenAlgorithm;
+ private DerInteger saltLength;
+ private DerInteger trailerField;
+
+ public readonly static AlgorithmIdentifier DefaultHashAlgorithm = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+ public readonly static AlgorithmIdentifier DefaultMaskGenFunction = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, DefaultHashAlgorithm);
+ public readonly static DerInteger DefaultSaltLength = new DerInteger(20);
+ public readonly static DerInteger DefaultTrailerField = new DerInteger(1);
+
+ public static RsassaPssParameters GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is RsassaPssParameters)
+ {
+ return (RsassaPssParameters)obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new RsassaPssParameters((Asn1Sequence)obj);
+ }
+
+ throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * The default version
+ */
+ public RsassaPssParameters()
+ {
+ hashAlgorithm = DefaultHashAlgorithm;
+ maskGenAlgorithm = DefaultMaskGenFunction;
+ saltLength = DefaultSaltLength;
+ trailerField = DefaultTrailerField;
+ }
+
+ public RsassaPssParameters(
+ AlgorithmIdentifier hashAlgorithm,
+ AlgorithmIdentifier maskGenAlgorithm,
+ DerInteger saltLength,
+ DerInteger trailerField)
+ {
+ this.hashAlgorithm = hashAlgorithm;
+ this.maskGenAlgorithm = maskGenAlgorithm;
+ this.saltLength = saltLength;
+ this.trailerField = trailerField;
+ }
+
+ public RsassaPssParameters(
+ Asn1Sequence seq)
+ {
+ hashAlgorithm = DefaultHashAlgorithm;
+ maskGenAlgorithm = DefaultMaskGenFunction;
+ saltLength = DefaultSaltLength;
+ trailerField = DefaultTrailerField;
+
+ for (int i = 0; i != seq.Count; i++)
+ {
+ Asn1TaggedObject o = (Asn1TaggedObject)seq[i];
+
+ switch (o.TagNo)
+ {
+ case 0:
+ hashAlgorithm = AlgorithmIdentifier.GetInstance(o, true);
+ break;
+ case 1:
+ maskGenAlgorithm = AlgorithmIdentifier.GetInstance(o, true);
+ break;
+ case 2:
+ saltLength = DerInteger.GetInstance(o, true);
+ break;
+ case 3:
+ trailerField = DerInteger.GetInstance(o, true);
+ break;
+ default:
+ throw new ArgumentException("unknown tag");
+ }
+ }
+ }
+
+ public AlgorithmIdentifier HashAlgorithm
+ {
+ get { return hashAlgorithm; }
+ }
+
+ public AlgorithmIdentifier MaskGenAlgorithm
+ {
+ get { return maskGenAlgorithm; }
+ }
+
+ public DerInteger SaltLength
+ {
+ get { return saltLength; }
+ }
+
+ public DerInteger TrailerField
+ {
+ get { return trailerField; }
+ }
+
+ /**
+ *
+ * RSASSA-PSS-params ::= SEQUENCE {
+ * hashAlgorithm [0] OAEP-PSSDigestAlgorithms DEFAULT sha1,
+ * maskGenAlgorithm [1] PKCS1MGFAlgorithms DEFAULT mgf1SHA1,
+ * saltLength [2] INTEGER DEFAULT 20,
+ * trailerField [3] TrailerField DEFAULT trailerFieldBC
+ * }
+ *
+ * OAEP-PSSDigestAlgorithms ALGORITHM-IDENTIFIER ::= {
+ * { OID id-sha1 PARAMETERS NULL }|
+ * { OID id-sha256 PARAMETERS NULL }|
+ * { OID id-sha384 PARAMETERS NULL }|
+ * { OID id-sha512 PARAMETERS NULL },
+ * ... -- Allows for future expansion --
+ * }
+ *
+ * PKCS1MGFAlgorithms ALGORITHM-IDENTIFIER ::= {
+ * { OID id-mgf1 PARAMETERS OAEP-PSSDigestAlgorithms },
+ * ... -- Allows for future expansion --
+ * }
+ *
+ * TrailerField ::= INTEGER { trailerFieldBC(1) }
+ *
+ * @return the asn1 primitive representing the parameters.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (!hashAlgorithm.Equals(DefaultHashAlgorithm))
+ {
+ v.Add(new DerTaggedObject(true, 0, hashAlgorithm));
+ }
+
+ if (!maskGenAlgorithm.Equals(DefaultMaskGenFunction))
+ {
+ v.Add(new DerTaggedObject(true, 1, maskGenAlgorithm));
+ }
+
+ if (!saltLength.Equals(DefaultSaltLength))
+ {
+ v.Add(new DerTaggedObject(true, 2, saltLength));
+ }
+
+ if (!trailerField.Equals(DefaultTrailerField))
+ {
+ v.Add(new DerTaggedObject(true, 3, trailerField));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/SafeBag.cs b/bc-sharp-crypto/src/asn1/pkcs/SafeBag.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4b9350bac88c63643cba33105a6eb74ba5a8d97c
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/SafeBag.cs
@@ -0,0 +1,70 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ public class SafeBag
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier bagID;
+ private readonly Asn1Object bagValue;
+ private readonly Asn1Set bagAttributes;
+
+ public SafeBag(
+ DerObjectIdentifier oid,
+ Asn1Object obj)
+ {
+ this.bagID = oid;
+ this.bagValue = obj;
+ this.bagAttributes = null;
+ }
+
+ public SafeBag(
+ DerObjectIdentifier oid,
+ Asn1Object obj,
+ Asn1Set bagAttributes)
+ {
+ this.bagID = oid;
+ this.bagValue = obj;
+ this.bagAttributes = bagAttributes;
+ }
+
+ public SafeBag(
+ Asn1Sequence seq)
+ {
+ this.bagID = (DerObjectIdentifier) seq[0];
+ this.bagValue = ((DerTaggedObject) seq[1]).GetObject();
+ if (seq.Count == 3)
+ {
+ this.bagAttributes = (Asn1Set) seq[2];
+ }
+ }
+
+ public DerObjectIdentifier BagID
+ {
+ get { return bagID; }
+ }
+
+ public Asn1Object BagValue
+ {
+ get { return bagValue; }
+ }
+
+ public Asn1Set BagAttributes
+ {
+ get { return bagAttributes; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ bagID, new DerTaggedObject(0, bagValue));
+
+ if (bagAttributes != null)
+ {
+ v.Add(bagAttributes);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/SignedData.cs b/bc-sharp-crypto/src/asn1/pkcs/SignedData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6e72bd0a9e60919c40f9cb887a4af7d0683e6e2a
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/SignedData.cs
@@ -0,0 +1,157 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ /**
+ * a Pkcs#7 signed data object.
+ */
+ public class SignedData
+ : Asn1Encodable
+ {
+ private readonly DerInteger version;
+ private readonly Asn1Set digestAlgorithms;
+ private readonly ContentInfo contentInfo;
+ private readonly Asn1Set certificates;
+ private readonly Asn1Set crls;
+ private readonly Asn1Set signerInfos;
+
+ public static SignedData GetInstance(object obj)
+ {
+ if (obj == null)
+ return null;
+ SignedData existing = obj as SignedData;
+ if (existing != null)
+ return existing;
+ return new SignedData(Asn1Sequence.GetInstance(obj));
+ }
+
+ public SignedData(
+ DerInteger _version,
+ Asn1Set _digestAlgorithms,
+ ContentInfo _contentInfo,
+ Asn1Set _certificates,
+ Asn1Set _crls,
+ Asn1Set _signerInfos)
+ {
+ version = _version;
+ digestAlgorithms = _digestAlgorithms;
+ contentInfo = _contentInfo;
+ certificates = _certificates;
+ crls = _crls;
+ signerInfos = _signerInfos;
+ }
+
+ private SignedData(
+ Asn1Sequence seq)
+ {
+ IEnumerator e = seq.GetEnumerator();
+
+ e.MoveNext();
+ version = (DerInteger) e.Current;
+
+ e.MoveNext();
+ digestAlgorithms = (Asn1Set) e.Current;
+
+ e.MoveNext();
+ contentInfo = ContentInfo.GetInstance(e.Current);
+
+ while (e.MoveNext())
+ {
+ Asn1Object o = (Asn1Object) e.Current;
+
+ //
+ // an interesting feature of SignedData is that there appear to be varying implementations...
+ // for the moment we ignore anything which doesn't fit.
+ //
+ if (o is DerTaggedObject)
+ {
+ DerTaggedObject tagged = (DerTaggedObject) o;
+
+ switch (tagged.TagNo)
+ {
+ case 0:
+ certificates = Asn1Set.GetInstance(tagged, false);
+ break;
+ case 1:
+ crls = Asn1Set.GetInstance(tagged, false);
+ break;
+ default:
+ throw new ArgumentException("unknown tag value " + tagged.TagNo);
+ }
+ }
+ else
+ {
+ signerInfos = (Asn1Set) o;
+ }
+ }
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public Asn1Set DigestAlgorithms
+ {
+ get { return digestAlgorithms; }
+ }
+
+ public ContentInfo ContentInfo
+ {
+ get { return contentInfo; }
+ }
+
+ public Asn1Set Certificates
+ {
+ get { return certificates; }
+ }
+
+ public Asn1Set Crls
+ {
+ get { return crls; }
+ }
+
+ public Asn1Set SignerInfos
+ {
+ get { return signerInfos; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * SignedData ::= Sequence {
+ * version Version,
+ * digestAlgorithms DigestAlgorithmIdentifiers,
+ * contentInfo ContentInfo,
+ * certificates
+ * [0] IMPLICIT ExtendedCertificatesAndCertificates
+ * OPTIONAL,
+ * crls
+ * [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+ * signerInfos SignerInfos }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ version, digestAlgorithms, contentInfo);
+
+ if (certificates != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, certificates));
+ }
+
+ if (crls != null)
+ {
+ v.Add(new DerTaggedObject(false, 1, crls));
+ }
+
+ v.Add(signerInfos);
+
+ return new BerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/pkcs/SignerInfo.cs b/bc-sharp-crypto/src/asn1/pkcs/SignerInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a3dc48b5b428f9910d5c92900516b0586f32eb60
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/pkcs/SignerInfo.cs
@@ -0,0 +1,154 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+ /**
+ * a Pkcs#7 signer info object.
+ */
+ public class SignerInfo
+ : Asn1Encodable
+ {
+ private DerInteger version;
+ private IssuerAndSerialNumber issuerAndSerialNumber;
+ private AlgorithmIdentifier digAlgorithm;
+ private Asn1Set authenticatedAttributes;
+ private AlgorithmIdentifier digEncryptionAlgorithm;
+ private Asn1OctetString encryptedDigest;
+ private Asn1Set unauthenticatedAttributes;
+
+ public static SignerInfo GetInstance(
+ object obj)
+ {
+ if (obj is SignerInfo)
+ {
+ return (SignerInfo) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new SignerInfo((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public SignerInfo(
+ DerInteger version,
+ IssuerAndSerialNumber issuerAndSerialNumber,
+ AlgorithmIdentifier digAlgorithm,
+ Asn1Set authenticatedAttributes,
+ AlgorithmIdentifier digEncryptionAlgorithm,
+ Asn1OctetString encryptedDigest,
+ Asn1Set unauthenticatedAttributes)
+ {
+ this.version = version;
+ this.issuerAndSerialNumber = issuerAndSerialNumber;
+ this.digAlgorithm = digAlgorithm;
+ this.authenticatedAttributes = authenticatedAttributes;
+ this.digEncryptionAlgorithm = digEncryptionAlgorithm;
+ this.encryptedDigest = encryptedDigest;
+ this.unauthenticatedAttributes = unauthenticatedAttributes;
+ }
+
+ public SignerInfo(
+ Asn1Sequence seq)
+ {
+ IEnumerator e = seq.GetEnumerator();
+
+ e.MoveNext();
+ version = (DerInteger) e.Current;
+
+ e.MoveNext();
+ issuerAndSerialNumber = IssuerAndSerialNumber.GetInstance(e.Current);
+
+ e.MoveNext();
+ digAlgorithm = AlgorithmIdentifier.GetInstance(e.Current);
+
+ e.MoveNext();
+ object obj = e.Current;
+
+ if (obj is Asn1TaggedObject)
+ {
+ authenticatedAttributes = Asn1Set.GetInstance((Asn1TaggedObject) obj, false);
+
+ e.MoveNext();
+ digEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(e.Current);
+ }
+ else
+ {
+ authenticatedAttributes = null;
+ digEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(obj);
+ }
+
+ e.MoveNext();
+ encryptedDigest = DerOctetString.GetInstance(e.Current);
+
+ if (e.MoveNext())
+ {
+ unauthenticatedAttributes = Asn1Set.GetInstance((Asn1TaggedObject)e.Current, false);
+ }
+ else
+ {
+ unauthenticatedAttributes = null;
+ }
+ }
+
+ public DerInteger Version { get { return version; } }
+
+ public IssuerAndSerialNumber IssuerAndSerialNumber { get { return issuerAndSerialNumber; } }
+
+ public Asn1Set AuthenticatedAttributes { get { return authenticatedAttributes; } }
+
+ public AlgorithmIdentifier DigestAlgorithm { get { return digAlgorithm; } }
+
+ public Asn1OctetString EncryptedDigest { get { return encryptedDigest; } }
+
+ public AlgorithmIdentifier DigestEncryptionAlgorithm { get { return digEncryptionAlgorithm; } }
+
+ public Asn1Set UnauthenticatedAttributes { get { return unauthenticatedAttributes; } }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * SignerInfo ::= Sequence {
+ * version Version,
+ * issuerAndSerialNumber IssuerAndSerialNumber,
+ * digestAlgorithm DigestAlgorithmIdentifier,
+ * authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
+ * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
+ * encryptedDigest EncryptedDigest,
+ * unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
+ * }
+ *
+ * EncryptedDigest ::= OCTET STRING
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ version, issuerAndSerialNumber, digAlgorithm);
+
+ if (authenticatedAttributes != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, authenticatedAttributes));
+ }
+
+ v.Add(digEncryptionAlgorithm, encryptedDigest);
+
+ if (unauthenticatedAttributes != null)
+ {
+ v.Add(new DerTaggedObject(false, 1, unauthenticatedAttributes));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/sec/ECPrivateKeyStructure.cs b/bc-sharp-crypto/src/asn1/sec/ECPrivateKeyStructure.cs
new file mode 100644
index 0000000000000000000000000000000000000000..32e020c0b27b004d7c92974da52a723053942c2b
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/sec/ECPrivateKeyStructure.cs
@@ -0,0 +1,184 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Sec
+{
+ /**
+ * the elliptic curve private key object from SEC 1
+ */
+ public class ECPrivateKeyStructure
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence seq;
+
+ public static ECPrivateKeyStructure GetInstance(object obj)
+ {
+ if (obj == null)
+ return null;
+ if (obj is ECPrivateKeyStructure)
+ return (ECPrivateKeyStructure)obj;
+ return new ECPrivateKeyStructure(Asn1Sequence.GetInstance(obj));
+ }
+
+ [Obsolete("Use 'GetInstance' instead")]
+ public ECPrivateKeyStructure(
+ Asn1Sequence seq)
+ {
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+
+ this.seq = seq;
+ }
+
+ [Obsolete("Use constructor which takes 'orderBitLength' instead, to guarantee correct encoding")]
+ public ECPrivateKeyStructure(
+ BigInteger key)
+ {
+ if (key == null)
+ throw new ArgumentNullException("key");
+
+ this.seq = new DerSequence(
+ new DerInteger(1),
+ new DerOctetString(key.ToByteArrayUnsigned()));
+ }
+
+ public ECPrivateKeyStructure(
+ int orderBitLength,
+ BigInteger key)
+ {
+ if (key == null)
+ throw new ArgumentNullException("key");
+ if (orderBitLength < key.BitLength)
+ throw new ArgumentException("must be >= key bitlength", "orderBitLength");
+
+ byte[] bytes = BigIntegers.AsUnsignedByteArray((orderBitLength + 7) / 8, key);
+
+ this.seq = new DerSequence(
+ new DerInteger(1),
+ new DerOctetString(bytes));
+ }
+
+ [Obsolete("Use constructor which takes 'orderBitLength' instead, to guarantee correct encoding")]
+ public ECPrivateKeyStructure(
+ BigInteger key,
+ Asn1Encodable parameters)
+ : this(key, null, parameters)
+ {
+ }
+
+ [Obsolete("Use constructor which takes 'orderBitLength' instead, to guarantee correct encoding")]
+ public ECPrivateKeyStructure(
+ BigInteger key,
+ DerBitString publicKey,
+ Asn1Encodable parameters)
+ {
+ if (key == null)
+ throw new ArgumentNullException("key");
+
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ new DerInteger(1),
+ new DerOctetString(key.ToByteArrayUnsigned()));
+
+ if (parameters != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, parameters));
+ }
+
+ if (publicKey != null)
+ {
+ v.Add(new DerTaggedObject(true, 1, publicKey));
+ }
+
+ this.seq = new DerSequence(v);
+ }
+
+ public ECPrivateKeyStructure(
+ int orderBitLength,
+ BigInteger key,
+ Asn1Encodable parameters)
+ : this(orderBitLength, key, null, parameters)
+ {
+ }
+
+ public ECPrivateKeyStructure(
+ int orderBitLength,
+ BigInteger key,
+ DerBitString publicKey,
+ Asn1Encodable parameters)
+ {
+ if (key == null)
+ throw new ArgumentNullException("key");
+ if (orderBitLength < key.BitLength)
+ throw new ArgumentException("must be >= key bitlength", "orderBitLength");
+
+ byte[] bytes = BigIntegers.AsUnsignedByteArray((orderBitLength + 7) / 8, key);
+
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ new DerInteger(1),
+ new DerOctetString(bytes));
+
+ if (parameters != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, parameters));
+ }
+
+ if (publicKey != null)
+ {
+ v.Add(new DerTaggedObject(true, 1, publicKey));
+ }
+
+ this.seq = new DerSequence(v);
+ }
+
+ public virtual BigInteger GetKey()
+ {
+ Asn1OctetString octs = (Asn1OctetString) seq[1];
+
+ return new BigInteger(1, octs.GetOctets());
+ }
+
+ public virtual DerBitString GetPublicKey()
+ {
+ return (DerBitString) GetObjectInTag(1);
+ }
+
+ public virtual Asn1Object GetParameters()
+ {
+ return GetObjectInTag(0);
+ }
+
+ private Asn1Object GetObjectInTag(int tagNo)
+ {
+ foreach (Asn1Encodable ae in seq)
+ {
+ Asn1Object obj = ae.ToAsn1Object();
+
+ if (obj is Asn1TaggedObject)
+ {
+ Asn1TaggedObject tag = (Asn1TaggedObject) obj;
+ if (tag.TagNo == tagNo)
+ {
+ return tag.GetObject();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * ECPrivateKey ::= SEQUENCE {
+ * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+ * privateKey OCTET STRING,
+ * parameters [0] Parameters OPTIONAL,
+ * publicKey [1] BIT STRING OPTIONAL }
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return seq;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/sec/SECNamedCurves.cs b/bc-sharp-crypto/src/asn1/sec/SECNamedCurves.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b753ac5d179184747a4f5ff6509a6a7f43243099
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/sec/SECNamedCurves.cs
@@ -0,0 +1,1184 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.EC.Endo;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.Sec
+{
+ public sealed class SecNamedCurves
+ {
+ private SecNamedCurves()
+ {
+ }
+
+ private static ECCurve ConfigureCurve(ECCurve curve)
+ {
+ return curve;
+ }
+
+ private static ECCurve ConfigureCurveGlv(ECCurve c, GlvTypeBParameters p)
+ {
+ return c.Configure().SetEndomorphism(new GlvTypeBEndomorphism(c, p)).Create();
+ }
+
+ private static BigInteger FromHex(string hex)
+ {
+ return new BigInteger(1, Hex.Decode(hex));
+ }
+
+ /*
+ * secp112r1
+ */
+ internal class Secp112r1Holder
+ : X9ECParametersHolder
+ {
+ private Secp112r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Secp112r1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ // p = (2^128 - 3) / 76439
+ BigInteger p = FromHex("DB7C2ABF62E35E668076BEAD208B");
+ BigInteger a = FromHex("DB7C2ABF62E35E668076BEAD2088");
+ BigInteger b = FromHex("659EF8BA043916EEDE8911702B22");
+ byte[] S = Hex.Decode("00F50B028E4D696E676875615175290472783FB1");
+ BigInteger n = FromHex("DB7C2ABF62E35E7628DFAC6561C5");
+ BigInteger h = BigInteger.One;
+
+ ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "09487239995A5EE76B55F9C2F098"
+ + "A89CE5AF8724C0A23E0E0FF77500"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * secp112r2
+ */
+ internal class Secp112r2Holder
+ : X9ECParametersHolder
+ {
+ private Secp112r2Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Secp112r2Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ // p = (2^128 - 3) / 76439
+ BigInteger p = FromHex("DB7C2ABF62E35E668076BEAD208B");
+ BigInteger a = FromHex("6127C24C05F38A0AAAF65C0EF02C");
+ BigInteger b = FromHex("51DEF1815DB5ED74FCC34C85D709");
+ byte[] S = Hex.Decode("002757A1114D696E6768756151755316C05E0BD4");
+ BigInteger n = FromHex("36DF0AAFD8B8D7597CA10520D04B");
+ BigInteger h = BigInteger.ValueOf(4);
+
+ ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "4BA30AB5E892B4E1649DD0928643"
+ + "ADCD46F5882E3747DEF36E956E97"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * secp128r1
+ */
+ internal class Secp128r1Holder
+ : X9ECParametersHolder
+ {
+ private Secp128r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Secp128r1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ // p = 2^128 - 2^97 - 1
+ BigInteger p = FromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF");
+ BigInteger a = FromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC");
+ BigInteger b = FromHex("E87579C11079F43DD824993C2CEE5ED3");
+ byte[] S = Hex.Decode("000E0D4D696E6768756151750CC03A4473D03679");
+ BigInteger n = FromHex("FFFFFFFE0000000075A30D1B9038A115");
+ BigInteger h = BigInteger.One;
+
+ ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "161FF7528B899B2D0C28607CA52C5B86"
+ + "CF5AC8395BAFEB13C02DA292DDED7A83"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * secp128r2
+ */
+ internal class Secp128r2Holder
+ : X9ECParametersHolder
+ {
+ private Secp128r2Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Secp128r2Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ // p = 2^128 - 2^97 - 1
+ BigInteger p = FromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF");
+ BigInteger a = FromHex("D6031998D1B3BBFEBF59CC9BBFF9AEE1");
+ BigInteger b = FromHex("5EEEFCA380D02919DC2C6558BB6D8A5D");
+ byte[] S = Hex.Decode("004D696E67687561517512D8F03431FCE63B88F4");
+ BigInteger n = FromHex("3FFFFFFF7FFFFFFFBE0024720613B5A3");
+ BigInteger h = BigInteger.ValueOf(4);
+
+ ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "7B6AA5D85E572983E6FB32A7CDEBC140"
+ + "27B6916A894D3AEE7106FE805FC34B44"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * secp160k1
+ */
+ internal class Secp160k1Holder
+ : X9ECParametersHolder
+ {
+ private Secp160k1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Secp160k1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ // p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1
+ BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73");
+ BigInteger a = BigInteger.Zero;
+ BigInteger b = BigInteger.ValueOf(7);
+ byte[] S = null;
+ BigInteger n = FromHex("0100000000000000000001B8FA16DFAB9ACA16B6B3");
+ BigInteger h = BigInteger.One;
+
+ GlvTypeBParameters glv = new GlvTypeBParameters(
+ new BigInteger("9ba48cba5ebcb9b6bd33b92830b2a2e0e192f10a", 16),
+ new BigInteger("c39c6c3b3a36d7701b9c71a1f5804ae5d0003f4", 16),
+ new BigInteger[]{
+ new BigInteger("9162fbe73984472a0a9e", 16),
+ new BigInteger("-96341f1138933bc2f505", 16) },
+ new BigInteger[]{
+ new BigInteger("127971af8721782ecffa3", 16),
+ new BigInteger("9162fbe73984472a0a9e", 16) },
+ new BigInteger("9162fbe73984472a0a9d0590", 16),
+ new BigInteger("96341f1138933bc2f503fd44", 16),
+ 176);
+
+ ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"
+ + "938CF935318FDCED6BC28286531733C3F03C4FEE"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * secp160r1
+ */
+ internal class Secp160r1Holder
+ : X9ECParametersHolder
+ {
+ private Secp160r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Secp160r1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ // p = 2^160 - 2^31 - 1
+ BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF");
+ BigInteger a = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC");
+ BigInteger b = FromHex("1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45");
+ byte[] S = Hex.Decode("1053CDE42C14D696E67687561517533BF3F83345");
+ BigInteger n = FromHex("0100000000000000000001F4C8F927AED3CA752257");
+ BigInteger h = BigInteger.One;
+
+ ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "4A96B5688EF573284664698968C38BB913CBFC82"
+ + "23A628553168947D59DCC912042351377AC5FB32"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * secp160r2
+ */
+ internal class Secp160r2Holder
+ : X9ECParametersHolder
+ {
+ private Secp160r2Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Secp160r2Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ // p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1
+ BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73");
+ BigInteger a = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70");
+ BigInteger b = FromHex("B4E134D3FB59EB8BAB57274904664D5AF50388BA");
+ byte[] S = Hex.Decode("B99B99B099B323E02709A4D696E6768756151751");
+ BigInteger n = FromHex("0100000000000000000000351EE786A818F3A1A16B");
+ BigInteger h = BigInteger.One;
+
+ ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "52DCB034293A117E1F4FF11B30F7199D3144CE6D"
+ + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * secp192k1
+ */
+ internal class Secp192k1Holder
+ : X9ECParametersHolder
+ {
+ private Secp192k1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Secp192k1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ // p = 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1
+ BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37");
+ BigInteger a = BigInteger.Zero;
+ BigInteger b = BigInteger.ValueOf(3);
+ byte[] S = null;
+ BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D");
+ BigInteger h = BigInteger.One;
+
+ GlvTypeBParameters glv = new GlvTypeBParameters(
+ new BigInteger("bb85691939b869c1d087f601554b96b80cb4f55b35f433c2", 16),
+ new BigInteger("3d84f26c12238d7b4f3d516613c1759033b1a5800175d0b1", 16),
+ new BigInteger[]{
+ new BigInteger("71169be7330b3038edb025f1", 16),
+ new BigInteger("-b3fb3400dec5c4adceb8655c", 16) },
+ new BigInteger[]{
+ new BigInteger("12511cfe811d0f4e6bc688b4d", 16),
+ new BigInteger("71169be7330b3038edb025f1", 16) },
+ new BigInteger("71169be7330b3038edb025f1d0f9", 16),
+ new BigInteger("b3fb3400dec5c4adceb8655d4c94", 16),
+ 208);
+
+ ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"
+ + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * secp192r1
+ */
+ internal class Secp192r1Holder
+ : X9ECParametersHolder
+ {
+ private Secp192r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Secp192r1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ // p = 2^192 - 2^64 - 1
+ BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF");
+ BigInteger a = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC");
+ BigInteger b = FromHex("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1");
+ byte[] S = Hex.Decode("3045AE6FC8422F64ED579528D38120EAE12196D5");
+ BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831");
+ BigInteger h = BigInteger.One;
+
+ ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"
+ + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * secp224k1
+ */
+ internal class Secp224k1Holder
+ : X9ECParametersHolder
+ {
+ private Secp224k1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Secp224k1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ // p = 2^224 - 2^32 - 2^12 - 2^11 - 2^9 - 2^7 - 2^4 - 2 - 1
+ BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D");
+ BigInteger a = BigInteger.Zero;
+ BigInteger b = BigInteger.ValueOf(5);
+ byte[] S = null;
+ BigInteger n = FromHex("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7");
+ BigInteger h = BigInteger.One;
+
+ GlvTypeBParameters glv = new GlvTypeBParameters(
+ new BigInteger("fe0e87005b4e83761908c5131d552a850b3f58b749c37cf5b84d6768", 16),
+ new BigInteger("60dcd2104c4cbc0be6eeefc2bdd610739ec34e317f9b33046c9e4788", 16),
+ new BigInteger[]{
+ new BigInteger("6b8cf07d4ca75c88957d9d670591", 16),
+ new BigInteger("-b8adf1378a6eb73409fa6c9c637d", 16) },
+ new BigInteger[]{
+ new BigInteger("1243ae1b4d71613bc9f780a03690e", 16),
+ new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) },
+ new BigInteger("6b8cf07d4ca75c88957d9d67059037a4", 16),
+ new BigInteger("b8adf1378a6eb73409fa6c9c637ba7f5", 16),
+ 240);
+
+ ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"
+ + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * secp224r1
+ */
+ internal class Secp224r1Holder
+ : X9ECParametersHolder
+ {
+ private Secp224r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Secp224r1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ // p = 2^224 - 2^96 + 1
+ BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001");
+ BigInteger a = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE");
+ BigInteger b = FromHex("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4");
+ byte[] S = Hex.Decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5");
+ BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D");
+ BigInteger h = BigInteger.One;
+
+ ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
+ + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * secp256k1
+ */
+ internal class Secp256k1Holder
+ : X9ECParametersHolder
+ {
+ private Secp256k1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Secp256k1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ // p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
+ BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F");
+ BigInteger a = BigInteger.Zero;
+ BigInteger b = BigInteger.ValueOf(7);
+ byte[] S = null;
+ BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
+ BigInteger h = BigInteger.One;
+
+ GlvTypeBParameters glv = new GlvTypeBParameters(
+ new BigInteger("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee", 16),
+ new BigInteger("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72", 16),
+ new BigInteger[]{
+ new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16),
+ new BigInteger("-e4437ed6010e88286f547fa90abfe4c3", 16) },
+ new BigInteger[]{
+ new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16),
+ new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) },
+ new BigInteger("3086d221a7d46bcde86c90e49284eb153dab", 16),
+ new BigInteger("e4437ed6010e88286f547fa90abfe4c42212", 16),
+ 272);
+
+ ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
+ + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * secp256r1
+ */
+ internal class Secp256r1Holder
+ : X9ECParametersHolder
+ {
+ private Secp256r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Secp256r1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ // p = 2^224 (2^32 - 1) + 2^192 + 2^96 - 1
+ BigInteger p = FromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF");
+ BigInteger a = FromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC");
+ BigInteger b = FromHex("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B");
+ byte[] S = Hex.Decode("C49D360886E704936A6678E1139D26B7819F7E90");
+ BigInteger n = FromHex("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
+ BigInteger h = BigInteger.One;
+
+ ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
+ + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * secp384r1
+ */
+ internal class Secp384r1Holder
+ : X9ECParametersHolder
+ {
+ private Secp384r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Secp384r1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ // p = 2^384 - 2^128 - 2^96 + 2^32 - 1
+ BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF");
+ BigInteger a = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC");
+ BigInteger b = FromHex("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF");
+ byte[] S = Hex.Decode("A335926AA319A27A1D00896A6773A4827ACDAC73");
+ BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973");
+ BigInteger h = BigInteger.One;
+
+ ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"
+ + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * secp521r1
+ */
+ internal class Secp521r1Holder
+ : X9ECParametersHolder
+ {
+ private Secp521r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Secp521r1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ // p = 2^521 - 1
+ BigInteger p = FromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+ BigInteger a = FromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC");
+ BigInteger b = FromHex("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00");
+ byte[] S = Hex.Decode("D09E8800291CB85396CC6717393284AAA0DA64BA");
+ BigInteger n = FromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409");
+ BigInteger h = BigInteger.One;
+
+ ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"
+ + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * sect113r1
+ */
+ internal class Sect113r1Holder
+ : X9ECParametersHolder
+ {
+ private Sect113r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Sect113r1Holder();
+
+ private const int m = 113;
+ private const int k = 9;
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger a = FromHex("003088250CA6E7C7FE649CE85820F7");
+ BigInteger b = FromHex("00E8BEE4D3E2260744188BE0E9C723");
+ byte[] S = Hex.Decode("10E723AB14D696E6768756151756FEBF8FCB49A9");
+ BigInteger n = FromHex("0100000000000000D9CCEC8A39E56F");
+ BigInteger h = BigInteger.ValueOf(2);
+
+ ECCurve curve = new F2mCurve(m, k, a, b, n, h);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "009D73616F35F4AB1407D73562C10F"
+ + "00A52830277958EE84D1315ED31886"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * sect113r2
+ */
+ internal class Sect113r2Holder
+ : X9ECParametersHolder
+ {
+ private Sect113r2Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Sect113r2Holder();
+
+ private const int m = 113;
+ private const int k = 9;
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger a = FromHex("00689918DBEC7E5A0DD6DFC0AA55C7");
+ BigInteger b = FromHex("0095E9A9EC9B297BD4BF36E059184F");
+ byte[] S = Hex.Decode("10C0FB15760860DEF1EEF4D696E676875615175D");
+ BigInteger n = FromHex("010000000000000108789B2496AF93");
+ BigInteger h = BigInteger.ValueOf(2);
+
+ ECCurve curve = new F2mCurve(m, k, a, b, n, h);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "01A57A6A7B26CA5EF52FCDB8164797"
+ + "00B3ADC94ED1FE674C06E695BABA1D"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * sect131r1
+ */
+ internal class Sect131r1Holder
+ : X9ECParametersHolder
+ {
+ private Sect131r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Sect131r1Holder();
+
+ private const int m = 131;
+ private const int k1 = 2;
+ private const int k2 = 3;
+ private const int k3 = 8;
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger a = FromHex("07A11B09A76B562144418FF3FF8C2570B8");
+ BigInteger b = FromHex("0217C05610884B63B9C6C7291678F9D341");
+ byte[] S = Hex.Decode("4D696E676875615175985BD3ADBADA21B43A97E2");
+ BigInteger n = FromHex("0400000000000000023123953A9464B54D");
+ BigInteger h = BigInteger.ValueOf(2);
+
+ ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "0081BAF91FDF9833C40F9C181343638399"
+ + "078C6E7EA38C001F73C8134B1B4EF9E150"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * sect131r2
+ */
+ internal class Sect131r2Holder
+ : X9ECParametersHolder
+ {
+ private Sect131r2Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Sect131r2Holder();
+
+ private const int m = 131;
+ private const int k1 = 2;
+ private const int k2 = 3;
+ private const int k3 = 8;
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger a = FromHex("03E5A88919D7CAFCBF415F07C2176573B2");
+ BigInteger b = FromHex("04B8266A46C55657AC734CE38F018F2192");
+ byte[] S = Hex.Decode("985BD3ADBAD4D696E676875615175A21B43A97E3");
+ BigInteger n = FromHex("0400000000000000016954A233049BA98F");
+ BigInteger h = BigInteger.ValueOf(2);
+
+ ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "0356DCD8F2F95031AD652D23951BB366A8"
+ + "0648F06D867940A5366D9E265DE9EB240F"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * sect163k1
+ */
+ internal class Sect163k1Holder
+ : X9ECParametersHolder
+ {
+ private Sect163k1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Sect163k1Holder();
+
+ private const int m = 163;
+ private const int k1 = 3;
+ private const int k2 = 6;
+ private const int k3 = 7;
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger a = BigInteger.One;
+ BigInteger b = BigInteger.One;
+ byte[] S = null;
+ BigInteger n = FromHex("04000000000000000000020108A2E0CC0D99F8A5EF");
+ BigInteger h = BigInteger.ValueOf(2);
+
+ ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8"
+ + "0289070FB05D38FF58321F2E800536D538CCDAA3D9"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * sect163r1
+ */
+ internal class Sect163r1Holder
+ : X9ECParametersHolder
+ {
+ private Sect163r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Sect163r1Holder();
+
+ private const int m = 163;
+ private const int k1 = 3;
+ private const int k2 = 6;
+ private const int k3 = 7;
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger a = FromHex("07B6882CAAEFA84F9554FF8428BD88E246D2782AE2");
+ BigInteger b = FromHex("0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9");
+ byte[] S = Hex.Decode("24B7B137C8A14D696E6768756151756FD0DA2E5C");
+ BigInteger n = FromHex("03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B");
+ BigInteger h = BigInteger.ValueOf(2);
+
+ ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "0369979697AB43897789566789567F787A7876A654"
+ + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * sect163r2
+ */
+ internal class Sect163r2Holder
+ : X9ECParametersHolder
+ {
+ private Sect163r2Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Sect163r2Holder();
+
+ private const int m = 163;
+ private const int k1 = 3;
+ private const int k2 = 6;
+ private const int k3 = 7;
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger a = BigInteger.One;
+ BigInteger b = FromHex("020A601907B8C953CA1481EB10512F78744A3205FD");
+ byte[] S = Hex.Decode("85E25BFE5C86226CDB12016F7553F9D0E693A268");
+ BigInteger n = FromHex("040000000000000000000292FE77E70C12A4234C33");
+ BigInteger h = BigInteger.ValueOf(2);
+
+ ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "03F0EBA16286A2D57EA0991168D4994637E8343E36"
+ + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * sect193r1
+ */
+ internal class Sect193r1Holder
+ : X9ECParametersHolder
+ {
+ private Sect193r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Sect193r1Holder();
+
+ private const int m = 193;
+ private const int k = 15;
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger a = FromHex("0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01");
+ BigInteger b = FromHex("00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814");
+ byte[] S = Hex.Decode("103FAEC74D696E676875615175777FC5B191EF30");
+ BigInteger n = FromHex("01000000000000000000000000C7F34A778F443ACC920EBA49");
+ BigInteger h = BigInteger.ValueOf(2);
+
+ ECCurve curve = new F2mCurve(m, k, a, b, n, h);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1"
+ + "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * sect193r2
+ */
+ internal class Sect193r2Holder
+ : X9ECParametersHolder
+ {
+ private Sect193r2Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Sect193r2Holder();
+
+ private const int m = 193;
+ private const int k = 15;
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger a = FromHex("0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B");
+ BigInteger b = FromHex("00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE");
+ byte[] S = Hex.Decode("10B7B4D696E676875615175137C8A16FD0DA2211");
+ BigInteger n = FromHex("010000000000000000000000015AAB561B005413CCD4EE99D5");
+ BigInteger h = BigInteger.ValueOf(2);
+
+ ECCurve curve = new F2mCurve(m, k, a, b, n, h);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F"
+ + "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * sect233k1
+ */
+ internal class Sect233k1Holder
+ : X9ECParametersHolder
+ {
+ private Sect233k1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Sect233k1Holder();
+
+ private const int m = 233;
+ private const int k = 74;
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger a = BigInteger.Zero;
+ BigInteger b = BigInteger.One;
+ byte[] S = null;
+ BigInteger n = FromHex("8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF");
+ BigInteger h = BigInteger.ValueOf(4);
+
+ ECCurve curve = new F2mCurve(m, k, a, b, n, h);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126"
+ + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * sect233r1
+ */
+ internal class Sect233r1Holder
+ : X9ECParametersHolder
+ {
+ private Sect233r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Sect233r1Holder();
+
+ private const int m = 233;
+ private const int k = 74;
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger a = BigInteger.One;
+ BigInteger b = FromHex("0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD");
+ byte[] S = Hex.Decode("74D59FF07F6B413D0EA14B344B20A2DB049B50C3");
+ BigInteger n = FromHex("01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7");
+ BigInteger h = BigInteger.ValueOf(2);
+
+ ECCurve curve = new F2mCurve(m, k, a, b, n, h);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"
+ + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * sect239k1
+ */
+ internal class Sect239k1Holder
+ : X9ECParametersHolder
+ {
+ private Sect239k1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Sect239k1Holder();
+
+ private const int m = 239;
+ private const int k = 158;
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger a = BigInteger.Zero;
+ BigInteger b = BigInteger.One;
+ byte[] S = null;
+ BigInteger n = FromHex("2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5");
+ BigInteger h = BigInteger.ValueOf(4);
+
+ ECCurve curve = new F2mCurve(m, k, a, b, n, h);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC"
+ + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * sect283k1
+ */
+ internal class Sect283k1Holder
+ : X9ECParametersHolder
+ {
+ private Sect283k1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Sect283k1Holder();
+
+ private const int m = 283;
+ private const int k1 = 5;
+ private const int k2 = 7;
+ private const int k3 = 12;
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger a = BigInteger.Zero;
+ BigInteger b = BigInteger.One;
+ byte[] S = null;
+ BigInteger n = FromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61");
+ BigInteger h = BigInteger.ValueOf(4);
+
+ ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836"
+ + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * sect283r1
+ */
+ internal class Sect283r1Holder
+ : X9ECParametersHolder
+ {
+ private Sect283r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Sect283r1Holder();
+
+ private const int m = 283;
+ private const int k1 = 5;
+ private const int k2 = 7;
+ private const int k3 = 12;
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger a = BigInteger.One;
+ BigInteger b = FromHex("027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5");
+ byte[] S = Hex.Decode("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE");
+ BigInteger n = FromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307");
+ BigInteger h = BigInteger.ValueOf(2);
+
+ ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053"
+ + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * sect409k1
+ */
+ internal class Sect409k1Holder
+ : X9ECParametersHolder
+ {
+ private Sect409k1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Sect409k1Holder();
+
+ private const int m = 409;
+ private const int k = 87;
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger a = BigInteger.Zero;
+ BigInteger b = BigInteger.One;
+ byte[] S = null;
+ BigInteger n = FromHex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF");
+ BigInteger h = BigInteger.ValueOf(4);
+
+ ECCurve curve = new F2mCurve(m, k, a, b, n, h);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746"
+ + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * sect409r1
+ */
+ internal class Sect409r1Holder
+ : X9ECParametersHolder
+ {
+ private Sect409r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Sect409r1Holder();
+
+ private const int m = 409;
+ private const int k = 87;
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger a = BigInteger.One;
+ BigInteger b = FromHex("0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F");
+ byte[] S = Hex.Decode("4099B5A457F9D69F79213D094C4BCD4D4262210B");
+ BigInteger n = FromHex("010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173");
+ BigInteger h = BigInteger.ValueOf(2);
+
+ ECCurve curve = new F2mCurve(m, k, a, b, n, h);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7"
+ + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * sect571k1
+ */
+ internal class Sect571k1Holder
+ : X9ECParametersHolder
+ {
+ private Sect571k1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Sect571k1Holder();
+
+ private const int m = 571;
+ private const int k1 = 2;
+ private const int k2 = 5;
+ private const int k3 = 10;
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger a = BigInteger.Zero;
+ BigInteger b = BigInteger.One;
+ byte[] S = null;
+ BigInteger n = FromHex("020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001");
+ BigInteger h = BigInteger.ValueOf(4);
+
+ ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972"
+ + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+ /*
+ * sect571r1
+ */
+ internal class Sect571r1Holder
+ : X9ECParametersHolder
+ {
+ private Sect571r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Sect571r1Holder();
+
+ private const int m = 571;
+ private const int k1 = 2;
+ private const int k2 = 5;
+ private const int k3 = 10;
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger a = BigInteger.One;
+ BigInteger b = FromHex("02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A");
+ byte[] S = Hex.Decode("2AA058F73A0E33AB486B0F610410C53A7F132310");
+ BigInteger n = FromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47");
+ BigInteger h = BigInteger.ValueOf(2);
+
+ ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19"
+ + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ }
+
+
+ private static readonly IDictionary objIds = Platform.CreateHashtable();
+ private static readonly IDictionary curves = Platform.CreateHashtable();
+ private static readonly IDictionary names = Platform.CreateHashtable();
+
+ private static void DefineCurve(
+ string name,
+ DerObjectIdentifier oid,
+ X9ECParametersHolder holder)
+ {
+ objIds.Add(Platform.ToUpperInvariant(name), oid);
+ names.Add(oid, name);
+ curves.Add(oid, holder);
+ }
+
+ static SecNamedCurves()
+ {
+ DefineCurve("secp112r1", SecObjectIdentifiers.SecP112r1, Secp112r1Holder.Instance);
+ DefineCurve("secp112r2", SecObjectIdentifiers.SecP112r2, Secp112r2Holder.Instance);
+ DefineCurve("secp128r1", SecObjectIdentifiers.SecP128r1, Secp128r1Holder.Instance);
+ DefineCurve("secp128r2", SecObjectIdentifiers.SecP128r2, Secp128r2Holder.Instance);
+ DefineCurve("secp160k1", SecObjectIdentifiers.SecP160k1, Secp160k1Holder.Instance);
+ DefineCurve("secp160r1", SecObjectIdentifiers.SecP160r1, Secp160r1Holder.Instance);
+ DefineCurve("secp160r2", SecObjectIdentifiers.SecP160r2, Secp160r2Holder.Instance);
+ DefineCurve("secp192k1", SecObjectIdentifiers.SecP192k1, Secp192k1Holder.Instance);
+ DefineCurve("secp192r1", SecObjectIdentifiers.SecP192r1, Secp192r1Holder.Instance);
+ DefineCurve("secp224k1", SecObjectIdentifiers.SecP224k1, Secp224k1Holder.Instance);
+ DefineCurve("secp224r1", SecObjectIdentifiers.SecP224r1, Secp224r1Holder.Instance);
+ DefineCurve("secp256k1", SecObjectIdentifiers.SecP256k1, Secp256k1Holder.Instance);
+ DefineCurve("secp256r1", SecObjectIdentifiers.SecP256r1, Secp256r1Holder.Instance);
+ DefineCurve("secp384r1", SecObjectIdentifiers.SecP384r1, Secp384r1Holder.Instance);
+ DefineCurve("secp521r1", SecObjectIdentifiers.SecP521r1, Secp521r1Holder.Instance);
+
+ DefineCurve("sect113r1", SecObjectIdentifiers.SecT113r1, Sect113r1Holder.Instance);
+ DefineCurve("sect113r2", SecObjectIdentifiers.SecT113r2, Sect113r2Holder.Instance);
+ DefineCurve("sect131r1", SecObjectIdentifiers.SecT131r1, Sect131r1Holder.Instance);
+ DefineCurve("sect131r2", SecObjectIdentifiers.SecT131r2, Sect131r2Holder.Instance);
+ DefineCurve("sect163k1", SecObjectIdentifiers.SecT163k1, Sect163k1Holder.Instance);
+ DefineCurve("sect163r1", SecObjectIdentifiers.SecT163r1, Sect163r1Holder.Instance);
+ DefineCurve("sect163r2", SecObjectIdentifiers.SecT163r2, Sect163r2Holder.Instance);
+ DefineCurve("sect193r1", SecObjectIdentifiers.SecT193r1, Sect193r1Holder.Instance);
+ DefineCurve("sect193r2", SecObjectIdentifiers.SecT193r2, Sect193r2Holder.Instance);
+ DefineCurve("sect233k1", SecObjectIdentifiers.SecT233k1, Sect233k1Holder.Instance);
+ DefineCurve("sect233r1", SecObjectIdentifiers.SecT233r1, Sect233r1Holder.Instance);
+ DefineCurve("sect239k1", SecObjectIdentifiers.SecT239k1, Sect239k1Holder.Instance);
+ DefineCurve("sect283k1", SecObjectIdentifiers.SecT283k1, Sect283k1Holder.Instance);
+ DefineCurve("sect283r1", SecObjectIdentifiers.SecT283r1, Sect283r1Holder.Instance);
+ DefineCurve("sect409k1", SecObjectIdentifiers.SecT409k1, Sect409k1Holder.Instance);
+ DefineCurve("sect409r1", SecObjectIdentifiers.SecT409r1, Sect409r1Holder.Instance);
+ DefineCurve("sect571k1", SecObjectIdentifiers.SecT571k1, Sect571k1Holder.Instance);
+ DefineCurve("sect571r1", SecObjectIdentifiers.SecT571r1, Sect571r1Holder.Instance);
+ }
+
+ public static X9ECParameters GetByName(
+ string name)
+ {
+ DerObjectIdentifier oid = GetOid(name);
+ return oid == null ? null : GetByOid(oid);
+ }
+
+ /**
+ * return the X9ECParameters object for the named curve represented by
+ * the passed in object identifier. Null if the curve isn't present.
+ *
+ * @param oid an object identifier representing a named curve, if present.
+ */
+ public static X9ECParameters GetByOid(
+ DerObjectIdentifier oid)
+ {
+ X9ECParametersHolder holder = (X9ECParametersHolder)curves[oid];
+ return holder == null ? null : holder.Parameters;
+ }
+
+ /**
+ * return the object identifier signified by the passed in name. Null
+ * if there is no object identifier associated with name.
+ *
+ * @return the object identifier associated with name, if present.
+ */
+ public static DerObjectIdentifier GetOid(
+ string name)
+ {
+ return (DerObjectIdentifier)objIds[Platform.ToUpperInvariant(name)];
+ }
+
+ /**
+ * return the named curve name represented by the given object identifier.
+ */
+ public static string GetName(
+ DerObjectIdentifier oid)
+ {
+ return (string)names[oid];
+ }
+
+ /**
+ * returns an enumeration containing the name strings for curves
+ * contained in this structure.
+ */
+ public static IEnumerable Names
+ {
+ get { return new EnumerableProxy(names.Values); }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/sec/SECObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/sec/SECObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..afc10e1d6e3c9a29f08feafa71b2b5c87b6fbe91
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/sec/SECObjectIdentifiers.cs
@@ -0,0 +1,52 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X9;
+
+namespace Org.BouncyCastle.Asn1.Sec
+{
+ public abstract class SecObjectIdentifiers
+ {
+ /**
+ * EllipticCurve OBJECT IDENTIFIER ::= {
+ * iso(1) identified-organization(3) certicom(132) curve(0)
+ * }
+ */
+ public static readonly DerObjectIdentifier EllipticCurve = new DerObjectIdentifier("1.3.132.0");
+
+ public static readonly DerObjectIdentifier SecT163k1 = new DerObjectIdentifier(EllipticCurve + ".1");
+ public static readonly DerObjectIdentifier SecT163r1 = new DerObjectIdentifier(EllipticCurve + ".2");
+ public static readonly DerObjectIdentifier SecT239k1 = new DerObjectIdentifier(EllipticCurve + ".3");
+ public static readonly DerObjectIdentifier SecT113r1 = new DerObjectIdentifier(EllipticCurve + ".4");
+ public static readonly DerObjectIdentifier SecT113r2 = new DerObjectIdentifier(EllipticCurve + ".5");
+ public static readonly DerObjectIdentifier SecP112r1 = new DerObjectIdentifier(EllipticCurve + ".6");
+ public static readonly DerObjectIdentifier SecP112r2 = new DerObjectIdentifier(EllipticCurve + ".7");
+ public static readonly DerObjectIdentifier SecP160r1 = new DerObjectIdentifier(EllipticCurve + ".8");
+ public static readonly DerObjectIdentifier SecP160k1 = new DerObjectIdentifier(EllipticCurve + ".9");
+ public static readonly DerObjectIdentifier SecP256k1 = new DerObjectIdentifier(EllipticCurve + ".10");
+ public static readonly DerObjectIdentifier SecT163r2 = new DerObjectIdentifier(EllipticCurve + ".15");
+ public static readonly DerObjectIdentifier SecT283k1 = new DerObjectIdentifier(EllipticCurve + ".16");
+ public static readonly DerObjectIdentifier SecT283r1 = new DerObjectIdentifier(EllipticCurve + ".17");
+ public static readonly DerObjectIdentifier SecT131r1 = new DerObjectIdentifier(EllipticCurve + ".22");
+ public static readonly DerObjectIdentifier SecT131r2 = new DerObjectIdentifier(EllipticCurve + ".23");
+ public static readonly DerObjectIdentifier SecT193r1 = new DerObjectIdentifier(EllipticCurve + ".24");
+ public static readonly DerObjectIdentifier SecT193r2 = new DerObjectIdentifier(EllipticCurve + ".25");
+ public static readonly DerObjectIdentifier SecT233k1 = new DerObjectIdentifier(EllipticCurve + ".26");
+ public static readonly DerObjectIdentifier SecT233r1 = new DerObjectIdentifier(EllipticCurve + ".27");
+ public static readonly DerObjectIdentifier SecP128r1 = new DerObjectIdentifier(EllipticCurve + ".28");
+ public static readonly DerObjectIdentifier SecP128r2 = new DerObjectIdentifier(EllipticCurve + ".29");
+ public static readonly DerObjectIdentifier SecP160r2 = new DerObjectIdentifier(EllipticCurve + ".30");
+ public static readonly DerObjectIdentifier SecP192k1 = new DerObjectIdentifier(EllipticCurve + ".31");
+ public static readonly DerObjectIdentifier SecP224k1 = new DerObjectIdentifier(EllipticCurve + ".32");
+ public static readonly DerObjectIdentifier SecP224r1 = new DerObjectIdentifier(EllipticCurve + ".33");
+ public static readonly DerObjectIdentifier SecP384r1 = new DerObjectIdentifier(EllipticCurve + ".34");
+ public static readonly DerObjectIdentifier SecP521r1 = new DerObjectIdentifier(EllipticCurve + ".35");
+ public static readonly DerObjectIdentifier SecT409k1 = new DerObjectIdentifier(EllipticCurve + ".36");
+ public static readonly DerObjectIdentifier SecT409r1 = new DerObjectIdentifier(EllipticCurve + ".37");
+ public static readonly DerObjectIdentifier SecT571k1 = new DerObjectIdentifier(EllipticCurve + ".38");
+ public static readonly DerObjectIdentifier SecT571r1 = new DerObjectIdentifier(EllipticCurve + ".39");
+
+ public static readonly DerObjectIdentifier SecP192r1 = X9ObjectIdentifiers.Prime192v1;
+ public static readonly DerObjectIdentifier SecP256r1 = X9ObjectIdentifiers.Prime256v1;
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/asn1/smime/SMIMEAttributes.cs b/bc-sharp-crypto/src/asn1/smime/SMIMEAttributes.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e154e5e742ee6cf61741d0fc42791cb56ca9870f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/smime/SMIMEAttributes.cs
@@ -0,0 +1,11 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Smime
+{
+ public abstract class SmimeAttributes
+ {
+ public static readonly DerObjectIdentifier SmimeCapabilities = PkcsObjectIdentifiers.Pkcs9AtSmimeCapabilities;
+ public static readonly DerObjectIdentifier EncrypKeyPref = PkcsObjectIdentifiers.IdAAEncrypKeyPref;
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/smime/SMIMECapabilities.cs b/bc-sharp-crypto/src/asn1/smime/SMIMECapabilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5bf48f32185286768c8ecfd2c61600f9ec872944
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/smime/SMIMECapabilities.cs
@@ -0,0 +1,134 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Smime
+{
+ /**
+ * Handler class for dealing with S/MIME Capabilities
+ */
+ public class SmimeCapabilities
+ : Asn1Encodable
+ {
+ /**
+ * general preferences
+ */
+ public static readonly DerObjectIdentifier PreferSignedData = PkcsObjectIdentifiers.PreferSignedData;
+ public static readonly DerObjectIdentifier CannotDecryptAny = PkcsObjectIdentifiers.CannotDecryptAny;
+ public static readonly DerObjectIdentifier SmimeCapabilitesVersions = PkcsObjectIdentifiers.SmimeCapabilitiesVersions;
+
+ /**
+ * encryption algorithms preferences
+ */
+ public static readonly DerObjectIdentifier Aes256Cbc = NistObjectIdentifiers.IdAes256Cbc;
+ public static readonly DerObjectIdentifier Aes192Cbc = NistObjectIdentifiers.IdAes192Cbc;
+ public static readonly DerObjectIdentifier Aes128Cbc = NistObjectIdentifiers.IdAes128Cbc;
+ public static readonly DerObjectIdentifier IdeaCbc = new DerObjectIdentifier("1.3.6.1.4.1.188.7.1.1.2");
+ public static readonly DerObjectIdentifier Cast5Cbc = new DerObjectIdentifier("1.2.840.113533.7.66.10");
+ public static readonly DerObjectIdentifier DesCbc = new DerObjectIdentifier("1.3.14.3.2.7");
+ public static readonly DerObjectIdentifier DesEde3Cbc = PkcsObjectIdentifiers.DesEde3Cbc;
+ public static readonly DerObjectIdentifier RC2Cbc = PkcsObjectIdentifiers.RC2Cbc;
+
+ private Asn1Sequence capabilities;
+
+ /**
+ * return an Attr object from the given object.
+ *
+ * @param o the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static SmimeCapabilities GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is SmimeCapabilities)
+ {
+ return (SmimeCapabilities) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new SmimeCapabilities((Asn1Sequence) obj);
+ }
+
+ if (obj is AttributeX509)
+ {
+ return new SmimeCapabilities(
+ (Asn1Sequence)(((AttributeX509) obj).AttrValues[0]));
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public SmimeCapabilities(
+ Asn1Sequence seq)
+ {
+ capabilities = seq;
+ }
+
+#if !(SILVERLIGHT || PORTABLE)
+ [Obsolete("Use 'GetCapabilitiesForOid' instead")]
+ public ArrayList GetCapabilities(
+ DerObjectIdentifier capability)
+ {
+ ArrayList list = new ArrayList();
+ DoGetCapabilitiesForOid(capability, list);
+ return list;
+ }
+#endif
+
+ /**
+ * returns an ArrayList with 0 or more objects of all the capabilities
+ * matching the passed in capability Oid. If the Oid passed is null the
+ * entire set is returned.
+ */
+ public IList GetCapabilitiesForOid(
+ DerObjectIdentifier capability)
+ {
+ IList list = Platform.CreateArrayList();
+ DoGetCapabilitiesForOid(capability, list);
+ return list;
+ }
+
+ private void DoGetCapabilitiesForOid(DerObjectIdentifier capability, IList list)
+ {
+ if (capability == null)
+ {
+ foreach (object o in capabilities)
+ {
+ SmimeCapability cap = SmimeCapability.GetInstance(o);
+
+ list.Add(cap);
+ }
+ }
+ else
+ {
+ foreach (object o in capabilities)
+ {
+ SmimeCapability cap = SmimeCapability.GetInstance(o);
+
+ if (capability.Equals(cap.CapabilityID))
+ {
+ list.Add(cap);
+ }
+ }
+ }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * SMIMECapabilities ::= Sequence OF SMIMECapability
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return capabilities;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/smime/SMIMECapabilitiesAttribute.cs b/bc-sharp-crypto/src/asn1/smime/SMIMECapabilitiesAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..310c478feb5dd4667098e92927d4098878e6727b
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/smime/SMIMECapabilitiesAttribute.cs
@@ -0,0 +1,16 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Smime
+{
+ public class SmimeCapabilitiesAttribute
+ : AttributeX509
+ {
+ public SmimeCapabilitiesAttribute(
+ SmimeCapabilityVector capabilities)
+ : base(SmimeAttributes.SmimeCapabilities,
+ new DerSet(new DerSequence(capabilities.ToAsn1EncodableVector())))
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/smime/SMIMECapability.cs b/bc-sharp-crypto/src/asn1/smime/SMIMECapability.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5709cb81548f8a736140d69eb6b9fdda93779177
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/smime/SMIMECapability.cs
@@ -0,0 +1,101 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Smime
+{
+ public class SmimeCapability
+ : Asn1Encodable
+ {
+ /**
+ * general preferences
+ */
+ public static readonly DerObjectIdentifier PreferSignedData = PkcsObjectIdentifiers.PreferSignedData;
+ public static readonly DerObjectIdentifier CannotDecryptAny = PkcsObjectIdentifiers.CannotDecryptAny;
+ public static readonly DerObjectIdentifier SmimeCapabilitiesVersions = PkcsObjectIdentifiers.SmimeCapabilitiesVersions;
+
+ /**
+ * encryption algorithms preferences
+ */
+ public static readonly DerObjectIdentifier DesCbc = new DerObjectIdentifier("1.3.14.3.2.7");
+ public static readonly DerObjectIdentifier DesEde3Cbc = PkcsObjectIdentifiers.DesEde3Cbc;
+ public static readonly DerObjectIdentifier RC2Cbc = PkcsObjectIdentifiers.RC2Cbc;
+
+ private DerObjectIdentifier capabilityID;
+ private Asn1Object parameters;
+
+ public SmimeCapability(
+ Asn1Sequence seq)
+ {
+ capabilityID = (DerObjectIdentifier) seq[0].ToAsn1Object();
+
+ if (seq.Count > 1)
+ {
+ parameters = seq[1].ToAsn1Object();
+ }
+ }
+
+ public SmimeCapability(
+ DerObjectIdentifier capabilityID,
+ Asn1Encodable parameters)
+ {
+ if (capabilityID == null)
+ throw new ArgumentNullException("capabilityID");
+
+ this.capabilityID = capabilityID;
+
+ if (parameters != null)
+ {
+ this.parameters = parameters.ToAsn1Object();
+ }
+ }
+
+ public static SmimeCapability GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is SmimeCapability)
+ {
+ return (SmimeCapability) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new SmimeCapability((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("Invalid SmimeCapability");
+ }
+
+ public DerObjectIdentifier CapabilityID
+ {
+ get { return capabilityID; }
+ }
+
+ public Asn1Object Parameters
+ {
+ get { return parameters; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * SMIMECapability ::= Sequence {
+ * capabilityID OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY capabilityID OPTIONAL
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(capabilityID);
+
+ if (parameters != null)
+ {
+ v.Add(parameters);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/smime/SMIMECapabilityVector.cs b/bc-sharp-crypto/src/asn1/smime/SMIMECapabilityVector.cs
new file mode 100644
index 0000000000000000000000000000000000000000..842825b882dc8c1473158d92fafcbb94ee4992df
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/smime/SMIMECapabilityVector.cs
@@ -0,0 +1,37 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Smime
+{
+ /**
+ * Handler for creating a vector S/MIME Capabilities
+ */
+ public class SmimeCapabilityVector
+ {
+ private readonly Asn1EncodableVector capabilities = new Asn1EncodableVector();
+
+ public void AddCapability(
+ DerObjectIdentifier capability)
+ {
+ capabilities.Add(new DerSequence(capability));
+ }
+
+ public void AddCapability(
+ DerObjectIdentifier capability,
+ int value)
+ {
+ capabilities.Add(new DerSequence(capability, new DerInteger(value)));
+ }
+
+ public void AddCapability(
+ DerObjectIdentifier capability,
+ Asn1Encodable parameters)
+ {
+ capabilities.Add(new DerSequence(capability, parameters));
+ }
+
+ public Asn1EncodableVector ToAsn1EncodableVector()
+ {
+ return capabilities;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.cs b/bc-sharp-crypto/src/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..19c5fd78a82aead95de5d822e13dd5f9d2b2bfd7
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.cs
@@ -0,0 +1,44 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Smime
+{
+ /**
+ * The SmimeEncryptionKeyPreference object.
+ *
+ * SmimeEncryptionKeyPreference ::= CHOICE {
+ * issuerAndSerialNumber [0] IssuerAndSerialNumber,
+ * receipentKeyId [1] RecipientKeyIdentifier,
+ * subjectAltKeyIdentifier [2] SubjectKeyIdentifier
+ * }
+ *
+ */
+ public class SmimeEncryptionKeyPreferenceAttribute
+ : AttributeX509
+ {
+ public SmimeEncryptionKeyPreferenceAttribute(
+ IssuerAndSerialNumber issAndSer)
+ : base(SmimeAttributes.EncrypKeyPref,
+ new DerSet(new DerTaggedObject(false, 0, issAndSer)))
+ {
+ }
+
+ public SmimeEncryptionKeyPreferenceAttribute(
+ RecipientKeyIdentifier rKeyID)
+ : base(SmimeAttributes.EncrypKeyPref,
+ new DerSet(new DerTaggedObject(false, 1, rKeyID)))
+ {
+ }
+
+ /**
+ * @param sKeyId the subjectKeyIdentifier value (normally the X.509 one)
+ */
+ public SmimeEncryptionKeyPreferenceAttribute(
+ Asn1OctetString sKeyID)
+ : base(SmimeAttributes.EncrypKeyPref,
+ new DerSet(new DerTaggedObject(false, 2, sKeyID)))
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs b/bc-sharp-crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9a82db319217c75af411573995c37baefe75a849
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
@@ -0,0 +1,470 @@
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.TeleTrust
+{
+ /**
+ * elliptic curves defined in "ECC Brainpool Standard Curves and Curve Generation"
+ * http://www.ecc-brainpool.org/download/draft_pkix_additional_ecc_dp.txt
+ */
+ public class TeleTrusTNamedCurves
+ {
+ private static ECCurve ConfigureCurve(ECCurve curve)
+ {
+ return curve;
+ }
+
+ internal class BrainpoolP160r1Holder
+ : X9ECParametersHolder
+ {
+ private BrainpoolP160r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new BrainpoolP160r1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("E95E4A5F737059DC60DF5991D45029409E60FC09", 16);
+ BigInteger h = new BigInteger("01", 16);
+
+ ECCurve curve = ConfigureCurve(new FpCurve(
+ new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620F", 16), // q
+ new BigInteger("340E7BE2A280EB74E2BE61BADA745D97E8F7C300", 16), // a
+ new BigInteger("1E589A8595423412134FAA2DBDEC95C8D8675E58", 16), // b
+ n, h));
+
+ return new X9ECParameters(
+ curve,
+ new X9ECPoint(curve, Hex.Decode("04BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC31667CB477A1A8EC338F94741669C976316DA6321")), // G
+ n, h);
+ }
+ }
+
+ internal class BrainpoolP160t1Holder
+ : X9ECParametersHolder
+ {
+ private BrainpoolP160t1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new BrainpoolP160t1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("E95E4A5F737059DC60DF5991D45029409E60FC09", 16);
+ BigInteger h = new BigInteger("01", 16);
+
+ ECCurve curve = ConfigureCurve(new FpCurve(
+ // new BigInteger("24DBFF5DEC9B986BBFE5295A29BFBAE45E0F5D0B", 16), // Z
+ new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620F", 16), // q
+ new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620C", 16), // a'
+ new BigInteger("7A556B6DAE535B7B51ED2C4D7DAA7A0B5C55F380", 16), // b'
+ n, h));
+
+ return new X9ECParameters(
+ curve,
+ new X9ECPoint(curve, Hex.Decode("04B199B13B9B34EFC1397E64BAEB05ACC265FF2378ADD6718B7C7C1961F0991B842443772152C9E0AD")), // G
+ n, h);
+ }
+ }
+
+ internal class BrainpoolP192r1Holder
+ : X9ECParametersHolder
+ {
+ private BrainpoolP192r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new BrainpoolP192r1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", 16);
+ BigInteger h = new BigInteger("01", 16);
+
+ ECCurve curve = ConfigureCurve(new FpCurve(
+ new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", 16), // q
+ new BigInteger("6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF", 16), // a
+ new BigInteger("469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9", 16), // b
+ n, h));
+
+ return new X9ECParameters(
+ curve,
+ new X9ECPoint(curve, Hex.Decode("04C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD614B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F")), // G
+ n, h);
+ }
+ }
+
+ internal class BrainpoolP192t1Holder
+ : X9ECParametersHolder
+ {
+ private BrainpoolP192t1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new BrainpoolP192t1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", 16);
+ BigInteger h = new BigInteger("01", 16);
+
+ ECCurve curve = ConfigureCurve(new FpCurve(
+ //new BigInteger("1B6F5CC8DB4DC7AF19458A9CB80DC2295E5EB9C3732104CB") //Z
+ new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", 16), // q
+ new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86294", 16), // a'
+ new BigInteger("13D56FFAEC78681E68F9DEB43B35BEC2FB68542E27897B79", 16), // b'
+ n, h));
+
+ return new X9ECParameters(
+ curve,
+ new X9ECPoint(curve, Hex.Decode("043AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9")), // G'
+ n, h);
+ }
+ }
+
+ internal class BrainpoolP224r1Holder
+ : X9ECParametersHolder
+ {
+ private BrainpoolP224r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new BrainpoolP224r1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", 16);
+ BigInteger h = new BigInteger("01", 16);
+
+ ECCurve curve = ConfigureCurve(new FpCurve(
+ new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", 16), // q
+ new BigInteger("68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43", 16), // a
+ new BigInteger("2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B", 16), // b
+ n, h));
+
+ return new X9ECParameters(
+ curve,
+ new X9ECPoint(curve, Hex.Decode("040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD")), // G
+ n, h);
+ }
+ }
+
+ internal class BrainpoolP224t1Holder
+ : X9ECParametersHolder
+ {
+ private BrainpoolP224t1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new BrainpoolP224t1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", 16);
+ BigInteger h = new BigInteger("01", 16);
+
+ ECCurve curve = ConfigureCurve(new FpCurve(
+ //new BigInteger("2DF271E14427A346910CF7A2E6CFA7B3F484E5C2CCE1C8B730E28B3F") //Z
+ new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", 16), // q
+ new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FC", 16), // a'
+ new BigInteger("4B337D934104CD7BEF271BF60CED1ED20DA14C08B3BB64F18A60888D", 16), // b'
+ n, h));
+
+ return new X9ECParameters(
+ curve,
+ new X9ECPoint(curve, Hex.Decode("046AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D5800374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C")), // G'
+ n, h);
+ }
+ }
+
+ internal class BrainpoolP256r1Holder
+ : X9ECParametersHolder
+ {
+ private BrainpoolP256r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new BrainpoolP256r1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16);
+ BigInteger h = new BigInteger("01", 16);
+
+ ECCurve curve = ConfigureCurve(new FpCurve(
+ new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16), // q
+ new BigInteger("7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", 16), // a
+ new BigInteger("26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", 16), // b
+ n, h));
+
+ return new X9ECParameters(
+ curve,
+ new X9ECPoint(curve, Hex.Decode("048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997")), // G
+ n, h);
+ }
+ }
+
+ internal class BrainpoolP256t1Holder
+ : X9ECParametersHolder
+ {
+ private BrainpoolP256t1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new BrainpoolP256t1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16);
+ BigInteger h = new BigInteger("01", 16);
+
+ ECCurve curve = ConfigureCurve(new FpCurve(
+ //new BigInteger("3E2D4BD9597B58639AE7AA669CAB9837CF5CF20A2C852D10F655668DFC150EF0") //Z
+ new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16), // q
+ new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5374", 16), // a'
+ new BigInteger("662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04", 16), // b'
+ n, h));
+
+ return new X9ECParameters(
+ curve,
+ new X9ECPoint(curve, Hex.Decode("04A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F42D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE")), // G'
+ n, h);
+ }
+ }
+
+ internal class BrainpoolP320r1Holder
+ : X9ECParametersHolder
+ {
+ private BrainpoolP320r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new BrainpoolP320r1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", 16);
+ BigInteger h = new BigInteger("01", 16);
+
+ ECCurve curve = ConfigureCurve(new FpCurve(
+ new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", 16), // q
+ new BigInteger("3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4", 16), // a
+ new BigInteger("520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6", 16), // b
+ n, h));
+
+ return new X9ECParameters(
+ curve,
+ new X9ECPoint(curve, Hex.Decode("0443BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E2061114FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1")), // G
+ n, h);
+ }
+ }
+
+ internal class BrainpoolP320t1Holder
+ : X9ECParametersHolder
+ {
+ private BrainpoolP320t1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new BrainpoolP320t1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", 16);
+ BigInteger h = new BigInteger("01", 16);
+
+ ECCurve curve = ConfigureCurve(new FpCurve(
+ //new BigInteger("15F75CAF668077F7E85B42EB01F0A81FF56ECD6191D55CB82B7D861458A18FEFC3E5AB7496F3C7B1") //Z
+ new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", 16), // q
+ new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E24", 16), // a'
+ new BigInteger("A7F561E038EB1ED560B3D147DB782013064C19F27ED27C6780AAF77FB8A547CEB5B4FEF422340353", 16), // b'
+ n, h));
+
+ return new X9ECParameters(
+ curve,
+ new X9ECPoint(curve, Hex.Decode("04925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF3357F624A21BED5263BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B1B9BC0455FB0D2C3")), // G'
+ n, h);
+ }
+ }
+
+ internal class BrainpoolP384r1Holder
+ : X9ECParametersHolder
+ {
+ private BrainpoolP384r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new BrainpoolP384r1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16);
+ BigInteger h = new BigInteger("01", 16);
+
+ ECCurve curve = ConfigureCurve(new FpCurve(
+ new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16), // q
+ new BigInteger("7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826", 16), // a
+ new BigInteger("4A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11", 16), // b
+ n, h));
+
+ return new X9ECParameters(
+ curve,
+ new X9ECPoint(curve, Hex.Decode("041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315")), // G
+ n, h);
+ }
+ }
+
+ internal class BrainpoolP384t1Holder
+ : X9ECParametersHolder
+ {
+ private BrainpoolP384t1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new BrainpoolP384t1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16);
+ BigInteger h = new BigInteger("01", 16);
+
+ ECCurve curve = ConfigureCurve(new FpCurve(
+ //new BigInteger("41DFE8DD399331F7166A66076734A89CD0D2BCDB7D068E44E1F378F41ECBAE97D2D63DBC87BCCDDCCC5DA39E8589291C") //Z
+ new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16), // q
+ new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC50", 16), // a'
+ new BigInteger("7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B88805CED70355A33B471EE", 16), // b'
+ n, h));
+
+ return new X9ECParameters(
+ curve,
+ new X9ECPoint(curve, Hex.Decode("0418DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928")), // G'
+ n, h);
+ }
+ }
+
+ internal class BrainpoolP512r1Holder
+ : X9ECParametersHolder
+ {
+ private BrainpoolP512r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new BrainpoolP512r1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16);
+ BigInteger h = new BigInteger("01", 16);
+
+ ECCurve curve = ConfigureCurve(new FpCurve(
+ new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16), // q
+ new BigInteger("7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA", 16), // a
+ new BigInteger("3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723", 16), // b
+ n, h));
+
+ return new X9ECParameters(
+ curve,
+ new X9ECPoint(curve, Hex.Decode("0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892")), // G
+ n, h);
+ }
+ }
+
+ internal class BrainpoolP512t1Holder
+ : X9ECParametersHolder
+ {
+ private BrainpoolP512t1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new BrainpoolP512t1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16);
+ BigInteger h = new BigInteger("01", 16);
+
+ ECCurve curve = ConfigureCurve(new FpCurve(
+ //new BigInteger("12EE58E6764838B69782136F0F2D3BA06E27695716054092E60A80BEDB212B64E585D90BCE13761F85C3F1D2A64E3BE8FEA2220F01EBA5EEB0F35DBD29D922AB") //Z
+ new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16), // q
+ new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F0", 16), // a'
+ new BigInteger("7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA2304976540F6450085F2DAE145C22553B465763689180EA2571867423E", 16), // b'
+ n, h));
+
+ return new X9ECParameters(
+ curve,
+ new X9ECPoint(curve, Hex.Decode("04640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332")), // G'
+ n, h);
+ }
+ }
+
+
+ private static readonly IDictionary objIds = Platform.CreateHashtable();
+ private static readonly IDictionary curves = Platform.CreateHashtable();
+ private static readonly IDictionary names = Platform.CreateHashtable();
+
+ private static void DefineCurve(
+ string name,
+ DerObjectIdentifier oid,
+ X9ECParametersHolder holder)
+ {
+ objIds.Add(Platform.ToUpperInvariant(name), oid);
+ names.Add(oid, name);
+ curves.Add(oid, holder);
+ }
+
+ static TeleTrusTNamedCurves()
+ {
+ DefineCurve("brainpoolP160r1", TeleTrusTObjectIdentifiers.BrainpoolP160R1, BrainpoolP160r1Holder.Instance);
+ DefineCurve("brainpoolP160t1", TeleTrusTObjectIdentifiers.BrainpoolP160T1, BrainpoolP160t1Holder.Instance);
+ DefineCurve("brainpoolP192r1", TeleTrusTObjectIdentifiers.BrainpoolP192R1, BrainpoolP192r1Holder.Instance);
+ DefineCurve("brainpoolP192t1", TeleTrusTObjectIdentifiers.BrainpoolP192T1, BrainpoolP192t1Holder.Instance);
+ DefineCurve("brainpoolP224r1", TeleTrusTObjectIdentifiers.BrainpoolP224R1, BrainpoolP224r1Holder.Instance);
+ DefineCurve("brainpoolP224t1", TeleTrusTObjectIdentifiers.BrainpoolP224T1, BrainpoolP224t1Holder.Instance);
+ DefineCurve("brainpoolP256r1", TeleTrusTObjectIdentifiers.BrainpoolP256R1, BrainpoolP256r1Holder.Instance);
+ DefineCurve("brainpoolP256t1", TeleTrusTObjectIdentifiers.BrainpoolP256T1, BrainpoolP256t1Holder.Instance);
+ DefineCurve("brainpoolP320r1", TeleTrusTObjectIdentifiers.BrainpoolP320R1, BrainpoolP320r1Holder.Instance);
+ DefineCurve("brainpoolP320t1", TeleTrusTObjectIdentifiers.BrainpoolP320T1, BrainpoolP320t1Holder.Instance);
+ DefineCurve("brainpoolP384r1", TeleTrusTObjectIdentifiers.BrainpoolP384R1, BrainpoolP384r1Holder.Instance);
+ DefineCurve("brainpoolP384t1", TeleTrusTObjectIdentifiers.BrainpoolP384T1, BrainpoolP384t1Holder.Instance);
+ DefineCurve("brainpoolP512r1", TeleTrusTObjectIdentifiers.BrainpoolP512R1, BrainpoolP512r1Holder.Instance);
+ DefineCurve("brainpoolP512t1", TeleTrusTObjectIdentifiers.BrainpoolP512T1, BrainpoolP512t1Holder.Instance);
+ }
+
+ public static X9ECParameters GetByName(
+ string name)
+ {
+ DerObjectIdentifier oid = GetOid(name);
+ return oid == null ? null : GetByOid(oid);
+ }
+
+ /**
+ * return the X9ECParameters object for the named curve represented by
+ * the passed in object identifier. Null if the curve isn't present.
+ *
+ * @param oid an object identifier representing a named curve, if present.
+ */
+ public static X9ECParameters GetByOid(
+ DerObjectIdentifier oid)
+ {
+ X9ECParametersHolder holder = (X9ECParametersHolder)curves[oid];
+ return holder == null ? null : holder.Parameters;
+ }
+
+ /**
+ * return the object identifier signified by the passed in name. Null
+ * if there is no object identifier associated with name.
+ *
+ * @return the object identifier associated with name, if present.
+ */
+ public static DerObjectIdentifier GetOid(
+ string name)
+ {
+ return (DerObjectIdentifier)objIds[Platform.ToUpperInvariant(name)];
+ }
+
+ /**
+ * return the named curve name represented by the given object identifier.
+ */
+ public static string GetName(
+ DerObjectIdentifier oid)
+ {
+ return (string)names[oid];
+ }
+
+ /**
+ * returns an enumeration containing the name strings for curves
+ * contained in this structure.
+ */
+ public static IEnumerable Names
+ {
+ get { return new EnumerableProxy(names.Values); }
+ }
+
+ public static DerObjectIdentifier GetOid(
+ short curvesize,
+ bool twisted)
+ {
+ return GetOid("brainpoolP" + curvesize + (twisted ? "t" : "r") + "1");
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/teletrust/TeleTrusTObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/teletrust/TeleTrusTObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..56e70842af9448382bb1ffce2eca5c89bb2f189f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/teletrust/TeleTrusTObjectIdentifiers.cs
@@ -0,0 +1,45 @@
+namespace Org.BouncyCastle.Asn1.TeleTrust
+{
+ public sealed class TeleTrusTObjectIdentifiers
+ {
+ private TeleTrusTObjectIdentifiers()
+ {
+ }
+
+ public static readonly DerObjectIdentifier TeleTrusTAlgorithm = new DerObjectIdentifier("1.3.36.3");
+
+ public static readonly DerObjectIdentifier RipeMD160 = new DerObjectIdentifier(TeleTrusTAlgorithm + ".2.1");
+ public static readonly DerObjectIdentifier RipeMD128 = new DerObjectIdentifier(TeleTrusTAlgorithm + ".2.2");
+ public static readonly DerObjectIdentifier RipeMD256 = new DerObjectIdentifier(TeleTrusTAlgorithm + ".2.3");
+
+ public static readonly DerObjectIdentifier TeleTrusTRsaSignatureAlgorithm = new DerObjectIdentifier(TeleTrusTAlgorithm + ".3.1");
+
+ public static readonly DerObjectIdentifier RsaSignatureWithRipeMD160 = new DerObjectIdentifier(TeleTrusTRsaSignatureAlgorithm + ".2");
+ public static readonly DerObjectIdentifier RsaSignatureWithRipeMD128 = new DerObjectIdentifier(TeleTrusTRsaSignatureAlgorithm + ".3");
+ public static readonly DerObjectIdentifier RsaSignatureWithRipeMD256 = new DerObjectIdentifier(TeleTrusTRsaSignatureAlgorithm + ".4");
+
+ public static readonly DerObjectIdentifier ECSign = new DerObjectIdentifier(TeleTrusTAlgorithm + ".3.2");
+
+ public static readonly DerObjectIdentifier ECSignWithSha1 = new DerObjectIdentifier(ECSign + ".1");
+ public static readonly DerObjectIdentifier ECSignWithRipeMD160 = new DerObjectIdentifier(ECSign + ".2");
+
+ public static readonly DerObjectIdentifier EccBrainpool = new DerObjectIdentifier(TeleTrusTAlgorithm + ".3.2.8");
+ public static readonly DerObjectIdentifier EllipticCurve = new DerObjectIdentifier(EccBrainpool + ".1");
+ public static readonly DerObjectIdentifier VersionOne = new DerObjectIdentifier(EllipticCurve + ".1");
+
+ public static readonly DerObjectIdentifier BrainpoolP160R1 = new DerObjectIdentifier(VersionOne + ".1");
+ public static readonly DerObjectIdentifier BrainpoolP160T1 = new DerObjectIdentifier(VersionOne + ".2");
+ public static readonly DerObjectIdentifier BrainpoolP192R1 = new DerObjectIdentifier(VersionOne + ".3");
+ public static readonly DerObjectIdentifier BrainpoolP192T1 = new DerObjectIdentifier(VersionOne + ".4");
+ public static readonly DerObjectIdentifier BrainpoolP224R1 = new DerObjectIdentifier(VersionOne + ".5");
+ public static readonly DerObjectIdentifier BrainpoolP224T1 = new DerObjectIdentifier(VersionOne + ".6");
+ public static readonly DerObjectIdentifier BrainpoolP256R1 = new DerObjectIdentifier(VersionOne + ".7");
+ public static readonly DerObjectIdentifier BrainpoolP256T1 = new DerObjectIdentifier(VersionOne + ".8");
+ public static readonly DerObjectIdentifier BrainpoolP320R1 = new DerObjectIdentifier(VersionOne + ".9");
+ public static readonly DerObjectIdentifier BrainpoolP320T1 = new DerObjectIdentifier(VersionOne + ".10");
+ public static readonly DerObjectIdentifier BrainpoolP384R1 = new DerObjectIdentifier(VersionOne + ".11");
+ public static readonly DerObjectIdentifier BrainpoolP384T1 = new DerObjectIdentifier(VersionOne + ".12");
+ public static readonly DerObjectIdentifier BrainpoolP512R1 = new DerObjectIdentifier(VersionOne + ".13");
+ public static readonly DerObjectIdentifier BrainpoolP512T1 = new DerObjectIdentifier(VersionOne + ".14");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/tsp/Accuracy.cs b/bc-sharp-crypto/src/asn1/tsp/Accuracy.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9f2c7e8cccbe9b70343f56a38cf64e450ed3a161
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/tsp/Accuracy.cs
@@ -0,0 +1,151 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+ public class Accuracy
+ : Asn1Encodable
+ {
+ private readonly DerInteger seconds;
+ private readonly DerInteger millis;
+ private readonly DerInteger micros;
+
+ // constants
+ protected const int MinMillis = 1;
+ protected const int MaxMillis = 999;
+ protected const int MinMicros = 1;
+ protected const int MaxMicros = 999;
+
+ public Accuracy(
+ DerInteger seconds,
+ DerInteger millis,
+ DerInteger micros)
+ {
+ //Verifications
+ if (millis != null
+ && (millis.Value.IntValue < MinMillis
+ || millis.Value.IntValue > MaxMillis))
+ {
+ throw new ArgumentException(
+ "Invalid millis field : not in (1..999)");
+ }
+
+ if (micros != null
+ && (micros.Value.IntValue < MinMicros
+ || micros.Value.IntValue > MaxMicros))
+ {
+ throw new ArgumentException(
+ "Invalid micros field : not in (1..999)");
+ }
+
+ this.seconds = seconds;
+ this.millis = millis;
+ this.micros = micros;
+ }
+
+ private Accuracy(
+ Asn1Sequence seq)
+ {
+ for (int i = 0; i < seq.Count; ++i)
+ {
+ // seconds
+ if (seq[i] is DerInteger)
+ {
+ seconds = (DerInteger) seq[i];
+ }
+ else if (seq[i] is DerTaggedObject)
+ {
+ DerTaggedObject extra = (DerTaggedObject) seq[i];
+
+ switch (extra.TagNo)
+ {
+ case 0:
+ millis = DerInteger.GetInstance(extra, false);
+ if (millis.Value.IntValue < MinMillis
+ || millis.Value.IntValue > MaxMillis)
+ {
+ throw new ArgumentException(
+ "Invalid millis field : not in (1..999).");
+ }
+ break;
+ case 1:
+ micros = DerInteger.GetInstance(extra, false);
+ if (micros.Value.IntValue < MinMicros
+ || micros.Value.IntValue > MaxMicros)
+ {
+ throw new ArgumentException(
+ "Invalid micros field : not in (1..999).");
+ }
+ break;
+ default:
+ throw new ArgumentException("Invalig tag number");
+ }
+ }
+ }
+ }
+
+ public static Accuracy GetInstance(
+ object o)
+ {
+ if (o == null || o is Accuracy)
+ {
+ return (Accuracy) o;
+ }
+
+ if (o is Asn1Sequence)
+ {
+ return new Accuracy((Asn1Sequence) o);
+ }
+
+ throw new ArgumentException(
+ "Unknown object in 'Accuracy' factory: " + Platform.GetTypeName(o));
+ }
+
+ public DerInteger Seconds
+ {
+ get { return seconds; }
+ }
+
+ public DerInteger Millis
+ {
+ get { return millis; }
+ }
+
+ public DerInteger Micros
+ {
+ get { return micros; }
+ }
+
+ /**
+ *
+ * Accuracy ::= SEQUENCE {
+ * seconds INTEGER OPTIONAL,
+ * millis [0] INTEGER (1..999) OPTIONAL,
+ * micros [1] INTEGER (1..999) OPTIONAL
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (seconds != null)
+ {
+ v.Add(seconds);
+ }
+
+ if (millis != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, millis));
+ }
+
+ if (micros != null)
+ {
+ v.Add(new DerTaggedObject(false, 1, micros));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/tsp/MessageImprint.cs b/bc-sharp-crypto/src/asn1/tsp/MessageImprint.cs
new file mode 100644
index 0000000000000000000000000000000000000000..44ef7d17754432e6fb473c9b3ca056bcda076b80
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/tsp/MessageImprint.cs
@@ -0,0 +1,75 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+ public class MessageImprint
+ : Asn1Encodable
+ {
+ private readonly AlgorithmIdentifier hashAlgorithm;
+ private readonly byte[] hashedMessage;
+
+ /**
+ * @param o
+ * @return a MessageImprint object.
+ */
+ public static MessageImprint GetInstance(
+ object o)
+ {
+ if (o == null || o is MessageImprint)
+ {
+ return (MessageImprint) o;
+ }
+
+ if (o is Asn1Sequence)
+ {
+ return new MessageImprint((Asn1Sequence) o);
+ }
+
+ throw new ArgumentException(
+ "Unknown object in 'MessageImprint' factory: " + Platform.GetTypeName(o));
+ }
+
+ private MessageImprint(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]);
+ this.hashedMessage = Asn1OctetString.GetInstance(seq[1]).GetOctets();
+ }
+
+ public MessageImprint(
+ AlgorithmIdentifier hashAlgorithm,
+ byte[] hashedMessage)
+ {
+ this.hashAlgorithm = hashAlgorithm;
+ this.hashedMessage = hashedMessage;
+ }
+
+ public AlgorithmIdentifier HashAlgorithm
+ {
+ get { return hashAlgorithm; }
+ }
+
+ public byte[] GetHashedMessage()
+ {
+ return hashedMessage;
+ }
+
+ /**
+ *
+ * MessageImprint ::= SEQUENCE {
+ * hashAlgorithm AlgorithmIdentifier,
+ * hashedMessage OCTET STRING }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(hashAlgorithm, new DerOctetString(hashedMessage));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/tsp/TSTInfo.cs b/bc-sharp-crypto/src/asn1/tsp/TSTInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..89f3e8b38be66389376e437eac7ffb927d28f360
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/tsp/TSTInfo.cs
@@ -0,0 +1,250 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+ public class TstInfo
+ : Asn1Encodable
+ {
+ private readonly DerInteger version;
+ private readonly DerObjectIdentifier tsaPolicyId;
+ private readonly MessageImprint messageImprint;
+ private readonly DerInteger serialNumber;
+ private readonly DerGeneralizedTime genTime;
+ private readonly Accuracy accuracy;
+ private readonly DerBoolean ordering;
+ private readonly DerInteger nonce;
+ private readonly GeneralName tsa;
+ private readonly X509Extensions extensions;
+
+ public static TstInfo GetInstance(
+ object o)
+ {
+ if (o == null || o is TstInfo)
+ {
+ return (TstInfo) o;
+ }
+
+ if (o is Asn1Sequence)
+ {
+ return new TstInfo((Asn1Sequence) o);
+ }
+
+ if (o is Asn1OctetString)
+ {
+ try
+ {
+ byte[] octets = ((Asn1OctetString)o).GetOctets();
+ return GetInstance(Asn1Object.FromByteArray(octets));
+ }
+ catch (IOException)
+ {
+ throw new ArgumentException(
+ "Bad object format in 'TstInfo' factory.");
+ }
+ }
+
+ throw new ArgumentException(
+ "Unknown object in 'TstInfo' factory: " + Platform.GetTypeName(o));
+ }
+
+ private TstInfo(
+ Asn1Sequence seq)
+ {
+ IEnumerator e = seq.GetEnumerator();
+
+ // version
+ e.MoveNext();
+ version = DerInteger.GetInstance(e.Current);
+
+ // tsaPolicy
+ e.MoveNext();
+ tsaPolicyId = DerObjectIdentifier.GetInstance(e.Current);
+
+ // messageImprint
+ e.MoveNext();
+ messageImprint = MessageImprint.GetInstance(e.Current);
+
+ // serialNumber
+ e.MoveNext();
+ serialNumber = DerInteger.GetInstance(e.Current);
+
+ // genTime
+ e.MoveNext();
+ genTime = DerGeneralizedTime.GetInstance(e.Current);
+
+ // default for ordering
+ ordering = DerBoolean.False;
+
+ while (e.MoveNext())
+ {
+ Asn1Object o = (Asn1Object) e.Current;
+
+ if (o is Asn1TaggedObject)
+ {
+ DerTaggedObject tagged = (DerTaggedObject) o;
+
+ switch (tagged.TagNo)
+ {
+ case 0:
+ tsa = GeneralName.GetInstance(tagged, true);
+ break;
+ case 1:
+ extensions = X509Extensions.GetInstance(tagged, false);
+ break;
+ default:
+ throw new ArgumentException("Unknown tag value " + tagged.TagNo);
+ }
+ }
+
+ if (o is DerSequence)
+ {
+ accuracy = Accuracy.GetInstance(o);
+ }
+
+ if (o is DerBoolean)
+ {
+ ordering = DerBoolean.GetInstance(o);
+ }
+
+ if (o is DerInteger)
+ {
+ nonce = DerInteger.GetInstance(o);
+ }
+ }
+ }
+
+ public TstInfo(
+ DerObjectIdentifier tsaPolicyId,
+ MessageImprint messageImprint,
+ DerInteger serialNumber,
+ DerGeneralizedTime genTime,
+ Accuracy accuracy,
+ DerBoolean ordering,
+ DerInteger nonce,
+ GeneralName tsa,
+ X509Extensions extensions)
+ {
+ this.version = new DerInteger(1);
+ this.tsaPolicyId = tsaPolicyId;
+ this.messageImprint = messageImprint;
+ this.serialNumber = serialNumber;
+ this.genTime = genTime;
+ this.accuracy = accuracy;
+ this.ordering = ordering;
+ this.nonce = nonce;
+ this.tsa = tsa;
+ this.extensions = extensions;
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public MessageImprint MessageImprint
+ {
+ get { return messageImprint; }
+ }
+
+ public DerObjectIdentifier Policy
+ {
+ get { return tsaPolicyId; }
+ }
+
+ public DerInteger SerialNumber
+ {
+ get { return serialNumber; }
+ }
+
+ public Accuracy Accuracy
+ {
+ get { return accuracy; }
+ }
+
+ public DerGeneralizedTime GenTime
+ {
+ get { return genTime; }
+ }
+
+ public DerBoolean Ordering
+ {
+ get { return ordering; }
+ }
+
+ public DerInteger Nonce
+ {
+ get { return nonce; }
+ }
+
+ public GeneralName Tsa
+ {
+ get { return tsa; }
+ }
+
+ public X509Extensions Extensions
+ {
+ get { return extensions; }
+ }
+
+ /**
+ *
+ *
+ * TstInfo ::= SEQUENCE {
+ * version INTEGER { v1(1) },
+ * policy TSAPolicyId,
+ * messageImprint MessageImprint,
+ * -- MUST have the same value as the similar field in
+ * -- TimeStampReq
+ * serialNumber INTEGER,
+ * -- Time-Stamping users MUST be ready to accommodate integers
+ * -- up to 160 bits.
+ * genTime GeneralizedTime,
+ * accuracy Accuracy OPTIONAL,
+ * ordering BOOLEAN DEFAULT FALSE,
+ * nonce INTEGER OPTIONAL,
+ * -- MUST be present if the similar field was present
+ * -- in TimeStampReq. In that case it MUST have the same value.
+ * tsa [0] GeneralName OPTIONAL,
+ * extensions [1] IMPLICIT Extensions OPTIONAL }
+ *
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ version, tsaPolicyId, messageImprint, serialNumber, genTime);
+
+ if (accuracy != null)
+ {
+ v.Add(accuracy);
+ }
+
+ if (ordering != null && ordering.IsTrue)
+ {
+ v.Add(ordering);
+ }
+
+ if (nonce != null)
+ {
+ v.Add(nonce);
+ }
+
+ if (tsa != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, tsa));
+ }
+
+ if (extensions != null)
+ {
+ v.Add(new DerTaggedObject(false, 1, extensions));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/tsp/TimeStampReq.cs b/bc-sharp-crypto/src/asn1/tsp/TimeStampReq.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5b05f33690b6e8e4c49a5196cece71ba46c3567c
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/tsp/TimeStampReq.cs
@@ -0,0 +1,165 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+ public class TimeStampReq
+ : Asn1Encodable
+ {
+ private readonly DerInteger version;
+ private readonly MessageImprint messageImprint;
+ private readonly DerObjectIdentifier tsaPolicy;
+ private readonly DerInteger nonce;
+ private readonly DerBoolean certReq;
+ private readonly X509Extensions extensions;
+
+ public static TimeStampReq GetInstance(
+ object o)
+ {
+ if (o == null || o is TimeStampReq)
+ {
+ return (TimeStampReq) o;
+ }
+
+ if (o is Asn1Sequence)
+ {
+ return new TimeStampReq((Asn1Sequence) o);
+ }
+
+ throw new ArgumentException(
+ "Unknown object in 'TimeStampReq' factory: " + Platform.GetTypeName(o));
+ }
+
+ private TimeStampReq(
+ Asn1Sequence seq)
+ {
+ int nbObjects = seq.Count;
+ int seqStart = 0;
+
+ // version
+ version = DerInteger.GetInstance(seq[seqStart++]);
+
+ // messageImprint
+ messageImprint = MessageImprint.GetInstance(seq[seqStart++]);
+
+ for (int opt = seqStart; opt < nbObjects; opt++)
+ {
+ // tsaPolicy
+ if (seq[opt] is DerObjectIdentifier)
+ {
+ tsaPolicy = DerObjectIdentifier.GetInstance(seq[opt]);
+ }
+ // nonce
+ else if (seq[opt] is DerInteger)
+ {
+ nonce = DerInteger.GetInstance(seq[opt]);
+ }
+ // certReq
+ else if (seq[opt] is DerBoolean)
+ {
+ certReq = DerBoolean.GetInstance(seq[opt]);
+ }
+ // extensions
+ else if (seq[opt] is Asn1TaggedObject)
+ {
+ Asn1TaggedObject tagged = (Asn1TaggedObject) seq[opt];
+ if (tagged.TagNo == 0)
+ {
+ extensions = X509Extensions.GetInstance(tagged, false);
+ }
+ }
+ }
+ }
+
+ public TimeStampReq(
+ MessageImprint messageImprint,
+ DerObjectIdentifier tsaPolicy,
+ DerInteger nonce,
+ DerBoolean certReq,
+ X509Extensions extensions)
+ {
+ // default
+ this.version = new DerInteger(1);
+
+ this.messageImprint = messageImprint;
+ this.tsaPolicy = tsaPolicy;
+ this.nonce = nonce;
+ this.certReq = certReq;
+ this.extensions = extensions;
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public MessageImprint MessageImprint
+ {
+ get { return messageImprint; }
+ }
+
+ public DerObjectIdentifier ReqPolicy
+ {
+ get { return tsaPolicy; }
+ }
+
+ public DerInteger Nonce
+ {
+ get { return nonce; }
+ }
+
+ public DerBoolean CertReq
+ {
+ get { return certReq; }
+ }
+
+ public X509Extensions Extensions
+ {
+ get { return extensions; }
+ }
+
+ /**
+ *
+ * TimeStampReq ::= SEQUENCE {
+ * version INTEGER { v1(1) },
+ * messageImprint MessageImprint,
+ * --a hash algorithm OID and the hash value of the data to be
+ * --time-stamped
+ * reqPolicy TSAPolicyId OPTIONAL,
+ * nonce INTEGER OPTIONAL,
+ * certReq BOOLEAN DEFAULT FALSE,
+ * extensions [0] IMPLICIT Extensions OPTIONAL
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ version, messageImprint);
+
+ if (tsaPolicy != null)
+ {
+ v.Add(tsaPolicy);
+ }
+
+ if (nonce != null)
+ {
+ v.Add(nonce);
+ }
+
+ if (certReq != null && certReq.IsTrue)
+ {
+ v.Add(certReq);
+ }
+
+ if (extensions != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, extensions));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/tsp/TimeStampResp.cs b/bc-sharp-crypto/src/asn1/tsp/TimeStampResp.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b91026064943e54348b98186f91cb1ff7c2c994d
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/tsp/TimeStampResp.cs
@@ -0,0 +1,80 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+ public class TimeStampResp
+ : Asn1Encodable
+ {
+ private readonly PkiStatusInfo pkiStatusInfo;
+ private readonly ContentInfo timeStampToken;
+
+ public static TimeStampResp GetInstance(
+ object o)
+ {
+ if (o == null || o is TimeStampResp)
+ {
+ return (TimeStampResp) o;
+ }
+
+ if (o is Asn1Sequence)
+ {
+ return new TimeStampResp((Asn1Sequence) o);
+ }
+
+ throw new ArgumentException(
+ "Unknown object in 'TimeStampResp' factory: " + Platform.GetTypeName(o));
+ }
+
+ private TimeStampResp(
+ Asn1Sequence seq)
+ {
+ this.pkiStatusInfo = PkiStatusInfo.GetInstance(seq[0]);
+
+ if (seq.Count > 1)
+ {
+ this.timeStampToken = ContentInfo.GetInstance(seq[1]);
+ }
+ }
+
+ public TimeStampResp(
+ PkiStatusInfo pkiStatusInfo,
+ ContentInfo timeStampToken)
+ {
+ this.pkiStatusInfo = pkiStatusInfo;
+ this.timeStampToken = timeStampToken;
+ }
+
+ public PkiStatusInfo Status
+ {
+ get { return pkiStatusInfo; }
+ }
+
+ public ContentInfo TimeStampToken
+ {
+ get { return timeStampToken; }
+ }
+
+ /**
+ *
+ * TimeStampResp ::= SEQUENCE {
+ * status PkiStatusInfo,
+ * timeStampToken TimeStampToken OPTIONAL }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(pkiStatusInfo);
+
+ if (timeStampToken != null)
+ {
+ v.Add(timeStampToken);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/util/Asn1Dump.cs b/bc-sharp-crypto/src/asn1/util/Asn1Dump.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6a21ee2af59e70377a26a9db9253917ca5f04439
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/util/Asn1Dump.cs
@@ -0,0 +1,381 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.Utilities
+{
+ public sealed class Asn1Dump
+ {
+ private static readonly string NewLine = Platform.NewLine;
+
+ private Asn1Dump()
+ {
+ }
+
+ private const string Tab = " ";
+ private const int SampleSize = 32;
+
+ /**
+ * dump a Der object as a formatted string with indentation
+ *
+ * @param obj the Asn1Object to be dumped out.
+ */
+ private static void AsString(
+ string indent,
+ bool verbose,
+ Asn1Object obj,
+ StringBuilder buf)
+ {
+ if (obj is Asn1Sequence)
+ {
+ string tab = indent + Tab;
+ buf.Append(indent);
+ if (obj is BerSequence)
+ {
+ buf.Append("BER Sequence");
+ }
+ else if (obj is DerSequence)
+ {
+ buf.Append("DER Sequence");
+ }
+ else
+ {
+ buf.Append("Sequence");
+ }
+
+ buf.Append(NewLine);
+
+ foreach (Asn1Encodable o in ((Asn1Sequence)obj))
+ {
+ if (o == null || o is Asn1Null)
+ {
+ buf.Append(tab);
+ buf.Append("NULL");
+ buf.Append(NewLine);
+ }
+ else
+ {
+ AsString(tab, verbose, o.ToAsn1Object(), buf);
+ }
+ }
+ }
+ else if (obj is DerTaggedObject)
+ {
+ string tab = indent + Tab;
+ buf.Append(indent);
+ if (obj is BerTaggedObject)
+ {
+ buf.Append("BER Tagged [");
+ }
+ else
+ {
+ buf.Append("Tagged [");
+ }
+
+ DerTaggedObject o = (DerTaggedObject)obj;
+
+ buf.Append(((int)o.TagNo).ToString());
+ buf.Append(']');
+
+ if (!o.IsExplicit())
+ {
+ buf.Append(" IMPLICIT ");
+ }
+
+ buf.Append(NewLine);
+
+ if (o.IsEmpty())
+ {
+ buf.Append(tab);
+ buf.Append("EMPTY");
+ buf.Append(NewLine);
+ }
+ else
+ {
+ AsString(tab, verbose, o.GetObject(), buf);
+ }
+ }
+ else if (obj is BerSet)
+ {
+ string tab = indent + Tab;
+
+ buf.Append(indent);
+ buf.Append("BER Set");
+ buf.Append(NewLine);
+
+ foreach (Asn1Encodable o in ((Asn1Set)obj))
+ {
+ if (o == null)
+ {
+ buf.Append(tab);
+ buf.Append("NULL");
+ buf.Append(NewLine);
+ }
+ else
+ {
+ AsString(tab, verbose, o.ToAsn1Object(), buf);
+ }
+ }
+ }
+ else if (obj is DerSet)
+ {
+ string tab = indent + Tab;
+
+ buf.Append(indent);
+ buf.Append("DER Set");
+ buf.Append(NewLine);
+
+ foreach (Asn1Encodable o in ((Asn1Set)obj))
+ {
+ if (o == null)
+ {
+ buf.Append(tab);
+ buf.Append("NULL");
+ buf.Append(NewLine);
+ }
+ else
+ {
+ AsString(tab, verbose, o.ToAsn1Object(), buf);
+ }
+ }
+ }
+ else if (obj is DerObjectIdentifier)
+ {
+ buf.Append(indent + "ObjectIdentifier(" + ((DerObjectIdentifier)obj).Id + ")" + NewLine);
+ }
+ else if (obj is DerBoolean)
+ {
+ buf.Append(indent + "Boolean(" + ((DerBoolean)obj).IsTrue + ")" + NewLine);
+ }
+ else if (obj is DerInteger)
+ {
+ buf.Append(indent + "Integer(" + ((DerInteger)obj).Value + ")" + NewLine);
+ }
+ else if (obj is BerOctetString)
+ {
+ byte[] octets = ((Asn1OctetString)obj).GetOctets();
+ string extra = verbose ? dumpBinaryDataAsString(indent, octets) : "";
+ buf.Append(indent + "BER Octet String" + "[" + octets.Length + "] " + extra + NewLine);
+ }
+ else if (obj is DerOctetString)
+ {
+ byte[] octets = ((Asn1OctetString)obj).GetOctets();
+ string extra = verbose ? dumpBinaryDataAsString(indent, octets) : "";
+ buf.Append(indent + "DER Octet String" + "[" + octets.Length + "] " + extra + NewLine);
+ }
+ else if (obj is DerBitString)
+ {
+ DerBitString bt = (DerBitString)obj;
+ byte[] bytes = bt.GetBytes();
+ string extra = verbose ? dumpBinaryDataAsString(indent, bytes) : "";
+ buf.Append(indent + "DER Bit String" + "[" + bytes.Length + ", " + bt.PadBits + "] " + extra + NewLine);
+ }
+ else if (obj is DerIA5String)
+ {
+ buf.Append(indent + "IA5String(" + ((DerIA5String)obj).GetString() + ") " + NewLine);
+ }
+ else if (obj is DerUtf8String)
+ {
+ buf.Append(indent + "UTF8String(" + ((DerUtf8String)obj).GetString() + ") " + NewLine);
+ }
+ else if (obj is DerPrintableString)
+ {
+ buf.Append(indent + "PrintableString(" + ((DerPrintableString)obj).GetString() + ") " + NewLine);
+ }
+ else if (obj is DerVisibleString)
+ {
+ buf.Append(indent + "VisibleString(" + ((DerVisibleString)obj).GetString() + ") " + NewLine);
+ }
+ else if (obj is DerBmpString)
+ {
+ buf.Append(indent + "BMPString(" + ((DerBmpString)obj).GetString() + ") " + NewLine);
+ }
+ else if (obj is DerT61String)
+ {
+ buf.Append(indent + "T61String(" + ((DerT61String)obj).GetString() + ") " + NewLine);
+ }
+ else if (obj is DerGraphicString)
+ {
+ buf.Append(indent + "GraphicString(" + ((DerGraphicString)obj).GetString() + ") " + NewLine);
+ }
+ else if (obj is DerVideotexString)
+ {
+ buf.Append(indent + "VideotexString(" + ((DerVideotexString)obj).GetString() + ") " + NewLine);
+ }
+ else if (obj is DerUtcTime)
+ {
+ buf.Append(indent + "UTCTime(" + ((DerUtcTime)obj).TimeString + ") " + NewLine);
+ }
+ else if (obj is DerGeneralizedTime)
+ {
+ buf.Append(indent + "GeneralizedTime(" + ((DerGeneralizedTime)obj).GetTime() + ") " + NewLine);
+ }
+ else if (obj is BerApplicationSpecific)
+ {
+ buf.Append(outputApplicationSpecific("BER", indent, verbose, (BerApplicationSpecific)obj));
+ }
+ else if (obj is DerApplicationSpecific)
+ {
+ buf.Append(outputApplicationSpecific("DER", indent, verbose, (DerApplicationSpecific)obj));
+ }
+ else if (obj is DerEnumerated)
+ {
+ DerEnumerated en = (DerEnumerated)obj;
+ buf.Append(indent + "DER Enumerated(" + en.Value + ")" + NewLine);
+ }
+ else if (obj is DerExternal)
+ {
+ DerExternal ext = (DerExternal)obj;
+ buf.Append(indent + "External " + NewLine);
+ string tab = indent + Tab;
+
+ if (ext.DirectReference != null)
+ {
+ buf.Append(tab + "Direct Reference: " + ext.DirectReference.Id + NewLine);
+ }
+ if (ext.IndirectReference != null)
+ {
+ buf.Append(tab + "Indirect Reference: " + ext.IndirectReference.ToString() + NewLine);
+ }
+ if (ext.DataValueDescriptor != null)
+ {
+ AsString(tab, verbose, ext.DataValueDescriptor, buf);
+ }
+ buf.Append(tab + "Encoding: " + ext.Encoding + NewLine);
+ AsString(tab, verbose, ext.ExternalContent, buf);
+ }
+ else
+ {
+ buf.Append(indent + obj.ToString() + NewLine);
+ }
+ }
+
+ private static string outputApplicationSpecific(
+ string type,
+ string indent,
+ bool verbose,
+ DerApplicationSpecific app)
+ {
+ StringBuilder buf = new StringBuilder();
+
+ if (app.IsConstructed())
+ {
+ try
+ {
+ Asn1Sequence s = Asn1Sequence.GetInstance(app.GetObject(Asn1Tags.Sequence));
+ buf.Append(indent + type + " ApplicationSpecific[" + app.ApplicationTag + "]" + NewLine);
+ foreach (Asn1Encodable ae in s)
+ {
+ AsString(indent + Tab, verbose, ae.ToAsn1Object(), buf);
+ }
+ }
+ catch (IOException e)
+ {
+ buf.Append(e);
+ }
+ return buf.ToString();
+ }
+
+ return indent + type + " ApplicationSpecific[" + app.ApplicationTag + "] ("
+ + Hex.ToHexString(app.GetContents()) + ")" + NewLine;
+ }
+
+ [Obsolete("Use version accepting Asn1Encodable")]
+ public static string DumpAsString(
+ object obj)
+ {
+ if (obj is Asn1Encodable)
+ {
+ StringBuilder buf = new StringBuilder();
+ AsString("", false, ((Asn1Encodable)obj).ToAsn1Object(), buf);
+ return buf.ToString();
+ }
+
+ return "unknown object type " + obj.ToString();
+ }
+
+ /**
+ * dump out a DER object as a formatted string, in non-verbose mode
+ *
+ * @param obj the Asn1Encodable to be dumped out.
+ * @return the resulting string.
+ */
+ public static string DumpAsString(
+ Asn1Encodable obj)
+ {
+ return DumpAsString(obj, false);
+ }
+
+ /**
+ * Dump out the object as a string
+ *
+ * @param obj the Asn1Encodable to be dumped out.
+ * @param verbose if true, dump out the contents of octet and bit strings.
+ * @return the resulting string.
+ */
+ public static string DumpAsString(
+ Asn1Encodable obj,
+ bool verbose)
+ {
+ StringBuilder buf = new StringBuilder();
+ AsString("", verbose, obj.ToAsn1Object(), buf);
+ return buf.ToString();
+ }
+
+ private static string dumpBinaryDataAsString(string indent, byte[] bytes)
+ {
+ indent += Tab;
+
+ StringBuilder buf = new StringBuilder(NewLine);
+
+ for (int i = 0; i < bytes.Length; i += SampleSize)
+ {
+ if (bytes.Length - i > SampleSize)
+ {
+ buf.Append(indent);
+ buf.Append(Hex.ToHexString(bytes, i, SampleSize));
+ buf.Append(Tab);
+ buf.Append(calculateAscString(bytes, i, SampleSize));
+ buf.Append(NewLine);
+ }
+ else
+ {
+ buf.Append(indent);
+ buf.Append(Hex.ToHexString(bytes, i, bytes.Length - i));
+ for (int j = bytes.Length - i; j != SampleSize; j++)
+ {
+ buf.Append(" ");
+ }
+ buf.Append(Tab);
+ buf.Append(calculateAscString(bytes, i, bytes.Length - i));
+ buf.Append(NewLine);
+ }
+ }
+
+ return buf.ToString();
+ }
+
+ private static string calculateAscString(
+ byte[] bytes,
+ int off,
+ int len)
+ {
+ StringBuilder buf = new StringBuilder();
+
+ for (int i = off; i != off + len; i++)
+ {
+ char c = (char)bytes[i];
+ if (c >= ' ' && c <= '~')
+ {
+ buf.Append(c);
+ }
+ }
+
+ return buf.ToString();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/util/Dump.cs b/bc-sharp-crypto/src/asn1/util/Dump.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6025c724a4a4ec20d68cc816d200313000e981b7
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/util/Dump.cs
@@ -0,0 +1,31 @@
+#if !PORTABLE
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Utilities
+{
+ public sealed class Dump
+ {
+ private Dump()
+ {
+ }
+
+ /* public static void Main(string[] args)
+ {
+ FileStream fIn = File.OpenRead(args[0]);
+ Asn1InputStream bIn = new Asn1InputStream(fIn);
+
+ Asn1Object obj;
+ while ((obj = bIn.ReadObject()) != null)
+ {
+ Console.WriteLine(Asn1Dump.DumpAsString(obj));
+ }
+
+ Platform.Dispose(bIn);
+ }
+ */
+ }
+}
+#endif
diff --git a/bc-sharp-crypto/src/asn1/util/FilterStream.cs b/bc-sharp-crypto/src/asn1/util/FilterStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0c38c5b6e39eaf06939ead96d7ab3a3fe32a9ba2
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/util/FilterStream.cs
@@ -0,0 +1,83 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Utilities
+{
+ [Obsolete("Use Org.BouncyCastle.Utilities.IO.FilterStream")]
+ public class FilterStream : Stream
+ {
+ [Obsolete("Use Org.BouncyCastle.Utilities.IO.FilterStream")]
+ public FilterStream(Stream s)
+ {
+ this.s = s;
+ }
+ public override bool CanRead
+ {
+ get { return s.CanRead; }
+ }
+ public override bool CanSeek
+ {
+ get { return s.CanSeek; }
+ }
+ public override bool CanWrite
+ {
+ get { return s.CanWrite; }
+ }
+ public override long Length
+ {
+ get { return s.Length; }
+ }
+ public override long Position
+ {
+ get { return s.Position; }
+ set { s.Position = value; }
+ }
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Platform.Dispose(s);
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ Platform.Dispose(s);
+ base.Close();
+ }
+#endif
+ public override void Flush()
+ {
+ s.Flush();
+ }
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ return s.Seek(offset, origin);
+ }
+ public override void SetLength(long value)
+ {
+ s.SetLength(value);
+ }
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ return s.Read(buffer, offset, count);
+ }
+ public override int ReadByte()
+ {
+ return s.ReadByte();
+ }
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ s.Write(buffer, offset, count);
+ }
+ public override void WriteByte(byte value)
+ {
+ s.WriteByte(value);
+ }
+ protected readonly Stream s;
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x500/DirectoryString.cs b/bc-sharp-crypto/src/asn1/x500/DirectoryString.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d907c6456c24c675602b2783bea96b3352f65383
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x500/DirectoryString.cs
@@ -0,0 +1,77 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X500
+{
+ public class DirectoryString
+ : Asn1Encodable, IAsn1Choice, IAsn1String
+ {
+ private readonly DerStringBase str;
+
+ public static DirectoryString GetInstance(
+ object obj)
+ {
+ if (obj is DirectoryString)
+ {
+ return (DirectoryString) obj;
+ }
+
+ if (obj is DerStringBase)
+ {
+ if (obj is DerT61String
+ || obj is DerPrintableString
+ || obj is DerUniversalString
+ || obj is DerUtf8String
+ || obj is DerBmpString)
+ {
+ return new DirectoryString((DerStringBase) obj);
+ }
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public static DirectoryString GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ if (!isExplicit)
+ throw new ArgumentException("choice item must be explicitly tagged");
+
+ return GetInstance(obj.GetObject());
+ }
+
+ private DirectoryString(
+ DerStringBase str)
+ {
+ this.str = str;
+ }
+
+ public DirectoryString(
+ string str)
+ {
+ this.str = new DerUtf8String(str);
+ }
+
+ public string GetString()
+ {
+ return str.GetString();
+ }
+
+ /**
+ *
+ * DirectoryString ::= CHOICE {
+ * teletexString TeletexString (SIZE (1..MAX)),
+ * printableString PrintableString (SIZE (1..MAX)),
+ * universalString UniversalString (SIZE (1..MAX)),
+ * utf8String UTF8String (SIZE (1..MAX)),
+ * bmpString BMPString (SIZE (1..MAX)) }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return str.ToAsn1Object();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/AccessDescription.cs b/bc-sharp-crypto/src/asn1/x509/AccessDescription.cs
new file mode 100644
index 0000000000000000000000000000000000000000..47374be8fbc911f6fc82682a590040635629e8e2
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/AccessDescription.cs
@@ -0,0 +1,85 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * The AccessDescription object.
+ *
+ * AccessDescription ::= SEQUENCE {
+ * accessMethod OBJECT IDENTIFIER,
+ * accessLocation GeneralName }
+ *
+ */
+ public class AccessDescription
+ : Asn1Encodable
+ {
+ public readonly static DerObjectIdentifier IdADCAIssuers = new DerObjectIdentifier("1.3.6.1.5.5.7.48.2");
+ public readonly static DerObjectIdentifier IdADOcsp = new DerObjectIdentifier("1.3.6.1.5.5.7.48.1");
+
+ private readonly DerObjectIdentifier accessMethod;
+ private readonly GeneralName accessLocation;
+
+ public static AccessDescription GetInstance(
+ object obj)
+ {
+ if (obj is AccessDescription)
+ return (AccessDescription) obj;
+
+ if (obj is Asn1Sequence)
+ return new AccessDescription((Asn1Sequence) obj);
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private AccessDescription(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("wrong number of elements in sequence");
+
+ accessMethod = DerObjectIdentifier.GetInstance(seq[0]);
+ accessLocation = GeneralName.GetInstance(seq[1]);
+ }
+
+ /**
+ * create an AccessDescription with the oid and location provided.
+ */
+ public AccessDescription(
+ DerObjectIdentifier oid,
+ GeneralName location)
+ {
+ accessMethod = oid;
+ accessLocation = location;
+ }
+
+ /**
+ *
+ * @return the access method.
+ */
+ public DerObjectIdentifier AccessMethod
+ {
+ get { return accessMethod; }
+ }
+
+ /**
+ *
+ * @return the access location
+ */
+ public GeneralName AccessLocation
+ {
+ get { return accessLocation; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(accessMethod, accessLocation);
+ }
+
+ public override string ToString()
+ {
+ return "AccessDescription: Oid(" + this.accessMethod.Id + ")";
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/AlgorithmIdentifier.cs b/bc-sharp-crypto/src/asn1/x509/AlgorithmIdentifier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..00e7ad8bc84e8ca93c16df83a7c490b68b9b1e49
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/AlgorithmIdentifier.cs
@@ -0,0 +1,96 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class AlgorithmIdentifier
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier algorithm;
+ private readonly Asn1Encodable parameters;
+
+ public static AlgorithmIdentifier GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static AlgorithmIdentifier GetInstance(
+ object obj)
+ {
+ if (obj == null)
+ return null;
+ if (obj is AlgorithmIdentifier)
+ return (AlgorithmIdentifier)obj;
+ return new AlgorithmIdentifier(Asn1Sequence.GetInstance(obj));
+ }
+
+ public AlgorithmIdentifier(
+ DerObjectIdentifier algorithm)
+ {
+ this.algorithm = algorithm;
+ }
+
+ [Obsolete("Use version taking a DerObjectIdentifier")]
+ public AlgorithmIdentifier(
+ string algorithm)
+ {
+ this.algorithm = new DerObjectIdentifier(algorithm);
+ }
+
+ public AlgorithmIdentifier(
+ DerObjectIdentifier algorithm,
+ Asn1Encodable parameters)
+ {
+ this.algorithm = algorithm;
+ this.parameters = parameters;
+ }
+
+ internal AlgorithmIdentifier(
+ Asn1Sequence seq)
+ {
+ if (seq.Count < 1 || seq.Count > 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+ this.algorithm = DerObjectIdentifier.GetInstance(seq[0]);
+ this.parameters = seq.Count < 2 ? null : seq[1];
+ }
+
+ ///
+ /// Return the OID in the Algorithm entry of this identifier.
+ ///
+ public virtual DerObjectIdentifier Algorithm
+ {
+ get { return algorithm; }
+ }
+
+ [Obsolete("Use 'Algorithm' property instead")]
+ public virtual DerObjectIdentifier ObjectID
+ {
+ get { return algorithm; }
+ }
+
+ ///
+ /// Return the parameters structure in the Parameters entry of this identifier.
+ ///
+ public virtual Asn1Encodable Parameters
+ {
+ get { return parameters; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * AlgorithmIdentifier ::= Sequence {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(algorithm);
+ v.AddOptional(parameters);
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/AttCertIssuer.cs b/bc-sharp-crypto/src/asn1/x509/AttCertIssuer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..407c4ae7a43d7cdfb2f4e4e7bb48f732a8446fa4
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/AttCertIssuer.cs
@@ -0,0 +1,86 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class AttCertIssuer
+ : Asn1Encodable, IAsn1Choice
+ {
+ internal readonly Asn1Encodable obj;
+ internal readonly Asn1Object choiceObj;
+
+ public static AttCertIssuer GetInstance(
+ object obj)
+ {
+ if (obj is AttCertIssuer)
+ {
+ return (AttCertIssuer)obj;
+ }
+ else if (obj is V2Form)
+ {
+ return new AttCertIssuer(V2Form.GetInstance(obj));
+ }
+ else if (obj is GeneralNames)
+ {
+ return new AttCertIssuer((GeneralNames)obj);
+ }
+ else if (obj is Asn1TaggedObject)
+ {
+ return new AttCertIssuer(V2Form.GetInstance((Asn1TaggedObject)obj, false));
+ }
+ else if (obj is Asn1Sequence)
+ {
+ return new AttCertIssuer(GeneralNames.GetInstance(obj));
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public static AttCertIssuer GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ return GetInstance(obj.GetObject()); // must be explictly tagged
+ }
+
+ ///
+ /// Don't use this one if you are trying to be RFC 3281 compliant.
+ /// Use it for v1 attribute certificates only.
+ ///
+ /// Our GeneralNames structure
+ public AttCertIssuer(
+ GeneralNames names)
+ {
+ obj = names;
+ choiceObj = obj.ToAsn1Object();
+ }
+
+ public AttCertIssuer(
+ V2Form v2Form)
+ {
+ obj = v2Form;
+ choiceObj = new DerTaggedObject(false, 0, obj);
+ }
+
+ public Asn1Encodable Issuer
+ {
+ get { return obj; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * AttCertIssuer ::= CHOICE {
+ * v1Form GeneralNames, -- MUST NOT be used in this
+ * -- profile
+ * v2Form [0] V2Form -- v2 only
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return choiceObj;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/AttCertValidityPeriod.cs b/bc-sharp-crypto/src/asn1/x509/AttCertValidityPeriod.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d31e07402f1f7a9e31f21910cfbe1fbe6beb3880
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/AttCertValidityPeriod.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class AttCertValidityPeriod
+ : Asn1Encodable
+ {
+ private readonly DerGeneralizedTime notBeforeTime;
+ private readonly DerGeneralizedTime notAfterTime;
+
+ public static AttCertValidityPeriod GetInstance(
+ object obj)
+ {
+ if (obj is AttCertValidityPeriod || obj == null)
+ {
+ return (AttCertValidityPeriod) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new AttCertValidityPeriod((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public static AttCertValidityPeriod GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ private AttCertValidityPeriod(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+ notBeforeTime = DerGeneralizedTime.GetInstance(seq[0]);
+ notAfterTime = DerGeneralizedTime.GetInstance(seq[1]);
+ }
+
+ public AttCertValidityPeriod(
+ DerGeneralizedTime notBeforeTime,
+ DerGeneralizedTime notAfterTime)
+ {
+ this.notBeforeTime = notBeforeTime;
+ this.notAfterTime = notAfterTime;
+ }
+
+ public DerGeneralizedTime NotBeforeTime
+ {
+ get { return notBeforeTime; }
+ }
+
+ public DerGeneralizedTime NotAfterTime
+ {
+ get { return notAfterTime; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * AttCertValidityPeriod ::= Sequence {
+ * notBeforeTime GeneralizedTime,
+ * notAfterTime GeneralizedTime
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(notBeforeTime, notAfterTime);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/Attribute.cs b/bc-sharp-crypto/src/asn1/x509/Attribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..da59b42851e2711a30fdaa77f3889e0bfc5b854c
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/Attribute.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class AttributeX509
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier attrType;
+ private readonly Asn1Set attrValues;
+
+ /**
+ * return an Attr object from the given object.
+ *
+ * @param o the object we want converted.
+ * @exception ArgumentException if the object cannot be converted.
+ */
+ public static AttributeX509 GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is AttributeX509)
+ {
+ return (AttributeX509) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new AttributeX509((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private AttributeX509(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+ attrType = DerObjectIdentifier.GetInstance(seq[0]);
+ attrValues = Asn1Set.GetInstance(seq[1]);
+ }
+
+ public AttributeX509(
+ DerObjectIdentifier attrType,
+ Asn1Set attrValues)
+ {
+ this.attrType = attrType;
+ this.attrValues = attrValues;
+ }
+
+ public DerObjectIdentifier AttrType
+ {
+ get { return attrType; }
+ }
+
+ public Asn1Encodable[] GetAttributeValues()
+ {
+ return attrValues.ToArray();
+ }
+
+ public Asn1Set AttrValues
+ {
+ get { return attrValues; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Attr ::= Sequence {
+ * attrType OBJECT IDENTIFIER,
+ * attrValues Set OF AttributeValue
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(attrType, attrValues);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/AttributeCertificate.cs b/bc-sharp-crypto/src/asn1/x509/AttributeCertificate.cs
new file mode 100644
index 0000000000000000000000000000000000000000..41893b6b4c41a177bdd168e7ba4bf9bd3af941ae
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/AttributeCertificate.cs
@@ -0,0 +1,86 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class AttributeCertificate
+ : Asn1Encodable
+ {
+ private readonly AttributeCertificateInfo acinfo;
+ private readonly AlgorithmIdentifier signatureAlgorithm;
+ private readonly DerBitString signatureValue;
+
+ /**
+ * @param obj
+ * @return
+ */
+ public static AttributeCertificate GetInstance(
+ object obj)
+ {
+ if (obj is AttributeCertificate)
+ return (AttributeCertificate) obj;
+
+ if (obj != null)
+ return new AttributeCertificate(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ public AttributeCertificate(
+ AttributeCertificateInfo acinfo,
+ AlgorithmIdentifier signatureAlgorithm,
+ DerBitString signatureValue)
+ {
+ this.acinfo = acinfo;
+ this.signatureAlgorithm = signatureAlgorithm;
+ this.signatureValue = signatureValue;
+ }
+
+ private AttributeCertificate(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 3)
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+ this.acinfo = AttributeCertificateInfo.GetInstance(seq[0]);
+ this.signatureAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+ this.signatureValue = DerBitString.GetInstance(seq[2]);
+ }
+
+ public AttributeCertificateInfo ACInfo
+ {
+ get { return acinfo; }
+ }
+
+ public AlgorithmIdentifier SignatureAlgorithm
+ {
+ get { return signatureAlgorithm; }
+ }
+
+ public DerBitString SignatureValue
+ {
+ get { return signatureValue; }
+ }
+
+ public byte[] GetSignatureOctets()
+ {
+ return signatureValue.GetOctets();
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * AttributeCertificate ::= Sequence {
+ * acinfo AttributeCertificateInfo,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signatureValue BIT STRING
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(acinfo, signatureAlgorithm, signatureValue);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/AttributeCertificateInfo.cs b/bc-sharp-crypto/src/asn1/x509/AttributeCertificateInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..526f8e69b3c2972b87096e8e1dacc7f635019db5
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/AttributeCertificateInfo.cs
@@ -0,0 +1,156 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class AttributeCertificateInfo
+ : Asn1Encodable
+ {
+ internal readonly DerInteger version;
+ internal readonly Holder holder;
+ internal readonly AttCertIssuer issuer;
+ internal readonly AlgorithmIdentifier signature;
+ internal readonly DerInteger serialNumber;
+ internal readonly AttCertValidityPeriod attrCertValidityPeriod;
+ internal readonly Asn1Sequence attributes;
+ internal readonly DerBitString issuerUniqueID;
+ internal readonly X509Extensions extensions;
+
+ public static AttributeCertificateInfo GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ public static AttributeCertificateInfo GetInstance(
+ object obj)
+ {
+ if (obj is AttributeCertificateInfo)
+ {
+ return (AttributeCertificateInfo) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new AttributeCertificateInfo((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private AttributeCertificateInfo(
+ Asn1Sequence seq)
+ {
+ if (seq.Count < 7 || seq.Count > 9)
+ {
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+ }
+
+ this.version = DerInteger.GetInstance(seq[0]);
+ this.holder = Holder.GetInstance(seq[1]);
+ this.issuer = AttCertIssuer.GetInstance(seq[2]);
+ this.signature = AlgorithmIdentifier.GetInstance(seq[3]);
+ this.serialNumber = DerInteger.GetInstance(seq[4]);
+ this.attrCertValidityPeriod = AttCertValidityPeriod.GetInstance(seq[5]);
+ this.attributes = Asn1Sequence.GetInstance(seq[6]);
+
+ for (int i = 7; i < seq.Count; i++)
+ {
+ Asn1Encodable obj = (Asn1Encodable) seq[i];
+
+ if (obj is DerBitString)
+ {
+ this.issuerUniqueID = DerBitString.GetInstance(seq[i]);
+ }
+ else if (obj is Asn1Sequence || obj is X509Extensions)
+ {
+ this.extensions = X509Extensions.GetInstance(seq[i]);
+ }
+ }
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public Holder Holder
+ {
+ get { return holder; }
+ }
+
+ public AttCertIssuer Issuer
+ {
+ get { return issuer; }
+ }
+
+ public AlgorithmIdentifier Signature
+ {
+ get { return signature; }
+ }
+
+ public DerInteger SerialNumber
+ {
+ get { return serialNumber; }
+ }
+
+ public AttCertValidityPeriod AttrCertValidityPeriod
+ {
+ get { return attrCertValidityPeriod; }
+ }
+
+ public Asn1Sequence Attributes
+ {
+ get { return attributes; }
+ }
+
+ public DerBitString IssuerUniqueID
+ {
+ get { return issuerUniqueID; }
+ }
+
+ public X509Extensions Extensions
+ {
+ get { return extensions; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * AttributeCertificateInfo ::= Sequence {
+ * version AttCertVersion -- version is v2,
+ * holder Holder,
+ * issuer AttCertIssuer,
+ * signature AlgorithmIdentifier,
+ * serialNumber CertificateSerialNumber,
+ * attrCertValidityPeriod AttCertValidityPeriod,
+ * attributes Sequence OF Attr,
+ * issuerUniqueID UniqueIdentifier OPTIONAL,
+ * extensions Extensions OPTIONAL
+ * }
+ *
+ * AttCertVersion ::= Integer { v2(1) }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ version, holder, issuer, signature, serialNumber,
+ attrCertValidityPeriod, attributes);
+
+ if (issuerUniqueID != null)
+ {
+ v.Add(issuerUniqueID);
+ }
+
+ if (extensions != null)
+ {
+ v.Add(extensions);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/AttributeTable.cs b/bc-sharp-crypto/src/asn1/x509/AttributeTable.cs
new file mode 100644
index 0000000000000000000000000000000000000000..33faad64a1d569e697fd853f051007abdb2b019e
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/AttributeTable.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class AttributeTable
+ {
+ private readonly IDictionary attributes;
+
+ public AttributeTable(
+ IDictionary attrs)
+ {
+ this.attributes = Platform.CreateHashtable(attrs);
+ }
+
+#if !(SILVERLIGHT || PORTABLE)
+ [Obsolete]
+ public AttributeTable(
+ Hashtable attrs)
+ {
+ this.attributes = Platform.CreateHashtable(attrs);
+ }
+#endif
+
+ public AttributeTable(
+ Asn1EncodableVector v)
+ {
+ this.attributes = Platform.CreateHashtable(v.Count);
+
+ for (int i = 0; i != v.Count; i++)
+ {
+ AttributeX509 a = AttributeX509.GetInstance(v[i]);
+
+ attributes.Add(a.AttrType, a);
+ }
+ }
+
+ public AttributeTable(
+ Asn1Set s)
+ {
+ this.attributes = Platform.CreateHashtable(s.Count);
+
+ for (int i = 0; i != s.Count; i++)
+ {
+ AttributeX509 a = AttributeX509.GetInstance(s[i]);
+
+ attributes.Add(a.AttrType, a);
+ }
+ }
+
+ public AttributeX509 Get(
+ DerObjectIdentifier oid)
+ {
+ return (AttributeX509) attributes[oid];
+ }
+
+#if !(SILVERLIGHT || PORTABLE)
+ [Obsolete("Use 'ToDictionary' instead")]
+ public Hashtable ToHashtable()
+ {
+ return new Hashtable(attributes);
+ }
+#endif
+
+ public IDictionary ToDictionary()
+ {
+ return Platform.CreateHashtable(attributes);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/AuthorityInformationAccess.cs b/bc-sharp-crypto/src/asn1/x509/AuthorityInformationAccess.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9329e2b985a8f5fe2fa99af9cd7f101349e44be2
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/AuthorityInformationAccess.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * The AuthorityInformationAccess object.
+ *
+ * id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
+ *
+ * AuthorityInfoAccessSyntax ::=
+ * Sequence SIZE (1..MAX) OF AccessDescription
+ * AccessDescription ::= Sequence {
+ * accessMethod OBJECT IDENTIFIER,
+ * accessLocation GeneralName }
+ *
+ * id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
+ * id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
+ * id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
+ *
+ */
+ public class AuthorityInformationAccess
+ : Asn1Encodable
+ {
+ private readonly AccessDescription[] descriptions;
+
+ public static AuthorityInformationAccess GetInstance(object obj)
+ {
+ if (obj is AuthorityInformationAccess)
+ return (AuthorityInformationAccess)obj;
+ if (obj == null)
+ return null;
+ return new AuthorityInformationAccess(Asn1Sequence.GetInstance(obj));
+ }
+
+ private AuthorityInformationAccess(
+ Asn1Sequence seq)
+ {
+ if (seq.Count < 1)
+ throw new ArgumentException("sequence may not be empty");
+
+ this.descriptions = new AccessDescription[seq.Count];
+
+ for (int i = 0; i < seq.Count; ++i)
+ {
+ descriptions[i] = AccessDescription.GetInstance(seq[i]);
+ }
+ }
+
+ public AuthorityInformationAccess(
+ AccessDescription description)
+ {
+ this.descriptions = new AccessDescription[]{ description };
+ }
+
+ /**
+ * create an AuthorityInformationAccess with the oid and location provided.
+ */
+ public AuthorityInformationAccess(DerObjectIdentifier oid, GeneralName location)
+ : this(new AccessDescription(oid, location))
+ {
+ }
+
+ public AccessDescription[] GetAccessDescriptions()
+ {
+ return (AccessDescription[])descriptions.Clone();
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(descriptions);
+ }
+
+ public override string ToString()
+ {
+ //return "AuthorityInformationAccess: Oid(" + this.descriptions[0].AccessMethod.Id + ")";
+
+ StringBuilder buf = new StringBuilder();
+ string sep = Platform.NewLine;
+
+ buf.Append("AuthorityInformationAccess:");
+ buf.Append(sep);
+
+ foreach (AccessDescription description in descriptions)
+ {
+ buf.Append(" ");
+ buf.Append(description);
+ buf.Append(sep);
+ }
+
+ return buf.ToString();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/AuthorityKeyIdentifier.cs b/bc-sharp-crypto/src/asn1/x509/AuthorityKeyIdentifier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d5a9048cc0474043f01e78877881953d964e51f4
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/AuthorityKeyIdentifier.cs
@@ -0,0 +1,211 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * The AuthorityKeyIdentifier object.
+ *
+ * id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 }
+ *
+ * AuthorityKeyIdentifier ::= Sequence {
+ * keyIdentifier [0] IMPLICIT KeyIdentifier OPTIONAL,
+ * authorityCertIssuer [1] IMPLICIT GeneralNames OPTIONAL,
+ * authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL }
+ *
+ * KeyIdentifier ::= OCTET STRING
+ *
+ *
+ */
+ public class AuthorityKeyIdentifier
+ : Asn1Encodable
+ {
+ internal readonly Asn1OctetString keyidentifier;
+ internal readonly GeneralNames certissuer;
+ internal readonly DerInteger certserno;
+
+ public static AuthorityKeyIdentifier GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static AuthorityKeyIdentifier GetInstance(
+ object obj)
+ {
+ if (obj is AuthorityKeyIdentifier)
+ {
+ return (AuthorityKeyIdentifier) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new AuthorityKeyIdentifier((Asn1Sequence) obj);
+ }
+
+ if (obj is X509Extension)
+ {
+ return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ protected internal AuthorityKeyIdentifier(
+ Asn1Sequence seq)
+ {
+ foreach (Asn1TaggedObject o in seq)
+ {
+ switch (o.TagNo)
+ {
+ case 0:
+ this.keyidentifier = Asn1OctetString.GetInstance(o, false);
+ break;
+ case 1:
+ this.certissuer = GeneralNames.GetInstance(o, false);
+ break;
+ case 2:
+ this.certserno = DerInteger.GetInstance(o, false);
+ break;
+ default:
+ throw new ArgumentException("illegal tag");
+ }
+ }
+ }
+
+ /**
+ *
+ * Calulates the keyidentifier using a SHA1 hash over the BIT STRING
+ * from SubjectPublicKeyInfo as defined in RFC2459.
+ *
+ * Example of making a AuthorityKeyIdentifier:
+ *
+ * SubjectPublicKeyInfo apki = new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(
+ * publicKey.getEncoded()).readObject());
+ * AuthorityKeyIdentifier aki = new AuthorityKeyIdentifier(apki);
+ *
+ *
+ **/
+ public AuthorityKeyIdentifier(
+ SubjectPublicKeyInfo spki)
+ {
+ IDigest digest = new Sha1Digest();
+ byte[] resBuf = new byte[digest.GetDigestSize()];
+
+ byte[] bytes = spki.PublicKeyData.GetBytes();
+ digest.BlockUpdate(bytes, 0, bytes.Length);
+ digest.DoFinal(resBuf, 0);
+ this.keyidentifier = new DerOctetString(resBuf);
+ }
+
+ /**
+ * create an AuthorityKeyIdentifier with the GeneralNames tag and
+ * the serial number provided as well.
+ */
+ public AuthorityKeyIdentifier(
+ SubjectPublicKeyInfo spki,
+ GeneralNames name,
+ BigInteger serialNumber)
+ {
+ IDigest digest = new Sha1Digest();
+ byte[] resBuf = new byte[digest.GetDigestSize()];
+
+ byte[] bytes = spki.PublicKeyData.GetBytes();
+ digest.BlockUpdate(bytes, 0, bytes.Length);
+ digest.DoFinal(resBuf, 0);
+
+ this.keyidentifier = new DerOctetString(resBuf);
+ this.certissuer = name;
+ this.certserno = new DerInteger(serialNumber);
+ }
+
+ /**
+ * create an AuthorityKeyIdentifier with the GeneralNames tag and
+ * the serial number provided.
+ */
+ public AuthorityKeyIdentifier(
+ GeneralNames name,
+ BigInteger serialNumber)
+ {
+ this.keyidentifier = null;
+ this.certissuer = GeneralNames.GetInstance(name.ToAsn1Object());
+ this.certserno = new DerInteger(serialNumber);
+ }
+
+ /**
+ * create an AuthorityKeyIdentifier with a precomputed key identifier
+ */
+ public AuthorityKeyIdentifier(
+ byte[] keyIdentifier)
+ {
+ this.keyidentifier = new DerOctetString(keyIdentifier);
+ this.certissuer = null;
+ this.certserno = null;
+ }
+
+ /**
+ * create an AuthorityKeyIdentifier with a precomupted key identifier
+ * and the GeneralNames tag and the serial number provided as well.
+ */
+ public AuthorityKeyIdentifier(
+ byte[] keyIdentifier,
+ GeneralNames name,
+ BigInteger serialNumber)
+ {
+ this.keyidentifier = new DerOctetString(keyIdentifier);
+ this.certissuer = GeneralNames.GetInstance(name.ToAsn1Object());
+ this.certserno = new DerInteger(serialNumber);
+ }
+
+ public byte[] GetKeyIdentifier()
+ {
+ return keyidentifier == null ? null : keyidentifier.GetOctets();
+ }
+
+ public GeneralNames AuthorityCertIssuer
+ {
+ get { return certissuer; }
+ }
+
+ public BigInteger AuthorityCertSerialNumber
+ {
+ get { return certserno == null ? null : certserno.Value; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (keyidentifier != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, keyidentifier));
+ }
+
+ if (certissuer != null)
+ {
+ v.Add(new DerTaggedObject(false, 1, certissuer));
+ }
+
+ if (certserno != null)
+ {
+ v.Add(new DerTaggedObject(false, 2, certserno));
+ }
+
+ return new DerSequence(v);
+ }
+
+ public override string ToString()
+ {
+ return ("AuthorityKeyIdentifier: KeyID(" + this.keyidentifier.GetOctets() + ")");
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/BasicConstraints.cs b/bc-sharp-crypto/src/asn1/x509/BasicConstraints.cs
new file mode 100644
index 0000000000000000000000000000000000000000..098801f227f508675896f8d54873384c9726fdbe
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/BasicConstraints.cs
@@ -0,0 +1,133 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class BasicConstraints
+ : Asn1Encodable
+ {
+ private readonly DerBoolean cA;
+ private readonly DerInteger pathLenConstraint;
+
+ public static BasicConstraints GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static BasicConstraints GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is BasicConstraints)
+ {
+ return (BasicConstraints) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new BasicConstraints((Asn1Sequence) obj);
+ }
+
+ if (obj is X509Extension)
+ {
+ return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private BasicConstraints(
+ Asn1Sequence seq)
+ {
+ if (seq.Count > 0)
+ {
+ if (seq[0] is DerBoolean)
+ {
+ this.cA = DerBoolean.GetInstance(seq[0]);
+ }
+ else
+ {
+ this.pathLenConstraint = DerInteger.GetInstance(seq[0]);
+ }
+
+ if (seq.Count > 1)
+ {
+ if (this.cA == null)
+ throw new ArgumentException("wrong sequence in constructor", "seq");
+
+ this.pathLenConstraint = DerInteger.GetInstance(seq[1]);
+ }
+ }
+ }
+
+ public BasicConstraints(
+ bool cA)
+ {
+ if (cA)
+ {
+ this.cA = DerBoolean.True;
+ }
+ }
+
+ /**
+ * create a cA=true object for the given path length constraint.
+ *
+ * @param pathLenConstraint
+ */
+ public BasicConstraints(
+ int pathLenConstraint)
+ {
+ this.cA = DerBoolean.True;
+ this.pathLenConstraint = new DerInteger(pathLenConstraint);
+ }
+
+ public bool IsCA()
+ {
+ return cA != null && cA.IsTrue;
+ }
+
+ public BigInteger PathLenConstraint
+ {
+ get { return pathLenConstraint == null ? null : pathLenConstraint.Value; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * BasicConstraints := Sequence {
+ * cA Boolean DEFAULT FALSE,
+ * pathLenConstraint Integer (0..MAX) OPTIONAL
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (cA != null)
+ {
+ v.Add(cA);
+ }
+
+ if (pathLenConstraint != null) // yes some people actually do this when cA is false...
+ {
+ v.Add(pathLenConstraint);
+ }
+
+ return new DerSequence(v);
+ }
+
+ public override string ToString()
+ {
+ if (pathLenConstraint == null)
+ {
+ return "BasicConstraints: isCa(" + this.IsCA() + ")";
+ }
+
+ return "BasicConstraints: isCa(" + this.IsCA() + "), pathLenConstraint = " + pathLenConstraint.Value;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/CRLDistPoint.cs b/bc-sharp-crypto/src/asn1/x509/CRLDistPoint.cs
new file mode 100644
index 0000000000000000000000000000000000000000..56ba79ca56594f42010c7bb097a182094eb3b018
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/CRLDistPoint.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class CrlDistPoint
+ : Asn1Encodable
+ {
+ internal readonly Asn1Sequence seq;
+
+ public static CrlDistPoint GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static CrlDistPoint GetInstance(
+ object obj)
+ {
+ if (obj is CrlDistPoint || obj == null)
+ {
+ return (CrlDistPoint) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new CrlDistPoint((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private CrlDistPoint(
+ Asn1Sequence seq)
+ {
+ this.seq = seq;
+ }
+
+ public CrlDistPoint(
+ DistributionPoint[] points)
+ {
+ seq = new DerSequence(points);
+ }
+
+ /**
+ * Return the distribution points making up the sequence.
+ *
+ * @return DistributionPoint[]
+ */
+ public DistributionPoint[] GetDistributionPoints()
+ {
+ DistributionPoint[] dp = new DistributionPoint[seq.Count];
+
+ for (int i = 0; i != seq.Count; ++i)
+ {
+ dp[i] = DistributionPoint.GetInstance(seq[i]);
+ }
+
+ return dp;
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * CrlDistPoint ::= Sequence SIZE {1..MAX} OF DistributionPoint
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return seq;
+ }
+
+ public override string ToString()
+ {
+ StringBuilder buf = new StringBuilder();
+ string sep = Platform.NewLine;
+
+ buf.Append("CRLDistPoint:");
+ buf.Append(sep);
+ DistributionPoint[] dp = GetDistributionPoints();
+ for (int i = 0; i != dp.Length; i++)
+ {
+ buf.Append(" ");
+ buf.Append(dp[i]);
+ buf.Append(sep);
+ }
+ return buf.ToString();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/CRLNumber.cs b/bc-sharp-crypto/src/asn1/x509/CRLNumber.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d744416a52590ac789363cc5b7e444310a5d6710
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/CRLNumber.cs
@@ -0,0 +1,30 @@
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * The CRLNumber object.
+ *
+ * CRLNumber::= Integer(0..MAX)
+ *
+ */
+ public class CrlNumber
+ : DerInteger
+ {
+ public CrlNumber(
+ BigInteger number)
+ : base(number)
+ {
+ }
+
+ public BigInteger Number
+ {
+ get { return PositiveValue; }
+ }
+
+ public override string ToString()
+ {
+ return "CRLNumber: " + Number;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/CRLReason.cs b/bc-sharp-crypto/src/asn1/x509/CRLReason.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e8eb53a591d56fcab8bcb4889b2a4aae538771a5
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/CRLReason.cs
@@ -0,0 +1,61 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * The CRLReason enumeration.
+ *
+ * CRLReason ::= Enumerated {
+ * unspecified (0),
+ * keyCompromise (1),
+ * cACompromise (2),
+ * affiliationChanged (3),
+ * superseded (4),
+ * cessationOfOperation (5),
+ * certificateHold (6),
+ * removeFromCRL (8),
+ * privilegeWithdrawn (9),
+ * aACompromise (10)
+ * }
+ *
+ */
+ public class CrlReason
+ : DerEnumerated
+ {
+ public const int Unspecified = 0;
+ public const int KeyCompromise = 1;
+ public const int CACompromise = 2;
+ public const int AffiliationChanged = 3;
+ public const int Superseded = 4;
+ public const int CessationOfOperation = 5;
+ public const int CertificateHold = 6;
+ // 7 -> Unknown
+ public const int RemoveFromCrl = 8;
+ public const int PrivilegeWithdrawn = 9;
+ public const int AACompromise = 10;
+
+ private static readonly string[] ReasonString = new string[]
+ {
+ "Unspecified", "KeyCompromise", "CACompromise", "AffiliationChanged",
+ "Superseded", "CessationOfOperation", "CertificateHold", "Unknown",
+ "RemoveFromCrl", "PrivilegeWithdrawn", "AACompromise"
+ };
+
+ public CrlReason(
+ int reason)
+ : base(reason)
+ {
+ }
+
+ public CrlReason(
+ DerEnumerated reason)
+ : base(reason.Value.IntValue)
+ {
+ }
+
+ public override string ToString()
+ {
+ int reason = Value.IntValue;
+ string str = (reason < 0 || reason > 10) ? "Invalid" : ReasonString[reason];
+ return "CrlReason: " + str;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/CertPolicyId.cs b/bc-sharp-crypto/src/asn1/x509/CertPolicyId.cs
new file mode 100644
index 0000000000000000000000000000000000000000..11cebcdd71e2e134be59e5a0db747d4e4b419167
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/CertPolicyId.cs
@@ -0,0 +1,20 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * CertPolicyId, used in the CertificatePolicies and PolicyMappings
+ * X509V3 Extensions.
+ *
+ *
+ * CertPolicyId ::= OBJECT IDENTIFIER
+ *
+ */
+ public class CertPolicyID
+ : DerObjectIdentifier
+ {
+ public CertPolicyID(
+ string id)
+ : base(id)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/CertificateList.cs b/bc-sharp-crypto/src/asn1/x509/CertificateList.cs
new file mode 100644
index 0000000000000000000000000000000000000000..567cf132ac71c235cf175d3507ce4f7347f7fa20
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/CertificateList.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * PKIX RFC-2459
+ *
+ * The X.509 v2 CRL syntax is as follows. For signature calculation,
+ * the data that is to be signed is ASN.1 Der encoded.
+ *
+ *
+ * CertificateList ::= Sequence {
+ * tbsCertList TbsCertList,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signatureValue BIT STRING }
+ *
+ */
+ public class CertificateList
+ : Asn1Encodable
+ {
+ private readonly TbsCertificateList tbsCertList;
+ private readonly AlgorithmIdentifier sigAlgID;
+ private readonly DerBitString sig;
+
+ public static CertificateList GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static CertificateList GetInstance(
+ object obj)
+ {
+ if (obj is CertificateList)
+ return (CertificateList) obj;
+
+ if (obj != null)
+ return new CertificateList(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ private CertificateList(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 3)
+ throw new ArgumentException("sequence wrong size for CertificateList", "seq");
+
+ tbsCertList = TbsCertificateList.GetInstance(seq[0]);
+ sigAlgID = AlgorithmIdentifier.GetInstance(seq[1]);
+ sig = DerBitString.GetInstance(seq[2]);
+ }
+
+ public TbsCertificateList TbsCertList
+ {
+ get { return tbsCertList; }
+ }
+
+ public CrlEntry[] GetRevokedCertificates()
+ {
+ return tbsCertList.GetRevokedCertificates();
+ }
+
+ public IEnumerable GetRevokedCertificateEnumeration()
+ {
+ return tbsCertList.GetRevokedCertificateEnumeration();
+ }
+
+ public AlgorithmIdentifier SignatureAlgorithm
+ {
+ get { return sigAlgID; }
+ }
+
+ public DerBitString Signature
+ {
+ get { return sig; }
+ }
+
+ public byte[] GetSignatureOctets()
+ {
+ return sig.GetOctets();
+ }
+
+ public int Version
+ {
+ get { return tbsCertList.Version; }
+ }
+
+ public X509Name Issuer
+ {
+ get { return tbsCertList.Issuer; }
+ }
+
+ public Time ThisUpdate
+ {
+ get { return tbsCertList.ThisUpdate; }
+ }
+
+ public Time NextUpdate
+ {
+ get { return tbsCertList.NextUpdate; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(tbsCertList, sigAlgID, sig);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/CertificatePair.cs b/bc-sharp-crypto/src/asn1/x509/CertificatePair.cs
new file mode 100644
index 0000000000000000000000000000000000000000..da92360105da74e1d42c43ef25e83a6eb83b47dc
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/CertificatePair.cs
@@ -0,0 +1,162 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * This class helps to support crossCerfificatePairs in a LDAP directory
+ * according RFC 2587
+ *
+ *
+ * crossCertificatePairATTRIBUTE::={
+ * WITH SYNTAX CertificatePair
+ * EQUALITY MATCHING RULE certificatePairExactMatch
+ * ID joint-iso-ccitt(2) ds(5) attributeType(4) crossCertificatePair(40)}
+ *
+ *
+ * The forward elements of the crossCertificatePair attribute of a
+ * CA's directory entry shall be used to store all, except self-issued
+ * certificates issued to this CA. Optionally, the reverse elements of the
+ * crossCertificatePair attribute, of a CA's directory entry may contain a
+ * subset of certificates issued by this CA to other CAs. When both the forward
+ * and the reverse elements are present in a single attribute value, issuer name
+ * in one certificate shall match the subject name in the other and vice versa,
+ * and the subject public key in one certificate shall be capable of verifying
+ * the digital signature on the other certificate and vice versa.
+ *
+ * When a reverse element is present, the forward element value and the reverse
+ * element value need not be stored in the same attribute value; in other words,
+ * they can be stored in either a single attribute value or two attribute
+ * values.
+ *
+ *
+ * CertificatePair ::= SEQUENCE {
+ * forward [0] Certificate OPTIONAL,
+ * reverse [1] Certificate OPTIONAL,
+ * -- at least one of the pair shall be present -- }
+ *
+ */
+ public class CertificatePair
+ : Asn1Encodable
+ {
+ private X509CertificateStructure forward, reverse;
+
+ public static CertificatePair GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is CertificatePair)
+ {
+ return (CertificatePair) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new CertificatePair((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * Constructor from Asn1Sequence.
+ *
+ * The sequence is of type CertificatePair:
+ *
+ *
+ * CertificatePair ::= SEQUENCE {
+ * forward [0] Certificate OPTIONAL,
+ * reverse [1] Certificate OPTIONAL,
+ * -- at least one of the pair shall be present -- }
+ *
+ *
+ * @param seq The ASN.1 sequence.
+ */
+ private CertificatePair(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 1 && seq.Count != 2)
+ {
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+ }
+
+ foreach (object obj in seq)
+ {
+ Asn1TaggedObject o = Asn1TaggedObject.GetInstance(obj);
+ if (o.TagNo == 0)
+ {
+ forward = X509CertificateStructure.GetInstance(o, true);
+ }
+ else if (o.TagNo == 1)
+ {
+ reverse = X509CertificateStructure.GetInstance(o, true);
+ }
+ else
+ {
+ throw new ArgumentException("Bad tag number: " + o.TagNo);
+ }
+ }
+ }
+
+ /**
+ * Constructor from a given details.
+ *
+ * @param forward Certificates issued to this CA.
+ * @param reverse Certificates issued by this CA to other CAs.
+ */
+ public CertificatePair(
+ X509CertificateStructure forward,
+ X509CertificateStructure reverse)
+ {
+ this.forward = forward;
+ this.reverse = reverse;
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * CertificatePair ::= SEQUENCE {
+ * forward [0] Certificate OPTIONAL,
+ * reverse [1] Certificate OPTIONAL,
+ * -- at least one of the pair shall be present -- }
+ *
+ *
+ * @return a DERObject
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector vec = new Asn1EncodableVector();
+
+ if (forward != null)
+ {
+ vec.Add(new DerTaggedObject(0, forward));
+ }
+
+ if (reverse != null)
+ {
+ vec.Add(new DerTaggedObject(1, reverse));
+ }
+
+ return new DerSequence(vec);
+ }
+
+ /**
+ * @return Returns the forward.
+ */
+ public X509CertificateStructure Forward
+ {
+ get { return forward; }
+ }
+
+ /**
+ * @return Returns the reverse.
+ */
+ public X509CertificateStructure Reverse
+ {
+ get { return reverse; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/CertificatePolicies.cs b/bc-sharp-crypto/src/asn1/x509/CertificatePolicies.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a83565bb2a6afd1ca34b8663fd8141e3effcf2b2
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/CertificatePolicies.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class CertificatePolicies
+ : Asn1Encodable
+ {
+ private readonly PolicyInformation[] policyInformation;
+
+ public static CertificatePolicies GetInstance(object obj)
+ {
+ if (obj == null || obj is CertificatePolicies)
+ return (CertificatePolicies)obj;
+
+ return new CertificatePolicies(Asn1Sequence.GetInstance(obj));
+ }
+
+ public static CertificatePolicies GetInstance(Asn1TaggedObject obj, bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ /**
+ * Construct a CertificatePolicies object containing one PolicyInformation.
+ *
+ * @param name the name to be contained.
+ */
+ public CertificatePolicies(PolicyInformation name)
+ {
+ this.policyInformation = new PolicyInformation[] { name };
+ }
+
+ public CertificatePolicies(PolicyInformation[] policyInformation)
+ {
+ this.policyInformation = policyInformation;
+ }
+
+ private CertificatePolicies(Asn1Sequence seq)
+ {
+ this.policyInformation = new PolicyInformation[seq.Count];
+
+ for (int i = 0; i < seq.Count; ++i)
+ {
+ policyInformation[i] = PolicyInformation.GetInstance(seq[i]);
+ }
+ }
+
+ public virtual PolicyInformation[] GetPolicyInformation()
+ {
+ return (PolicyInformation[])policyInformation.Clone();
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ *
+ * CertificatePolicies ::= SEQUENCE SIZE {1..MAX} OF PolicyInformation
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(policyInformation);
+ }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder("CertificatePolicies:");
+ if (policyInformation != null && policyInformation.Length > 0)
+ {
+ sb.Append(' ');
+ sb.Append(policyInformation[0]);
+ for (int i = 1; i < policyInformation.Length; ++i)
+ {
+ sb.Append(", ");
+ sb.Append(policyInformation[i]);
+ }
+ }
+ return sb.ToString();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/DSAParameter.cs b/bc-sharp-crypto/src/asn1/x509/DSAParameter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2eb65024bdef706ff3c5f495702dd6d384a31729
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/DSAParameter.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class DsaParameter
+ : Asn1Encodable
+ {
+ internal readonly DerInteger p, q, g;
+
+ public static DsaParameter GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static DsaParameter GetInstance(
+ object obj)
+ {
+ if(obj == null || obj is DsaParameter)
+ {
+ return (DsaParameter) obj;
+ }
+
+ if(obj is Asn1Sequence)
+ {
+ return new DsaParameter((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("Invalid DsaParameter: " + Platform.GetTypeName(obj));
+ }
+
+ public DsaParameter(
+ BigInteger p,
+ BigInteger q,
+ BigInteger g)
+ {
+ this.p = new DerInteger(p);
+ this.q = new DerInteger(q);
+ this.g = new DerInteger(g);
+ }
+
+ private DsaParameter(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 3)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ this.p = DerInteger.GetInstance(seq[0]);
+ this.q = DerInteger.GetInstance(seq[1]);
+ this.g = DerInteger.GetInstance(seq[2]);
+ }
+
+ public BigInteger P
+ {
+ get { return p.PositiveValue; }
+ }
+
+ public BigInteger Q
+ {
+ get { return q.PositiveValue; }
+ }
+
+ public BigInteger G
+ {
+ get { return g.PositiveValue; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(p, q, g);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/DigestInfo.cs b/bc-sharp-crypto/src/asn1/x509/DigestInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3ac535e2e52553325fea605458a26e1eb9a13ead
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/DigestInfo.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * The DigestInfo object.
+ *
+ * DigestInfo::=Sequence{
+ * digestAlgorithm AlgorithmIdentifier,
+ * digest OCTET STRING }
+ *
+ */
+ public class DigestInfo
+ : Asn1Encodable
+ {
+ private readonly byte[] digest;
+ private readonly AlgorithmIdentifier algID;
+
+ public static DigestInfo GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static DigestInfo GetInstance(
+ object obj)
+ {
+ if (obj is DigestInfo)
+ {
+ return (DigestInfo) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new DigestInfo((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public DigestInfo(
+ AlgorithmIdentifier algID,
+ byte[] digest)
+ {
+ this.digest = digest;
+ this.algID = algID;
+ }
+
+ private DigestInfo(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ algID = AlgorithmIdentifier.GetInstance(seq[0]);
+ digest = Asn1OctetString.GetInstance(seq[1]).GetOctets();
+ }
+
+ public AlgorithmIdentifier AlgorithmID
+ {
+ get { return algID; }
+ }
+
+ public byte[] GetDigest()
+ {
+ return digest;
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(algID, new DerOctetString(digest));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/DisplayText.cs b/bc-sharp-crypto/src/asn1/x509/DisplayText.cs
new file mode 100644
index 0000000000000000000000000000000000000000..39b3c98d757d85bbb2e195447be504a4d25cecf1
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/DisplayText.cs
@@ -0,0 +1,174 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * DisplayText
class, used in
+ * CertificatePolicies
X509 V3 extensions (in policy qualifiers).
+ *
+ * It stores a string in a chosen encoding.
+ *
+ * DisplayText ::= CHOICE {
+ * ia5String IA5String (SIZE (1..200)),
+ * visibleString VisibleString (SIZE (1..200)),
+ * bmpString BMPString (SIZE (1..200)),
+ * utf8String UTF8String (SIZE (1..200)) }
+ *
+ * @see PolicyQualifierInfo
+ * @see PolicyInformation
+ */
+ public class DisplayText
+ : Asn1Encodable, IAsn1Choice
+ {
+ /**
+ * Constant corresponding to ia5String encoding.
+ *
+ */
+ public const int ContentTypeIA5String = 0;
+ /**
+ * Constant corresponding to bmpString encoding.
+ *
+ */
+ public const int ContentTypeBmpString = 1;
+ /**
+ * Constant corresponding to utf8String encoding.
+ *
+ */
+ public const int ContentTypeUtf8String = 2;
+ /**
+ * Constant corresponding to visibleString encoding.
+ *
+ */
+ public const int ContentTypeVisibleString = 3;
+ /**
+ * Describe constant DisplayTextMaximumSize
here.
+ *
+ */
+ public const int DisplayTextMaximumSize = 200;
+
+ internal readonly int contentType;
+ internal readonly IAsn1String contents;
+
+ /**
+ * Creates a new DisplayText
instance.
+ *
+ * @param type the desired encoding type for the text.
+ * @param text the text to store. Strings longer than 200
+ * characters are truncated.
+ */
+ public DisplayText(
+ int type,
+ string text)
+ {
+ if (text.Length > DisplayTextMaximumSize)
+ {
+ // RFC3280 limits these strings to 200 chars
+ // truncate the string
+ text = text.Substring(0, DisplayTextMaximumSize);
+ }
+
+ contentType = type;
+ switch (type)
+ {
+ case ContentTypeIA5String:
+ contents = (IAsn1String)new DerIA5String (text);
+ break;
+ case ContentTypeUtf8String:
+ contents = (IAsn1String)new DerUtf8String(text);
+ break;
+ case ContentTypeVisibleString:
+ contents = (IAsn1String)new DerVisibleString(text);
+ break;
+ case ContentTypeBmpString:
+ contents = (IAsn1String)new DerBmpString(text);
+ break;
+ default:
+ contents = (IAsn1String)new DerUtf8String(text);
+ break;
+ }
+ }
+
+// /**
+// * return true if the passed in string can be represented without
+// * loss as a PrintableString, false otherwise.
+// */
+// private bool CanBePrintable(
+// string str)
+// {
+// for (int i = str.Length - 1; i >= 0; i--)
+// {
+// if (str[i] > 0x007f)
+// {
+// return false;
+// }
+// }
+//
+// return true;
+// }
+
+ /**
+ * Creates a new DisplayText
instance.
+ *
+ * @param text the text to encapsulate. Strings longer than 200
+ * characters are truncated.
+ */
+ public DisplayText(
+ string text)
+ {
+ // by default use UTF8String
+ if (text.Length > DisplayTextMaximumSize)
+ {
+ text = text.Substring(0, DisplayTextMaximumSize);
+ }
+
+ contentType = ContentTypeUtf8String;
+ contents = new DerUtf8String(text);
+ }
+
+ /**
+ * Creates a new DisplayText
instance.
+ * Useful when reading back a DisplayText
class
+ * from it's Asn1Encodable form.
+ *
+ * @param contents an Asn1Encodable
instance.
+ */
+ public DisplayText(
+ IAsn1String contents)
+ {
+ this.contents = contents;
+ }
+
+ public static DisplayText GetInstance(
+ object obj)
+ {
+ if (obj is IAsn1String)
+ {
+ return new DisplayText((IAsn1String) obj);
+ }
+
+ if (obj is DisplayText)
+ {
+ return (DisplayText) obj;
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return (Asn1Object) contents;
+ }
+
+ /**
+ * Returns the stored string
object.
+ *
+ * @return the stored text as a string
.
+ */
+ public string GetString()
+ {
+ return contents.GetString();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/DistributionPoint.cs b/bc-sharp-crypto/src/asn1/x509/DistributionPoint.cs
new file mode 100644
index 0000000000000000000000000000000000000000..40814c7a8f77490722e19546d1f7533350f6f74d
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/DistributionPoint.cs
@@ -0,0 +1,161 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * The DistributionPoint object.
+ *
+ * DistributionPoint ::= Sequence {
+ * distributionPoint [0] DistributionPointName OPTIONAL,
+ * reasons [1] ReasonFlags OPTIONAL,
+ * cRLIssuer [2] GeneralNames OPTIONAL
+ * }
+ *
+ */
+ public class DistributionPoint
+ : Asn1Encodable
+ {
+ internal readonly DistributionPointName distributionPoint;
+ internal readonly ReasonFlags reasons;
+ internal readonly GeneralNames cRLIssuer;
+
+ public static DistributionPoint GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static DistributionPoint GetInstance(
+ object obj)
+ {
+ if(obj == null || obj is DistributionPoint)
+ {
+ return (DistributionPoint) obj;
+ }
+
+ if(obj is Asn1Sequence)
+ {
+ return new DistributionPoint((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("Invalid DistributionPoint: " + Platform.GetTypeName(obj));
+ }
+
+ private DistributionPoint(
+ Asn1Sequence seq)
+ {
+ for (int i = 0; i != seq.Count; i++)
+ {
+ Asn1TaggedObject t = Asn1TaggedObject.GetInstance(seq[i]);
+
+ switch (t.TagNo)
+ {
+ case 0:
+ distributionPoint = DistributionPointName.GetInstance(t, true);
+ break;
+ case 1:
+ reasons = new ReasonFlags(DerBitString.GetInstance(t, false));
+ break;
+ case 2:
+ cRLIssuer = GeneralNames.GetInstance(t, false);
+ break;
+ }
+ }
+ }
+
+ public DistributionPoint(
+ DistributionPointName distributionPointName,
+ ReasonFlags reasons,
+ GeneralNames crlIssuer)
+ {
+ this.distributionPoint = distributionPointName;
+ this.reasons = reasons;
+ this.cRLIssuer = crlIssuer;
+ }
+
+ public DistributionPointName DistributionPointName
+ {
+ get { return distributionPoint; }
+ }
+
+ public ReasonFlags Reasons
+ {
+ get { return reasons; }
+ }
+
+ public GeneralNames CrlIssuer
+ {
+ get { return cRLIssuer; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (distributionPoint != null)
+ {
+ //
+ // as this is a CHOICE it must be explicitly tagged
+ //
+ v.Add(new DerTaggedObject(0, distributionPoint));
+ }
+
+ if (reasons != null)
+ {
+ v.Add(new DerTaggedObject(false, 1, reasons));
+ }
+
+ if (cRLIssuer != null)
+ {
+ v.Add(new DerTaggedObject(false, 2, cRLIssuer));
+ }
+
+ return new DerSequence(v);
+ }
+
+ public override string ToString()
+ {
+ string sep = Platform.NewLine;
+ StringBuilder buf = new StringBuilder();
+ buf.Append("DistributionPoint: [");
+ buf.Append(sep);
+ if (distributionPoint != null)
+ {
+ appendObject(buf, sep, "distributionPoint", distributionPoint.ToString());
+ }
+ if (reasons != null)
+ {
+ appendObject(buf, sep, "reasons", reasons.ToString());
+ }
+ if (cRLIssuer != null)
+ {
+ appendObject(buf, sep, "cRLIssuer", cRLIssuer.ToString());
+ }
+ buf.Append("]");
+ buf.Append(sep);
+ return buf.ToString();
+ }
+
+ private void appendObject(
+ StringBuilder buf,
+ string sep,
+ string name,
+ string val)
+ {
+ string indent = " ";
+
+ buf.Append(indent);
+ buf.Append(name);
+ buf.Append(":");
+ buf.Append(sep);
+ buf.Append(indent);
+ buf.Append(indent);
+ buf.Append(val);
+ buf.Append(sep);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/DistributionPointName.cs b/bc-sharp-crypto/src/asn1/x509/DistributionPointName.cs
new file mode 100644
index 0000000000000000000000000000000000000000..43fdaf53359f5e33b1d0e94094c9c0a5f828b366
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/DistributionPointName.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * The DistributionPointName object.
+ *
+ * DistributionPointName ::= CHOICE {
+ * fullName [0] GeneralNames,
+ * nameRelativeToCRLIssuer [1] RDN
+ * }
+ *
+ */
+ public class DistributionPointName
+ : Asn1Encodable, IAsn1Choice
+ {
+ internal readonly Asn1Encodable name;
+ internal readonly int type;
+
+ public const int FullName = 0;
+ public const int NameRelativeToCrlIssuer = 1;
+
+ public static DistributionPointName GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1TaggedObject.GetInstance(obj, true));
+ }
+
+ public static DistributionPointName GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is DistributionPointName)
+ {
+ return (DistributionPointName) obj;
+ }
+
+ if (obj is Asn1TaggedObject)
+ {
+ return new DistributionPointName((Asn1TaggedObject) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public DistributionPointName(
+ int type,
+ Asn1Encodable name)
+ {
+ this.type = type;
+ this.name = name;
+ }
+
+ public DistributionPointName(
+ GeneralNames name)
+ : this(FullName, name)
+ {
+ }
+
+ public int PointType
+ {
+ get { return type; }
+ }
+
+ public Asn1Encodable Name
+ {
+ get { return name; }
+ }
+
+ public DistributionPointName(
+ Asn1TaggedObject obj)
+ {
+ this.type = obj.TagNo;
+
+ if (type == FullName)
+ {
+ this.name = GeneralNames.GetInstance(obj, false);
+ }
+ else
+ {
+ this.name = Asn1Set.GetInstance(obj, false);
+ }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerTaggedObject(false, type, name);
+ }
+
+ public override string ToString()
+ {
+ string sep = Platform.NewLine;
+ StringBuilder buf = new StringBuilder();
+ buf.Append("DistributionPointName: [");
+ buf.Append(sep);
+ if (type == FullName)
+ {
+ appendObject(buf, sep, "fullName", name.ToString());
+ }
+ else
+ {
+ appendObject(buf, sep, "nameRelativeToCRLIssuer", name.ToString());
+ }
+ buf.Append("]");
+ buf.Append(sep);
+ return buf.ToString();
+ }
+
+ private void appendObject(
+ StringBuilder buf,
+ string sep,
+ string name,
+ string val)
+ {
+ string indent = " ";
+
+ buf.Append(indent);
+ buf.Append(name);
+ buf.Append(":");
+ buf.Append(sep);
+ buf.Append(indent);
+ buf.Append(indent);
+ buf.Append(val);
+ buf.Append(sep);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/ExtendedKeyUsage.cs b/bc-sharp-crypto/src/asn1/x509/ExtendedKeyUsage.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8f7e6a353e7315e4000f96e24ecda3db4f9066ea
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/ExtendedKeyUsage.cs
@@ -0,0 +1,132 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * The extendedKeyUsage object.
+ *
+ * extendedKeyUsage ::= Sequence SIZE (1..MAX) OF KeyPurposeId
+ *
+ */
+ public class ExtendedKeyUsage
+ : Asn1Encodable
+ {
+ internal readonly IDictionary usageTable = Platform.CreateHashtable();
+ internal readonly Asn1Sequence seq;
+
+ public static ExtendedKeyUsage GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static ExtendedKeyUsage GetInstance(
+ object obj)
+ {
+ if (obj is ExtendedKeyUsage)
+ {
+ return (ExtendedKeyUsage) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new ExtendedKeyUsage((Asn1Sequence) obj);
+ }
+
+ if (obj is X509Extension)
+ {
+ return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+ }
+
+ throw new ArgumentException("Invalid ExtendedKeyUsage: " + Platform.GetTypeName(obj));
+ }
+
+ private ExtendedKeyUsage(
+ Asn1Sequence seq)
+ {
+ this.seq = seq;
+
+ foreach (object o in seq)
+ {
+ if (!(o is DerObjectIdentifier))
+ throw new ArgumentException("Only DerObjectIdentifier instances allowed in ExtendedKeyUsage.");
+
+ this.usageTable[o] = o;
+ }
+ }
+
+ public ExtendedKeyUsage(
+ params KeyPurposeID[] usages)
+ {
+ this.seq = new DerSequence(usages);
+
+ foreach (KeyPurposeID usage in usages)
+ {
+ this.usageTable[usage] = usage;
+ }
+ }
+
+#if !(SILVERLIGHT || PORTABLE)
+ [Obsolete]
+ public ExtendedKeyUsage(
+ ArrayList usages)
+ : this((IEnumerable)usages)
+ {
+ }
+#endif
+
+ public ExtendedKeyUsage(
+ IEnumerable usages)
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ foreach (object usage in usages)
+ {
+ Asn1Encodable o = KeyPurposeID.GetInstance(usage);
+
+ v.Add(o);
+ this.usageTable[o] = o;
+ }
+
+ this.seq = new DerSequence(v);
+ }
+
+ public bool HasKeyPurposeId(
+ KeyPurposeID keyPurposeId)
+ {
+ return usageTable.Contains(keyPurposeId);
+ }
+
+#if !(SILVERLIGHT || PORTABLE)
+ [Obsolete("Use 'GetAllUsages'")]
+ public ArrayList GetUsages()
+ {
+ return new ArrayList(usageTable.Values);
+ }
+#endif
+
+ /**
+ * Returns all extended key usages.
+ * The returned ArrayList contains DerObjectIdentifier instances.
+ * @return An ArrayList with all key purposes.
+ */
+ public IList GetAllUsages()
+ {
+ return Platform.CreateArrayList(usageTable.Values);
+ }
+
+ public int Count
+ {
+ get { return usageTable.Count; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return seq;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/GeneralName.cs b/bc-sharp-crypto/src/asn1/x509/GeneralName.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b8794ea8fa9bc93c363178a4f39eec560bafb7c7
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/GeneralName.cs
@@ -0,0 +1,419 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+using NetUtils = Org.BouncyCastle.Utilities.Net;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * The GeneralName object.
+ *
+ * GeneralName ::= CHOICE {
+ * otherName [0] OtherName,
+ * rfc822Name [1] IA5String,
+ * dNSName [2] IA5String,
+ * x400Address [3] ORAddress,
+ * directoryName [4] Name,
+ * ediPartyName [5] EDIPartyName,
+ * uniformResourceIdentifier [6] IA5String,
+ * iPAddress [7] OCTET STRING,
+ * registeredID [8] OBJECT IDENTIFIER}
+ *
+ * OtherName ::= Sequence {
+ * type-id OBJECT IDENTIFIER,
+ * value [0] EXPLICIT ANY DEFINED BY type-id }
+ *
+ * EDIPartyName ::= Sequence {
+ * nameAssigner [0] DirectoryString OPTIONAL,
+ * partyName [1] DirectoryString }
+ *
+ */
+ public class GeneralName
+ : Asn1Encodable, IAsn1Choice
+ {
+ public const int OtherName = 0;
+ public const int Rfc822Name = 1;
+ public const int DnsName = 2;
+ public const int X400Address = 3;
+ public const int DirectoryName = 4;
+ public const int EdiPartyName = 5;
+ public const int UniformResourceIdentifier = 6;
+ public const int IPAddress = 7;
+ public const int RegisteredID = 8;
+
+ internal readonly Asn1Encodable obj;
+ internal readonly int tag;
+
+ public GeneralName(
+ X509Name directoryName)
+ {
+ this.obj = directoryName;
+ this.tag = 4;
+ }
+
+ /**
+ * When the subjectAltName extension contains an Internet mail address,
+ * the address MUST be included as an rfc822Name. The format of an
+ * rfc822Name is an "addr-spec" as defined in RFC 822 [RFC 822].
+ *
+ * When the subjectAltName extension contains a domain name service
+ * label, the domain name MUST be stored in the dNSName (an IA5String).
+ * The name MUST be in the "preferred name syntax," as specified by RFC
+ * 1034 [RFC 1034].
+ *
+ * When the subjectAltName extension contains a URI, the name MUST be
+ * stored in the uniformResourceIdentifier (an IA5String). The name MUST
+ * be a non-relative URL, and MUST follow the URL syntax and encoding
+ * rules specified in [RFC 1738]. The name must include both a scheme
+ * (e.g., "http" or "ftp") and a scheme-specific-part. The scheme-
+ * specific-part must include a fully qualified domain name or IP
+ * address as the host.
+ *
+ * When the subjectAltName extension contains a iPAddress, the address
+ * MUST be stored in the octet string in "network byte order," as
+ * specified in RFC 791 [RFC 791]. The least significant bit (LSB) of
+ * each octet is the LSB of the corresponding byte in the network
+ * address. For IP Version 4, as specified in RFC 791, the octet string
+ * MUST contain exactly four octets. For IP Version 6, as specified in
+ * RFC 1883, the octet string MUST contain exactly sixteen octets [RFC
+ * 1883].
+ */
+ public GeneralName(
+ Asn1Object name,
+ int tag)
+ {
+ this.obj = name;
+ this.tag = tag;
+ }
+
+ public GeneralName(
+ int tag,
+ Asn1Encodable name)
+ {
+ this.obj = name;
+ this.tag = tag;
+ }
+
+ /**
+ * Create a GeneralName for the given tag from the passed in string.
+ *
+ * This constructor can handle:
+ *
+ * rfc822Name
+ * iPAddress
+ * directoryName
+ * dNSName
+ * uniformResourceIdentifier
+ * registeredID
+ *
+ * For x400Address, otherName and ediPartyName there is no common string
+ * format defined.
+ *
+ * Note: A directory name can be encoded in different ways into a byte
+ * representation. Be aware of this if the byte representation is used for
+ * comparing results.
+ *
+ *
+ * @param tag tag number
+ * @param name string representation of name
+ * @throws ArgumentException if the string encoding is not correct or
+ * not supported.
+ */
+ public GeneralName(
+ int tag,
+ string name)
+ {
+ this.tag = tag;
+
+ if (tag == Rfc822Name || tag == DnsName || tag == UniformResourceIdentifier)
+ {
+ this.obj = new DerIA5String(name);
+ }
+ else if (tag == RegisteredID)
+ {
+ this.obj = new DerObjectIdentifier(name);
+ }
+ else if (tag == DirectoryName)
+ {
+ this.obj = new X509Name(name);
+ }
+ else if (tag == IPAddress)
+ {
+ byte[] enc = toGeneralNameEncoding(name);
+ if (enc == null)
+ throw new ArgumentException("IP Address is invalid", "name");
+
+ this.obj = new DerOctetString(enc);
+ }
+ else
+ {
+ throw new ArgumentException("can't process string for tag: " + tag, "tag");
+ }
+ }
+
+ public static GeneralName GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is GeneralName)
+ {
+ return (GeneralName) obj;
+ }
+
+ if (obj is Asn1TaggedObject)
+ {
+ Asn1TaggedObject tagObj = (Asn1TaggedObject) obj;
+ int tag = tagObj.TagNo;
+
+ switch (tag)
+ {
+ case OtherName:
+ return new GeneralName(tag, Asn1Sequence.GetInstance(tagObj, false));
+ case Rfc822Name:
+ return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false));
+ case DnsName:
+ return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false));
+ case X400Address:
+ throw new ArgumentException("unknown tag: " + tag);
+ case DirectoryName:
+ return new GeneralName(tag, X509Name.GetInstance(tagObj, true));
+ case EdiPartyName:
+ return new GeneralName(tag, Asn1Sequence.GetInstance(tagObj, false));
+ case UniformResourceIdentifier:
+ return new GeneralName(tag, DerIA5String.GetInstance(tagObj, false));
+ case IPAddress:
+ return new GeneralName(tag, Asn1OctetString.GetInstance(tagObj, false));
+ case RegisteredID:
+ return new GeneralName(tag, DerObjectIdentifier.GetInstance(tagObj, false));
+ }
+ }
+
+ if (obj is byte[])
+ {
+ try
+ {
+ return GetInstance(Asn1Object.FromByteArray((byte[])obj));
+ }
+ catch (IOException)
+ {
+ throw new ArgumentException("unable to parse encoded general name");
+ }
+ }
+
+ throw new ArgumentException("unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public static GeneralName GetInstance(
+ Asn1TaggedObject tagObj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1TaggedObject.GetInstance(tagObj, true));
+ }
+
+ public int TagNo
+ {
+ get { return tag; }
+ }
+
+ public Asn1Encodable Name
+ {
+ get { return obj; }
+ }
+
+ public override string ToString()
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.Append(tag);
+ buf.Append(": ");
+
+ switch (tag)
+ {
+ case Rfc822Name:
+ case DnsName:
+ case UniformResourceIdentifier:
+ buf.Append(DerIA5String.GetInstance(obj).GetString());
+ break;
+ case DirectoryName:
+ buf.Append(X509Name.GetInstance(obj).ToString());
+ break;
+ default:
+ buf.Append(obj.ToString());
+ break;
+ }
+
+ return buf.ToString();
+ }
+
+ private byte[] toGeneralNameEncoding(
+ string ip)
+ {
+ if (NetUtils.IPAddress.IsValidIPv6WithNetmask(ip) || NetUtils.IPAddress.IsValidIPv6(ip))
+ {
+ int slashIndex = ip.IndexOf('/');
+
+ if (slashIndex < 0)
+ {
+ byte[] addr = new byte[16];
+ int[] parsedIp = parseIPv6(ip);
+ copyInts(parsedIp, addr, 0);
+
+ return addr;
+ }
+ else
+ {
+ byte[] addr = new byte[32];
+ int[] parsedIp = parseIPv6(ip.Substring(0, slashIndex));
+ copyInts(parsedIp, addr, 0);
+ string mask = ip.Substring(slashIndex + 1);
+ if (mask.IndexOf(':') > 0)
+ {
+ parsedIp = parseIPv6(mask);
+ }
+ else
+ {
+ parsedIp = parseMask(mask);
+ }
+ copyInts(parsedIp, addr, 16);
+
+ return addr;
+ }
+ }
+ else if (NetUtils.IPAddress.IsValidIPv4WithNetmask(ip) || NetUtils.IPAddress.IsValidIPv4(ip))
+ {
+ int slashIndex = ip.IndexOf('/');
+
+ if (slashIndex < 0)
+ {
+ byte[] addr = new byte[4];
+
+ parseIPv4(ip, addr, 0);
+
+ return addr;
+ }
+ else
+ {
+ byte[] addr = new byte[8];
+
+ parseIPv4(ip.Substring(0, slashIndex), addr, 0);
+
+ string mask = ip.Substring(slashIndex + 1);
+ if (mask.IndexOf('.') > 0)
+ {
+ parseIPv4(mask, addr, 4);
+ }
+ else
+ {
+ parseIPv4Mask(mask, addr, 4);
+ }
+
+ return addr;
+ }
+ }
+
+ return null;
+ }
+
+ private void parseIPv4Mask(string mask, byte[] addr, int offset)
+ {
+ int maskVal = Int32.Parse(mask);
+
+ for (int i = 0; i != maskVal; i++)
+ {
+ addr[(i / 8) + offset] |= (byte)(1 << (i % 8));
+ }
+ }
+
+ private void parseIPv4(string ip, byte[] addr, int offset)
+ {
+ foreach (string token in ip.Split('.', '/'))
+ {
+ addr[offset++] = (byte)Int32.Parse(token);
+ }
+ }
+
+ private int[] parseMask(string mask)
+ {
+ int[] res = new int[8];
+ int maskVal = Int32.Parse(mask);
+
+ for (int i = 0; i != maskVal; i++)
+ {
+ res[i / 16] |= 1 << (i % 16);
+ }
+ return res;
+ }
+
+ private void copyInts(int[] parsedIp, byte[] addr, int offSet)
+ {
+ for (int i = 0; i != parsedIp.Length; i++)
+ {
+ addr[(i * 2) + offSet] = (byte)(parsedIp[i] >> 8);
+ addr[(i * 2 + 1) + offSet] = (byte)parsedIp[i];
+ }
+ }
+
+ private int[] parseIPv6(string ip)
+ {
+ if (Platform.StartsWith(ip, "::"))
+ {
+ ip = ip.Substring(1);
+ }
+ else if (Platform.EndsWith(ip, "::"))
+ {
+ ip = ip.Substring(0, ip.Length - 1);
+ }
+
+ IEnumerator sEnum = ip.Split(':').GetEnumerator();
+
+ int index = 0;
+ int[] val = new int[8];
+
+ int doubleColon = -1;
+
+ while (sEnum.MoveNext())
+ {
+ string e = (string) sEnum.Current;
+
+ if (e.Length == 0)
+ {
+ doubleColon = index;
+ val[index++] = 0;
+ }
+ else
+ {
+ if (e.IndexOf('.') < 0)
+ {
+ val[index++] = Int32.Parse(e, NumberStyles.AllowHexSpecifier);
+ }
+ else
+ {
+ string[] tokens = e.Split('.');
+
+ val[index++] = (Int32.Parse(tokens[0]) << 8) | Int32.Parse(tokens[1]);
+ val[index++] = (Int32.Parse(tokens[2]) << 8) | Int32.Parse(tokens[3]);
+ }
+ }
+ }
+
+ if (index != val.Length)
+ {
+ Array.Copy(val, doubleColon, val, val.Length - (index - doubleColon), index - doubleColon);
+ for (int i = doubleColon; i != val.Length - (index - doubleColon); i++)
+ {
+ val[i] = 0;
+ }
+ }
+
+ return val;
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ // Explicitly tagged if DirectoryName
+ return new DerTaggedObject(tag == DirectoryName, tag, obj);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/GeneralNames.cs b/bc-sharp-crypto/src/asn1/x509/GeneralNames.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fcd2ecb2482b39cb80e746a029ea44e805dc1b00
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/GeneralNames.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class GeneralNames
+ : Asn1Encodable
+ {
+ private readonly GeneralName[] names;
+
+ public static GeneralNames GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is GeneralNames)
+ {
+ return (GeneralNames) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new GeneralNames((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public static GeneralNames GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ /// Construct a GeneralNames object containing one GeneralName.
+ /// The name to be contained.
+ public GeneralNames(
+ GeneralName name)
+ {
+ names = new GeneralName[]{ name };
+ }
+
+ public GeneralNames(
+ GeneralName[] names)
+ {
+ this.names = (GeneralName[])names.Clone();
+ }
+
+ private GeneralNames(
+ Asn1Sequence seq)
+ {
+ this.names = new GeneralName[seq.Count];
+
+ for (int i = 0; i != seq.Count; i++)
+ {
+ names[i] = GeneralName.GetInstance(seq[i]);
+ }
+ }
+
+ public GeneralName[] GetNames()
+ {
+ return (GeneralName[]) names.Clone();
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * GeneralNames ::= Sequence SIZE {1..MAX} OF GeneralName
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(names);
+ }
+
+ public override string ToString()
+ {
+ StringBuilder buf = new StringBuilder();
+ string sep = Platform.NewLine;
+
+ buf.Append("GeneralNames:");
+ buf.Append(sep);
+
+ foreach (GeneralName name in names)
+ {
+ buf.Append(" ");
+ buf.Append(name);
+ buf.Append(sep);
+ }
+
+ return buf.ToString();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/GeneralSubtree.cs b/bc-sharp-crypto/src/asn1/x509/GeneralSubtree.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e918a027714dea5ff82d25d61eeb519788d7a77c
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/GeneralSubtree.cs
@@ -0,0 +1,189 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * Class for containing a restriction object subtrees in NameConstraints. See
+ * RFC 3280.
+ *
+ *
+ *
+ * GeneralSubtree ::= SEQUENCE
+ * {
+ * baseName GeneralName,
+ * minimum [0] BaseDistance DEFAULT 0,
+ * maximum [1] BaseDistance OPTIONAL
+ * }
+ *
+ *
+ * @see org.bouncycastle.asn1.x509.NameConstraints
+ *
+ */
+ public class GeneralSubtree
+ : Asn1Encodable
+ {
+ private readonly GeneralName baseName;
+ private readonly DerInteger minimum;
+ private readonly DerInteger maximum;
+
+ private GeneralSubtree(
+ Asn1Sequence seq)
+ {
+ baseName = GeneralName.GetInstance(seq[0]);
+
+ switch (seq.Count)
+ {
+ case 1:
+ break;
+ case 2:
+ {
+ Asn1TaggedObject o = Asn1TaggedObject.GetInstance(seq[1]);
+ switch (o.TagNo)
+ {
+ case 0:
+ minimum = DerInteger.GetInstance(o, false);
+ break;
+ case 1:
+ maximum = DerInteger.GetInstance(o, false);
+ break;
+ default:
+ throw new ArgumentException("Bad tag number: " + o.TagNo);
+ }
+ break;
+ }
+ case 3:
+ {
+ {
+ Asn1TaggedObject oMin = Asn1TaggedObject.GetInstance(seq[1]);
+ if (oMin.TagNo != 0)
+ throw new ArgumentException("Bad tag number for 'minimum': " + oMin.TagNo);
+ minimum = DerInteger.GetInstance(oMin, false);
+ }
+
+ {
+ Asn1TaggedObject oMax = Asn1TaggedObject.GetInstance(seq[2]);
+ if (oMax.TagNo != 1)
+ throw new ArgumentException("Bad tag number for 'maximum': " + oMax.TagNo);
+ maximum = DerInteger.GetInstance(oMax, false);
+ }
+
+ break;
+ }
+ default:
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+ }
+ }
+
+ /**
+ * Constructor from a given details.
+ *
+ * According RFC 3280, the minimum and maximum fields are not used with any
+ * name forms, thus minimum MUST be zero, and maximum MUST be absent.
+ *
+ * If minimum is null
, zero is assumed, if
+ * maximum is null
, maximum is absent.
+ *
+ * @param baseName
+ * A restriction.
+ * @param minimum
+ * Minimum
+ *
+ * @param maximum
+ * Maximum
+ */
+ public GeneralSubtree(
+ GeneralName baseName,
+ BigInteger minimum,
+ BigInteger maximum)
+ {
+ this.baseName = baseName;
+ if (minimum != null)
+ {
+ this.minimum = new DerInteger(minimum);
+ }
+ if (maximum != null)
+ {
+ this.maximum = new DerInteger(maximum);
+ }
+ }
+
+ public GeneralSubtree(
+ GeneralName baseName)
+ : this(baseName, null, null)
+ {
+ }
+
+ public static GeneralSubtree GetInstance(
+ Asn1TaggedObject o,
+ bool isExplicit)
+ {
+ return new GeneralSubtree(Asn1Sequence.GetInstance(o, isExplicit));
+ }
+
+ public static GeneralSubtree GetInstance(
+ object obj)
+ {
+ if (obj == null)
+ {
+ return null;
+ }
+
+ if (obj is GeneralSubtree)
+ {
+ return (GeneralSubtree) obj;
+ }
+
+ return new GeneralSubtree(Asn1Sequence.GetInstance(obj));
+ }
+
+ public GeneralName Base
+ {
+ get { return baseName; }
+ }
+
+ public BigInteger Minimum
+ {
+ get { return minimum == null ? BigInteger.Zero : minimum.Value; }
+ }
+
+ public BigInteger Maximum
+ {
+ get { return maximum == null ? null : maximum.Value; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * GeneralSubtree ::= SEQUENCE
+ * {
+ * baseName GeneralName,
+ * minimum [0] BaseDistance DEFAULT 0,
+ * maximum [1] BaseDistance OPTIONAL
+ * }
+ *
+ *
+ * @return a DERObject
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(baseName);
+
+ if (minimum != null && minimum.Value.SignValue != 0)
+ {
+ v.Add(new DerTaggedObject(false, 0, minimum));
+ }
+
+ if (maximum != null)
+ {
+ v.Add(new DerTaggedObject(false, 1, maximum));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/Holder.cs b/bc-sharp-crypto/src/asn1/x509/Holder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6e5315b8055317f37585cd7902190bbf16e2ec78
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/Holder.cs
@@ -0,0 +1,259 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * The Holder object.
+ *
+ * For an v2 attribute certificate this is:
+ *
+ *
+ * Holder ::= SEQUENCE {
+ * baseCertificateID [0] IssuerSerial OPTIONAL,
+ * -- the issuer and serial number of
+ * -- the holder's Public Key Certificate
+ * entityName [1] GeneralNames OPTIONAL,
+ * -- the name of the claimant or role
+ * objectDigestInfo [2] ObjectDigestInfo OPTIONAL
+ * -- used to directly authenticate the holder,
+ * -- for example, an executable
+ * }
+ *
+ *
+ *
+ * For an v1 attribute certificate this is:
+ *
+ *
+ * subject CHOICE {
+ * baseCertificateID [0] IssuerSerial,
+ * -- associated with a Public Key Certificate
+ * subjectName [1] GeneralNames },
+ * -- associated with a name
+ *
+ *
+ */
+ public class Holder
+ : Asn1Encodable
+ {
+ internal readonly IssuerSerial baseCertificateID;
+ internal readonly GeneralNames entityName;
+ internal readonly ObjectDigestInfo objectDigestInfo;
+ private readonly int version;
+
+ public static Holder GetInstance(
+ object obj)
+ {
+ if (obj is Holder)
+ {
+ return (Holder) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new Holder((Asn1Sequence) obj);
+ }
+
+ if (obj is Asn1TaggedObject)
+ {
+ return new Holder((Asn1TaggedObject) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * Constructor for a holder for an v1 attribute certificate.
+ *
+ * @param tagObj The ASN.1 tagged holder object.
+ */
+ public Holder(
+ Asn1TaggedObject tagObj)
+ {
+ switch (tagObj.TagNo)
+ {
+ case 0:
+ baseCertificateID = IssuerSerial.GetInstance(tagObj, false);
+ break;
+ case 1:
+ entityName = GeneralNames.GetInstance(tagObj, false);
+ break;
+ default:
+ throw new ArgumentException("unknown tag in Holder");
+ }
+
+ this.version = 0;
+ }
+
+ /**
+ * Constructor for a holder for an v2 attribute certificate. *
+ *
+ * @param seq The ASN.1 sequence.
+ */
+ private Holder(
+ Asn1Sequence seq)
+ {
+ if (seq.Count > 3)
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+ for (int i = 0; i != seq.Count; i++)
+ {
+ Asn1TaggedObject tObj = Asn1TaggedObject.GetInstance(seq[i]);
+
+ switch (tObj.TagNo)
+ {
+ case 0:
+ baseCertificateID = IssuerSerial.GetInstance(tObj, false);
+ break;
+ case 1:
+ entityName = GeneralNames.GetInstance(tObj, false);
+ break;
+ case 2:
+ objectDigestInfo = ObjectDigestInfo.GetInstance(tObj, false);
+ break;
+ default:
+ throw new ArgumentException("unknown tag in Holder");
+ }
+ }
+
+ this.version = 1;
+ }
+
+ public Holder(
+ IssuerSerial baseCertificateID)
+ : this(baseCertificateID, 1)
+ {
+ }
+
+ /**
+ * Constructs a holder from a IssuerSerial.
+ * @param baseCertificateID The IssuerSerial.
+ * @param version The version of the attribute certificate.
+ */
+ public Holder(
+ IssuerSerial baseCertificateID,
+ int version)
+ {
+ this.baseCertificateID = baseCertificateID;
+ this.version = version;
+ }
+
+ /**
+ * Returns 1 for v2 attribute certificates or 0 for v1 attribute
+ * certificates.
+ * @return The version of the attribute certificate.
+ */
+ public int Version
+ {
+ get { return version; }
+ }
+
+ /**
+ * Constructs a holder with an entityName for v2 attribute certificates or
+ * with a subjectName for v1 attribute certificates.
+ *
+ * @param entityName The entity or subject name.
+ */
+ public Holder(
+ GeneralNames entityName)
+ : this(entityName, 1)
+ {
+ }
+
+ /**
+ * Constructs a holder with an entityName for v2 attribute certificates or
+ * with a subjectName for v1 attribute certificates.
+ *
+ * @param entityName The entity or subject name.
+ * @param version The version of the attribute certificate.
+ */
+ public Holder(
+ GeneralNames entityName,
+ int version)
+ {
+ this.entityName = entityName;
+ this.version = version;
+ }
+
+ /**
+ * Constructs a holder from an object digest info.
+ *
+ * @param objectDigestInfo The object digest info object.
+ */
+ public Holder(
+ ObjectDigestInfo objectDigestInfo)
+ {
+ this.objectDigestInfo = objectDigestInfo;
+ this.version = 1;
+ }
+
+ public IssuerSerial BaseCertificateID
+ {
+ get { return baseCertificateID; }
+ }
+
+ /**
+ * Returns the entityName for an v2 attribute certificate or the subjectName
+ * for an v1 attribute certificate.
+ *
+ * @return The entityname or subjectname.
+ */
+ public GeneralNames EntityName
+ {
+ get { return entityName; }
+ }
+
+ public ObjectDigestInfo ObjectDigestInfo
+ {
+ get { return objectDigestInfo; }
+ }
+
+ /**
+ * The Holder object.
+ *
+ * Holder ::= Sequence {
+ * baseCertificateID [0] IssuerSerial OPTIONAL,
+ * -- the issuer and serial number of
+ * -- the holder's Public Key Certificate
+ * entityName [1] GeneralNames OPTIONAL,
+ * -- the name of the claimant or role
+ * objectDigestInfo [2] ObjectDigestInfo OPTIONAL
+ * -- used to directly authenticate the holder,
+ * -- for example, an executable
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ if (version == 1)
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (baseCertificateID != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, baseCertificateID));
+ }
+
+ if (entityName != null)
+ {
+ v.Add(new DerTaggedObject(false, 1, entityName));
+ }
+
+ if (objectDigestInfo != null)
+ {
+ v.Add(new DerTaggedObject(false, 2, objectDigestInfo));
+ }
+
+ return new DerSequence(v);
+ }
+
+ if (entityName != null)
+ {
+ return new DerTaggedObject(false, 1, entityName);
+ }
+
+ return new DerTaggedObject(false, 0, baseCertificateID);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/IetfAttrSyntax.cs b/bc-sharp-crypto/src/asn1/x509/IetfAttrSyntax.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e719865b3a5377c893f33b7afa0e1cf2909ef8de
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/IetfAttrSyntax.cs
@@ -0,0 +1,161 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * Implementation of IetfAttrSyntax
as specified by RFC3281.
+ */
+ public class IetfAttrSyntax
+ : Asn1Encodable
+ {
+ public const int ValueOctets = 1;
+ public const int ValueOid = 2;
+ public const int ValueUtf8 = 3;
+
+ internal readonly GeneralNames policyAuthority;
+ internal readonly Asn1EncodableVector values = new Asn1EncodableVector();
+
+ internal int valueChoice = -1;
+
+ /**
+ *
+ */
+ public IetfAttrSyntax(
+ Asn1Sequence seq)
+ {
+ int i = 0;
+
+ if (seq[0] is Asn1TaggedObject)
+ {
+ policyAuthority = GeneralNames.GetInstance(((Asn1TaggedObject)seq[0]), false);
+ i++;
+ }
+ else if (seq.Count == 2)
+ { // VOMS fix
+ policyAuthority = GeneralNames.GetInstance(seq[0]);
+ i++;
+ }
+
+ if (!(seq[i] is Asn1Sequence))
+ {
+ throw new ArgumentException("Non-IetfAttrSyntax encoding");
+ }
+
+ seq = (Asn1Sequence) seq[i];
+
+ foreach (Asn1Object obj in seq)
+ {
+ int type;
+
+ if (obj is DerObjectIdentifier)
+ {
+ type = ValueOid;
+ }
+ else if (obj is DerUtf8String)
+ {
+ type = ValueUtf8;
+ }
+ else if (obj is DerOctetString)
+ {
+ type = ValueOctets;
+ }
+ else
+ {
+ throw new ArgumentException("Bad value type encoding IetfAttrSyntax");
+ }
+
+ if (valueChoice < 0)
+ {
+ valueChoice = type;
+ }
+
+ if (type != valueChoice)
+ {
+ throw new ArgumentException("Mix of value types in IetfAttrSyntax");
+ }
+
+ values.Add(obj);
+ }
+ }
+
+ public GeneralNames PolicyAuthority
+ {
+ get { return policyAuthority; }
+ }
+
+ public int ValueType
+ {
+ get { return valueChoice; }
+ }
+
+ public object[] GetValues()
+ {
+ if (this.ValueType == ValueOctets)
+ {
+ Asn1OctetString[] tmp = new Asn1OctetString[values.Count];
+
+ for (int i = 0; i != tmp.Length; i++)
+ {
+ tmp[i] = (Asn1OctetString) values[i];
+ }
+
+ return tmp;
+ }
+
+ if (this.ValueType == ValueOid)
+ {
+ DerObjectIdentifier[] tmp = new DerObjectIdentifier[values.Count];
+
+ for (int i = 0; i != tmp.Length; i++)
+ {
+ tmp[i] = (DerObjectIdentifier) values[i];
+ }
+
+ return tmp;
+ }
+
+ {
+ DerUtf8String[] tmp = new DerUtf8String[values.Count];
+
+ for (int i = 0; i != tmp.Length; i++)
+ {
+ tmp[i] = (DerUtf8String) values[i];
+ }
+
+ return tmp;
+ }
+ }
+
+ /**
+ *
+ *
+ *
+ * IetfAttrSyntax ::= Sequence {
+ * policyAuthority [0] GeneralNames OPTIONAL,
+ * values Sequence OF CHOICE {
+ * octets OCTET STRING,
+ * oid OBJECT IDENTIFIER,
+ * string UTF8String
+ * }
+ * }
+ *
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (policyAuthority != null)
+ {
+ v.Add(new DerTaggedObject(0, policyAuthority));
+ }
+
+ v.Add(new DerSequence(values));
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/IssuerSerial.cs b/bc-sharp-crypto/src/asn1/x509/IssuerSerial.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1e47e022b50db1b5db620358a4080637dc1bbffd
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/IssuerSerial.cs
@@ -0,0 +1,100 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class IssuerSerial
+ : Asn1Encodable
+ {
+ internal readonly GeneralNames issuer;
+ internal readonly DerInteger serial;
+ internal readonly DerBitString issuerUid;
+
+ public static IssuerSerial GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is IssuerSerial)
+ {
+ return (IssuerSerial) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new IssuerSerial((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public static IssuerSerial GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ private IssuerSerial(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2 && seq.Count != 3)
+ {
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+ }
+
+ issuer = GeneralNames.GetInstance(seq[0]);
+ serial = DerInteger.GetInstance(seq[1]);
+
+ if (seq.Count == 3)
+ {
+ issuerUid = DerBitString.GetInstance(seq[2]);
+ }
+ }
+
+ public IssuerSerial(
+ GeneralNames issuer,
+ DerInteger serial)
+ {
+ this.issuer = issuer;
+ this.serial = serial;
+ }
+
+ public GeneralNames Issuer
+ {
+ get { return issuer; }
+ }
+
+ public DerInteger Serial
+ {
+ get { return serial; }
+ }
+
+ public DerBitString IssuerUid
+ {
+ get { return issuerUid; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * IssuerSerial ::= Sequence {
+ * issuer GeneralNames,
+ * serial CertificateSerialNumber,
+ * issuerUid UniqueIdentifier OPTIONAL
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ issuer, serial);
+
+ if (issuerUid != null)
+ {
+ v.Add(issuerUid);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/IssuingDistributionPoint.cs b/bc-sharp-crypto/src/asn1/x509/IssuingDistributionPoint.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8e9362b90bf217fcb2f1f336f46ea669103264d1
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/IssuingDistributionPoint.cs
@@ -0,0 +1,247 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ *
+ * IssuingDistributionPoint ::= SEQUENCE {
+ * distributionPoint [0] DistributionPointName OPTIONAL,
+ * onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE,
+ * onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE,
+ * onlySomeReasons [3] ReasonFlags OPTIONAL,
+ * indirectCRL [4] BOOLEAN DEFAULT FALSE,
+ * onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }
+ *
+ */
+ public class IssuingDistributionPoint
+ : Asn1Encodable
+ {
+ private readonly DistributionPointName _distributionPoint;
+ private readonly bool _onlyContainsUserCerts;
+ private readonly bool _onlyContainsCACerts;
+ private readonly ReasonFlags _onlySomeReasons;
+ private readonly bool _indirectCRL;
+ private readonly bool _onlyContainsAttributeCerts;
+
+ private readonly Asn1Sequence seq;
+
+ public static IssuingDistributionPoint GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static IssuingDistributionPoint GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is IssuingDistributionPoint)
+ {
+ return (IssuingDistributionPoint) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new IssuingDistributionPoint((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * Constructor from given details.
+ *
+ * @param distributionPoint
+ * May contain an URI as pointer to most current CRL.
+ * @param onlyContainsUserCerts Covers revocation information for end certificates.
+ * @param onlyContainsCACerts Covers revocation information for CA certificates.
+ *
+ * @param onlySomeReasons
+ * Which revocation reasons does this point cover.
+ * @param indirectCRL
+ * If true
then the CRL contains revocation
+ * information about certificates ssued by other CAs.
+ * @param onlyContainsAttributeCerts Covers revocation information for attribute certificates.
+ */
+ public IssuingDistributionPoint(
+ DistributionPointName distributionPoint,
+ bool onlyContainsUserCerts,
+ bool onlyContainsCACerts,
+ ReasonFlags onlySomeReasons,
+ bool indirectCRL,
+ bool onlyContainsAttributeCerts)
+ {
+ this._distributionPoint = distributionPoint;
+ this._indirectCRL = indirectCRL;
+ this._onlyContainsAttributeCerts = onlyContainsAttributeCerts;
+ this._onlyContainsCACerts = onlyContainsCACerts;
+ this._onlyContainsUserCerts = onlyContainsUserCerts;
+ this._onlySomeReasons = onlySomeReasons;
+
+ Asn1EncodableVector vec = new Asn1EncodableVector();
+ if (distributionPoint != null)
+ { // CHOICE item so explicitly tagged
+ vec.Add(new DerTaggedObject(true, 0, distributionPoint));
+ }
+ if (onlyContainsUserCerts)
+ {
+ vec.Add(new DerTaggedObject(false, 1, DerBoolean.True));
+ }
+ if (onlyContainsCACerts)
+ {
+ vec.Add(new DerTaggedObject(false, 2, DerBoolean.True));
+ }
+ if (onlySomeReasons != null)
+ {
+ vec.Add(new DerTaggedObject(false, 3, onlySomeReasons));
+ }
+ if (indirectCRL)
+ {
+ vec.Add(new DerTaggedObject(false, 4, DerBoolean.True));
+ }
+ if (onlyContainsAttributeCerts)
+ {
+ vec.Add(new DerTaggedObject(false, 5, DerBoolean.True));
+ }
+
+ seq = new DerSequence(vec);
+ }
+
+ /**
+ * Constructor from Asn1Sequence
+ */
+ private IssuingDistributionPoint(
+ Asn1Sequence seq)
+ {
+ this.seq = seq;
+
+ for (int i = 0; i != seq.Count; i++)
+ {
+ Asn1TaggedObject o = Asn1TaggedObject.GetInstance(seq[i]);
+
+ switch (o.TagNo)
+ {
+ case 0:
+ // CHOICE so explicit
+ _distributionPoint = DistributionPointName.GetInstance(o, true);
+ break;
+ case 1:
+ _onlyContainsUserCerts = DerBoolean.GetInstance(o, false).IsTrue;
+ break;
+ case 2:
+ _onlyContainsCACerts = DerBoolean.GetInstance(o, false).IsTrue;
+ break;
+ case 3:
+ _onlySomeReasons = new ReasonFlags(ReasonFlags.GetInstance(o, false));
+ break;
+ case 4:
+ _indirectCRL = DerBoolean.GetInstance(o, false).IsTrue;
+ break;
+ case 5:
+ _onlyContainsAttributeCerts = DerBoolean.GetInstance(o, false).IsTrue;
+ break;
+ default:
+ throw new ArgumentException("unknown tag in IssuingDistributionPoint");
+ }
+ }
+ }
+
+ public bool OnlyContainsUserCerts
+ {
+ get { return _onlyContainsUserCerts; }
+ }
+
+ public bool OnlyContainsCACerts
+ {
+ get { return _onlyContainsCACerts; }
+ }
+
+ public bool IsIndirectCrl
+ {
+ get { return _indirectCRL; }
+ }
+
+ public bool OnlyContainsAttributeCerts
+ {
+ get { return _onlyContainsAttributeCerts; }
+ }
+
+ /**
+ * @return Returns the distributionPoint.
+ */
+ public DistributionPointName DistributionPoint
+ {
+ get { return _distributionPoint; }
+ }
+
+ /**
+ * @return Returns the onlySomeReasons.
+ */
+ public ReasonFlags OnlySomeReasons
+ {
+ get { return _onlySomeReasons; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return seq;
+ }
+
+ public override string ToString()
+ {
+ string sep = Platform.NewLine;
+ StringBuilder buf = new StringBuilder();
+
+ buf.Append("IssuingDistributionPoint: [");
+ buf.Append(sep);
+ if (_distributionPoint != null)
+ {
+ appendObject(buf, sep, "distributionPoint", _distributionPoint.ToString());
+ }
+ if (_onlyContainsUserCerts)
+ {
+ appendObject(buf, sep, "onlyContainsUserCerts", _onlyContainsUserCerts.ToString());
+ }
+ if (_onlyContainsCACerts)
+ {
+ appendObject(buf, sep, "onlyContainsCACerts", _onlyContainsCACerts.ToString());
+ }
+ if (_onlySomeReasons != null)
+ {
+ appendObject(buf, sep, "onlySomeReasons", _onlySomeReasons.ToString());
+ }
+ if (_onlyContainsAttributeCerts)
+ {
+ appendObject(buf, sep, "onlyContainsAttributeCerts", _onlyContainsAttributeCerts.ToString());
+ }
+ if (_indirectCRL)
+ {
+ appendObject(buf, sep, "indirectCRL", _indirectCRL.ToString());
+ }
+ buf.Append("]");
+ buf.Append(sep);
+ return buf.ToString();
+ }
+
+ private void appendObject(
+ StringBuilder buf,
+ string sep,
+ string name,
+ string val)
+ {
+ string indent = " ";
+
+ buf.Append(indent);
+ buf.Append(name);
+ buf.Append(":");
+ buf.Append(sep);
+ buf.Append(indent);
+ buf.Append(indent);
+ buf.Append(val);
+ buf.Append(sep);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/KeyPurposeId.cs b/bc-sharp-crypto/src/asn1/x509/KeyPurposeId.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1a564b97a1efeb2748b4e8840f4b0926fc0232f2
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/KeyPurposeId.cs
@@ -0,0 +1,38 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * The KeyPurposeID object.
+ *
+ * KeyPurposeID ::= OBJECT IDENTIFIER
+ *
+ */
+ public sealed class KeyPurposeID
+ : DerObjectIdentifier
+ {
+ private const string IdKP = "1.3.6.1.5.5.7.3";
+
+ private KeyPurposeID(
+ string id)
+ : base(id)
+ {
+ }
+
+ public static readonly KeyPurposeID AnyExtendedKeyUsage = new KeyPurposeID(X509Extensions.ExtendedKeyUsage.Id + ".0");
+ public static readonly KeyPurposeID IdKPServerAuth = new KeyPurposeID(IdKP + ".1");
+ public static readonly KeyPurposeID IdKPClientAuth = new KeyPurposeID(IdKP + ".2");
+ public static readonly KeyPurposeID IdKPCodeSigning = new KeyPurposeID(IdKP + ".3");
+ public static readonly KeyPurposeID IdKPEmailProtection = new KeyPurposeID(IdKP + ".4");
+ public static readonly KeyPurposeID IdKPIpsecEndSystem = new KeyPurposeID(IdKP + ".5");
+ public static readonly KeyPurposeID IdKPIpsecTunnel = new KeyPurposeID(IdKP + ".6");
+ public static readonly KeyPurposeID IdKPIpsecUser = new KeyPurposeID(IdKP + ".7");
+ public static readonly KeyPurposeID IdKPTimeStamping = new KeyPurposeID(IdKP + ".8");
+ public static readonly KeyPurposeID IdKPOcspSigning = new KeyPurposeID(IdKP + ".9");
+
+ //
+ // microsoft key purpose ids
+ //
+ public static readonly KeyPurposeID IdKPSmartCardLogon = new KeyPurposeID("1.3.6.1.4.1.311.20.2.2");
+
+ public static readonly KeyPurposeID IdKPMacAddress = new KeyPurposeID("1.3.6.1.1.1.1.22");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/KeyUsage.cs b/bc-sharp-crypto/src/asn1/x509/KeyUsage.cs
new file mode 100644
index 0000000000000000000000000000000000000000..aeaffb70827d2b5f85e537b0d46c8246baad8c01
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/KeyUsage.cs
@@ -0,0 +1,78 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * The KeyUsage object.
+ *
+ * id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 }
+ *
+ * KeyUsage ::= BIT STRING {
+ * digitalSignature (0),
+ * nonRepudiation (1),
+ * keyEncipherment (2),
+ * dataEncipherment (3),
+ * keyAgreement (4),
+ * keyCertSign (5),
+ * cRLSign (6),
+ * encipherOnly (7),
+ * decipherOnly (8) }
+ *
+ */
+ public class KeyUsage
+ : DerBitString
+ {
+ public const int DigitalSignature = (1 << 7);
+ public const int NonRepudiation = (1 << 6);
+ public const int KeyEncipherment = (1 << 5);
+ public const int DataEncipherment = (1 << 4);
+ public const int KeyAgreement = (1 << 3);
+ public const int KeyCertSign = (1 << 2);
+ public const int CrlSign = (1 << 1);
+ public const int EncipherOnly = (1 << 0);
+ public const int DecipherOnly = (1 << 15);
+
+ public static new KeyUsage GetInstance(
+ object obj)
+ {
+ if (obj is KeyUsage)
+ {
+ return (KeyUsage)obj;
+ }
+
+ if (obj is X509Extension)
+ {
+ return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+ }
+
+ return new KeyUsage(DerBitString.GetInstance(obj));
+ }
+
+ /**
+ * Basic constructor.
+ *
+ * @param usage - the bitwise OR of the Key Usage flags giving the
+ * allowed uses for the key.
+ * e.g. (KeyUsage.keyEncipherment | KeyUsage.dataEncipherment)
+ */
+ public KeyUsage(int usage)
+ : base(usage)
+ {
+ }
+
+ private KeyUsage(
+ DerBitString usage)
+ : base(usage.GetBytes(), usage.PadBits)
+ {
+ }
+
+ public override string ToString()
+ {
+ byte[] data = GetBytes();
+ if (data.Length == 1)
+ {
+ return "KeyUsage: 0x" + (data[0] & 0xff).ToString("X");
+ }
+
+ return "KeyUsage: 0x" + ((data[1] & 0xff) << 8 | (data[0] & 0xff)).ToString("X");
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/NameConstraints.cs b/bc-sharp-crypto/src/asn1/x509/NameConstraints.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0c5fea8b3cf2c8382fb2d1c6b611b9e119fb4c00
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/NameConstraints.cs
@@ -0,0 +1,120 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class NameConstraints
+ : Asn1Encodable
+ {
+ private Asn1Sequence permitted, excluded;
+
+ public static NameConstraints GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is NameConstraints)
+ {
+ return (NameConstraints) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new NameConstraints((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public NameConstraints(
+ Asn1Sequence seq)
+ {
+ foreach (Asn1TaggedObject o in seq)
+ {
+ switch (o.TagNo)
+ {
+ case 0:
+ permitted = Asn1Sequence.GetInstance(o, false);
+ break;
+ case 1:
+ excluded = Asn1Sequence.GetInstance(o, false);
+ break;
+ }
+ }
+ }
+
+#if !(SILVERLIGHT || PORTABLE)
+ public NameConstraints(
+ ArrayList permitted,
+ ArrayList excluded)
+ : this((IList)permitted, (IList)excluded)
+ {
+ }
+#endif
+
+ /**
+ * Constructor from a given details.
+ *
+ * permitted and excluded are Vectors of GeneralSubtree objects.
+ *
+ * @param permitted Permitted subtrees
+ * @param excluded Excluded subtrees
+ */
+ public NameConstraints(
+ IList permitted,
+ IList excluded)
+ {
+ if (permitted != null)
+ {
+ this.permitted = CreateSequence(permitted);
+ }
+
+ if (excluded != null)
+ {
+ this.excluded = CreateSequence(excluded);
+ }
+ }
+
+ private DerSequence CreateSequence(
+ IList subtrees)
+ {
+ GeneralSubtree[] gsts = new GeneralSubtree[subtrees.Count];
+ for (int i = 0; i < subtrees.Count; ++i)
+ {
+ gsts[i] = (GeneralSubtree)subtrees[i];
+ }
+ return new DerSequence(gsts);
+ }
+
+ public Asn1Sequence PermittedSubtrees
+ {
+ get { return permitted; }
+ }
+
+ public Asn1Sequence ExcludedSubtrees
+ {
+ get { return excluded; }
+ }
+
+ /*
+ * NameConstraints ::= SEQUENCE { permittedSubtrees [0] GeneralSubtrees
+ * OPTIONAL, excludedSubtrees [1] GeneralSubtrees OPTIONAL }
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (permitted != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, permitted));
+ }
+
+ if (excluded != null)
+ {
+ v.Add(new DerTaggedObject(false, 1, excluded));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/NoticeReference.cs b/bc-sharp-crypto/src/asn1/x509/NoticeReference.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f0d3a7b7f686b0bd18d3d2298820959025f8cc0c
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/NoticeReference.cs
@@ -0,0 +1,143 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * NoticeReference
class, used in
+ * CertificatePolicies
X509 V3 extensions
+ * (in policy qualifiers).
+ *
+ *
+ * NoticeReference ::= Sequence {
+ * organization DisplayText,
+ * noticeNumbers Sequence OF Integer }
+ *
+ *
+ *
+ * @see PolicyQualifierInfo
+ * @see PolicyInformation
+ */
+ public class NoticeReference
+ : Asn1Encodable
+ {
+ private readonly DisplayText organization;
+ private readonly Asn1Sequence noticeNumbers;
+
+ private static Asn1EncodableVector ConvertVector(IList numbers)
+ {
+ Asn1EncodableVector av = new Asn1EncodableVector();
+
+ foreach (object o in numbers)
+ {
+ DerInteger di;
+
+ if (o is BigInteger)
+ {
+ di = new DerInteger((BigInteger)o);
+ }
+ else if (o is int)
+ {
+ di = new DerInteger((int)o);
+ }
+ else
+ {
+ throw new ArgumentException();
+ }
+
+ av.Add(di);
+ }
+ return av;
+ }
+
+ /**
+ * Creates a new NoticeReference
instance.
+ *
+ * @param organization a String
value
+ * @param numbers a Vector
value
+ */
+ public NoticeReference(string organization, IList numbers)
+ : this(organization, ConvertVector(numbers))
+ {
+ }
+
+ /**
+ * Creates a new NoticeReference
instance.
+ *
+ * @param organization a String
value
+ * @param noticeNumbers an ASN1EncodableVector
value
+ */
+ public NoticeReference(string organization, Asn1EncodableVector noticeNumbers)
+ : this(new DisplayText(organization), noticeNumbers)
+ {
+ }
+
+ /**
+ * Creates a new NoticeReference
instance.
+ *
+ * @param organization displayText
+ * @param noticeNumbers an ASN1EncodableVector
value
+ */
+ public NoticeReference(DisplayText organization, Asn1EncodableVector noticeNumbers)
+ {
+ this.organization = organization;
+ this.noticeNumbers = new DerSequence(noticeNumbers);
+ }
+
+ /**
+ * Creates a new NoticeReference
instance.
+ * Useful for reconstructing a NoticeReference
+ * instance from its encodable/encoded form.
+ *
+ * @param as an Asn1Sequence
value obtained from either
+ * calling @{link ToAsn1Object()} for a NoticeReference
+ * instance or from parsing it from a Der-encoded stream.
+ */
+ private NoticeReference(Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ organization = DisplayText.GetInstance(seq[0]);
+ noticeNumbers = Asn1Sequence.GetInstance(seq[1]);
+ }
+
+ public static NoticeReference GetInstance(object obj)
+ {
+ if (obj is NoticeReference)
+ return (NoticeReference)obj;
+ if (obj == null)
+ return null;
+ return new NoticeReference(Asn1Sequence.GetInstance(obj));
+ }
+
+ public virtual DisplayText Organization
+ {
+ get { return organization; }
+ }
+
+ public virtual DerInteger[] GetNoticeNumbers()
+ {
+ DerInteger[] tmp = new DerInteger[noticeNumbers.Count];
+
+ for (int i = 0; i != noticeNumbers.Count; ++i)
+ {
+ tmp[i] = DerInteger.GetInstance(noticeNumbers[i]);
+ }
+
+ return tmp;
+ }
+
+ /**
+ * Describe ToAsn1Object
method here.
+ *
+ * @return a Asn1Object
value
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(organization, noticeNumbers);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/ObjectDigestInfo.cs b/bc-sharp-crypto/src/asn1/x509/ObjectDigestInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9cd9a5f4cfd4250521d34e29a59b8c7aba305c24
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/ObjectDigestInfo.cs
@@ -0,0 +1,179 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * ObjectDigestInfo ASN.1 structure used in v2 attribute certificates.
+ *
+ *
+ *
+ * ObjectDigestInfo ::= SEQUENCE {
+ * digestedObjectType ENUMERATED {
+ * publicKey (0),
+ * publicKeyCert (1),
+ * otherObjectTypes (2) },
+ * -- otherObjectTypes MUST NOT
+ * -- be used in this profile
+ * otherObjectTypeID OBJECT IDENTIFIER OPTIONAL,
+ * digestAlgorithm AlgorithmIdentifier,
+ * objectDigest BIT STRING
+ * }
+ *
+ *
+ *
+ */
+ public class ObjectDigestInfo
+ : Asn1Encodable
+ {
+ /**
+ * The public key is hashed.
+ */
+ public const int PublicKey = 0;
+
+ /**
+ * The public key certificate is hashed.
+ */
+ public const int PublicKeyCert = 1;
+
+ /**
+ * An other object is hashed.
+ */
+ public const int OtherObjectDigest = 2;
+
+ internal readonly DerEnumerated digestedObjectType;
+ internal readonly DerObjectIdentifier otherObjectTypeID;
+ internal readonly AlgorithmIdentifier digestAlgorithm;
+ internal readonly DerBitString objectDigest;
+
+ public static ObjectDigestInfo GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is ObjectDigestInfo)
+ {
+ return (ObjectDigestInfo) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new ObjectDigestInfo((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public static ObjectDigestInfo GetInstance(
+ Asn1TaggedObject obj,
+ bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ /**
+ * Constructor from given details.
+ *
+ * If digestedObjectType
is not {@link #publicKeyCert} or
+ * {@link #publicKey} otherObjectTypeID
must be given,
+ * otherwise it is ignored.
+ *
+ * @param digestedObjectType The digest object type.
+ * @param otherObjectTypeID The object type ID for
+ * otherObjectDigest
.
+ * @param digestAlgorithm The algorithm identifier for the hash.
+ * @param objectDigest The hash value.
+ */
+ public ObjectDigestInfo(
+ int digestedObjectType,
+ string otherObjectTypeID,
+ AlgorithmIdentifier digestAlgorithm,
+ byte[] objectDigest)
+ {
+ this.digestedObjectType = new DerEnumerated(digestedObjectType);
+
+ if (digestedObjectType == OtherObjectDigest)
+ {
+ this.otherObjectTypeID = new DerObjectIdentifier(otherObjectTypeID);
+ }
+
+ this.digestAlgorithm = digestAlgorithm;
+
+ this.objectDigest = new DerBitString(objectDigest);
+ }
+
+ private ObjectDigestInfo(
+ Asn1Sequence seq)
+ {
+ if (seq.Count > 4 || seq.Count < 3)
+ {
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+ }
+
+ digestedObjectType = DerEnumerated.GetInstance(seq[0]);
+
+ int offset = 0;
+
+ if (seq.Count == 4)
+ {
+ otherObjectTypeID = DerObjectIdentifier.GetInstance(seq[1]);
+ offset++;
+ }
+
+ digestAlgorithm = AlgorithmIdentifier.GetInstance(seq[1 + offset]);
+ objectDigest = DerBitString.GetInstance(seq[2 + offset]);
+ }
+
+ public DerEnumerated DigestedObjectType
+ {
+ get { return digestedObjectType; }
+ }
+
+ public DerObjectIdentifier OtherObjectTypeID
+ {
+ get { return otherObjectTypeID; }
+ }
+
+ public AlgorithmIdentifier DigestAlgorithm
+ {
+ get { return digestAlgorithm; }
+ }
+
+ public DerBitString ObjectDigest
+ {
+ get { return objectDigest; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ *
+ *
+ * ObjectDigestInfo ::= SEQUENCE {
+ * digestedObjectType ENUMERATED {
+ * publicKey (0),
+ * publicKeyCert (1),
+ * otherObjectTypes (2) },
+ * -- otherObjectTypes MUST NOT
+ * -- be used in this profile
+ * otherObjectTypeID OBJECT IDENTIFIER OPTIONAL,
+ * digestAlgorithm AlgorithmIdentifier,
+ * objectDigest BIT STRING
+ * }
+ *
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(digestedObjectType);
+
+ if (otherObjectTypeID != null)
+ {
+ v.Add(otherObjectTypeID);
+ }
+
+ v.Add(digestAlgorithm, objectDigest);
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/PolicyInformation.cs b/bc-sharp-crypto/src/asn1/x509/PolicyInformation.cs
new file mode 100644
index 0000000000000000000000000000000000000000..29d245084a149e87e00c1fbcee3f2b53233965aa
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/PolicyInformation.cs
@@ -0,0 +1,80 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class PolicyInformation
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier policyIdentifier;
+ private readonly Asn1Sequence policyQualifiers;
+
+ private PolicyInformation(
+ Asn1Sequence seq)
+ {
+ if (seq.Count < 1 || seq.Count > 2)
+ {
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+ }
+
+ policyIdentifier = DerObjectIdentifier.GetInstance(seq[0]);
+
+ if (seq.Count > 1)
+ {
+ policyQualifiers = Asn1Sequence.GetInstance(seq[1]);
+ }
+ }
+
+ public PolicyInformation(
+ DerObjectIdentifier policyIdentifier)
+ {
+ this.policyIdentifier = policyIdentifier;
+ }
+
+ public PolicyInformation(
+ DerObjectIdentifier policyIdentifier,
+ Asn1Sequence policyQualifiers)
+ {
+ this.policyIdentifier = policyIdentifier;
+ this.policyQualifiers = policyQualifiers;
+ }
+
+ public static PolicyInformation GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is PolicyInformation)
+ {
+ return (PolicyInformation) obj;
+ }
+
+ return new PolicyInformation(Asn1Sequence.GetInstance(obj));
+ }
+
+ public DerObjectIdentifier PolicyIdentifier
+ {
+ get { return policyIdentifier; }
+ }
+
+ public Asn1Sequence PolicyQualifiers
+ {
+ get { return policyQualifiers; }
+ }
+
+ /*
+ * PolicyInformation ::= Sequence {
+ * policyIdentifier CertPolicyId,
+ * policyQualifiers Sequence SIZE (1..MAX) OF
+ * PolicyQualifierInfo OPTIONAL }
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(policyIdentifier);
+
+ if (policyQualifiers != null)
+ {
+ v.Add(policyQualifiers);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/PolicyMappings.cs b/bc-sharp-crypto/src/asn1/x509/PolicyMappings.cs
new file mode 100644
index 0000000000000000000000000000000000000000..928ad134d5bbb6aa38e0323c7e9be894ebdb4856
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/PolicyMappings.cs
@@ -0,0 +1,70 @@
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * PolicyMappings V3 extension, described in RFC3280.
+ *
+ * PolicyMappings ::= Sequence SIZE (1..MAX) OF Sequence {
+ * issuerDomainPolicy CertPolicyId,
+ * subjectDomainPolicy CertPolicyId }
+ *
+ *
+ * @see RFC 3280, section 4.2.1.6
+ */
+ public class PolicyMappings
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence seq;
+
+ /**
+ * Creates a new PolicyMappings
instance.
+ *
+ * @param seq an Asn1Sequence
constructed as specified
+ * in RFC 3280
+ */
+ public PolicyMappings(
+ Asn1Sequence seq)
+ {
+ this.seq = seq;
+ }
+
+#if !(SILVERLIGHT || PORTABLE)
+ public PolicyMappings(
+ Hashtable mappings)
+ : this((IDictionary)mappings)
+ {
+ }
+#endif
+
+ /**
+ * Creates a new PolicyMappings
instance.
+ *
+ * @param mappings a HashMap
value that maps
+ * string
oids
+ * to other string
oids.
+ */
+ public PolicyMappings(
+ IDictionary mappings)
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ foreach (string idp in mappings.Keys)
+ {
+ string sdp = (string) mappings[idp];
+
+ v.Add(
+ new DerSequence(
+ new DerObjectIdentifier(idp),
+ new DerObjectIdentifier(sdp)));
+ }
+
+ seq = new DerSequence(v);
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return seq;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/PolicyQualifierId.cs b/bc-sharp-crypto/src/asn1/x509/PolicyQualifierId.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c858f08645caf5cd846e76b56981e3b8c102c096
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/PolicyQualifierId.cs
@@ -0,0 +1,28 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * PolicyQualifierId, used in the CertificatePolicies
+ * X509V3 extension.
+ *
+ *
+ * id-qt OBJECT IDENTIFIER ::= { id-pkix 2 }
+ * id-qt-cps OBJECT IDENTIFIER ::= { id-qt 1 }
+ * id-qt-unotice OBJECT IDENTIFIER ::= { id-qt 2 }
+ * PolicyQualifierId ::=
+ * OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )
+ *
+ */
+ public sealed class PolicyQualifierID : DerObjectIdentifier
+ {
+ private const string IdQt = "1.3.6.1.5.5.7.2";
+
+ private PolicyQualifierID(
+ string id)
+ : base(id)
+ {
+ }
+
+ public static readonly PolicyQualifierID IdQtCps = new PolicyQualifierID(IdQt + ".1");
+ public static readonly PolicyQualifierID IdQtUnotice = new PolicyQualifierID(IdQt + ".2");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/PolicyQualifierInfo.cs b/bc-sharp-crypto/src/asn1/x509/PolicyQualifierInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3cf6d7e10d6942800f4bb5c476d7cf78822e1efe
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/PolicyQualifierInfo.cs
@@ -0,0 +1,95 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * Policy qualifiers, used in the X509V3 CertificatePolicies
+ * extension.
+ *
+ *
+ * PolicyQualifierInfo ::= Sequence {
+ * policyQualifierId PolicyQualifierId,
+ * qualifier ANY DEFINED BY policyQualifierId }
+ *
+ */
+ public class PolicyQualifierInfo
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier policyQualifierId;
+ private readonly Asn1Encodable qualifier;
+
+ /**
+ * Creates a new PolicyQualifierInfo
instance.
+ *
+ * @param policyQualifierId a PolicyQualifierId
value
+ * @param qualifier the qualifier, defined by the above field.
+ */
+ public PolicyQualifierInfo(
+ DerObjectIdentifier policyQualifierId,
+ Asn1Encodable qualifier)
+ {
+ this.policyQualifierId = policyQualifierId;
+ this.qualifier = qualifier;
+ }
+
+ /**
+ * Creates a new PolicyQualifierInfo
containing a
+ * cPSuri qualifier.
+ *
+ * @param cps the CPS (certification practice statement) uri as a
+ * string
.
+ */
+ public PolicyQualifierInfo(
+ string cps)
+ {
+ policyQualifierId = PolicyQualifierID.IdQtCps;
+ qualifier = new DerIA5String(cps);
+ }
+
+ /**
+ * Creates a new PolicyQualifierInfo
instance.
+ *
+ * @param as PolicyQualifierInfo
X509 structure
+ * encoded as an Asn1Sequence.
+ */
+ private PolicyQualifierInfo(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ policyQualifierId = DerObjectIdentifier.GetInstance(seq[0]);
+ qualifier = seq[1];
+ }
+
+ public static PolicyQualifierInfo GetInstance(
+ object obj)
+ {
+ if (obj is PolicyQualifierInfo)
+ return (PolicyQualifierInfo)obj;
+ if (obj == null)
+ return null;
+ return new PolicyQualifierInfo(Asn1Sequence.GetInstance(obj));
+ }
+
+ public virtual DerObjectIdentifier PolicyQualifierId
+ {
+ get { return policyQualifierId; }
+ }
+
+ public virtual Asn1Encodable Qualifier
+ {
+ get { return qualifier; }
+ }
+
+ /**
+ * Returns a Der-encodable representation of this instance.
+ *
+ * @return a Asn1Object
value
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(policyQualifierId, qualifier);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs b/bc-sharp-crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a3d7a3608666640ead522c62103746a67a3d553b
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs
@@ -0,0 +1,84 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ ///
+ ///
+ /// PrivateKeyUsagePeriod ::= SEQUENCE
+ /// {
+ /// notBefore [0] GeneralizedTime OPTIONAL,
+ /// notAfter [1] GeneralizedTime OPTIONAL }
+ ///
+ ///
+ public class PrivateKeyUsagePeriod
+ : Asn1Encodable
+ {
+ public static PrivateKeyUsagePeriod GetInstance(
+ object obj)
+ {
+ if (obj is PrivateKeyUsagePeriod)
+ {
+ return (PrivateKeyUsagePeriod) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new PrivateKeyUsagePeriod((Asn1Sequence) obj);
+ }
+
+ if (obj is X509Extension)
+ {
+ return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+ }
+
+ throw new ArgumentException("unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private DerGeneralizedTime _notBefore, _notAfter;
+
+ private PrivateKeyUsagePeriod(
+ Asn1Sequence seq)
+ {
+ foreach (Asn1TaggedObject tObj in seq)
+ {
+ if (tObj.TagNo == 0)
+ {
+ _notBefore = DerGeneralizedTime.GetInstance(tObj, false);
+ }
+ else if (tObj.TagNo == 1)
+ {
+ _notAfter = DerGeneralizedTime.GetInstance(tObj, false);
+ }
+ }
+ }
+
+ public DerGeneralizedTime NotBefore
+ {
+ get { return _notBefore; }
+ }
+
+ public DerGeneralizedTime NotAfter
+ {
+ get { return _notAfter; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (_notBefore != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, _notBefore));
+ }
+
+ if (_notAfter != null)
+ {
+ v.Add(new DerTaggedObject(false, 1, _notAfter));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/RSAPublicKeyStructure.cs b/bc-sharp-crypto/src/asn1/x509/RSAPublicKeyStructure.cs
new file mode 100644
index 0000000000000000000000000000000000000000..20fdd96ac467092e8ecf3db8fbcb33fa607cdf2d
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/RSAPublicKeyStructure.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class RsaPublicKeyStructure
+ : Asn1Encodable
+ {
+ private BigInteger modulus;
+ private BigInteger publicExponent;
+
+ public static RsaPublicKeyStructure GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static RsaPublicKeyStructure GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is RsaPublicKeyStructure)
+ {
+ return (RsaPublicKeyStructure) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new RsaPublicKeyStructure((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("Invalid RsaPublicKeyStructure: " + Platform.GetTypeName(obj));
+ }
+
+ public RsaPublicKeyStructure(
+ BigInteger modulus,
+ BigInteger publicExponent)
+ {
+ if (modulus == null)
+ throw new ArgumentNullException("modulus");
+ if (publicExponent == null)
+ throw new ArgumentNullException("publicExponent");
+ if (modulus.SignValue <= 0)
+ throw new ArgumentException("Not a valid RSA modulus", "modulus");
+ if (publicExponent.SignValue <= 0)
+ throw new ArgumentException("Not a valid RSA public exponent", "publicExponent");
+
+ this.modulus = modulus;
+ this.publicExponent = publicExponent;
+ }
+
+ private RsaPublicKeyStructure(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+ // Note: we are accepting technically incorrect (i.e. negative) values here
+ modulus = DerInteger.GetInstance(seq[0]).PositiveValue;
+ publicExponent = DerInteger.GetInstance(seq[1]).PositiveValue;
+ }
+
+ public BigInteger Modulus
+ {
+ get { return modulus; }
+ }
+
+ public BigInteger PublicExponent
+ {
+ get { return publicExponent; }
+ }
+
+ /**
+ * This outputs the key in Pkcs1v2 format.
+ *
+ * RSAPublicKey ::= Sequence {
+ * modulus Integer, -- n
+ * publicExponent Integer, -- e
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(
+ new DerInteger(Modulus),
+ new DerInteger(PublicExponent));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/ReasonFlags.cs b/bc-sharp-crypto/src/asn1/x509/ReasonFlags.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ad45e84aed92d19cec66aed9bbbab96b404454e4
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/ReasonFlags.cs
@@ -0,0 +1,45 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * The ReasonFlags object.
+ *
+ * ReasonFlags ::= BIT STRING {
+ * unused(0),
+ * keyCompromise(1),
+ * cACompromise(2),
+ * affiliationChanged(3),
+ * superseded(4),
+ * cessationOfOperation(5),
+ * certficateHold(6)
+ * }
+ *
+ */
+ public class ReasonFlags
+ : DerBitString
+ {
+ public const int Unused = (1 << 7);
+ public const int KeyCompromise = (1 << 6);
+ public const int CACompromise = (1 << 5);
+ public const int AffiliationChanged = (1 << 4);
+ public const int Superseded = (1 << 3);
+ public const int CessationOfOperation = (1 << 2);
+ public const int CertificateHold = (1 << 1);
+ public const int PrivilegeWithdrawn = (1 << 0);
+ public const int AACompromise = (1 << 15);
+
+ /**
+ * @param reasons - the bitwise OR of the Key Reason flags giving the
+ * allowed uses for the key.
+ */
+ public ReasonFlags(int reasons)
+ : base(reasons)
+ {
+ }
+
+ public ReasonFlags(
+ DerBitString reasons)
+ : base(reasons.GetBytes(), reasons.PadBits)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/RoleSyntax.cs b/bc-sharp-crypto/src/asn1/x509/RoleSyntax.cs
new file mode 100644
index 0000000000000000000000000000000000000000..48c3c6caeda5d3caf4a3b9414a54a06f57b09598
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/RoleSyntax.cs
@@ -0,0 +1,230 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * Implementation of the RoleSyntax object as specified by the RFC3281.
+ *
+ *
+ * RoleSyntax ::= SEQUENCE {
+ * roleAuthority [0] GeneralNames OPTIONAL,
+ * roleName [1] GeneralName
+ * }
+ *
+ */
+ public class RoleSyntax
+ : Asn1Encodable
+ {
+ private readonly GeneralNames roleAuthority;
+ private readonly GeneralName roleName;
+
+ /**
+ * RoleSyntax factory method.
+ * @param obj the object used to construct an instance of
+ * RoleSyntax
. It must be an instance of RoleSyntax
+ *
or Asn1Sequence
.
+ * @return the instance of RoleSyntax
built from the
+ * supplied object.
+ * @throws java.lang.ArgumentException if the object passed
+ * to the factory is not an instance of RoleSyntax
or
+ * Asn1Sequence
.
+ */
+ public static RoleSyntax GetInstance(
+ object obj)
+ {
+ if (obj is RoleSyntax)
+ return (RoleSyntax)obj;
+
+ if (obj != null)
+ return new RoleSyntax(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ /**
+ * Constructor.
+ * @param roleAuthority the role authority of this RoleSyntax.
+ * @param roleName the role name of this RoleSyntax.
+ */
+ public RoleSyntax(
+ GeneralNames roleAuthority,
+ GeneralName roleName)
+ {
+ if (roleName == null
+ || roleName.TagNo != GeneralName.UniformResourceIdentifier
+ || ((IAsn1String) roleName.Name).GetString().Equals(""))
+ {
+ throw new ArgumentException("the role name MUST be non empty and MUST " +
+ "use the URI option of GeneralName");
+ }
+
+ this.roleAuthority = roleAuthority;
+ this.roleName = roleName;
+ }
+
+ /**
+ * Constructor. Invoking this constructor is the same as invoking
+ * new RoleSyntax(null, roleName)
.
+ * @param roleName the role name of this RoleSyntax.
+ */
+ public RoleSyntax(
+ GeneralName roleName)
+ : this(null, roleName)
+ {
+ }
+
+ /**
+ * Utility constructor. Takes a string
argument representing
+ * the role name, builds a GeneralName
to hold the role name
+ * and calls the constructor that takes a GeneralName
.
+ * @param roleName
+ */
+ public RoleSyntax(
+ string roleName)
+ : this(new GeneralName(GeneralName.UniformResourceIdentifier,
+ (roleName == null)? "": roleName))
+ {
+ }
+
+ /**
+ * Constructor that builds an instance of RoleSyntax
by
+ * extracting the encoded elements from the Asn1Sequence
+ * object supplied.
+ * @param seq an instance of Asn1Sequence
that holds
+ * the encoded elements used to build this RoleSyntax
.
+ */
+ private RoleSyntax(
+ Asn1Sequence seq)
+ {
+ if (seq.Count < 1 || seq.Count > 2)
+ {
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+ }
+
+ for (int i = 0; i != seq.Count; i++)
+ {
+ Asn1TaggedObject taggedObject = Asn1TaggedObject.GetInstance(seq[i]);
+ switch (taggedObject.TagNo)
+ {
+ case 0:
+ roleAuthority = GeneralNames.GetInstance(taggedObject, false);
+ break;
+ case 1:
+ roleName = GeneralName.GetInstance(taggedObject, true);
+ break;
+ default:
+ throw new ArgumentException("Unknown tag in RoleSyntax");
+ }
+ }
+ }
+
+ /**
+ * Gets the role authority of this RoleSyntax.
+ * @return an instance of GeneralNames
holding the
+ * role authority of this RoleSyntax.
+ */
+ public GeneralNames RoleAuthority
+ {
+ get { return this.roleAuthority; }
+ }
+
+ /**
+ * Gets the role name of this RoleSyntax.
+ * @return an instance of GeneralName
holding the
+ * role name of this RoleSyntax.
+ */
+ public GeneralName RoleName
+ {
+ get { return this.roleName; }
+ }
+
+ /**
+ * Gets the role name as a java.lang.string
object.
+ * @return the role name of this RoleSyntax represented as a
+ * string
object.
+ */
+ public string GetRoleNameAsString()
+ {
+ return ((IAsn1String) this.roleName.Name).GetString();
+ }
+
+ /**
+ * Gets the role authority as a string[]
object.
+ * @return the role authority of this RoleSyntax represented as a
+ * string[]
array.
+ */
+ public string[] GetRoleAuthorityAsString()
+ {
+ if (roleAuthority == null)
+ {
+ return new string[0];
+ }
+
+ GeneralName[] names = roleAuthority.GetNames();
+ string[] namesString = new string[names.Length];
+ for(int i = 0; i < names.Length; i++)
+ {
+ Asn1Encodable asn1Value = names[i].Name;
+ if (asn1Value is IAsn1String)
+ {
+ namesString[i] = ((IAsn1String) asn1Value).GetString();
+ }
+ else
+ {
+ namesString[i] = asn1Value.ToString();
+ }
+ }
+
+ return namesString;
+ }
+
+ /**
+ * Implementation of the method ToAsn1Object
as
+ * required by the superclass ASN1Encodable
.
+ *
+ *
+ * RoleSyntax ::= SEQUENCE {
+ * roleAuthority [0] GeneralNames OPTIONAL,
+ * roleName [1] GeneralName
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (this.roleAuthority != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, roleAuthority));
+ }
+
+ v.Add(new DerTaggedObject(true, 1, roleName));
+
+ return new DerSequence(v);
+ }
+
+ public override string ToString()
+ {
+ StringBuilder buff = new StringBuilder("Name: " + this.GetRoleNameAsString() +
+ " - Auth: ");
+
+ if (this.roleAuthority == null || roleAuthority.GetNames().Length == 0)
+ {
+ buff.Append("N/A");
+ }
+ else
+ {
+ string[] names = this.GetRoleAuthorityAsString();
+ buff.Append('[').Append(names[0]);
+ for(int i = 1; i < names.Length; i++)
+ {
+ buff.Append(", ").Append(names[i]);
+ }
+ buff.Append(']');
+ }
+
+ return buff.ToString();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/SubjectDirectoryAttributes.cs b/bc-sharp-crypto/src/asn1/x509/SubjectDirectoryAttributes.cs
new file mode 100644
index 0000000000000000000000000000000000000000..77923e0d204bd9f14acdd7fa6d12791a583f8cda
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/SubjectDirectoryAttributes.cs
@@ -0,0 +1,142 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * This extension may contain further X.500 attributes of the subject. See also
+ * RFC 3039.
+ *
+ *
+ * SubjectDirectoryAttributes ::= Attributes
+ * Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+ * Attribute ::= SEQUENCE
+ * {
+ * type AttributeType
+ * values SET OF AttributeValue
+ * }
+ *
+ * AttributeType ::= OBJECT IDENTIFIER
+ * AttributeValue ::= ANY DEFINED BY AttributeType
+ *
+ *
+ * @see org.bouncycastle.asn1.x509.X509Name for AttributeType ObjectIdentifiers.
+ */
+ public class SubjectDirectoryAttributes
+ : Asn1Encodable
+ {
+ private readonly IList attributes;
+
+ public static SubjectDirectoryAttributes GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is SubjectDirectoryAttributes)
+ {
+ return (SubjectDirectoryAttributes) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new SubjectDirectoryAttributes((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * Constructor from Asn1Sequence.
+ *
+ * The sequence is of type SubjectDirectoryAttributes:
+ *
+ *
+ * SubjectDirectoryAttributes ::= Attributes
+ * Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+ * Attribute ::= SEQUENCE
+ * {
+ * type AttributeType
+ * values SET OF AttributeValue
+ * }
+ *
+ * AttributeType ::= OBJECT IDENTIFIER
+ * AttributeValue ::= ANY DEFINED BY AttributeType
+ *
+ *
+ * @param seq
+ * The ASN.1 sequence.
+ */
+ private SubjectDirectoryAttributes(
+ Asn1Sequence seq)
+ {
+ this.attributes = Platform.CreateArrayList();
+ foreach (object o in seq)
+ {
+ Asn1Sequence s = Asn1Sequence.GetInstance(o);
+ attributes.Add(AttributeX509.GetInstance(s));
+ }
+ }
+
+#if !(SILVERLIGHT || PORTABLE)
+ [Obsolete]
+ public SubjectDirectoryAttributes(
+ ArrayList attributes)
+ : this((IList)attributes)
+ {
+ }
+#endif
+
+ /**
+ * Constructor from an ArrayList of attributes.
+ *
+ * The ArrayList consists of attributes of type {@link Attribute Attribute}
+ *
+ * @param attributes The attributes.
+ *
+ */
+ public SubjectDirectoryAttributes(
+ IList attributes)
+ {
+ this.attributes = Platform.CreateArrayList(attributes);
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * SubjectDirectoryAttributes ::= Attributes
+ * Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+ * Attribute ::= SEQUENCE
+ * {
+ * type AttributeType
+ * values SET OF AttributeValue
+ * }
+ *
+ * AttributeType ::= OBJECT IDENTIFIER
+ * AttributeValue ::= ANY DEFINED BY AttributeType
+ *
+ *
+ * @return a DERObject
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ AttributeX509[] v = new AttributeX509[attributes.Count];
+ for (int i = 0; i < attributes.Count; ++i)
+ {
+ v[i] = (AttributeX509)attributes[i];
+ }
+ return new DerSequence(v);
+ }
+
+ /**
+ * @return Returns the attributes.
+ */
+ public IEnumerable Attributes
+ {
+ get { return new EnumerableProxy(attributes); }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/SubjectKeyIdentifier.cs b/bc-sharp-crypto/src/asn1/x509/SubjectKeyIdentifier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f2e6cc00614aeaa9033709e5a2551d190e03c23a
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/SubjectKeyIdentifier.cs
@@ -0,0 +1,142 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * The SubjectKeyIdentifier object.
+ *
+ * SubjectKeyIdentifier::= OCTET STRING
+ *
+ */
+ public class SubjectKeyIdentifier
+ : Asn1Encodable
+ {
+ private readonly byte[] keyIdentifier;
+
+ public static SubjectKeyIdentifier GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1OctetString.GetInstance(obj, explicitly));
+ }
+
+ public static SubjectKeyIdentifier GetInstance(
+ object obj)
+ {
+ if (obj is SubjectKeyIdentifier)
+ {
+ return (SubjectKeyIdentifier) obj;
+ }
+
+ if (obj is SubjectPublicKeyInfo)
+ {
+ return new SubjectKeyIdentifier((SubjectPublicKeyInfo) obj);
+ }
+
+ if (obj is Asn1OctetString)
+ {
+ return new SubjectKeyIdentifier((Asn1OctetString) obj);
+ }
+
+ if (obj is X509Extension)
+ {
+ return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+ }
+
+ throw new ArgumentException("Invalid SubjectKeyIdentifier: " + Platform.GetTypeName(obj));
+ }
+
+ public SubjectKeyIdentifier(
+ byte[] keyID)
+ {
+ if (keyID == null)
+ throw new ArgumentNullException("keyID");
+
+ this.keyIdentifier = keyID;
+ }
+
+ public SubjectKeyIdentifier(
+ Asn1OctetString keyID)
+ {
+ this.keyIdentifier = keyID.GetOctets();
+ }
+
+ /**
+ * Calculates the keyIdentifier using a SHA1 hash over the BIT STRING
+ * from SubjectPublicKeyInfo as defined in RFC3280.
+ *
+ * @param spki the subject public key info.
+ */
+ public SubjectKeyIdentifier(
+ SubjectPublicKeyInfo spki)
+ {
+ this.keyIdentifier = GetDigest(spki);
+ }
+
+ public byte[] GetKeyIdentifier()
+ {
+ return keyIdentifier;
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerOctetString(keyIdentifier);
+ }
+
+ /**
+ * Return a RFC 3280 type 1 key identifier. As in:
+ *
+ * (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the
+ * value of the BIT STRING subjectPublicKey (excluding the tag,
+ * length, and number of unused bits).
+ *
+ * @param keyInfo the key info object containing the subjectPublicKey field.
+ * @return the key identifier.
+ */
+ public static SubjectKeyIdentifier CreateSha1KeyIdentifier(
+ SubjectPublicKeyInfo keyInfo)
+ {
+ return new SubjectKeyIdentifier(keyInfo);
+ }
+
+ /**
+ * Return a RFC 3280 type 2 key identifier. As in:
+ *
+ * (2) The keyIdentifier is composed of a four bit type field with
+ * the value 0100 followed by the least significant 60 bits of the
+ * SHA-1 hash of the value of the BIT STRING subjectPublicKey.
+ *
+ * @param keyInfo the key info object containing the subjectPublicKey field.
+ * @return the key identifier.
+ */
+ public static SubjectKeyIdentifier CreateTruncatedSha1KeyIdentifier(
+ SubjectPublicKeyInfo keyInfo)
+ {
+ byte[] dig = GetDigest(keyInfo);
+ byte[] id = new byte[8];
+
+ Array.Copy(dig, dig.Length - 8, id, 0, id.Length);
+
+ id[0] &= 0x0f;
+ id[0] |= 0x40;
+
+ return new SubjectKeyIdentifier(id);
+ }
+
+ private static byte[] GetDigest(
+ SubjectPublicKeyInfo spki)
+ {
+ IDigest digest = new Sha1Digest();
+ byte[] resBuf = new byte[digest.GetDigestSize()];
+
+ byte[] bytes = spki.PublicKeyData.GetBytes();
+ digest.BlockUpdate(bytes, 0, bytes.Length);
+ digest.DoFinal(resBuf, 0);
+ return resBuf;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/SubjectPublicKeyInfo.cs b/bc-sharp-crypto/src/asn1/x509/SubjectPublicKeyInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..477329b7e4ad797a12f7fa26f26793b9ef64361d
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/SubjectPublicKeyInfo.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * The object that contains the public key stored in a certficate.
+ *
+ * The GetEncoded() method in the public keys in the JCE produces a DER
+ * encoded one of these.
+ */
+ public class SubjectPublicKeyInfo
+ : Asn1Encodable
+ {
+ private readonly AlgorithmIdentifier algID;
+ private readonly DerBitString keyData;
+
+ public static SubjectPublicKeyInfo GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static SubjectPublicKeyInfo GetInstance(
+ object obj)
+ {
+ if (obj is SubjectPublicKeyInfo)
+ return (SubjectPublicKeyInfo) obj;
+
+ if (obj != null)
+ return new SubjectPublicKeyInfo(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ public SubjectPublicKeyInfo(
+ AlgorithmIdentifier algID,
+ Asn1Encodable publicKey)
+ {
+ this.keyData = new DerBitString(publicKey);
+ this.algID = algID;
+ }
+
+ public SubjectPublicKeyInfo(
+ AlgorithmIdentifier algID,
+ byte[] publicKey)
+ {
+ this.keyData = new DerBitString(publicKey);
+ this.algID = algID;
+ }
+
+ private SubjectPublicKeyInfo(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ this.algID = AlgorithmIdentifier.GetInstance(seq[0]);
+ this.keyData = DerBitString.GetInstance(seq[1]);
+ }
+
+ public AlgorithmIdentifier AlgorithmID
+ {
+ get { return algID; }
+ }
+
+ /**
+ * for when the public key is an encoded object - if the bitstring
+ * can't be decoded this routine raises an IOException.
+ *
+ * @exception IOException - if the bit string doesn't represent a Der
+ * encoded object.
+ */
+ public Asn1Object GetPublicKey()
+ {
+ return Asn1Object.FromByteArray(keyData.GetOctets());
+ }
+
+ /**
+ * for when the public key is raw bits...
+ */
+ public DerBitString PublicKeyData
+ {
+ get { return keyData; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * SubjectPublicKeyInfo ::= Sequence {
+ * algorithm AlgorithmIdentifier,
+ * publicKey BIT STRING }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(algID, keyData);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/TBSCertList.cs b/bc-sharp-crypto/src/asn1/x509/TBSCertList.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5767a7f21d56e1f0150a77595d20c676224bb063
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/TBSCertList.cs
@@ -0,0 +1,275 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class CrlEntry
+ : Asn1Encodable
+ {
+ internal Asn1Sequence seq;
+ internal DerInteger userCertificate;
+ internal Time revocationDate;
+ internal X509Extensions crlEntryExtensions;
+
+ public CrlEntry(
+ Asn1Sequence seq)
+ {
+ if (seq.Count < 2 || seq.Count > 3)
+ {
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+ }
+
+ this.seq = seq;
+
+ userCertificate = DerInteger.GetInstance(seq[0]);
+ revocationDate = Time.GetInstance(seq[1]);
+ }
+
+ public DerInteger UserCertificate
+ {
+ get { return userCertificate; }
+ }
+
+ public Time RevocationDate
+ {
+ get { return revocationDate; }
+ }
+
+ public X509Extensions Extensions
+ {
+ get
+ {
+ if (crlEntryExtensions == null && seq.Count == 3)
+ {
+ crlEntryExtensions = X509Extensions.GetInstance(seq[2]);
+ }
+
+ return crlEntryExtensions;
+ }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return seq;
+ }
+ }
+
+ /**
+ * PKIX RFC-2459 - TbsCertList object.
+ *
+ * TbsCertList ::= Sequence {
+ * version Version OPTIONAL,
+ * -- if present, shall be v2
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * thisUpdate Time,
+ * nextUpdate Time OPTIONAL,
+ * revokedCertificates Sequence OF Sequence {
+ * userCertificate CertificateSerialNumber,
+ * revocationDate Time,
+ * crlEntryExtensions Extensions OPTIONAL
+ * -- if present, shall be v2
+ * } OPTIONAL,
+ * crlExtensions [0] EXPLICIT Extensions OPTIONAL
+ * -- if present, shall be v2
+ * }
+ *
+ */
+ public class TbsCertificateList
+ : Asn1Encodable
+ {
+ private class RevokedCertificatesEnumeration
+ : IEnumerable
+ {
+ private readonly IEnumerable en;
+
+ internal RevokedCertificatesEnumeration(
+ IEnumerable en)
+ {
+ this.en = en;
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return new RevokedCertificatesEnumerator(en.GetEnumerator());
+ }
+
+ private class RevokedCertificatesEnumerator
+ : IEnumerator
+ {
+ private readonly IEnumerator e;
+
+ internal RevokedCertificatesEnumerator(
+ IEnumerator e)
+ {
+ this.e = e;
+ }
+
+ public bool MoveNext()
+ {
+ return e.MoveNext();
+ }
+
+ public void Reset()
+ {
+ e.Reset();
+ }
+
+ public object Current
+ {
+ get { return new CrlEntry(Asn1Sequence.GetInstance(e.Current)); }
+ }
+ }
+ }
+
+ internal Asn1Sequence seq;
+ internal DerInteger version;
+ internal AlgorithmIdentifier signature;
+ internal X509Name issuer;
+ internal Time thisUpdate;
+ internal Time nextUpdate;
+ internal Asn1Sequence revokedCertificates;
+ internal X509Extensions crlExtensions;
+
+ public static TbsCertificateList GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static TbsCertificateList GetInstance(
+ object obj)
+ {
+ TbsCertificateList list = obj as TbsCertificateList;
+
+ if (obj == null || list != null)
+ {
+ return list;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new TbsCertificateList((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ internal TbsCertificateList(
+ Asn1Sequence seq)
+ {
+ if (seq.Count < 3 || seq.Count > 7)
+ {
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+ }
+
+ int seqPos = 0;
+
+ this.seq = seq;
+
+ if (seq[seqPos] is DerInteger)
+ {
+ version = DerInteger.GetInstance(seq[seqPos++]);
+ }
+ else
+ {
+ version = new DerInteger(0);
+ }
+
+ signature = AlgorithmIdentifier.GetInstance(seq[seqPos++]);
+ issuer = X509Name.GetInstance(seq[seqPos++]);
+ thisUpdate = Time.GetInstance(seq[seqPos++]);
+
+ if (seqPos < seq.Count
+ && (seq[seqPos] is DerUtcTime
+ || seq[seqPos] is DerGeneralizedTime
+ || seq[seqPos] is Time))
+ {
+ nextUpdate = Time.GetInstance(seq[seqPos++]);
+ }
+
+ if (seqPos < seq.Count
+ && !(seq[seqPos] is DerTaggedObject))
+ {
+ revokedCertificates = Asn1Sequence.GetInstance(seq[seqPos++]);
+ }
+
+ if (seqPos < seq.Count
+ && seq[seqPos] is DerTaggedObject)
+ {
+ crlExtensions = X509Extensions.GetInstance(seq[seqPos]);
+ }
+ }
+
+ public int Version
+ {
+ get { return version.Value.IntValue + 1; }
+ }
+
+ public DerInteger VersionNumber
+ {
+ get { return version; }
+ }
+
+ public AlgorithmIdentifier Signature
+ {
+ get { return signature; }
+ }
+
+ public X509Name Issuer
+ {
+ get { return issuer; }
+ }
+
+ public Time ThisUpdate
+ {
+ get { return thisUpdate; }
+ }
+
+ public Time NextUpdate
+ {
+ get { return nextUpdate; }
+ }
+
+ public CrlEntry[] GetRevokedCertificates()
+ {
+ if (revokedCertificates == null)
+ {
+ return new CrlEntry[0];
+ }
+
+ CrlEntry[] entries = new CrlEntry[revokedCertificates.Count];
+
+ for (int i = 0; i < entries.Length; i++)
+ {
+ entries[i] = new CrlEntry(Asn1Sequence.GetInstance(revokedCertificates[i]));
+ }
+
+ return entries;
+ }
+
+ public IEnumerable GetRevokedCertificateEnumeration()
+ {
+ if (revokedCertificates == null)
+ {
+ return EmptyEnumerable.Instance;
+ }
+
+ return new RevokedCertificatesEnumeration(revokedCertificates);
+ }
+
+ public X509Extensions Extensions
+ {
+ get { return crlExtensions; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return seq;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/TBSCertificateStructure.cs b/bc-sharp-crypto/src/asn1/x509/TBSCertificateStructure.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fc7c39ba2f560dbe0314e61130979b595d172a75
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/TBSCertificateStructure.cs
@@ -0,0 +1,185 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * The TbsCertificate object.
+ *
+ * TbsCertificate ::= Sequence {
+ * version [ 0 ] Version DEFAULT v1(0),
+ * serialNumber CertificateSerialNumber,
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * validity Validity,
+ * subject Name,
+ * subjectPublicKeyInfo SubjectPublicKeyInfo,
+ * issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ * subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ * extensions [ 3 ] Extensions OPTIONAL
+ * }
+ *
+ *
+ * Note: issuerUniqueID and subjectUniqueID are both deprecated by the IETF. This class
+ * will parse them, but you really shouldn't be creating new ones.
+ */
+ public class TbsCertificateStructure
+ : Asn1Encodable
+ {
+ internal Asn1Sequence seq;
+ internal DerInteger version;
+ internal DerInteger serialNumber;
+ internal AlgorithmIdentifier signature;
+ internal X509Name issuer;
+ internal Time startDate, endDate;
+ internal X509Name subject;
+ internal SubjectPublicKeyInfo subjectPublicKeyInfo;
+ internal DerBitString issuerUniqueID;
+ internal DerBitString subjectUniqueID;
+ internal X509Extensions extensions;
+
+ public static TbsCertificateStructure GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static TbsCertificateStructure GetInstance(
+ object obj)
+ {
+ if (obj is TbsCertificateStructure)
+ return (TbsCertificateStructure) obj;
+
+ if (obj != null)
+ return new TbsCertificateStructure(Asn1Sequence.GetInstance(obj));
+
+ return null;
+ }
+
+ internal TbsCertificateStructure(
+ Asn1Sequence seq)
+ {
+ int seqStart = 0;
+
+ this.seq = seq;
+
+ //
+ // some certficates don't include a version number - we assume v1
+ //
+ if (seq[0] is DerTaggedObject)
+ {
+ version = DerInteger.GetInstance((Asn1TaggedObject)seq[0], true);
+ }
+ else
+ {
+ seqStart = -1; // field 0 is missing!
+ version = new DerInteger(0);
+ }
+
+ serialNumber = DerInteger.GetInstance(seq[seqStart + 1]);
+
+ signature = AlgorithmIdentifier.GetInstance(seq[seqStart + 2]);
+ issuer = X509Name.GetInstance(seq[seqStart + 3]);
+
+ //
+ // before and after dates
+ //
+ Asn1Sequence dates = (Asn1Sequence)seq[seqStart + 4];
+
+ startDate = Time.GetInstance(dates[0]);
+ endDate = Time.GetInstance(dates[1]);
+
+ subject = X509Name.GetInstance(seq[seqStart + 5]);
+
+ //
+ // public key info.
+ //
+ subjectPublicKeyInfo = SubjectPublicKeyInfo.GetInstance(seq[seqStart + 6]);
+
+ for (int extras = seq.Count - (seqStart + 6) - 1; extras > 0; extras--)
+ {
+ DerTaggedObject extra = (DerTaggedObject) seq[seqStart + 6 + extras];
+
+ switch (extra.TagNo)
+ {
+ case 1:
+ issuerUniqueID = DerBitString.GetInstance(extra, false);
+ break;
+ case 2:
+ subjectUniqueID = DerBitString.GetInstance(extra, false);
+ break;
+ case 3:
+ extensions = X509Extensions.GetInstance(extra);
+ break;
+ }
+ }
+ }
+
+ public int Version
+ {
+ get { return version.Value.IntValue + 1; }
+ }
+
+ public DerInteger VersionNumber
+ {
+ get { return version; }
+ }
+
+ public DerInteger SerialNumber
+ {
+ get { return serialNumber; }
+ }
+
+ public AlgorithmIdentifier Signature
+ {
+ get { return signature; }
+ }
+
+ public X509Name Issuer
+ {
+ get { return issuer; }
+ }
+
+ public Time StartDate
+ {
+ get { return startDate; }
+ }
+
+ public Time EndDate
+ {
+ get { return endDate; }
+ }
+
+ public X509Name Subject
+ {
+ get { return subject; }
+ }
+
+ public SubjectPublicKeyInfo SubjectPublicKeyInfo
+ {
+ get { return subjectPublicKeyInfo; }
+ }
+
+ public DerBitString IssuerUniqueID
+ {
+ get { return issuerUniqueID; }
+ }
+
+ public DerBitString SubjectUniqueID
+ {
+ get { return subjectUniqueID; }
+ }
+
+ public X509Extensions Extensions
+ {
+ get { return extensions; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return seq;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/Target.cs b/bc-sharp-crypto/src/asn1/x509/Target.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7c4f9db7eaf233b87a3f66554f2e30fc5589dad5
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/Target.cs
@@ -0,0 +1,141 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * Target structure used in target information extension for attribute
+ * certificates from RFC 3281.
+ *
+ *
+ * Target ::= CHOICE {
+ * targetName [0] GeneralName,
+ * targetGroup [1] GeneralName,
+ * targetCert [2] TargetCert
+ * }
+ *
+ *
+ *
+ * The targetCert field is currently not supported and must not be used
+ * according to RFC 3281.
+ */
+ public class Target
+ : Asn1Encodable, IAsn1Choice
+ {
+ public enum Choice
+ {
+ Name = 0,
+ Group = 1
+ };
+
+ private readonly GeneralName targetName;
+ private readonly GeneralName targetGroup;
+
+ /**
+ * Creates an instance of a Target from the given object.
+ *
+ * obj
can be a Target or a {@link Asn1TaggedObject}
+ *
+ * @param obj The object.
+ * @return A Target instance.
+ * @throws ArgumentException if the given object cannot be
+ * interpreted as Target.
+ */
+ public static Target GetInstance(
+ object obj)
+ {
+ if (obj is Target)
+ {
+ return (Target) obj;
+ }
+
+ if (obj is Asn1TaggedObject)
+ {
+ return new Target((Asn1TaggedObject) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * Constructor from Asn1TaggedObject.
+ *
+ * @param tagObj The tagged object.
+ * @throws ArgumentException if the encoding is wrong.
+ */
+ private Target(
+ Asn1TaggedObject tagObj)
+ {
+ switch ((Choice) tagObj.TagNo)
+ {
+ case Choice.Name: // GeneralName is already a choice so explicit
+ targetName = GeneralName.GetInstance(tagObj, true);
+ break;
+ case Choice.Group:
+ targetGroup = GeneralName.GetInstance(tagObj, true);
+ break;
+ default:
+ throw new ArgumentException("unknown tag: " + tagObj.TagNo);
+ }
+ }
+
+ /**
+ * Constructor from given details.
+ *
+ * Exactly one of the parameters must be not null
.
+ *
+ * @param type the choice type to apply to the name.
+ * @param name the general name.
+ * @throws ArgumentException if type is invalid.
+ */
+ public Target(
+ Choice type,
+ GeneralName name)
+ : this(new DerTaggedObject((int) type, name))
+ {
+ }
+
+ /**
+ * @return Returns the targetGroup.
+ */
+ public virtual GeneralName TargetGroup
+ {
+ get { return targetGroup; }
+ }
+
+ /**
+ * @return Returns the targetName.
+ */
+ public virtual GeneralName TargetName
+ {
+ get { return targetName; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * Target ::= CHOICE {
+ * targetName [0] GeneralName,
+ * targetGroup [1] GeneralName,
+ * targetCert [2] TargetCert
+ * }
+ *
+ *
+ * @return an Asn1Object
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ // GeneralName is a choice already so most be explicitly tagged
+ if (targetName != null)
+ {
+ return new DerTaggedObject(true, 0, targetName);
+ }
+
+ return new DerTaggedObject(true, 1, targetGroup);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/TargetInformation.cs b/bc-sharp-crypto/src/asn1/x509/TargetInformation.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2bf218977036db0729a5517de9552b440231fa1b
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/TargetInformation.cs
@@ -0,0 +1,125 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * Target information extension for attributes certificates according to RFC
+ * 3281.
+ *
+ *
+ * SEQUENCE OF Targets
+ *
+ *
+ */
+ public class TargetInformation
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence targets;
+
+ /**
+ * Creates an instance of a TargetInformation from the given object.
+ *
+ * obj
can be a TargetInformation or a {@link Asn1Sequence}
+ *
+ * @param obj The object.
+ * @return A TargetInformation instance.
+ * @throws ArgumentException if the given object cannot be interpreted as TargetInformation.
+ */
+ public static TargetInformation GetInstance(
+ object obj)
+ {
+ if (obj is TargetInformation)
+ {
+ return (TargetInformation) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new TargetInformation((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * Constructor from a Asn1Sequence.
+ *
+ * @param seq The Asn1Sequence.
+ * @throws ArgumentException if the sequence does not contain
+ * correctly encoded Targets elements.
+ */
+ private TargetInformation(
+ Asn1Sequence targets)
+ {
+ this.targets = targets;
+ }
+
+ /**
+ * Returns the targets in this target information extension.
+ *
+ * The ArrayList is cloned before it is returned.
+ *
+ * @return Returns the targets.
+ */
+ public virtual Targets[] GetTargetsObjects()
+ {
+ Targets[] result = new Targets[targets.Count];
+
+ for (int i = 0; i < targets.Count; ++i)
+ {
+ result[i] = Targets.GetInstance(targets[i]);
+ }
+
+ return result;
+ }
+
+ /**
+ * Constructs a target information from a single targets element.
+ * According to RFC 3281 only one targets element must be produced.
+ *
+ * @param targets A Targets instance.
+ */
+ public TargetInformation(
+ Targets targets)
+ {
+ this.targets = new DerSequence(targets);
+ }
+
+ /**
+ * According to RFC 3281 only one targets element must be produced. If
+ * multiple targets are given they must be merged in
+ * into one targets element.
+ *
+ * @param targets An array with {@link Targets}.
+ */
+ public TargetInformation(
+ Target[] targets)
+ : this(new Targets(targets))
+ {
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * SEQUENCE OF Targets
+ *
+ *
+ *
+ * According to RFC 3281 only one targets element must be produced. If
+ * multiple targets are given in the constructor they are merged into one
+ * targets element. If this was produced from a
+ * {@link Org.BouncyCastle.Asn1.Asn1Sequence} the encoding is kept.
+ *
+ * @return an Asn1Object
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return targets;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/Targets.cs b/bc-sharp-crypto/src/asn1/x509/Targets.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0387e1f6b4932a60fdc2befefe3494c898e56eec
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/Targets.cs
@@ -0,0 +1,123 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * Targets structure used in target information extension for attribute
+ * certificates from RFC 3281.
+ *
+ *
+ * Targets ::= SEQUENCE OF Target
+ *
+ * Target ::= CHOICE {
+ * targetName [0] GeneralName,
+ * targetGroup [1] GeneralName,
+ * targetCert [2] TargetCert
+ * }
+ *
+ * TargetCert ::= SEQUENCE {
+ * targetCertificate IssuerSerial,
+ * targetName GeneralName OPTIONAL,
+ * certDigestInfo ObjectDigestInfo OPTIONAL
+ * }
+ *
+ *
+ * @see org.bouncycastle.asn1.x509.Target
+ * @see org.bouncycastle.asn1.x509.TargetInformation
+ */
+ public class Targets
+ : Asn1Encodable
+ {
+ private readonly Asn1Sequence targets;
+
+ /**
+ * Creates an instance of a Targets from the given object.
+ *
+ * obj
can be a Targets or a {@link Asn1Sequence}
+ *
+ * @param obj The object.
+ * @return A Targets instance.
+ * @throws ArgumentException if the given object cannot be interpreted as Target.
+ */
+ public static Targets GetInstance(
+ object obj)
+ {
+ if (obj is Targets)
+ {
+ return (Targets) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new Targets((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * Constructor from Asn1Sequence.
+ *
+ * @param targets The ASN.1 SEQUENCE.
+ * @throws ArgumentException if the contents of the sequence are
+ * invalid.
+ */
+ private Targets(
+ Asn1Sequence targets)
+ {
+ this.targets = targets;
+ }
+
+ /**
+ * Constructor from given targets.
+ *
+ * The ArrayList is copied.
+ *
+ * @param targets An ArrayList
of {@link Target}s.
+ * @see Target
+ * @throws ArgumentException if the ArrayList contains not only Targets.
+ */
+ public Targets(
+ Target[] targets)
+ {
+ this.targets = new DerSequence(targets);
+ }
+
+ /**
+ * Returns the targets in an ArrayList
.
+ *
+ * The ArrayList is cloned before it is returned.
+ *
+ * @return Returns the targets.
+ */
+ public virtual Target[] GetTargets()
+ {
+ Target[] result = new Target[targets.Count];
+
+ for (int i = 0; i < targets.Count; ++i)
+ {
+ result[i] = Target.GetInstance(targets[i]);
+ }
+
+ return result;
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * Targets ::= SEQUENCE OF Target
+ *
+ *
+ * @return an Asn1Object
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return targets;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/Time.cs b/bc-sharp-crypto/src/asn1/x509/Time.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fa3936d63577ffdb20f38deedc9e9fad902d3d14
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/Time.cs
@@ -0,0 +1,122 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class Time
+ : Asn1Encodable, IAsn1Choice
+ {
+ private readonly Asn1Object time;
+
+ public static Time GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(obj.GetObject());
+ }
+
+ public Time(
+ Asn1Object time)
+ {
+ if (time == null)
+ throw new ArgumentNullException("time");
+ if (!(time is DerUtcTime) && !(time is DerGeneralizedTime))
+ throw new ArgumentException("unknown object passed to Time");
+
+ this.time = time;
+ }
+
+ /**
+ * creates a time object from a given date - if the date is between 1950
+ * and 2049 a UTCTime object is Generated, otherwise a GeneralizedTime
+ * is used.
+ */
+ public Time(
+ DateTime date)
+ {
+#if PORTABLE
+ string d = date.ToUniversalTime().ToString("yyyyMMddHHmmss", CultureInfo.InvariantCulture) + "Z";
+#else
+ string d = date.ToString("yyyyMMddHHmmss", CultureInfo.InvariantCulture) + "Z";
+#endif
+
+ int year = int.Parse(d.Substring(0, 4));
+
+ if (year < 1950 || year > 2049)
+ {
+ time = new DerGeneralizedTime(d);
+ }
+ else
+ {
+ time = new DerUtcTime(d.Substring(2));
+ }
+ }
+
+ public static Time GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is Time)
+ return (Time)obj;
+ if (obj is DerUtcTime)
+ return new Time((DerUtcTime)obj);
+ if (obj is DerGeneralizedTime)
+ return new Time((DerGeneralizedTime)obj);
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public string GetTime()
+ {
+ if (time is DerUtcTime)
+ {
+ return ((DerUtcTime) time).AdjustedTimeString;
+ }
+
+ return ((DerGeneralizedTime) time).GetTime();
+ }
+
+ ///
+ /// Return our time as DateTime.
+ ///
+ /// A date time.
+ public DateTime ToDateTime()
+ {
+ try
+ {
+ if (time is DerUtcTime)
+ {
+ return ((DerUtcTime)time).ToAdjustedDateTime();
+ }
+ else
+ {
+ return ((DerGeneralizedTime)time).ToDateTime();
+ }
+ }
+ catch (FormatException e)
+ {
+ // this should never happen
+ throw new InvalidOperationException("invalid date string: " + e.Message);
+ }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Time ::= CHOICE {
+ * utcTime UTCTime,
+ * generalTime GeneralizedTime }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return time;
+ }
+
+ public override string ToString()
+ {
+ return GetTime();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/UserNotice.cs b/bc-sharp-crypto/src/asn1/x509/UserNotice.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f40916434e0ac47c510f5b0bc3d940420f7af50f
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/UserNotice.cs
@@ -0,0 +1,130 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * UserNotice
class, used in
+ * CertificatePolicies
X509 extensions (in policy
+ * qualifiers).
+ *
+ * UserNotice ::= Sequence {
+ * noticeRef NoticeReference OPTIONAL,
+ * explicitText DisplayText OPTIONAL}
+ *
+ *
+ *
+ * @see PolicyQualifierId
+ * @see PolicyInformation
+ */
+ public class UserNotice
+ : Asn1Encodable
+ {
+ private readonly NoticeReference noticeRef;
+ private readonly DisplayText explicitText;
+
+ /**
+ * Creates a new UserNotice
instance.
+ *
+ * @param noticeRef a NoticeReference
value
+ * @param explicitText a DisplayText
value
+ */
+ public UserNotice(
+ NoticeReference noticeRef,
+ DisplayText explicitText)
+ {
+ this.noticeRef = noticeRef;
+ this.explicitText = explicitText;
+ }
+
+ /**
+ * Creates a new UserNotice
instance.
+ *
+ * @param noticeRef a NoticeReference
value
+ * @param str the explicitText field as a string.
+ */
+ public UserNotice(
+ NoticeReference noticeRef,
+ string str)
+ : this(noticeRef, new DisplayText(str))
+ {
+ }
+
+ /**
+ * Creates a new UserNotice
instance.
+ * Useful from reconstructing a UserNotice
instance
+ * from its encodable/encoded form.
+ *
+ * @param as an ASN1Sequence
value obtained from either
+ * calling @{link toASN1Object()} for a UserNotice
+ * instance or from parsing it from a DER-encoded stream.
+ */
+ [Obsolete("Use GetInstance() instead")]
+ public UserNotice(
+ Asn1Sequence seq)
+ {
+ if (seq.Count == 2)
+ {
+ noticeRef = NoticeReference.GetInstance(seq[0]);
+ explicitText = DisplayText.GetInstance(seq[1]);
+ }
+ else if (seq.Count == 1)
+ {
+ if (seq[0].ToAsn1Object() is Asn1Sequence)
+ {
+ noticeRef = NoticeReference.GetInstance(seq[0]);
+ explicitText = null;
+ }
+ else
+ {
+ noticeRef = null;
+ explicitText = DisplayText.GetInstance(seq[0]);
+ }
+ }
+ else if (seq.Count == 0)
+ {
+ noticeRef = null; // neither field set!
+ explicitText = null;
+ }
+ else
+ {
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+ }
+ }
+
+ public static UserNotice GetInstance(object obj)
+ {
+ if (obj is UserNotice)
+ return (UserNotice)obj;
+ if (obj == null)
+ return null;
+ return new UserNotice(Asn1Sequence.GetInstance(obj));
+ }
+
+ public virtual NoticeReference NoticeRef
+ {
+ get { return noticeRef; }
+ }
+
+ public virtual DisplayText ExplicitText
+ {
+ get { return explicitText; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector av = new Asn1EncodableVector();
+
+ if (noticeRef != null)
+ {
+ av.Add(noticeRef);
+ }
+
+ if (explicitText != null)
+ {
+ av.Add(explicitText);
+ }
+
+ return new DerSequence(av);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/V1TBSCertificateGenerator.cs b/bc-sharp-crypto/src/asn1/x509/V1TBSCertificateGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..20b525a488d46256d53b9946d7180419620d03df
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/V1TBSCertificateGenerator.cs
@@ -0,0 +1,108 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * Generator for Version 1 TbsCertificateStructures.
+ *
+ * TbsCertificate ::= Sequence {
+ * version [ 0 ] Version DEFAULT v1(0),
+ * serialNumber CertificateSerialNumber,
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * validity Validity,
+ * subject Name,
+ * subjectPublicKeyInfo SubjectPublicKeyInfo,
+ * }
+ *
+ *
+ */
+ public class V1TbsCertificateGenerator
+ {
+ internal DerTaggedObject version = new DerTaggedObject(0, new DerInteger(0));
+ internal DerInteger serialNumber;
+ internal AlgorithmIdentifier signature;
+ internal X509Name issuer;
+ internal Time startDate, endDate;
+ internal X509Name subject;
+ internal SubjectPublicKeyInfo subjectPublicKeyInfo;
+
+ public V1TbsCertificateGenerator()
+ {
+ }
+
+ public void SetSerialNumber(
+ DerInteger serialNumber)
+ {
+ this.serialNumber = serialNumber;
+ }
+
+ public void SetSignature(
+ AlgorithmIdentifier signature)
+ {
+ this.signature = signature;
+ }
+
+ public void SetIssuer(
+ X509Name issuer)
+ {
+ this.issuer = issuer;
+ }
+
+ public void SetStartDate(
+ Time startDate)
+ {
+ this.startDate = startDate;
+ }
+
+ public void SetStartDate(
+ DerUtcTime startDate)
+ {
+ this.startDate = new Time(startDate);
+ }
+
+ public void SetEndDate(
+ Time endDate)
+ {
+ this.endDate = endDate;
+ }
+
+ public void SetEndDate(
+ DerUtcTime endDate)
+ {
+ this.endDate = new Time(endDate);
+ }
+
+ public void SetSubject(
+ X509Name subject)
+ {
+ this.subject = subject;
+ }
+
+ public void SetSubjectPublicKeyInfo(
+ SubjectPublicKeyInfo pubKeyInfo)
+ {
+ this.subjectPublicKeyInfo = pubKeyInfo;
+ }
+
+ public TbsCertificateStructure GenerateTbsCertificate()
+ {
+ if ((serialNumber == null) || (signature == null)
+ || (issuer == null) || (startDate == null) || (endDate == null)
+ || (subject == null) || (subjectPublicKeyInfo == null))
+ {
+ throw new InvalidOperationException("not all mandatory fields set in V1 TBScertificate generator");
+ }
+
+ return new TbsCertificateStructure(
+ new DerSequence(
+ //version, - not required as default value
+ serialNumber,
+ signature,
+ issuer,
+ new DerSequence(startDate, endDate), // before and after dates
+ subject,
+ subjectPublicKeyInfo));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs b/bc-sharp-crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..02580b5b81ed7db7c2abbfbb6e6e06682a6ea6a2
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs
@@ -0,0 +1,137 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * Generator for Version 2 AttributeCertificateInfo
+ *
+ * AttributeCertificateInfo ::= Sequence {
+ * version AttCertVersion -- version is v2,
+ * holder Holder,
+ * issuer AttCertIssuer,
+ * signature AlgorithmIdentifier,
+ * serialNumber CertificateSerialNumber,
+ * attrCertValidityPeriod AttCertValidityPeriod,
+ * attributes Sequence OF Attr,
+ * issuerUniqueID UniqueIdentifier OPTIONAL,
+ * extensions Extensions OPTIONAL
+ * }
+ *
+ *
+ */
+ public class V2AttributeCertificateInfoGenerator
+ {
+ internal DerInteger version;
+ internal Holder holder;
+ internal AttCertIssuer issuer;
+ internal AlgorithmIdentifier signature;
+ internal DerInteger serialNumber;
+// internal AttCertValidityPeriod attrCertValidityPeriod;
+ internal Asn1EncodableVector attributes;
+ internal DerBitString issuerUniqueID;
+ internal X509Extensions extensions;
+ internal DerGeneralizedTime startDate, endDate;
+
+ public V2AttributeCertificateInfoGenerator()
+ {
+ this.version = new DerInteger(1);
+ attributes = new Asn1EncodableVector();
+ }
+
+ public void SetHolder(
+ Holder holder)
+ {
+ this.holder = holder;
+ }
+
+ public void AddAttribute(
+ string oid,
+ Asn1Encodable value)
+ {
+ attributes.Add(new AttributeX509(new DerObjectIdentifier(oid), new DerSet(value)));
+ }
+
+ /**
+ * @param attribute
+ */
+ public void AddAttribute(AttributeX509 attribute)
+ {
+ attributes.Add(attribute);
+ }
+
+ public void SetSerialNumber(
+ DerInteger serialNumber)
+ {
+ this.serialNumber = serialNumber;
+ }
+
+ public void SetSignature(
+ AlgorithmIdentifier signature)
+ {
+ this.signature = signature;
+ }
+
+ public void SetIssuer(
+ AttCertIssuer issuer)
+ {
+ this.issuer = issuer;
+ }
+
+ public void SetStartDate(
+ DerGeneralizedTime startDate)
+ {
+ this.startDate = startDate;
+ }
+
+ public void SetEndDate(
+ DerGeneralizedTime endDate)
+ {
+ this.endDate = endDate;
+ }
+
+ public void SetIssuerUniqueID(
+ DerBitString issuerUniqueID)
+ {
+ this.issuerUniqueID = issuerUniqueID;
+ }
+
+ public void SetExtensions(
+ X509Extensions extensions)
+ {
+ this.extensions = extensions;
+ }
+
+ public AttributeCertificateInfo GenerateAttributeCertificateInfo()
+ {
+ if ((serialNumber == null) || (signature == null)
+ || (issuer == null) || (startDate == null) || (endDate == null)
+ || (holder == null) || (attributes == null))
+ {
+ throw new InvalidOperationException("not all mandatory fields set in V2 AttributeCertificateInfo generator");
+ }
+
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ version, holder, issuer, signature, serialNumber);
+
+ //
+ // before and after dates => AttCertValidityPeriod
+ //
+ v.Add(new AttCertValidityPeriod(startDate, endDate));
+
+ // Attributes
+ v.Add(new DerSequence(attributes));
+
+ if (issuerUniqueID != null)
+ {
+ v.Add(issuerUniqueID);
+ }
+
+ if (extensions != null)
+ {
+ v.Add(extensions);
+ }
+
+ return AttributeCertificateInfo.GetInstance(new DerSequence(v));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/V2Form.cs b/bc-sharp-crypto/src/asn1/x509/V2Form.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2c6e54a7735d6fb04c2ac02f6e8ce68f09034c9a
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/V2Form.cs
@@ -0,0 +1,137 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class V2Form
+ : Asn1Encodable
+ {
+ internal GeneralNames issuerName;
+ internal IssuerSerial baseCertificateID;
+ internal ObjectDigestInfo objectDigestInfo;
+
+ public static V2Form GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static V2Form GetInstance(object obj)
+ {
+ if (obj is V2Form)
+ return (V2Form)obj;
+ if (obj != null)
+ return new V2Form(Asn1Sequence.GetInstance(obj));
+ return null;
+ }
+
+ public V2Form(GeneralNames issuerName)
+ : this(issuerName, null, null)
+ {
+ }
+
+ public V2Form(GeneralNames issuerName, IssuerSerial baseCertificateID)
+ : this(issuerName, baseCertificateID, null)
+ {
+ }
+
+ public V2Form(GeneralNames issuerName, ObjectDigestInfo objectDigestInfo)
+ : this(issuerName, null, objectDigestInfo)
+ {
+ }
+
+ public V2Form(
+ GeneralNames issuerName,
+ IssuerSerial baseCertificateID,
+ ObjectDigestInfo objectDigestInfo)
+ {
+ this.issuerName = issuerName;
+ this.baseCertificateID = baseCertificateID;
+ this.objectDigestInfo = objectDigestInfo;
+ }
+
+ private V2Form(
+ Asn1Sequence seq)
+ {
+ if (seq.Count > 3)
+ {
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+ }
+
+ int index = 0;
+
+ if (!(seq[0] is Asn1TaggedObject))
+ {
+ index++;
+ this.issuerName = GeneralNames.GetInstance(seq[0]);
+ }
+
+ for (int i = index; i != seq.Count; i++)
+ {
+ Asn1TaggedObject o = Asn1TaggedObject.GetInstance(seq[i]);
+ if (o.TagNo == 0)
+ {
+ baseCertificateID = IssuerSerial.GetInstance(o, false);
+ }
+ else if (o.TagNo == 1)
+ {
+ objectDigestInfo = ObjectDigestInfo.GetInstance(o, false);
+ }
+ else
+ {
+ throw new ArgumentException("Bad tag number: " + o.TagNo);
+ }
+ }
+ }
+
+ public GeneralNames IssuerName
+ {
+ get { return issuerName; }
+ }
+
+ public IssuerSerial BaseCertificateID
+ {
+ get { return baseCertificateID; }
+ }
+
+ public ObjectDigestInfo ObjectDigestInfo
+ {
+ get { return objectDigestInfo; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * V2Form ::= Sequence {
+ * issuerName GeneralNames OPTIONAL,
+ * baseCertificateID [0] IssuerSerial OPTIONAL,
+ * objectDigestInfo [1] ObjectDigestInfo OPTIONAL
+ * -- issuerName MUST be present in this profile
+ * -- baseCertificateID and objectDigestInfo MUST NOT
+ * -- be present in this profile
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (issuerName != null)
+ {
+ v.Add(issuerName);
+ }
+
+ if (baseCertificateID != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, baseCertificateID));
+ }
+
+ if (objectDigestInfo != null)
+ {
+ v.Add(new DerTaggedObject(false, 1, objectDigestInfo));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/V2TBSCertListGenerator.cs b/bc-sharp-crypto/src/asn1/x509/V2TBSCertListGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2c929188f6760c082d9ed4599ac9aae643d2aa96
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/V2TBSCertListGenerator.cs
@@ -0,0 +1,201 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * Generator for Version 2 TbsCertList structures.
+ *
+ * TbsCertList ::= Sequence {
+ * version Version OPTIONAL,
+ * -- if present, shall be v2
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * thisUpdate Time,
+ * nextUpdate Time OPTIONAL,
+ * revokedCertificates Sequence OF Sequence {
+ * userCertificate CertificateSerialNumber,
+ * revocationDate Time,
+ * crlEntryExtensions Extensions OPTIONAL
+ * -- if present, shall be v2
+ * } OPTIONAL,
+ * crlExtensions [0] EXPLICIT Extensions OPTIONAL
+ * -- if present, shall be v2
+ * }
+ *
+ *
+ * Note: This class may be subject to change
+ */
+ public class V2TbsCertListGenerator
+ {
+ private DerInteger version = new DerInteger(1);
+ private AlgorithmIdentifier signature;
+ private X509Name issuer;
+ private Time thisUpdate, nextUpdate;
+ private X509Extensions extensions;
+ private IList crlEntries;
+
+ public V2TbsCertListGenerator()
+ {
+ }
+
+ public void SetSignature(
+ AlgorithmIdentifier signature)
+ {
+ this.signature = signature;
+ }
+
+ public void SetIssuer(
+ X509Name issuer)
+ {
+ this.issuer = issuer;
+ }
+
+ public void SetThisUpdate(
+ DerUtcTime thisUpdate)
+ {
+ this.thisUpdate = new Time(thisUpdate);
+ }
+
+ public void SetNextUpdate(
+ DerUtcTime nextUpdate)
+ {
+ this.nextUpdate = (nextUpdate != null)
+ ? new Time(nextUpdate)
+ : null;
+ }
+
+ public void SetThisUpdate(
+ Time thisUpdate)
+ {
+ this.thisUpdate = thisUpdate;
+ }
+
+ public void SetNextUpdate(
+ Time nextUpdate)
+ {
+ this.nextUpdate = nextUpdate;
+ }
+
+ public void AddCrlEntry(
+ Asn1Sequence crlEntry)
+ {
+ if (crlEntries == null)
+ {
+ crlEntries = Platform.CreateArrayList();
+ }
+
+ crlEntries.Add(crlEntry);
+ }
+
+ public void AddCrlEntry(DerInteger userCertificate, DerUtcTime revocationDate, int reason)
+ {
+ AddCrlEntry(userCertificate, new Time(revocationDate), reason);
+ }
+
+ public void AddCrlEntry(DerInteger userCertificate, Time revocationDate, int reason)
+ {
+ AddCrlEntry(userCertificate, revocationDate, reason, null);
+ }
+
+ public void AddCrlEntry(DerInteger userCertificate, Time revocationDate, int reason,
+ DerGeneralizedTime invalidityDate)
+ {
+ IList extOids = Platform.CreateArrayList();
+ IList extValues = Platform.CreateArrayList();
+
+ if (reason != 0)
+ {
+ CrlReason crlReason = new CrlReason(reason);
+
+ try
+ {
+ extOids.Add(X509Extensions.ReasonCode);
+ extValues.Add(new X509Extension(false, new DerOctetString(crlReason.GetEncoded())));
+ }
+ catch (IOException e)
+ {
+ throw new ArgumentException("error encoding reason: " + e);
+ }
+ }
+
+ if (invalidityDate != null)
+ {
+ try
+ {
+ extOids.Add(X509Extensions.InvalidityDate);
+ extValues.Add(new X509Extension(false, new DerOctetString(invalidityDate.GetEncoded())));
+ }
+ catch (IOException e)
+ {
+ throw new ArgumentException("error encoding invalidityDate: " + e);
+ }
+ }
+
+ if (extOids.Count != 0)
+ {
+ AddCrlEntry(userCertificate, revocationDate, new X509Extensions(extOids, extValues));
+ }
+ else
+ {
+ AddCrlEntry(userCertificate, revocationDate, null);
+ }
+ }
+
+ public void AddCrlEntry(DerInteger userCertificate, Time revocationDate, X509Extensions extensions)
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ userCertificate, revocationDate);
+
+ if (extensions != null)
+ {
+ v.Add(extensions);
+ }
+
+ AddCrlEntry(new DerSequence(v));
+ }
+
+ public void SetExtensions(
+ X509Extensions extensions)
+ {
+ this.extensions = extensions;
+ }
+
+ public TbsCertificateList GenerateTbsCertList()
+ {
+ if ((signature == null) || (issuer == null) || (thisUpdate == null))
+ {
+ throw new InvalidOperationException("Not all mandatory fields set in V2 TbsCertList generator.");
+ }
+
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ version, signature, issuer, thisUpdate);
+
+ if (nextUpdate != null)
+ {
+ v.Add(nextUpdate);
+ }
+
+ // Add CRLEntries if they exist
+ if (crlEntries != null)
+ {
+ Asn1Sequence[] certs = new Asn1Sequence[crlEntries.Count];
+ for (int i = 0; i < crlEntries.Count; ++i)
+ {
+ certs[i] = (Asn1Sequence)crlEntries[i];
+ }
+ v.Add(new DerSequence(certs));
+ }
+
+ if (extensions != null)
+ {
+ v.Add(new DerTaggedObject(0, extensions));
+ }
+
+ return new TbsCertificateList(new DerSequence(v));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/V3TBSCertificateGenerator.cs b/bc-sharp-crypto/src/asn1/x509/V3TBSCertificateGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..beb469a0d83ba658da36e81375357a33b96959ce
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/V3TBSCertificateGenerator.cs
@@ -0,0 +1,168 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * Generator for Version 3 TbsCertificateStructures.
+ *
+ * TbsCertificate ::= Sequence {
+ * version [ 0 ] Version DEFAULT v1(0),
+ * serialNumber CertificateSerialNumber,
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * validity Validity,
+ * subject Name,
+ * subjectPublicKeyInfo SubjectPublicKeyInfo,
+ * issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ * subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ * extensions [ 3 ] Extensions OPTIONAL
+ * }
+ *
+ *
+ */
+ public class V3TbsCertificateGenerator
+ {
+ internal DerTaggedObject version = new DerTaggedObject(0, new DerInteger(2));
+ internal DerInteger serialNumber;
+ internal AlgorithmIdentifier signature;
+ internal X509Name issuer;
+ internal Time startDate, endDate;
+ internal X509Name subject;
+ internal SubjectPublicKeyInfo subjectPublicKeyInfo;
+ internal X509Extensions extensions;
+
+ private bool altNamePresentAndCritical;
+ private DerBitString issuerUniqueID;
+ private DerBitString subjectUniqueID;
+
+ public V3TbsCertificateGenerator()
+ {
+ }
+
+ public void SetSerialNumber(
+ DerInteger serialNumber)
+ {
+ this.serialNumber = serialNumber;
+ }
+
+ public void SetSignature(
+ AlgorithmIdentifier signature)
+ {
+ this.signature = signature;
+ }
+
+ public void SetIssuer(
+ X509Name issuer)
+ {
+ this.issuer = issuer;
+ }
+
+ public void SetStartDate(
+ DerUtcTime startDate)
+ {
+ this.startDate = new Time(startDate);
+ }
+
+ public void SetStartDate(
+ Time startDate)
+ {
+ this.startDate = startDate;
+ }
+
+ public void SetEndDate(
+ DerUtcTime endDate)
+ {
+ this.endDate = new Time(endDate);
+ }
+
+ public void SetEndDate(
+ Time endDate)
+ {
+ this.endDate = endDate;
+ }
+
+ public void SetSubject(
+ X509Name subject)
+ {
+ this.subject = subject;
+ }
+
+ public void SetIssuerUniqueID(
+ DerBitString uniqueID)
+ {
+ this.issuerUniqueID = uniqueID;
+ }
+
+ public void SetSubjectUniqueID(
+ DerBitString uniqueID)
+ {
+ this.subjectUniqueID = uniqueID;
+ }
+
+ public void SetSubjectPublicKeyInfo(
+ SubjectPublicKeyInfo pubKeyInfo)
+ {
+ this.subjectPublicKeyInfo = pubKeyInfo;
+ }
+
+ public void SetExtensions(
+ X509Extensions extensions)
+ {
+ this.extensions = extensions;
+
+ if (extensions != null)
+ {
+ X509Extension altName = extensions.GetExtension(X509Extensions.SubjectAlternativeName);
+
+ if (altName != null && altName.IsCritical)
+ {
+ altNamePresentAndCritical = true;
+ }
+ }
+ }
+
+ public TbsCertificateStructure GenerateTbsCertificate()
+ {
+ if ((serialNumber == null) || (signature == null)
+ || (issuer == null) || (startDate == null) || (endDate == null)
+ || (subject == null && !altNamePresentAndCritical)
+ || (subjectPublicKeyInfo == null))
+ {
+ throw new InvalidOperationException("not all mandatory fields set in V3 TBScertificate generator");
+ }
+
+ DerSequence validity = new DerSequence(startDate, endDate); // before and after dates
+
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ version, serialNumber, signature, issuer, validity);
+
+ if (subject != null)
+ {
+ v.Add(subject);
+ }
+ else
+ {
+ v.Add(DerSequence.Empty);
+ }
+
+ v.Add(subjectPublicKeyInfo);
+
+ if (issuerUniqueID != null)
+ {
+ v.Add(new DerTaggedObject(false, 1, issuerUniqueID));
+ }
+
+ if (subjectUniqueID != null)
+ {
+ v.Add(new DerTaggedObject(false, 2, subjectUniqueID));
+ }
+
+ if (extensions != null)
+ {
+ v.Add(new DerTaggedObject(3, extensions));
+ }
+
+ return new TbsCertificateStructure(new DerSequence(v));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/X509Attributes.cs b/bc-sharp-crypto/src/asn1/x509/X509Attributes.cs
new file mode 100644
index 0000000000000000000000000000000000000000..291329a625cfbc1e632f0f1099ab0851434eb18d
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/X509Attributes.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class X509Attributes
+ {
+ public static readonly DerObjectIdentifier RoleSyntax = new DerObjectIdentifier("2.5.4.72");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/X509CertificateStructure.cs b/bc-sharp-crypto/src/asn1/x509/X509CertificateStructure.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6e7c85de6cb993eabd6f12255bbdbfdc9ff5e36e
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/X509CertificateStructure.cs
@@ -0,0 +1,132 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * an X509Certificate structure.
+ *
+ * Certificate ::= Sequence {
+ * tbsCertificate TbsCertificate,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING
+ * }
+ *
+ */
+ public class X509CertificateStructure
+ : Asn1Encodable
+ {
+ private readonly TbsCertificateStructure tbsCert;
+ private readonly AlgorithmIdentifier sigAlgID;
+ private readonly DerBitString sig;
+
+ public static X509CertificateStructure GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static X509CertificateStructure GetInstance(
+ object obj)
+ {
+ if (obj is X509CertificateStructure)
+ return (X509CertificateStructure)obj;
+ if (obj == null)
+ return null;
+ return new X509CertificateStructure(Asn1Sequence.GetInstance(obj));
+ }
+
+ public X509CertificateStructure(
+ TbsCertificateStructure tbsCert,
+ AlgorithmIdentifier sigAlgID,
+ DerBitString sig)
+ {
+ if (tbsCert == null)
+ throw new ArgumentNullException("tbsCert");
+ if (sigAlgID == null)
+ throw new ArgumentNullException("sigAlgID");
+ if (sig == null)
+ throw new ArgumentNullException("sig");
+
+ this.tbsCert = tbsCert;
+ this.sigAlgID = sigAlgID;
+ this.sig = sig;
+ }
+
+ private X509CertificateStructure(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 3)
+ throw new ArgumentException("sequence wrong size for a certificate", "seq");
+
+ //
+ // correct x509 certficate
+ //
+ tbsCert = TbsCertificateStructure.GetInstance(seq[0]);
+ sigAlgID = AlgorithmIdentifier.GetInstance(seq[1]);
+ sig = DerBitString.GetInstance(seq[2]);
+ }
+
+ public TbsCertificateStructure TbsCertificate
+ {
+ get { return tbsCert; }
+ }
+
+ public int Version
+ {
+ get { return tbsCert.Version; }
+ }
+
+ public DerInteger SerialNumber
+ {
+ get { return tbsCert.SerialNumber; }
+ }
+
+ public X509Name Issuer
+ {
+ get { return tbsCert.Issuer; }
+ }
+
+ public Time StartDate
+ {
+ get { return tbsCert.StartDate; }
+ }
+
+ public Time EndDate
+ {
+ get { return tbsCert.EndDate; }
+ }
+
+ public X509Name Subject
+ {
+ get { return tbsCert.Subject; }
+ }
+
+ public SubjectPublicKeyInfo SubjectPublicKeyInfo
+ {
+ get { return tbsCert.SubjectPublicKeyInfo; }
+ }
+
+ public AlgorithmIdentifier SignatureAlgorithm
+ {
+ get { return sigAlgID; }
+ }
+
+ public DerBitString Signature
+ {
+ get { return sig; }
+ }
+
+ public byte[] GetSignatureOctets()
+ {
+ return sig.GetOctets();
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(tbsCert, sigAlgID, sig);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/X509DefaultEntryConverter.cs b/bc-sharp-crypto/src/asn1/x509/X509DefaultEntryConverter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7282ead2627b4491ff979462a5b3a743c6930aa5
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/X509DefaultEntryConverter.cs
@@ -0,0 +1,63 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * The default converter for X509 DN entries when going from their
+ * string value to ASN.1 strings.
+ */
+ public class X509DefaultEntryConverter
+ : X509NameEntryConverter
+ {
+ /**
+ * Apply default conversion for the given value depending on the oid
+ * and the character range of the value.
+ *
+ * @param oid the object identifier for the DN entry
+ * @param value the value associated with it
+ * @return the ASN.1 equivalent for the string value.
+ */
+ public override Asn1Object GetConvertedValue(
+ DerObjectIdentifier oid,
+ string value)
+ {
+ if (value.Length != 0 && value[0] == '#')
+ {
+ try
+ {
+ return ConvertHexEncoded(value, 1);
+ }
+ catch (IOException)
+ {
+ throw new Exception("can't recode value for oid " + oid.Id);
+ }
+ }
+
+ if (value.Length != 0 && value[0] == '\\')
+ {
+ value = value.Substring(1);
+ }
+
+ if (oid.Equals(X509Name.EmailAddress) || oid.Equals(X509Name.DC))
+ {
+ return new DerIA5String(value);
+ }
+
+ if (oid.Equals(X509Name.DateOfBirth)) // accept time string as well as # (for compatibility)
+ {
+ return new DerGeneralizedTime(value);
+ }
+
+ if (oid.Equals(X509Name.C)
+ || oid.Equals(X509Name.SerialNumber)
+ || oid.Equals(X509Name.DnQualifier)
+ || oid.Equals(X509Name.TelephoneNumber))
+ {
+ return new DerPrintableString(value);
+ }
+
+ return new DerUtf8String(value);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/X509Extension.cs b/bc-sharp-crypto/src/asn1/x509/X509Extension.cs
new file mode 100644
index 0000000000000000000000000000000000000000..430ce4447b10b1c937e27f36a822bc9cdcdb68a2
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/X509Extension.cs
@@ -0,0 +1,79 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * an object for the elements in the X.509 V3 extension block.
+ */
+ public class X509Extension
+ {
+ internal bool critical;
+ internal Asn1OctetString value;
+
+ public X509Extension(
+ DerBoolean critical,
+ Asn1OctetString value)
+ {
+ if (critical == null)
+ {
+ throw new ArgumentNullException("critical");
+ }
+
+ this.critical = critical.IsTrue;
+ this.value = value;
+ }
+
+ public X509Extension(
+ bool critical,
+ Asn1OctetString value)
+ {
+ this.critical = critical;
+ this.value = value;
+ }
+
+ public bool IsCritical { get { return critical; } }
+
+ public Asn1OctetString Value { get { return value; } }
+
+ public Asn1Encodable GetParsedValue()
+ {
+ return ConvertValueToObject(this);
+ }
+
+ public override int GetHashCode()
+ {
+ int vh = this.Value.GetHashCode();
+
+ return IsCritical ? vh : ~vh;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ X509Extension other = obj as X509Extension;
+ if (other == null)
+ {
+ return false;
+ }
+
+ return Value.Equals(other.Value) && IsCritical == other.IsCritical;
+ }
+
+ /// Convert the value of the passed in extension to an object.
+ /// The extension to parse.
+ /// The object the value string contains.
+ /// If conversion is not possible.
+ public static Asn1Object ConvertValueToObject(
+ X509Extension ext)
+ {
+ try
+ {
+ return Asn1Object.FromByteArray(ext.Value.GetOctets());
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("can't convert extension", e);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/X509Extensions.cs b/bc-sharp-crypto/src/asn1/x509/X509Extensions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..049d728bb6a28074a81088266367e9c275861aa1
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/X509Extensions.cs
@@ -0,0 +1,456 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public class X509Extensions
+ : Asn1Encodable
+ {
+ /**
+ * Subject Directory Attributes
+ */
+ public static readonly DerObjectIdentifier SubjectDirectoryAttributes = new DerObjectIdentifier("2.5.29.9");
+
+ /**
+ * Subject Key Identifier
+ */
+ public static readonly DerObjectIdentifier SubjectKeyIdentifier = new DerObjectIdentifier("2.5.29.14");
+
+ /**
+ * Key Usage
+ */
+ public static readonly DerObjectIdentifier KeyUsage = new DerObjectIdentifier("2.5.29.15");
+
+ /**
+ * Private Key Usage Period
+ */
+ public static readonly DerObjectIdentifier PrivateKeyUsagePeriod = new DerObjectIdentifier("2.5.29.16");
+
+ /**
+ * Subject Alternative Name
+ */
+ public static readonly DerObjectIdentifier SubjectAlternativeName = new DerObjectIdentifier("2.5.29.17");
+
+ /**
+ * Issuer Alternative Name
+ */
+ public static readonly DerObjectIdentifier IssuerAlternativeName = new DerObjectIdentifier("2.5.29.18");
+
+ /**
+ * Basic Constraints
+ */
+ public static readonly DerObjectIdentifier BasicConstraints = new DerObjectIdentifier("2.5.29.19");
+
+ /**
+ * CRL Number
+ */
+ public static readonly DerObjectIdentifier CrlNumber = new DerObjectIdentifier("2.5.29.20");
+
+ /**
+ * Reason code
+ */
+ public static readonly DerObjectIdentifier ReasonCode = new DerObjectIdentifier("2.5.29.21");
+
+ /**
+ * Hold Instruction Code
+ */
+ public static readonly DerObjectIdentifier InstructionCode = new DerObjectIdentifier("2.5.29.23");
+
+ /**
+ * Invalidity Date
+ */
+ public static readonly DerObjectIdentifier InvalidityDate = new DerObjectIdentifier("2.5.29.24");
+
+ /**
+ * Delta CRL indicator
+ */
+ public static readonly DerObjectIdentifier DeltaCrlIndicator = new DerObjectIdentifier("2.5.29.27");
+
+ /**
+ * Issuing Distribution Point
+ */
+ public static readonly DerObjectIdentifier IssuingDistributionPoint = new DerObjectIdentifier("2.5.29.28");
+
+ /**
+ * Certificate Issuer
+ */
+ public static readonly DerObjectIdentifier CertificateIssuer = new DerObjectIdentifier("2.5.29.29");
+
+ /**
+ * Name Constraints
+ */
+ public static readonly DerObjectIdentifier NameConstraints = new DerObjectIdentifier("2.5.29.30");
+
+ /**
+ * CRL Distribution Points
+ */
+ public static readonly DerObjectIdentifier CrlDistributionPoints = new DerObjectIdentifier("2.5.29.31");
+
+ /**
+ * Certificate Policies
+ */
+ public static readonly DerObjectIdentifier CertificatePolicies = new DerObjectIdentifier("2.5.29.32");
+
+ /**
+ * Policy Mappings
+ */
+ public static readonly DerObjectIdentifier PolicyMappings = new DerObjectIdentifier("2.5.29.33");
+
+ /**
+ * Authority Key Identifier
+ */
+ public static readonly DerObjectIdentifier AuthorityKeyIdentifier = new DerObjectIdentifier("2.5.29.35");
+
+ /**
+ * Policy Constraints
+ */
+ public static readonly DerObjectIdentifier PolicyConstraints = new DerObjectIdentifier("2.5.29.36");
+
+ /**
+ * Extended Key Usage
+ */
+ public static readonly DerObjectIdentifier ExtendedKeyUsage = new DerObjectIdentifier("2.5.29.37");
+
+ /**
+ * Freshest CRL
+ */
+ public static readonly DerObjectIdentifier FreshestCrl = new DerObjectIdentifier("2.5.29.46");
+
+ /**
+ * Inhibit Any Policy
+ */
+ public static readonly DerObjectIdentifier InhibitAnyPolicy = new DerObjectIdentifier("2.5.29.54");
+
+ /**
+ * Authority Info Access
+ */
+ public static readonly DerObjectIdentifier AuthorityInfoAccess = new DerObjectIdentifier("1.3.6.1.5.5.7.1.1");
+
+ /**
+ * Subject Info Access
+ */
+ public static readonly DerObjectIdentifier SubjectInfoAccess = new DerObjectIdentifier("1.3.6.1.5.5.7.1.11");
+
+ /**
+ * Logo Type
+ */
+ public static readonly DerObjectIdentifier LogoType = new DerObjectIdentifier("1.3.6.1.5.5.7.1.12");
+
+ /**
+ * BiometricInfo
+ */
+ public static readonly DerObjectIdentifier BiometricInfo = new DerObjectIdentifier("1.3.6.1.5.5.7.1.2");
+
+ /**
+ * QCStatements
+ */
+ public static readonly DerObjectIdentifier QCStatements = new DerObjectIdentifier("1.3.6.1.5.5.7.1.3");
+
+ /**
+ * Audit identity extension in attribute certificates.
+ */
+ public static readonly DerObjectIdentifier AuditIdentity = new DerObjectIdentifier("1.3.6.1.5.5.7.1.4");
+
+ /**
+ * NoRevAvail extension in attribute certificates.
+ */
+ public static readonly DerObjectIdentifier NoRevAvail = new DerObjectIdentifier("2.5.29.56");
+
+ /**
+ * TargetInformation extension in attribute certificates.
+ */
+ public static readonly DerObjectIdentifier TargetInformation = new DerObjectIdentifier("2.5.29.55");
+
+ /**
+ * Expired Certificates on CRL extension
+ */
+ public static readonly DerObjectIdentifier ExpiredCertsOnCrl = new DerObjectIdentifier("2.5.29.60");
+
+ private readonly IDictionary extensions = Platform.CreateHashtable();
+ private readonly IList ordering;
+
+ public static X509Extensions GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static X509Extensions GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is X509Extensions)
+ {
+ return (X509Extensions) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new X509Extensions((Asn1Sequence) obj);
+ }
+
+ if (obj is Asn1TaggedObject)
+ {
+ return GetInstance(((Asn1TaggedObject) obj).GetObject());
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * Constructor from Asn1Sequence.
+ *
+ * the extensions are a list of constructed sequences, either with (Oid, OctetString) or (Oid, Boolean, OctetString)
+ */
+ private X509Extensions(
+ Asn1Sequence seq)
+ {
+ this.ordering = Platform.CreateArrayList();
+
+ foreach (Asn1Encodable ae in seq)
+ {
+ Asn1Sequence s = Asn1Sequence.GetInstance(ae.ToAsn1Object());
+
+ if (s.Count < 2 || s.Count > 3)
+ throw new ArgumentException("Bad sequence size: " + s.Count);
+
+ DerObjectIdentifier oid = DerObjectIdentifier.GetInstance(s[0].ToAsn1Object());
+
+ bool isCritical = s.Count == 3
+ && DerBoolean.GetInstance(s[1].ToAsn1Object()).IsTrue;
+
+ Asn1OctetString octets = Asn1OctetString.GetInstance(s[s.Count - 1].ToAsn1Object());
+
+ extensions.Add(oid, new X509Extension(isCritical, octets));
+ ordering.Add(oid);
+ }
+ }
+
+ /**
+ * constructor from a table of extensions.
+ *
+ * it's is assumed the table contains Oid/string pairs.
+ */
+ public X509Extensions(
+ IDictionary extensions)
+ : this(null, extensions)
+ {
+ }
+
+ /**
+ * Constructor from a table of extensions with ordering.
+ *
+ * It's is assumed the table contains Oid/string pairs.
+ */
+ public X509Extensions(
+ IList ordering,
+ IDictionary extensions)
+ {
+ if (ordering == null)
+ {
+ this.ordering = Platform.CreateArrayList(extensions.Keys);
+ }
+ else
+ {
+ this.ordering = Platform.CreateArrayList(ordering);
+ }
+
+ foreach (DerObjectIdentifier oid in this.ordering)
+ {
+ this.extensions.Add(oid, (X509Extension)extensions[oid]);
+ }
+ }
+
+ /**
+ * Constructor from two vectors
+ *
+ * @param objectIDs an ArrayList of the object identifiers.
+ * @param values an ArrayList of the extension values.
+ */
+ public X509Extensions(
+ IList oids,
+ IList values)
+ {
+ this.ordering = Platform.CreateArrayList(oids);
+
+ int count = 0;
+ foreach (DerObjectIdentifier oid in this.ordering)
+ {
+ this.extensions.Add(oid, (X509Extension)values[count++]);
+ }
+ }
+
+#if !(SILVERLIGHT || PORTABLE)
+ /**
+ * constructor from a table of extensions.
+ *
+ * it's is assumed the table contains Oid/string pairs.
+ */
+ [Obsolete]
+ public X509Extensions(
+ Hashtable extensions)
+ : this(null, extensions)
+ {
+ }
+
+ /**
+ * Constructor from a table of extensions with ordering.
+ *
+ * It's is assumed the table contains Oid/string pairs.
+ */
+ [Obsolete]
+ public X509Extensions(
+ ArrayList ordering,
+ Hashtable extensions)
+ {
+ if (ordering == null)
+ {
+ this.ordering = Platform.CreateArrayList(extensions.Keys);
+ }
+ else
+ {
+ this.ordering = Platform.CreateArrayList(ordering);
+ }
+
+ foreach (DerObjectIdentifier oid in this.ordering)
+ {
+ this.extensions.Add(oid, (X509Extension) extensions[oid]);
+ }
+ }
+
+ /**
+ * Constructor from two vectors
+ *
+ * @param objectIDs an ArrayList of the object identifiers.
+ * @param values an ArrayList of the extension values.
+ */
+ [Obsolete]
+ public X509Extensions(
+ ArrayList oids,
+ ArrayList values)
+ {
+ this.ordering = Platform.CreateArrayList(oids);
+
+ int count = 0;
+ foreach (DerObjectIdentifier oid in this.ordering)
+ {
+ this.extensions.Add(oid, (X509Extension) values[count++]);
+ }
+ }
+#endif
+
+ [Obsolete("Use ExtensionOids IEnumerable property")]
+ public IEnumerator Oids()
+ {
+ return ExtensionOids.GetEnumerator();
+ }
+
+ /**
+ * return an Enumeration of the extension field's object ids.
+ */
+ public IEnumerable ExtensionOids
+ {
+ get { return new EnumerableProxy(ordering); }
+ }
+
+ /**
+ * return the extension represented by the object identifier
+ * passed in.
+ *
+ * @return the extension if it's present, null otherwise.
+ */
+ public X509Extension GetExtension(
+ DerObjectIdentifier oid)
+ {
+ return (X509Extension) extensions[oid];
+ }
+
+ /**
+ *
+ * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
+ *
+ * Extension ::= SEQUENCE {
+ * extnId EXTENSION.&id ({ExtensionSet}),
+ * critical BOOLEAN DEFAULT FALSE,
+ * extnValue OCTET STRING }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector vec = new Asn1EncodableVector();
+
+ foreach (DerObjectIdentifier oid in ordering)
+ {
+ X509Extension ext = (X509Extension) extensions[oid];
+ Asn1EncodableVector v = new Asn1EncodableVector(oid);
+
+ if (ext.IsCritical)
+ {
+ v.Add(DerBoolean.True);
+ }
+
+ v.Add(ext.Value);
+
+ vec.Add(new DerSequence(v));
+ }
+
+ return new DerSequence(vec);
+ }
+
+ public bool Equivalent(
+ X509Extensions other)
+ {
+ if (extensions.Count != other.extensions.Count)
+ return false;
+
+ foreach (DerObjectIdentifier oid in extensions.Keys)
+ {
+ if (!extensions[oid].Equals(other.extensions[oid]))
+ return false;
+ }
+
+ return true;
+ }
+
+ public DerObjectIdentifier[] GetExtensionOids()
+ {
+ return ToOidArray(ordering);
+ }
+
+ public DerObjectIdentifier[] GetNonCriticalExtensionOids()
+ {
+ return GetExtensionOids(false);
+ }
+
+ public DerObjectIdentifier[] GetCriticalExtensionOids()
+ {
+ return GetExtensionOids(true);
+ }
+
+ private DerObjectIdentifier[] GetExtensionOids(bool isCritical)
+ {
+ IList oids = Platform.CreateArrayList();
+
+ foreach (DerObjectIdentifier oid in this.ordering)
+ {
+ X509Extension ext = (X509Extension)extensions[oid];
+ if (ext.IsCritical == isCritical)
+ {
+ oids.Add(oid);
+ }
+ }
+
+ return ToOidArray(oids);
+ }
+
+ private static DerObjectIdentifier[] ToOidArray(IList oids)
+ {
+ DerObjectIdentifier[] oidArray = new DerObjectIdentifier[oids.Count];
+ oids.CopyTo(oidArray, 0);
+ return oidArray;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/X509ExtensionsGenerator.cs b/bc-sharp-crypto/src/asn1/x509/X509ExtensionsGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d6f567b22b8cd542e24713996150f1e6879cb0f9
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/X509ExtensionsGenerator.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /// Generator for X.509 extensions
+ public class X509ExtensionsGenerator
+ {
+ private IDictionary extensions = Platform.CreateHashtable();
+ private IList extOrdering = Platform.CreateArrayList();
+
+ /// Reset the generator
+ public void Reset()
+ {
+ extensions = Platform.CreateHashtable();
+ extOrdering = Platform.CreateArrayList();
+ }
+
+ ///
+ /// Add an extension with the given oid and the passed in value to be included
+ /// in the OCTET STRING associated with the extension.
+ ///
+ /// OID for the extension.
+ /// True if critical, false otherwise.
+ /// The ASN.1 object to be included in the extension.
+ public void AddExtension(
+ DerObjectIdentifier oid,
+ bool critical,
+ Asn1Encodable extValue)
+ {
+ byte[] encoded;
+ try
+ {
+ encoded = extValue.GetDerEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("error encoding value: " + e);
+ }
+
+ this.AddExtension(oid, critical, encoded);
+ }
+
+ ///
+ /// Add an extension with the given oid and the passed in byte array to be wrapped
+ /// in the OCTET STRING associated with the extension.
+ ///
+ /// OID for the extension.
+ /// True if critical, false otherwise.
+ /// The byte array to be wrapped.
+ public void AddExtension(
+ DerObjectIdentifier oid,
+ bool critical,
+ byte[] extValue)
+ {
+ if (extensions.Contains(oid))
+ {
+ throw new ArgumentException("extension " + oid + " already added");
+ }
+
+ extOrdering.Add(oid);
+ extensions.Add(oid, new X509Extension(critical, new DerOctetString(extValue)));
+ }
+
+ /// Return true if there are no extension present in this generator.
+ /// True if empty, false otherwise
+ public bool IsEmpty
+ {
+ get { return extOrdering.Count < 1; }
+ }
+
+ /// Generate an X509Extensions object based on the current state of the generator.
+ /// An X509Extensions object
+ public X509Extensions Generate()
+ {
+ return new X509Extensions(extOrdering, extensions);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/X509Name.cs b/bc-sharp-crypto/src/asn1/x509/X509Name.cs
new file mode 100644
index 0000000000000000000000000000000000000000..01a7ec04a215c0c71504e4f81beba6b4b4be874d
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/X509Name.cs
@@ -0,0 +1,1077 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+#if SILVERLIGHT || PORTABLE
+using System.Collections.Generic;
+#endif
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ *
+ * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+ *
+ * RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
+ *
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type OBJECT IDENTIFIER,
+ * value ANY }
+ *
+ */
+ public class X509Name
+ : Asn1Encodable
+ {
+ /**
+ * country code - StringType(SIZE(2))
+ */
+ public static readonly DerObjectIdentifier C = new DerObjectIdentifier("2.5.4.6");
+
+ /**
+ * organization - StringType(SIZE(1..64))
+ */
+ public static readonly DerObjectIdentifier O = new DerObjectIdentifier("2.5.4.10");
+
+ /**
+ * organizational unit name - StringType(SIZE(1..64))
+ */
+ public static readonly DerObjectIdentifier OU = new DerObjectIdentifier("2.5.4.11");
+
+ /**
+ * Title
+ */
+ public static readonly DerObjectIdentifier T = new DerObjectIdentifier("2.5.4.12");
+
+ /**
+ * common name - StringType(SIZE(1..64))
+ */
+ public static readonly DerObjectIdentifier CN = new DerObjectIdentifier("2.5.4.3");
+
+ /**
+ * street - StringType(SIZE(1..64))
+ */
+ public static readonly DerObjectIdentifier Street = new DerObjectIdentifier("2.5.4.9");
+
+ /**
+ * device serial number name - StringType(SIZE(1..64))
+ */
+ public static readonly DerObjectIdentifier SerialNumber = new DerObjectIdentifier("2.5.4.5");
+
+ /**
+ * locality name - StringType(SIZE(1..64))
+ */
+ public static readonly DerObjectIdentifier L = new DerObjectIdentifier("2.5.4.7");
+
+ /**
+ * state, or province name - StringType(SIZE(1..64))
+ */
+ public static readonly DerObjectIdentifier ST = new DerObjectIdentifier("2.5.4.8");
+
+ /**
+ * Naming attributes of type X520name
+ */
+ public static readonly DerObjectIdentifier Surname = new DerObjectIdentifier("2.5.4.4");
+ public static readonly DerObjectIdentifier GivenName = new DerObjectIdentifier("2.5.4.42");
+ public static readonly DerObjectIdentifier Initials = new DerObjectIdentifier("2.5.4.43");
+ public static readonly DerObjectIdentifier Generation = new DerObjectIdentifier("2.5.4.44");
+ public static readonly DerObjectIdentifier UniqueIdentifier = new DerObjectIdentifier("2.5.4.45");
+
+ /**
+ * businessCategory - DirectoryString(SIZE(1..128)
+ */
+ public static readonly DerObjectIdentifier BusinessCategory = new DerObjectIdentifier(
+ "2.5.4.15");
+
+ /**
+ * postalCode - DirectoryString(SIZE(1..40)
+ */
+ public static readonly DerObjectIdentifier PostalCode = new DerObjectIdentifier(
+ "2.5.4.17");
+
+ /**
+ * dnQualifier - DirectoryString(SIZE(1..64)
+ */
+ public static readonly DerObjectIdentifier DnQualifier = new DerObjectIdentifier(
+ "2.5.4.46");
+
+ /**
+ * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64)
+ */
+ public static readonly DerObjectIdentifier Pseudonym = new DerObjectIdentifier(
+ "2.5.4.65");
+
+ /**
+ * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z
+ */
+ public static readonly DerObjectIdentifier DateOfBirth = new DerObjectIdentifier(
+ "1.3.6.1.5.5.7.9.1");
+
+ /**
+ * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128)
+ */
+ public static readonly DerObjectIdentifier PlaceOfBirth = new DerObjectIdentifier(
+ "1.3.6.1.5.5.7.9.2");
+
+ /**
+ * RFC 3039 DateOfBirth - PrintableString (SIZE(1)) -- "M", "F", "m" or "f"
+ */
+ public static readonly DerObjectIdentifier Gender = new DerObjectIdentifier(
+ "1.3.6.1.5.5.7.9.3");
+
+ /**
+ * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
+ * codes only
+ */
+ public static readonly DerObjectIdentifier CountryOfCitizenship = new DerObjectIdentifier(
+ "1.3.6.1.5.5.7.9.4");
+
+ /**
+ * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
+ * codes only
+ */
+ public static readonly DerObjectIdentifier CountryOfResidence = new DerObjectIdentifier(
+ "1.3.6.1.5.5.7.9.5");
+
+ /**
+ * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64)
+ */
+ public static readonly DerObjectIdentifier NameAtBirth = new DerObjectIdentifier("1.3.36.8.3.14");
+
+ /**
+ * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF
+ * DirectoryString(SIZE(1..30))
+ */
+ public static readonly DerObjectIdentifier PostalAddress = new DerObjectIdentifier("2.5.4.16");
+
+ /**
+ * RFC 2256 dmdName
+ */
+ public static readonly DerObjectIdentifier DmdName = new DerObjectIdentifier("2.5.4.54");
+
+ /**
+ * id-at-telephoneNumber
+ */
+ public static readonly DerObjectIdentifier TelephoneNumber = X509ObjectIdentifiers.id_at_telephoneNumber;
+
+ /**
+ * id-at-name
+ */
+ public static readonly DerObjectIdentifier Name = X509ObjectIdentifiers.id_at_name;
+
+ /**
+ * Email address (RSA PKCS#9 extension) - IA5String.
+ * Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.
+ */
+ public static readonly DerObjectIdentifier EmailAddress = PkcsObjectIdentifiers.Pkcs9AtEmailAddress;
+
+ /**
+ * more from PKCS#9
+ */
+ public static readonly DerObjectIdentifier UnstructuredName = PkcsObjectIdentifiers.Pkcs9AtUnstructuredName;
+ public static readonly DerObjectIdentifier UnstructuredAddress = PkcsObjectIdentifiers.Pkcs9AtUnstructuredAddress;
+
+ /**
+ * email address in Verisign certificates
+ */
+ public static readonly DerObjectIdentifier E = EmailAddress;
+
+ /*
+ * others...
+ */
+ public static readonly DerObjectIdentifier DC = new DerObjectIdentifier("0.9.2342.19200300.100.1.25");
+
+ /**
+ * LDAP User id.
+ */
+ public static readonly DerObjectIdentifier UID = new DerObjectIdentifier("0.9.2342.19200300.100.1.1");
+
+ /**
+ * determines whether or not strings should be processed and printed
+ * from back to front.
+ */
+// public static bool DefaultReverse = false;
+ public static bool DefaultReverse
+ {
+ get { return defaultReverse[0]; }
+ set { defaultReverse[0] = value; }
+ }
+
+ private static readonly bool[] defaultReverse = { false };
+
+#if SILVERLIGHT || PORTABLE
+ /**
+ * default look up table translating OID values into their common symbols following
+ * the convention in RFC 2253 with a few extras
+ */
+ public static readonly IDictionary DefaultSymbols = Platform.CreateHashtable();
+
+ /**
+ * look up table translating OID values into their common symbols following the convention in RFC 2253
+ */
+ public static readonly IDictionary RFC2253Symbols = Platform.CreateHashtable();
+
+ /**
+ * look up table translating OID values into their common symbols following the convention in RFC 1779
+ *
+ */
+ public static readonly IDictionary RFC1779Symbols = Platform.CreateHashtable();
+
+ /**
+ * look up table translating common symbols into their OIDS.
+ */
+ public static readonly IDictionary DefaultLookup = Platform.CreateHashtable();
+#else
+ /**
+ * default look up table translating OID values into their common symbols following
+ * the convention in RFC 2253 with a few extras
+ */
+ public static readonly Hashtable DefaultSymbols = new Hashtable();
+
+ /**
+ * look up table translating OID values into their common symbols following the convention in RFC 2253
+ */
+ public static readonly Hashtable RFC2253Symbols = new Hashtable();
+
+ /**
+ * look up table translating OID values into their common symbols following the convention in RFC 1779
+ *
+ */
+ public static readonly Hashtable RFC1779Symbols = new Hashtable();
+
+ /**
+ * look up table translating common symbols into their OIDS.
+ */
+ public static readonly Hashtable DefaultLookup = new Hashtable();
+#endif
+
+ static X509Name()
+ {
+ DefaultSymbols.Add(C, "C");
+ DefaultSymbols.Add(O, "O");
+ DefaultSymbols.Add(T, "T");
+ DefaultSymbols.Add(OU, "OU");
+ DefaultSymbols.Add(CN, "CN");
+ DefaultSymbols.Add(L, "L");
+ DefaultSymbols.Add(ST, "ST");
+ DefaultSymbols.Add(SerialNumber, "SERIALNUMBER");
+ DefaultSymbols.Add(EmailAddress, "E");
+ DefaultSymbols.Add(DC, "DC");
+ DefaultSymbols.Add(UID, "UID");
+ DefaultSymbols.Add(Street, "STREET");
+ DefaultSymbols.Add(Surname, "SURNAME");
+ DefaultSymbols.Add(GivenName, "GIVENNAME");
+ DefaultSymbols.Add(Initials, "INITIALS");
+ DefaultSymbols.Add(Generation, "GENERATION");
+ DefaultSymbols.Add(UnstructuredAddress, "unstructuredAddress");
+ DefaultSymbols.Add(UnstructuredName, "unstructuredName");
+ DefaultSymbols.Add(UniqueIdentifier, "UniqueIdentifier");
+ DefaultSymbols.Add(DnQualifier, "DN");
+ DefaultSymbols.Add(Pseudonym, "Pseudonym");
+ DefaultSymbols.Add(PostalAddress, "PostalAddress");
+ DefaultSymbols.Add(NameAtBirth, "NameAtBirth");
+ DefaultSymbols.Add(CountryOfCitizenship, "CountryOfCitizenship");
+ DefaultSymbols.Add(CountryOfResidence, "CountryOfResidence");
+ DefaultSymbols.Add(Gender, "Gender");
+ DefaultSymbols.Add(PlaceOfBirth, "PlaceOfBirth");
+ DefaultSymbols.Add(DateOfBirth, "DateOfBirth");
+ DefaultSymbols.Add(PostalCode, "PostalCode");
+ DefaultSymbols.Add(BusinessCategory, "BusinessCategory");
+ DefaultSymbols.Add(TelephoneNumber, "TelephoneNumber");
+
+ RFC2253Symbols.Add(C, "C");
+ RFC2253Symbols.Add(O, "O");
+ RFC2253Symbols.Add(OU, "OU");
+ RFC2253Symbols.Add(CN, "CN");
+ RFC2253Symbols.Add(L, "L");
+ RFC2253Symbols.Add(ST, "ST");
+ RFC2253Symbols.Add(Street, "STREET");
+ RFC2253Symbols.Add(DC, "DC");
+ RFC2253Symbols.Add(UID, "UID");
+
+ RFC1779Symbols.Add(C, "C");
+ RFC1779Symbols.Add(O, "O");
+ RFC1779Symbols.Add(OU, "OU");
+ RFC1779Symbols.Add(CN, "CN");
+ RFC1779Symbols.Add(L, "L");
+ RFC1779Symbols.Add(ST, "ST");
+ RFC1779Symbols.Add(Street, "STREET");
+
+ DefaultLookup.Add("c", C);
+ DefaultLookup.Add("o", O);
+ DefaultLookup.Add("t", T);
+ DefaultLookup.Add("ou", OU);
+ DefaultLookup.Add("cn", CN);
+ DefaultLookup.Add("l", L);
+ DefaultLookup.Add("st", ST);
+ DefaultLookup.Add("serialnumber", SerialNumber);
+ DefaultLookup.Add("street", Street);
+ DefaultLookup.Add("emailaddress", E);
+ DefaultLookup.Add("dc", DC);
+ DefaultLookup.Add("e", E);
+ DefaultLookup.Add("uid", UID);
+ DefaultLookup.Add("surname", Surname);
+ DefaultLookup.Add("givenname", GivenName);
+ DefaultLookup.Add("initials", Initials);
+ DefaultLookup.Add("generation", Generation);
+ DefaultLookup.Add("unstructuredaddress", UnstructuredAddress);
+ DefaultLookup.Add("unstructuredname", UnstructuredName);
+ DefaultLookup.Add("uniqueidentifier", UniqueIdentifier);
+ DefaultLookup.Add("dn", DnQualifier);
+ DefaultLookup.Add("pseudonym", Pseudonym);
+ DefaultLookup.Add("postaladdress", PostalAddress);
+ DefaultLookup.Add("nameofbirth", NameAtBirth);
+ DefaultLookup.Add("countryofcitizenship", CountryOfCitizenship);
+ DefaultLookup.Add("countryofresidence", CountryOfResidence);
+ DefaultLookup.Add("gender", Gender);
+ DefaultLookup.Add("placeofbirth", PlaceOfBirth);
+ DefaultLookup.Add("dateofbirth", DateOfBirth);
+ DefaultLookup.Add("postalcode", PostalCode);
+ DefaultLookup.Add("businesscategory", BusinessCategory);
+ DefaultLookup.Add("telephonenumber", TelephoneNumber);
+ }
+
+ private readonly IList ordering = Platform.CreateArrayList();
+ private readonly X509NameEntryConverter converter;
+
+ private IList values = Platform.CreateArrayList();
+ private IList added = Platform.CreateArrayList();
+ private Asn1Sequence seq;
+
+ /**
+ * Return a X509Name based on the passed in tagged object.
+ *
+ * @param obj tag object holding name.
+ * @param explicitly true if explicitly tagged false otherwise.
+ * @return the X509Name
+ */
+ public static X509Name GetInstance(
+ Asn1TaggedObject obj,
+ bool explicitly)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+ }
+
+ public static X509Name GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is X509Name)
+ return (X509Name)obj;
+
+ if (obj != null)
+ return new X509Name(Asn1Sequence.GetInstance(obj));
+
+ throw new ArgumentException("null object in factory", "obj");
+ }
+
+ protected X509Name()
+ {
+ }
+
+ /**
+ * Constructor from Asn1Sequence
+ *
+ * the principal will be a list of constructed sets, each containing an (OID, string) pair.
+ */
+ protected X509Name(
+ Asn1Sequence seq)
+ {
+ this.seq = seq;
+
+ foreach (Asn1Encodable asn1Obj in seq)
+ {
+ Asn1Set asn1Set = Asn1Set.GetInstance(asn1Obj.ToAsn1Object());
+
+ for (int i = 0; i < asn1Set.Count; i++)
+ {
+ Asn1Sequence s = Asn1Sequence.GetInstance(asn1Set[i].ToAsn1Object());
+
+ if (s.Count != 2)
+ throw new ArgumentException("badly sized pair");
+
+ ordering.Add(DerObjectIdentifier.GetInstance(s[0].ToAsn1Object()));
+
+ Asn1Object derValue = s[1].ToAsn1Object();
+ if (derValue is IAsn1String && !(derValue is DerUniversalString))
+ {
+ string v = ((IAsn1String)derValue).GetString();
+ if (Platform.StartsWith(v, "#"))
+ {
+ v = "\\" + v;
+ }
+
+ values.Add(v);
+ }
+ else
+ {
+ values.Add("#" + Hex.ToHexString(derValue.GetEncoded()));
+ }
+
+ added.Add(i != 0);
+ }
+ }
+ }
+
+ /**
+ * Constructor from a table of attributes with ordering.
+ *
+ * it's is assumed the table contains OID/string pairs, and the contents
+ * of the table are copied into an internal table as part of the
+ * construction process. The ordering ArrayList should contain the OIDs
+ * in the order they are meant to be encoded or printed in ToString.
+ */
+ public X509Name(
+ IList ordering,
+ IDictionary attributes)
+ : this(ordering, attributes, new X509DefaultEntryConverter())
+ {
+ }
+
+ /**
+ * Constructor from a table of attributes with ordering.
+ *
+ * it's is assumed the table contains OID/string pairs, and the contents
+ * of the table are copied into an internal table as part of the
+ * construction process. The ordering ArrayList should contain the OIDs
+ * in the order they are meant to be encoded or printed in ToString.
+ *
+ * The passed in converter will be used to convert the strings into their
+ * ASN.1 counterparts.
+ */
+ public X509Name(
+ IList ordering,
+ IDictionary attributes,
+ X509NameEntryConverter converter)
+ {
+ this.converter = converter;
+
+ foreach (DerObjectIdentifier oid in ordering)
+ {
+ object attribute = attributes[oid];
+ if (attribute == null)
+ {
+ throw new ArgumentException("No attribute for object id - " + oid + " - passed to distinguished name");
+ }
+
+ this.ordering.Add(oid);
+ this.added.Add(false);
+ this.values.Add(attribute); // copy the hash table
+ }
+ }
+
+ /**
+ * Takes two vectors one of the oids and the other of the values.
+ */
+ public X509Name(
+ IList oids,
+ IList values)
+ : this(oids, values, new X509DefaultEntryConverter())
+ {
+ }
+
+ /**
+ * Takes two vectors one of the oids and the other of the values.
+ *
+ * The passed in converter will be used to convert the strings into their
+ * ASN.1 counterparts.
+ */
+ public X509Name(
+ IList oids,
+ IList values,
+ X509NameEntryConverter converter)
+ {
+ this.converter = converter;
+
+ if (oids.Count != values.Count)
+ {
+ throw new ArgumentException("'oids' must be same length as 'values'.");
+ }
+
+ for (int i = 0; i < oids.Count; i++)
+ {
+ this.ordering.Add(oids[i]);
+ this.values.Add(values[i]);
+ this.added.Add(false);
+ }
+ }
+
+ /**
+ * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+ * some such, converting it into an ordered set of name attributes.
+ */
+ public X509Name(
+ string dirName)
+ : this(DefaultReverse, (IDictionary)DefaultLookup, dirName)
+ {
+ }
+
+ /**
+ * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+ * some such, converting it into an ordered set of name attributes with each
+ * string value being converted to its associated ASN.1 type using the passed
+ * in converter.
+ */
+ public X509Name(
+ string dirName,
+ X509NameEntryConverter converter)
+ : this(DefaultReverse, DefaultLookup, dirName, converter)
+ {
+ }
+
+ /**
+ * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+ * some such, converting it into an ordered set of name attributes. If reverse
+ * is true, create the encoded version of the sequence starting from the
+ * last element in the string.
+ */
+ public X509Name(
+ bool reverse,
+ string dirName)
+ : this(reverse, (IDictionary)DefaultLookup, dirName)
+ {
+ }
+
+ /**
+ * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+ * some such, converting it into an ordered set of name attributes with each
+ * string value being converted to its associated ASN.1 type using the passed
+ * in converter. If reverse is true the ASN.1 sequence representing the DN will
+ * be built by starting at the end of the string, rather than the start.
+ */
+ public X509Name(
+ bool reverse,
+ string dirName,
+ X509NameEntryConverter converter)
+ : this(reverse, DefaultLookup, dirName, converter)
+ {
+ }
+
+ /**
+ * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+ * some such, converting it into an ordered set of name attributes. lookUp
+ * should provide a table of lookups, indexed by lowercase only strings and
+ * yielding a DerObjectIdentifier, other than that OID. and numeric oids
+ * will be processed automatically.
+ *
+ * If reverse is true, create the encoded version of the sequence
+ * starting from the last element in the string.
+ * @param reverse true if we should start scanning from the end (RFC 2553).
+ * @param lookUp table of names and their oids.
+ * @param dirName the X.500 string to be parsed.
+ */
+ public X509Name(
+ bool reverse,
+ IDictionary lookUp,
+ string dirName)
+ : this(reverse, lookUp, dirName, new X509DefaultEntryConverter())
+ {
+ }
+
+ private DerObjectIdentifier DecodeOid(
+ string name,
+ IDictionary lookUp)
+ {
+ if (Platform.StartsWith(Platform.ToUpperInvariant(name), "OID."))
+ {
+ return new DerObjectIdentifier(name.Substring(4));
+ }
+ else if (name[0] >= '0' && name[0] <= '9')
+ {
+ return new DerObjectIdentifier(name);
+ }
+
+ DerObjectIdentifier oid = (DerObjectIdentifier)lookUp[Platform.ToLowerInvariant(name)];
+ if (oid == null)
+ {
+ throw new ArgumentException("Unknown object id - " + name + " - passed to distinguished name");
+ }
+
+ return oid;
+ }
+
+ /**
+ * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+ * some such, converting it into an ordered set of name attributes. lookUp
+ * should provide a table of lookups, indexed by lowercase only strings and
+ * yielding a DerObjectIdentifier, other than that OID. and numeric oids
+ * will be processed automatically. The passed in converter is used to convert the
+ * string values to the right of each equals sign to their ASN.1 counterparts.
+ *
+ * @param reverse true if we should start scanning from the end, false otherwise.
+ * @param lookUp table of names and oids.
+ * @param dirName the string dirName
+ * @param converter the converter to convert string values into their ASN.1 equivalents
+ */
+ public X509Name(
+ bool reverse,
+ IDictionary lookUp,
+ string dirName,
+ X509NameEntryConverter converter)
+ {
+ this.converter = converter;
+ X509NameTokenizer nTok = new X509NameTokenizer(dirName);
+
+ while (nTok.HasMoreTokens())
+ {
+ string token = nTok.NextToken();
+ int index = token.IndexOf('=');
+
+ if (index == -1)
+ {
+ throw new ArgumentException("badly formated directory string");
+ }
+
+ string name = token.Substring(0, index);
+ string value = token.Substring(index + 1);
+ DerObjectIdentifier oid = DecodeOid(name, lookUp);
+
+ if (value.IndexOf('+') > 0)
+ {
+ X509NameTokenizer vTok = new X509NameTokenizer(value, '+');
+ string v = vTok.NextToken();
+
+ this.ordering.Add(oid);
+ this.values.Add(v);
+ this.added.Add(false);
+
+ while (vTok.HasMoreTokens())
+ {
+ string sv = vTok.NextToken();
+ int ndx = sv.IndexOf('=');
+
+ string nm = sv.Substring(0, ndx);
+ string vl = sv.Substring(ndx + 1);
+ this.ordering.Add(DecodeOid(nm, lookUp));
+ this.values.Add(vl);
+ this.added.Add(true);
+ }
+ }
+ else
+ {
+ this.ordering.Add(oid);
+ this.values.Add(value);
+ this.added.Add(false);
+ }
+ }
+
+ if (reverse)
+ {
+// this.ordering.Reverse();
+// this.values.Reverse();
+// this.added.Reverse();
+ IList o = Platform.CreateArrayList();
+ IList v = Platform.CreateArrayList();
+ IList a = Platform.CreateArrayList();
+ int count = 1;
+
+ for (int i = 0; i < this.ordering.Count; i++)
+ {
+ if (!((bool) this.added[i]))
+ {
+ count = 0;
+ }
+
+ int index = count++;
+
+ o.Insert(index, this.ordering[i]);
+ v.Insert(index, this.values[i]);
+ a.Insert(index, this.added[i]);
+ }
+
+ this.ordering = o;
+ this.values = v;
+ this.added = a;
+ }
+ }
+
+ /**
+ * return an IList of the oids in the name, in the order they were found.
+ */
+ public IList GetOidList()
+ {
+ return Platform.CreateArrayList(ordering);
+ }
+
+ /**
+ * return an IList of the values found in the name, in the order they
+ * were found.
+ */
+ public IList GetValueList()
+ {
+ return GetValueList(null);
+ }
+
+ /**
+ * return an IList of the values found in the name, in the order they
+ * were found, with the DN label corresponding to passed in oid.
+ */
+ public IList GetValueList(DerObjectIdentifier oid)
+ {
+ IList v = Platform.CreateArrayList();
+ for (int i = 0; i != values.Count; i++)
+ {
+ if (null == oid || oid.Equals(ordering[i]))
+ {
+ string val = (string)values[i];
+
+ if (Platform.StartsWith(val, "\\#"))
+ {
+ val = val.Substring(1);
+ }
+
+ v.Add(val);
+ }
+ }
+ return v;
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ if (seq == null)
+ {
+ Asn1EncodableVector vec = new Asn1EncodableVector();
+ Asn1EncodableVector sVec = new Asn1EncodableVector();
+ DerObjectIdentifier lstOid = null;
+
+ for (int i = 0; i != ordering.Count; i++)
+ {
+ DerObjectIdentifier oid = (DerObjectIdentifier)ordering[i];
+ string str = (string)values[i];
+
+ if (lstOid == null
+ || ((bool)this.added[i]))
+ {
+ }
+ else
+ {
+ vec.Add(new DerSet(sVec));
+ sVec = new Asn1EncodableVector();
+ }
+
+ sVec.Add(
+ new DerSequence(
+ oid,
+ converter.GetConvertedValue(oid, str)));
+
+ lstOid = oid;
+ }
+
+ vec.Add(new DerSet(sVec));
+
+ seq = new DerSequence(vec);
+ }
+
+ return seq;
+ }
+
+ /// The X509Name object to test equivalency against.
+ /// If true, the order of elements must be the same,
+ /// as well as the values associated with each element.
+ public bool Equivalent(
+ X509Name other,
+ bool inOrder)
+ {
+ if (!inOrder)
+ return this.Equivalent(other);
+
+ if (other == null)
+ return false;
+
+ if (other == this)
+ return true;
+
+ int orderingSize = ordering.Count;
+
+ if (orderingSize != other.ordering.Count)
+ return false;
+
+ for (int i = 0; i < orderingSize; i++)
+ {
+ DerObjectIdentifier oid = (DerObjectIdentifier) ordering[i];
+ DerObjectIdentifier oOid = (DerObjectIdentifier) other.ordering[i];
+
+ if (!oid.Equals(oOid))
+ return false;
+
+ string val = (string) values[i];
+ string oVal = (string) other.values[i];
+
+ if (!equivalentStrings(val, oVal))
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * test for equivalence - note: case is ignored.
+ */
+ public bool Equivalent(
+ X509Name other)
+ {
+ if (other == null)
+ return false;
+
+ if (other == this)
+ return true;
+
+ int orderingSize = ordering.Count;
+
+ if (orderingSize != other.ordering.Count)
+ {
+ return false;
+ }
+
+ bool[] indexes = new bool[orderingSize];
+ int start, end, delta;
+
+ if (ordering[0].Equals(other.ordering[0])) // guess forward
+ {
+ start = 0;
+ end = orderingSize;
+ delta = 1;
+ }
+ else // guess reversed - most common problem
+ {
+ start = orderingSize - 1;
+ end = -1;
+ delta = -1;
+ }
+
+ for (int i = start; i != end; i += delta)
+ {
+ bool found = false;
+ DerObjectIdentifier oid = (DerObjectIdentifier)ordering[i];
+ string value = (string)values[i];
+
+ for (int j = 0; j < orderingSize; j++)
+ {
+ if (indexes[j])
+ {
+ continue;
+ }
+
+ DerObjectIdentifier oOid = (DerObjectIdentifier)other.ordering[j];
+
+ if (oid.Equals(oOid))
+ {
+ string oValue = (string)other.values[j];
+
+ if (equivalentStrings(value, oValue))
+ {
+ indexes[j] = true;
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static bool equivalentStrings(
+ string s1,
+ string s2)
+ {
+ string v1 = canonicalize(s1);
+ string v2 = canonicalize(s2);
+
+ if (!v1.Equals(v2))
+ {
+ v1 = stripInternalSpaces(v1);
+ v2 = stripInternalSpaces(v2);
+
+ if (!v1.Equals(v2))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static string canonicalize(
+ string s)
+ {
+ string v = Platform.ToLowerInvariant(s).Trim();
+
+ if (Platform.StartsWith(v, "#"))
+ {
+ Asn1Object obj = decodeObject(v);
+
+ if (obj is IAsn1String)
+ {
+ v = Platform.ToLowerInvariant(((IAsn1String)obj).GetString()).Trim();
+ }
+ }
+
+ return v;
+ }
+
+ private static Asn1Object decodeObject(
+ string v)
+ {
+ try
+ {
+ return Asn1Object.FromByteArray(Hex.Decode(v.Substring(1)));
+ }
+ catch (IOException e)
+ {
+ throw new InvalidOperationException("unknown encoding in name: " + e.Message, e);
+ }
+ }
+
+ private static string stripInternalSpaces(
+ string str)
+ {
+ StringBuilder res = new StringBuilder();
+
+ if (str.Length != 0)
+ {
+ char c1 = str[0];
+
+ res.Append(c1);
+
+ for (int k = 1; k < str.Length; k++)
+ {
+ char c2 = str[k];
+ if (!(c1 == ' ' && c2 == ' '))
+ {
+ res.Append(c2);
+ }
+ c1 = c2;
+ }
+ }
+
+ return res.ToString();
+ }
+
+ private void AppendValue(
+ StringBuilder buf,
+ IDictionary oidSymbols,
+ DerObjectIdentifier oid,
+ string val)
+ {
+ string sym = (string)oidSymbols[oid];
+
+ if (sym != null)
+ {
+ buf.Append(sym);
+ }
+ else
+ {
+ buf.Append(oid.Id);
+ }
+
+ buf.Append('=');
+
+ int index = buf.Length;
+
+ buf.Append(val);
+
+ int end = buf.Length;
+
+ if (Platform.StartsWith(val, "\\#"))
+ {
+ index += 2;
+ }
+
+ while (index != end)
+ {
+ if ((buf[index] == ',')
+ || (buf[index] == '"')
+ || (buf[index] == '\\')
+ || (buf[index] == '+')
+ || (buf[index] == '=')
+ || (buf[index] == '<')
+ || (buf[index] == '>')
+ || (buf[index] == ';'))
+ {
+ buf.Insert(index++, "\\");
+ end++;
+ }
+
+ index++;
+ }
+ }
+
+ /**
+ * convert the structure to a string - if reverse is true the
+ * oids and values are listed out starting with the last element
+ * in the sequence (ala RFC 2253), otherwise the string will begin
+ * with the first element of the structure. If no string definition
+ * for the oid is found in oidSymbols the string value of the oid is
+ * added. Two standard symbol tables are provided DefaultSymbols, and
+ * RFC2253Symbols as part of this class.
+ *
+ * @param reverse if true start at the end of the sequence and work back.
+ * @param oidSymbols look up table strings for oids.
+ */
+ public string ToString(
+ bool reverse,
+ IDictionary oidSymbols)
+ {
+#if SILVERLIGHT || PORTABLE
+ List components = new List();
+#else
+ ArrayList components = new ArrayList();
+#endif
+
+ StringBuilder ava = null;
+
+ for (int i = 0; i < ordering.Count; i++)
+ {
+ if ((bool) added[i])
+ {
+ ava.Append('+');
+ AppendValue(ava, oidSymbols,
+ (DerObjectIdentifier)ordering[i],
+ (string)values[i]);
+ }
+ else
+ {
+ ava = new StringBuilder();
+ AppendValue(ava, oidSymbols,
+ (DerObjectIdentifier)ordering[i],
+ (string)values[i]);
+ components.Add(ava);
+ }
+ }
+
+ if (reverse)
+ {
+ components.Reverse();
+ }
+
+ StringBuilder buf = new StringBuilder();
+
+ if (components.Count > 0)
+ {
+ buf.Append(components[0].ToString());
+
+ for (int i = 1; i < components.Count; ++i)
+ {
+ buf.Append(',');
+ buf.Append(components[i].ToString());
+ }
+ }
+
+ return buf.ToString();
+ }
+
+ public override string ToString()
+ {
+ return ToString(DefaultReverse, (IDictionary)DefaultSymbols);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/X509NameEntryConverter.cs b/bc-sharp-crypto/src/asn1/x509/X509NameEntryConverter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5872656a9cbebf31a4d93e24ae6f77ff788d9618
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/X509NameEntryConverter.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * It turns out that the number of standard ways the fields in a DN should be
+ * encoded into their ASN.1 counterparts is rapidly approaching the
+ * number of machines on the internet. By default the X509Name class
+ * will produce UTF8Strings in line with the current recommendations (RFC 3280).
+ *
+ * An example of an encoder look like below:
+ *
+ * public class X509DirEntryConverter
+ * : X509NameEntryConverter
+ * {
+ * public Asn1Object GetConvertedValue(
+ * DerObjectIdentifier oid,
+ * string value)
+ * {
+ * if (str.Length() != 0 && str.charAt(0) == '#')
+ * {
+ * return ConvertHexEncoded(str, 1);
+ * }
+ * if (oid.Equals(EmailAddress))
+ * {
+ * return new DerIA5String(str);
+ * }
+ * else if (CanBePrintable(str))
+ * {
+ * return new DerPrintableString(str);
+ * }
+ * else if (CanBeUTF8(str))
+ * {
+ * return new DerUtf8String(str);
+ * }
+ * else
+ * {
+ * return new DerBmpString(str);
+ * }
+ * }
+ * }
+ *
+ *
+ */
+ public abstract class X509NameEntryConverter
+ {
+ /**
+ * Convert an inline encoded hex string rendition of an ASN.1
+ * object back into its corresponding ASN.1 object.
+ *
+ * @param str the hex encoded object
+ * @param off the index at which the encoding starts
+ * @return the decoded object
+ */
+ protected Asn1Object ConvertHexEncoded(
+ string hexString,
+ int offset)
+ {
+ string str = hexString.Substring(offset);
+
+ return Asn1Object.FromByteArray(Hex.Decode(str));
+ }
+
+ /**
+ * return true if the passed in string can be represented without
+ * loss as a PrintableString, false otherwise.
+ */
+ protected bool CanBePrintable(
+ string str)
+ {
+ return DerPrintableString.IsPrintableString(str);
+ }
+
+ /**
+ * Convert the passed in string value into the appropriate ASN.1
+ * encoded object.
+ *
+ * @param oid the oid associated with the value in the DN.
+ * @param value the value of the particular DN component.
+ * @return the ASN.1 equivalent for the value.
+ */
+ public abstract Asn1Object GetConvertedValue(DerObjectIdentifier oid, string value);
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/X509NameTokenizer.cs b/bc-sharp-crypto/src/asn1/x509/X509NameTokenizer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ab5529535d36640c557e4ba146b2889c10cce217
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/X509NameTokenizer.cs
@@ -0,0 +1,104 @@
+using System.Text;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+ /**
+ * class for breaking up an X500 Name into it's component tokens, ala
+ * java.util.StringTokenizer. We need this class as some of the
+ * lightweight Java environment don't support classes like
+ * StringTokenizer.
+ */
+ public class X509NameTokenizer
+ {
+ private string value;
+ private int index;
+ private char separator;
+ private StringBuilder buffer = new StringBuilder();
+
+ public X509NameTokenizer(
+ string oid)
+ : this(oid, ',')
+ {
+ }
+
+ public X509NameTokenizer(
+ string oid,
+ char separator)
+ {
+ this.value = oid;
+ this.index = -1;
+ this.separator = separator;
+ }
+
+ public bool HasMoreTokens()
+ {
+ return index != value.Length;
+ }
+
+ public string NextToken()
+ {
+ if (index == value.Length)
+ {
+ return null;
+ }
+
+ int end = index + 1;
+ bool quoted = false;
+ bool escaped = false;
+
+ buffer.Remove(0, buffer.Length);
+
+ while (end != value.Length)
+ {
+ char c = value[end];
+
+ if (c == '"')
+ {
+ if (!escaped)
+ {
+ quoted = !quoted;
+ }
+ else
+ {
+ buffer.Append(c);
+ escaped = false;
+ }
+ }
+ else
+ {
+ if (escaped || quoted)
+ {
+ if (c == '#' && buffer[buffer.Length - 1] == '=')
+ {
+ buffer.Append('\\');
+ }
+ else if (c == '+' && separator != '+')
+ {
+ buffer.Append('\\');
+ }
+ buffer.Append(c);
+ escaped = false;
+ }
+ else if (c == '\\')
+ {
+ escaped = true;
+ }
+ else if (c == separator)
+ {
+ break;
+ }
+ else
+ {
+ buffer.Append(c);
+ }
+ }
+
+ end++;
+ }
+
+ index = end;
+
+ return buffer.ToString().Trim();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/X509ObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/x509/X509ObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f00e314755f972c4f4d8113851c174ca767cc2ed
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/X509ObjectIdentifiers.cs
@@ -0,0 +1,59 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+ public abstract class X509ObjectIdentifiers
+ {
+ //
+ // base id
+ //
+ internal const string ID = "2.5.4";
+
+ public static readonly DerObjectIdentifier CommonName = new DerObjectIdentifier(ID + ".3");
+ public static readonly DerObjectIdentifier CountryName = new DerObjectIdentifier(ID + ".6");
+ public static readonly DerObjectIdentifier LocalityName = new DerObjectIdentifier(ID + ".7");
+ public static readonly DerObjectIdentifier StateOrProvinceName = new DerObjectIdentifier(ID + ".8");
+ public static readonly DerObjectIdentifier Organization = new DerObjectIdentifier(ID + ".10");
+ public static readonly DerObjectIdentifier OrganizationalUnitName = new DerObjectIdentifier(ID + ".11");
+
+ public static readonly DerObjectIdentifier id_at_telephoneNumber = new DerObjectIdentifier(ID + ".20");
+ public static readonly DerObjectIdentifier id_at_name = new DerObjectIdentifier(ID + ".41");
+
+ // id-SHA1 OBJECT IDENTIFIER ::=
+ // {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } //
+ public static readonly DerObjectIdentifier IdSha1 = new DerObjectIdentifier("1.3.14.3.2.26");
+
+ //
+ // ripemd160 OBJECT IDENTIFIER ::=
+ // {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) hashAlgorithm(2) RipeMD-160(1)}
+ //
+ public static readonly DerObjectIdentifier RipeMD160 = new DerObjectIdentifier("1.3.36.3.2.1");
+
+ //
+ // ripemd160WithRSAEncryption OBJECT IDENTIFIER ::=
+ // {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) signatureAlgorithm(3) rsaSignature(1) rsaSignatureWithripemd160(2) }
+ //
+ public static readonly DerObjectIdentifier RipeMD160WithRsaEncryption = new DerObjectIdentifier("1.3.36.3.3.1.2");
+
+ public static readonly DerObjectIdentifier IdEARsa = new DerObjectIdentifier("2.5.8.1.1");
+
+ // id-pkix
+ public static readonly DerObjectIdentifier IdPkix = new DerObjectIdentifier("1.3.6.1.5.5.7");
+
+ //
+ // private internet extensions
+ //
+ public static readonly DerObjectIdentifier IdPE = new DerObjectIdentifier(IdPkix + ".1");
+
+ //
+ // authority information access
+ //
+ public static readonly DerObjectIdentifier IdAD = new DerObjectIdentifier(IdPkix + ".48");
+ public static readonly DerObjectIdentifier IdADCAIssuers = new DerObjectIdentifier(IdAD + ".2");
+ public static readonly DerObjectIdentifier IdADOcsp = new DerObjectIdentifier(IdAD + ".1");
+
+ //
+ // OID for ocsp and crl uri in AuthorityInformationAccess extension
+ //
+ public static readonly DerObjectIdentifier OcspAccessMethod = IdADOcsp;
+ public static readonly DerObjectIdentifier CrlAccessMethod = IdADCAIssuers;
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/qualified/BiometricData.cs b/bc-sharp-crypto/src/asn1/x509/qualified/BiometricData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bb70c342c9682273297b135fbed64c3318a594ad
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/qualified/BiometricData.cs
@@ -0,0 +1,110 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+ /**
+ * The BiometricData object.
+ *
+ * BiometricData ::= SEQUENCE {
+ * typeOfBiometricData TypeOfBiometricData,
+ * hashAlgorithm AlgorithmIdentifier,
+ * biometricDataHash OCTET STRING,
+ * sourceDataUri IA5String OPTIONAL }
+ *
+ */
+ public class BiometricData
+ : Asn1Encodable
+ {
+ private readonly TypeOfBiometricData typeOfBiometricData;
+ private readonly AlgorithmIdentifier hashAlgorithm;
+ private readonly Asn1OctetString biometricDataHash;
+ private readonly DerIA5String sourceDataUri;
+
+ public static BiometricData GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is BiometricData)
+ {
+ return (BiometricData)obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new BiometricData(Asn1Sequence.GetInstance(obj));
+ }
+
+ throw new ArgumentException("unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private BiometricData(
+ Asn1Sequence seq)
+ {
+ typeOfBiometricData = TypeOfBiometricData.GetInstance(seq[0]);
+ hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+ biometricDataHash = Asn1OctetString.GetInstance(seq[2]);
+
+ if (seq.Count > 3)
+ {
+ sourceDataUri = DerIA5String.GetInstance(seq[3]);
+ }
+ }
+
+ public BiometricData(
+ TypeOfBiometricData typeOfBiometricData,
+ AlgorithmIdentifier hashAlgorithm,
+ Asn1OctetString biometricDataHash,
+ DerIA5String sourceDataUri)
+ {
+ this.typeOfBiometricData = typeOfBiometricData;
+ this.hashAlgorithm = hashAlgorithm;
+ this.biometricDataHash = biometricDataHash;
+ this.sourceDataUri = sourceDataUri;
+ }
+
+ public BiometricData(
+ TypeOfBiometricData typeOfBiometricData,
+ AlgorithmIdentifier hashAlgorithm,
+ Asn1OctetString biometricDataHash)
+ {
+ this.typeOfBiometricData = typeOfBiometricData;
+ this.hashAlgorithm = hashAlgorithm;
+ this.biometricDataHash = biometricDataHash;
+ this.sourceDataUri = null;
+ }
+
+ public TypeOfBiometricData TypeOfBiometricData
+ {
+ get { return typeOfBiometricData; }
+ }
+
+ public AlgorithmIdentifier HashAlgorithm
+ {
+ get { return hashAlgorithm; }
+ }
+
+ public Asn1OctetString BiometricDataHash
+ {
+ get { return biometricDataHash; }
+ }
+
+ public DerIA5String SourceDataUri
+ {
+ get { return sourceDataUri; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector seq = new Asn1EncodableVector(
+ typeOfBiometricData, hashAlgorithm, biometricDataHash);
+
+ if (sourceDataUri != null)
+ {
+ seq.Add(sourceDataUri);
+ }
+
+ return new DerSequence(seq);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..86a4eee0af0c1b49b73d8fc004e65c4b95ccc94d
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs
@@ -0,0 +1,19 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+ public abstract class EtsiQCObjectIdentifiers
+ {
+ //
+ // base id
+ //
+ public static readonly DerObjectIdentifier IdEtsiQcs = new DerObjectIdentifier("0.4.0.1862.1");
+
+ public static readonly DerObjectIdentifier IdEtsiQcsQcCompliance = new DerObjectIdentifier(IdEtsiQcs+".1");
+ public static readonly DerObjectIdentifier IdEtsiQcsLimitValue = new DerObjectIdentifier(IdEtsiQcs+".2");
+ public static readonly DerObjectIdentifier IdEtsiQcsRetentionPeriod = new DerObjectIdentifier(IdEtsiQcs+".3");
+ public static readonly DerObjectIdentifier IdEtsiQcsQcSscd = new DerObjectIdentifier(IdEtsiQcs+".4");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs b/bc-sharp-crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9ec88f5ed23df2c9c7ecf2bd9cff28ec3008a5bb
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs
@@ -0,0 +1,84 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+ /**
+ * The Iso4217CurrencyCode object.
+ *
+ * Iso4217CurrencyCode ::= CHOICE {
+ * alphabetic PrintableString (SIZE 3), --Recommended
+ * numeric INTEGER (1..999) }
+ * -- Alphabetic or numeric currency code as defined in ISO 4217
+ * -- It is recommended that the Alphabetic form is used
+ *
+ */
+ public class Iso4217CurrencyCode
+ : Asn1Encodable, IAsn1Choice
+ {
+ internal const int AlphabeticMaxSize = 3;
+ internal const int NumericMinSize = 1;
+ internal const int NumericMaxSize = 999;
+
+ internal Asn1Encodable obj;
+// internal int numeric;
+
+ public static Iso4217CurrencyCode GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is Iso4217CurrencyCode)
+ {
+ return (Iso4217CurrencyCode) obj;
+ }
+
+ if (obj is DerInteger)
+ {
+ DerInteger numericobj = DerInteger.GetInstance(obj);
+ int numeric = numericobj.Value.IntValue;
+ return new Iso4217CurrencyCode(numeric);
+ }
+
+ if (obj is DerPrintableString)
+ {
+ DerPrintableString alphabetic = DerPrintableString.GetInstance(obj);
+ return new Iso4217CurrencyCode(alphabetic.GetString());
+ }
+
+ throw new ArgumentException("unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public Iso4217CurrencyCode(
+ int numeric)
+ {
+ if (numeric > NumericMaxSize || numeric < NumericMinSize)
+ {
+ throw new ArgumentException("wrong size in numeric code : not in (" + NumericMinSize + ".." + NumericMaxSize + ")");
+ }
+
+ obj = new DerInteger(numeric);
+ }
+
+ public Iso4217CurrencyCode(
+ string alphabetic)
+ {
+ if (alphabetic.Length > AlphabeticMaxSize)
+ {
+ throw new ArgumentException("wrong size in alphabetic code : max size is " + AlphabeticMaxSize);
+ }
+
+ obj = new DerPrintableString(alphabetic);
+ }
+
+ public bool IsAlphabetic { get { return obj is DerPrintableString; } }
+
+ public string Alphabetic { get { return ((DerPrintableString) obj).GetString(); } }
+
+ public int Numeric { get { return ((DerInteger)obj).Value.IntValue; } }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return obj.ToAsn1Object();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/qualified/MonetaryValue.cs b/bc-sharp-crypto/src/asn1/x509/qualified/MonetaryValue.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d703de943fa722340054144f3675005890117939
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/qualified/MonetaryValue.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+ /**
+ * The MonetaryValue object.
+ *
+ * MonetaryValue ::= SEQUENCE {
+ * currency Iso4217CurrencyCode,
+ * amount INTEGER,
+ * exponent INTEGER }
+ * -- value = amount * 10^exponent
+ *
+ */
+ public class MonetaryValue
+ : Asn1Encodable
+ {
+ internal Iso4217CurrencyCode currency;
+ internal DerInteger amount;
+ internal DerInteger exponent;
+
+ public static MonetaryValue GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is MonetaryValue)
+ {
+ return (MonetaryValue) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new MonetaryValue(Asn1Sequence.GetInstance(obj));
+ }
+
+ throw new ArgumentException("unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private MonetaryValue(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 3)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ currency = Iso4217CurrencyCode.GetInstance(seq[0]);
+ amount = DerInteger.GetInstance(seq[1]);
+ exponent = DerInteger.GetInstance(seq[2]);
+ }
+
+ public MonetaryValue(
+ Iso4217CurrencyCode currency,
+ int amount,
+ int exponent)
+ {
+ this.currency = currency;
+ this.amount = new DerInteger(amount);
+ this.exponent = new DerInteger(exponent);
+ }
+
+ public Iso4217CurrencyCode Currency
+ {
+ get { return currency; }
+ }
+
+ public BigInteger Amount
+ {
+ get { return amount.Value; }
+ }
+
+ public BigInteger Exponent
+ {
+ get { return exponent.Value; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(currency, amount, exponent);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/qualified/QCStatement.cs b/bc-sharp-crypto/src/asn1/x509/qualified/QCStatement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a8e214cbf34c68b2e71eb3d59f6f909f2ec101af
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/qualified/QCStatement.cs
@@ -0,0 +1,84 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+ /**
+ * The QCStatement object.
+ *
+ * QCStatement ::= SEQUENCE {
+ * statementId OBJECT IDENTIFIER,
+ * statementInfo ANY DEFINED BY statementId OPTIONAL}
+ *
+ */
+ public class QCStatement
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier qcStatementId;
+ private readonly Asn1Encodable qcStatementInfo;
+
+ public static QCStatement GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is QCStatement)
+ {
+ return (QCStatement) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new QCStatement(Asn1Sequence.GetInstance(obj));
+ }
+
+ throw new ArgumentException("unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ private QCStatement(
+ Asn1Sequence seq)
+ {
+ qcStatementId = DerObjectIdentifier.GetInstance(seq[0]);
+
+ if (seq.Count > 1)
+ {
+ qcStatementInfo = seq[1];
+ }
+ }
+
+ public QCStatement(
+ DerObjectIdentifier qcStatementId)
+ {
+ this.qcStatementId = qcStatementId;
+ }
+
+ public QCStatement(
+ DerObjectIdentifier qcStatementId,
+ Asn1Encodable qcStatementInfo)
+ {
+ this.qcStatementId = qcStatementId;
+ this.qcStatementInfo = qcStatementInfo;
+ }
+
+ public DerObjectIdentifier StatementId
+ {
+ get { return qcStatementId; }
+ }
+
+ public Asn1Encodable StatementInfo
+ {
+ get { return qcStatementInfo; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector seq = new Asn1EncodableVector(qcStatementId);
+
+ if (qcStatementInfo != null)
+ {
+ seq.Add(qcStatementInfo);
+ }
+
+ return new DerSequence(seq);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8ebd69edb163bed439135b3478bfcae2eb3cb25e
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs
@@ -0,0 +1,21 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+ public sealed class Rfc3739QCObjectIdentifiers
+ {
+ private Rfc3739QCObjectIdentifiers()
+ {
+ }
+
+ //
+ // base id
+ //
+ public static readonly DerObjectIdentifier IdQcs = new DerObjectIdentifier("1.3.6.1.5.5.7.11");
+
+ public static readonly DerObjectIdentifier IdQcsPkixQCSyntaxV1 = new DerObjectIdentifier(IdQcs+".1");
+ public static readonly DerObjectIdentifier IdQcsPkixQCSyntaxV2 = new DerObjectIdentifier(IdQcs+".2");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/qualified/SemanticsInformation.cs b/bc-sharp-crypto/src/asn1/x509/qualified/SemanticsInformation.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5fe5f936c0e23ad6574f308441536354fa8fd854
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/qualified/SemanticsInformation.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+ /**
+ * The SemanticsInformation object.
+ *
+ * SemanticsInformation ::= SEQUENCE {
+ * semanticsIdentifier OBJECT IDENTIFIER OPTIONAL,
+ * nameRegistrationAuthorities NameRegistrationAuthorities
+ * OPTIONAL }
+ * (WITH COMPONENTS {..., semanticsIdentifier PRESENT}|
+ * WITH COMPONENTS {..., nameRegistrationAuthorities PRESENT})
+ *
+ * NameRegistrationAuthorities ::= SEQUENCE SIZE (1..MAX) OF
+ * GeneralName
+ *
+ */
+ public class SemanticsInformation
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier semanticsIdentifier;
+ private readonly GeneralName[] nameRegistrationAuthorities;
+
+ public static SemanticsInformation GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is SemanticsInformation)
+ {
+ return (SemanticsInformation) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new SemanticsInformation(Asn1Sequence.GetInstance(obj));
+ }
+
+ throw new ArgumentException("unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public SemanticsInformation(
+ Asn1Sequence seq)
+ {
+ if (seq.Count < 1)
+ {
+ throw new ArgumentException("no objects in SemanticsInformation");
+ }
+
+ IEnumerator e = seq.GetEnumerator();
+ e.MoveNext();
+ object obj = e.Current;
+ if (obj is DerObjectIdentifier)
+ {
+ semanticsIdentifier = DerObjectIdentifier.GetInstance(obj);
+ if (e.MoveNext())
+ {
+ obj = e.Current;
+ }
+ else
+ {
+ obj = null;
+ }
+ }
+
+ if (obj != null)
+ {
+ Asn1Sequence generalNameSeq = Asn1Sequence.GetInstance(obj );
+ nameRegistrationAuthorities = new GeneralName[generalNameSeq.Count];
+ for (int i= 0; i < generalNameSeq.Count; i++)
+ {
+ nameRegistrationAuthorities[i] = GeneralName.GetInstance(generalNameSeq[i]);
+ }
+ }
+ }
+
+ public SemanticsInformation(
+ DerObjectIdentifier semanticsIdentifier,
+ GeneralName[] generalNames)
+ {
+ this.semanticsIdentifier = semanticsIdentifier;
+ this.nameRegistrationAuthorities = generalNames;
+ }
+
+ public SemanticsInformation(
+ DerObjectIdentifier semanticsIdentifier)
+ {
+ this.semanticsIdentifier = semanticsIdentifier;
+ }
+
+ public SemanticsInformation(
+ GeneralName[] generalNames)
+ {
+ this.nameRegistrationAuthorities = generalNames;
+ }
+
+ public DerObjectIdentifier SemanticsIdentifier { get { return semanticsIdentifier; } }
+
+ public GeneralName[] GetNameRegistrationAuthorities()
+ {
+ return nameRegistrationAuthorities;
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector seq = new Asn1EncodableVector();
+
+ if (this.semanticsIdentifier != null)
+ {
+ seq.Add(semanticsIdentifier);
+ }
+
+ if (this.nameRegistrationAuthorities != null)
+ {
+ seq.Add(new DerSequence(nameRegistrationAuthorities));
+ }
+
+ return new DerSequence(seq);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs b/bc-sharp-crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..17b7841c37d2a1bc81163a6625ed27f3daebc0ad
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs
@@ -0,0 +1,91 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+ /**
+ * The TypeOfBiometricData object.
+ *
+ * TypeOfBiometricData ::= CHOICE {
+ * predefinedBiometricType PredefinedBiometricType,
+ * biometricDataOid OBJECT IDENTIFIER }
+ *
+ * PredefinedBiometricType ::= INTEGER {
+ * picture(0),handwritten-signature(1)}
+ * (picture|handwritten-signature)
+ *
+ */
+ public class TypeOfBiometricData
+ : Asn1Encodable, IAsn1Choice
+ {
+ public const int Picture = 0;
+ public const int HandwrittenSignature = 1;
+
+ internal Asn1Encodable obj;
+
+ public static TypeOfBiometricData GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is TypeOfBiometricData)
+ {
+ return (TypeOfBiometricData) obj;
+ }
+
+ if (obj is DerInteger)
+ {
+ DerInteger predefinedBiometricTypeObj = DerInteger.GetInstance(obj);
+ int predefinedBiometricType = predefinedBiometricTypeObj.Value.IntValue;
+
+ return new TypeOfBiometricData(predefinedBiometricType);
+ }
+
+ if (obj is DerObjectIdentifier)
+ {
+ DerObjectIdentifier BiometricDataOid = DerObjectIdentifier.GetInstance(obj);
+ return new TypeOfBiometricData(BiometricDataOid);
+ }
+
+ throw new ArgumentException("unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public TypeOfBiometricData(
+ int predefinedBiometricType)
+ {
+ if (predefinedBiometricType == Picture || predefinedBiometricType == HandwrittenSignature)
+ {
+ obj = new DerInteger(predefinedBiometricType);
+ }
+ else
+ {
+ throw new ArgumentException("unknow PredefinedBiometricType : " + predefinedBiometricType);
+ }
+ }
+
+ public TypeOfBiometricData(
+ DerObjectIdentifier biometricDataOid)
+ {
+ obj = biometricDataOid;
+ }
+
+ public bool IsPredefined
+ {
+ get { return obj is DerInteger; }
+ }
+
+ public int PredefinedBiometricType
+ {
+ get { return ((DerInteger) obj).Value.IntValue; }
+ }
+
+ public DerObjectIdentifier BiometricDataOid
+ {
+ get { return (DerObjectIdentifier) obj; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return obj.ToAsn1Object();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/sigi/NameOrPseudonym.cs b/bc-sharp-crypto/src/asn1/x509/sigi/NameOrPseudonym.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2402e3832162abf395839842c39234b53c64d9e9
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/sigi/NameOrPseudonym.cs
@@ -0,0 +1,178 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509.SigI
+{
+ /**
+ * Structure for a name or pseudonym.
+ *
+ *
+ * NameOrPseudonym ::= CHOICE {
+ * surAndGivenName SEQUENCE {
+ * surName DirectoryString,
+ * givenName SEQUENCE OF DirectoryString
+ * },
+ * pseudonym DirectoryString
+ * }
+ *
+ *
+ * @see org.bouncycastle.asn1.x509.sigi.PersonalData
+ *
+ */
+ public class NameOrPseudonym
+ : Asn1Encodable, IAsn1Choice
+ {
+ private readonly DirectoryString pseudonym;
+ private readonly DirectoryString surname;
+ private readonly Asn1Sequence givenName;
+
+ public static NameOrPseudonym GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is NameOrPseudonym)
+ {
+ return (NameOrPseudonym)obj;
+ }
+
+ if (obj is IAsn1String)
+ {
+ return new NameOrPseudonym(DirectoryString.GetInstance(obj));
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new NameOrPseudonym((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * Constructor from DERString.
+ *
+ * The sequence is of type NameOrPseudonym:
+ *
+ *
+ * NameOrPseudonym ::= CHOICE {
+ * surAndGivenName SEQUENCE {
+ * surName DirectoryString,
+ * givenName SEQUENCE OF DirectoryString
+ * },
+ * pseudonym DirectoryString
+ * }
+ *
+ * @param pseudonym pseudonym value to use.
+ */
+ public NameOrPseudonym(
+ DirectoryString pseudonym)
+ {
+ this.pseudonym = pseudonym;
+ }
+
+ /**
+ * Constructor from Asn1Sequence.
+ *
+ * The sequence is of type NameOrPseudonym:
+ *
+ *
+ * NameOrPseudonym ::= CHOICE {
+ * surAndGivenName SEQUENCE {
+ * surName DirectoryString,
+ * givenName SEQUENCE OF DirectoryString
+ * },
+ * pseudonym DirectoryString
+ * }
+ *
+ *
+ * @param seq The ASN.1 sequence.
+ */
+ private NameOrPseudonym(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+ if (!(seq[0] is IAsn1String))
+ throw new ArgumentException("Bad object encountered: " + Platform.GetTypeName(seq[0]));
+
+ surname = DirectoryString.GetInstance(seq[0]);
+ givenName = Asn1Sequence.GetInstance(seq[1]);
+ }
+
+ /**
+ * Constructor from a given details.
+ *
+ * @param pseudonym The pseudonym.
+ */
+ public NameOrPseudonym(
+ string pseudonym)
+ : this(new DirectoryString(pseudonym))
+ {
+ }
+
+ /**
+ * Constructor from a given details.
+ *
+ * @param surname The surname.
+ * @param givenName A sequence of directory strings making up the givenName
+ */
+ public NameOrPseudonym(
+ DirectoryString surname,
+ Asn1Sequence givenName)
+ {
+ this.surname = surname;
+ this.givenName = givenName;
+ }
+
+ public DirectoryString Pseudonym
+ {
+ get { return pseudonym; }
+ }
+
+ public DirectoryString Surname
+ {
+ get { return surname; }
+ }
+
+ public DirectoryString[] GetGivenName()
+ {
+ DirectoryString[] items = new DirectoryString[givenName.Count];
+ int count = 0;
+ foreach (object o in givenName)
+ {
+ items[count++] = DirectoryString.GetInstance(o);
+ }
+ return items;
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * NameOrPseudonym ::= CHOICE {
+ * surAndGivenName SEQUENCE {
+ * surName DirectoryString,
+ * givenName SEQUENCE OF DirectoryString
+ * },
+ * pseudonym DirectoryString
+ * }
+ *
+ *
+ * @return an Asn1Object
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ if (pseudonym != null)
+ {
+ return pseudonym.ToAsn1Object();
+ }
+
+ return new DerSequence(surname, givenName);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/sigi/PersonalData.cs b/bc-sharp-crypto/src/asn1/x509/sigi/PersonalData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..dba345c42082f30149c14242bd907dc3487d204a
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/sigi/PersonalData.cs
@@ -0,0 +1,211 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509.SigI
+{
+ /**
+ * Contains personal data for the otherName field in the subjectAltNames
+ * extension.
+ *
+ *
+ * PersonalData ::= SEQUENCE {
+ * nameOrPseudonym NameOrPseudonym,
+ * nameDistinguisher [0] INTEGER OPTIONAL,
+ * dateOfBirth [1] GeneralizedTime OPTIONAL,
+ * placeOfBirth [2] DirectoryString OPTIONAL,
+ * gender [3] PrintableString OPTIONAL,
+ * postalAddress [4] DirectoryString OPTIONAL
+ * }
+ *
+ *
+ * @see org.bouncycastle.asn1.x509.sigi.NameOrPseudonym
+ * @see org.bouncycastle.asn1.x509.sigi.SigIObjectIdentifiers
+ */
+ public class PersonalData
+ : Asn1Encodable
+ {
+ private readonly NameOrPseudonym nameOrPseudonym;
+ private readonly BigInteger nameDistinguisher;
+ private readonly DerGeneralizedTime dateOfBirth;
+ private readonly DirectoryString placeOfBirth;
+ private readonly string gender;
+ private readonly DirectoryString postalAddress;
+
+ public static PersonalData GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is PersonalData)
+ {
+ return (PersonalData) obj;
+ }
+
+ if (obj is Asn1Sequence)
+ {
+ return new PersonalData((Asn1Sequence) obj);
+ }
+
+ throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ /**
+ * Constructor from Asn1Sequence.
+ *
+ * The sequence is of type NameOrPseudonym:
+ *
+ *
+ * PersonalData ::= SEQUENCE {
+ * nameOrPseudonym NameOrPseudonym,
+ * nameDistinguisher [0] INTEGER OPTIONAL,
+ * dateOfBirth [1] GeneralizedTime OPTIONAL,
+ * placeOfBirth [2] DirectoryString OPTIONAL,
+ * gender [3] PrintableString OPTIONAL,
+ * postalAddress [4] DirectoryString OPTIONAL
+ * }
+ *
+ *
+ * @param seq The ASN.1 sequence.
+ */
+ private PersonalData(
+ Asn1Sequence seq)
+ {
+ if (seq.Count < 1)
+ throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+ IEnumerator e = seq.GetEnumerator();
+ e.MoveNext();
+
+ nameOrPseudonym = NameOrPseudonym.GetInstance(e.Current);
+
+ while (e.MoveNext())
+ {
+ Asn1TaggedObject o = Asn1TaggedObject.GetInstance(e.Current);
+ int tag = o.TagNo;
+ switch (tag)
+ {
+ case 0:
+ nameDistinguisher = DerInteger.GetInstance(o, false).Value;
+ break;
+ case 1:
+ dateOfBirth = DerGeneralizedTime.GetInstance(o, false);
+ break;
+ case 2:
+ placeOfBirth = DirectoryString.GetInstance(o, true);
+ break;
+ case 3:
+ gender = DerPrintableString.GetInstance(o, false).GetString();
+ break;
+ case 4:
+ postalAddress = DirectoryString.GetInstance(o, true);
+ break;
+ default:
+ throw new ArgumentException("Bad tag number: " + o.TagNo);
+ }
+ }
+ }
+
+ /**
+ * Constructor from a given details.
+ *
+ * @param nameOrPseudonym Name or pseudonym.
+ * @param nameDistinguisher Name distinguisher.
+ * @param dateOfBirth Date of birth.
+ * @param placeOfBirth Place of birth.
+ * @param gender Gender.
+ * @param postalAddress Postal Address.
+ */
+ public PersonalData(
+ NameOrPseudonym nameOrPseudonym,
+ BigInteger nameDistinguisher,
+ DerGeneralizedTime dateOfBirth,
+ DirectoryString placeOfBirth,
+ string gender,
+ DirectoryString postalAddress)
+ {
+ this.nameOrPseudonym = nameOrPseudonym;
+ this.dateOfBirth = dateOfBirth;
+ this.gender = gender;
+ this.nameDistinguisher = nameDistinguisher;
+ this.postalAddress = postalAddress;
+ this.placeOfBirth = placeOfBirth;
+ }
+
+ public NameOrPseudonym NameOrPseudonym
+ {
+ get { return nameOrPseudonym; }
+ }
+
+ public BigInteger NameDistinguisher
+ {
+ get { return nameDistinguisher; }
+ }
+
+ public DerGeneralizedTime DateOfBirth
+ {
+ get { return dateOfBirth; }
+ }
+
+ public DirectoryString PlaceOfBirth
+ {
+ get { return placeOfBirth; }
+ }
+
+ public string Gender
+ {
+ get { return gender; }
+ }
+
+ public DirectoryString PostalAddress
+ {
+ get { return postalAddress; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Returns:
+ *
+ *
+ * PersonalData ::= SEQUENCE {
+ * nameOrPseudonym NameOrPseudonym,
+ * nameDistinguisher [0] INTEGER OPTIONAL,
+ * dateOfBirth [1] GeneralizedTime OPTIONAL,
+ * placeOfBirth [2] DirectoryString OPTIONAL,
+ * gender [3] PrintableString OPTIONAL,
+ * postalAddress [4] DirectoryString OPTIONAL
+ * }
+ *
+ *
+ * @return an Asn1Object
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector vec = new Asn1EncodableVector();
+ vec.Add(nameOrPseudonym);
+ if (nameDistinguisher != null)
+ {
+ vec.Add(new DerTaggedObject(false, 0, new DerInteger(nameDistinguisher)));
+ }
+ if (dateOfBirth != null)
+ {
+ vec.Add(new DerTaggedObject(false, 1, dateOfBirth));
+ }
+ if (placeOfBirth != null)
+ {
+ vec.Add(new DerTaggedObject(true, 2, placeOfBirth));
+ }
+ if (gender != null)
+ {
+ vec.Add(new DerTaggedObject(false, 3, new DerPrintableString(gender, true)));
+ }
+ if (postalAddress != null)
+ {
+ vec.Add(new DerTaggedObject(true, 4, postalAddress));
+ }
+ return new DerSequence(vec);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x509/sigi/SigIObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/x509/sigi/SigIObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..682311adc9b9aeffc6e6d0804557154396bbc54a
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x509/sigi/SigIObjectIdentifiers.cs
@@ -0,0 +1,49 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509.SigI
+{
+ /**
+ * Object Identifiers of SigI specifciation (German Signature Law
+ * Interoperability specification).
+ */
+ public sealed class SigIObjectIdentifiers
+ {
+ private SigIObjectIdentifiers()
+ {
+ }
+
+ public readonly static DerObjectIdentifier IdSigI = new DerObjectIdentifier("1.3.36.8");
+
+ /**
+ * Key purpose IDs for German SigI (Signature Interoperability
+ * Specification)
+ */
+ public readonly static DerObjectIdentifier IdSigIKP = new DerObjectIdentifier(IdSigI + ".2");
+
+ /**
+ * Certificate policy IDs for German SigI (Signature Interoperability
+ * Specification)
+ */
+ public readonly static DerObjectIdentifier IdSigICP = new DerObjectIdentifier(IdSigI + ".1");
+
+ /**
+ * Other Name IDs for German SigI (Signature Interoperability Specification)
+ */
+ public readonly static DerObjectIdentifier IdSigION = new DerObjectIdentifier(IdSigI + ".4");
+
+ /**
+ * To be used for for the generation of directory service certificates.
+ */
+ public static readonly DerObjectIdentifier IdSigIKPDirectoryService = new DerObjectIdentifier(IdSigIKP + ".1");
+
+ /**
+ * ID for PersonalData
+ */
+ public static readonly DerObjectIdentifier IdSigIONPersonalData = new DerObjectIdentifier(IdSigION + ".1");
+
+ /**
+ * Certificate is conform to german signature law.
+ */
+ public static readonly DerObjectIdentifier IdSigICPSigConform = new DerObjectIdentifier(IdSigICP + ".1");
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x9/DHDomainParameters.cs b/bc-sharp-crypto/src/asn1/x9/DHDomainParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b8c1ac0305fb1f0ba6af58c1bfcfcb992388a050
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x9/DHDomainParameters.cs
@@ -0,0 +1,118 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+ public class DHDomainParameters
+ : Asn1Encodable
+ {
+ private readonly DerInteger p, g, q, j;
+ private readonly DHValidationParms validationParms;
+
+ public static DHDomainParameters GetInstance(Asn1TaggedObject obj, bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ public static DHDomainParameters GetInstance(object obj)
+ {
+ if (obj == null || obj is DHDomainParameters)
+ return (DHDomainParameters)obj;
+
+ if (obj is Asn1Sequence)
+ return new DHDomainParameters((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid DHDomainParameters: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public DHDomainParameters(DerInteger p, DerInteger g, DerInteger q, DerInteger j,
+ DHValidationParms validationParms)
+ {
+ if (p == null)
+ throw new ArgumentNullException("p");
+ if (g == null)
+ throw new ArgumentNullException("g");
+ if (q == null)
+ throw new ArgumentNullException("q");
+
+ this.p = p;
+ this.g = g;
+ this.q = q;
+ this.j = j;
+ this.validationParms = validationParms;
+ }
+
+ private DHDomainParameters(Asn1Sequence seq)
+ {
+ if (seq.Count < 3 || seq.Count > 5)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ IEnumerator e = seq.GetEnumerator();
+ this.p = DerInteger.GetInstance(GetNext(e));
+ this.g = DerInteger.GetInstance(GetNext(e));
+ this.q = DerInteger.GetInstance(GetNext(e));
+
+ Asn1Encodable next = GetNext(e);
+
+ if (next != null && next is DerInteger)
+ {
+ this.j = DerInteger.GetInstance(next);
+ next = GetNext(e);
+ }
+
+ if (next != null)
+ {
+ this.validationParms = DHValidationParms.GetInstance(next.ToAsn1Object());
+ }
+ }
+
+ private static Asn1Encodable GetNext(IEnumerator e)
+ {
+ return e.MoveNext() ? (Asn1Encodable)e.Current : null;
+ }
+
+ public DerInteger P
+ {
+ get { return this.p; }
+ }
+
+ public DerInteger G
+ {
+ get { return this.g; }
+ }
+
+ public DerInteger Q
+ {
+ get { return this.q; }
+ }
+
+ public DerInteger J
+ {
+ get { return this.j; }
+ }
+
+ public DHValidationParms ValidationParms
+ {
+ get { return this.validationParms; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(p, g, q);
+
+ if (this.j != null)
+ {
+ v.Add(this.j);
+ }
+
+ if (this.validationParms != null)
+ {
+ v.Add(this.validationParms);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x9/DHPublicKey.cs b/bc-sharp-crypto/src/asn1/x9/DHPublicKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..74a14a2eea14126b9550d528b24555d9eaca321b
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x9/DHPublicKey.cs
@@ -0,0 +1,46 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+ public class DHPublicKey
+ : Asn1Encodable
+ {
+ private readonly DerInteger y;
+
+ public static DHPublicKey GetInstance(Asn1TaggedObject obj, bool isExplicit)
+ {
+ return GetInstance(DerInteger.GetInstance(obj, isExplicit));
+ }
+
+ public static DHPublicKey GetInstance(object obj)
+ {
+ if (obj == null || obj is DHPublicKey)
+ return (DHPublicKey)obj;
+
+ if (obj is DerInteger)
+ return new DHPublicKey((DerInteger)obj);
+
+ throw new ArgumentException("Invalid DHPublicKey: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public DHPublicKey(DerInteger y)
+ {
+ if (y == null)
+ throw new ArgumentNullException("y");
+
+ this.y = y;
+ }
+
+ public DerInteger Y
+ {
+ get { return this.y; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return this.y;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x9/DHValidationParms.cs b/bc-sharp-crypto/src/asn1/x9/DHValidationParms.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c63c502050827daecab245bfda679d869a70531b
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x9/DHValidationParms.cs
@@ -0,0 +1,64 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+ public class DHValidationParms
+ : Asn1Encodable
+ {
+ private readonly DerBitString seed;
+ private readonly DerInteger pgenCounter;
+
+ public static DHValidationParms GetInstance(Asn1TaggedObject obj, bool isExplicit)
+ {
+ return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+ }
+
+ public static DHValidationParms GetInstance(object obj)
+ {
+ if (obj == null || obj is DHDomainParameters)
+ return (DHValidationParms)obj;
+
+ if (obj is Asn1Sequence)
+ return new DHValidationParms((Asn1Sequence)obj);
+
+ throw new ArgumentException("Invalid DHValidationParms: " + Platform.GetTypeName(obj), "obj");
+ }
+
+ public DHValidationParms(DerBitString seed, DerInteger pgenCounter)
+ {
+ if (seed == null)
+ throw new ArgumentNullException("seed");
+ if (pgenCounter == null)
+ throw new ArgumentNullException("pgenCounter");
+
+ this.seed = seed;
+ this.pgenCounter = pgenCounter;
+ }
+
+ private DHValidationParms(Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+ this.seed = DerBitString.GetInstance(seq[0]);
+ this.pgenCounter = DerInteger.GetInstance(seq[1]);
+ }
+
+ public DerBitString Seed
+ {
+ get { return this.seed; }
+ }
+
+ public DerInteger PgenCounter
+ {
+ get { return this.pgenCounter; }
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(seed, pgenCounter);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x9/ECNamedCurveTable.cs b/bc-sharp-crypto/src/asn1/x9/ECNamedCurveTable.cs
new file mode 100644
index 0000000000000000000000000000000000000000..317ef17b41120e46ea6aadb93e1f4de5366ab36b
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x9/ECNamedCurveTable.cs
@@ -0,0 +1,162 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.Anssi;
+using Org.BouncyCastle.Asn1.GM;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+ /**
+ * A general class that reads all X9.62 style EC curve tables.
+ */
+ public class ECNamedCurveTable
+ {
+ /**
+ * return a X9ECParameters object representing the passed in named
+ * curve. The routine returns null if the curve is not present.
+ *
+ * @param name the name of the curve requested
+ * @return an X9ECParameters object or null if the curve is not available.
+ */
+ public static X9ECParameters GetByName(string name)
+ {
+ X9ECParameters ecP = X962NamedCurves.GetByName(name);
+ if (ecP == null)
+ {
+ ecP = SecNamedCurves.GetByName(name);
+ }
+ if (ecP == null)
+ {
+ ecP = NistNamedCurves.GetByName(name);
+ }
+ if (ecP == null)
+ {
+ ecP = TeleTrusTNamedCurves.GetByName(name);
+ }
+ if (ecP == null)
+ {
+ ecP = AnssiNamedCurves.GetByName(name);
+ }
+ if (ecP == null)
+ {
+ ecP = GMNamedCurves.GetByName(name);
+ }
+ return ecP;
+ }
+
+ public static string GetName(DerObjectIdentifier oid)
+ {
+ string name = X962NamedCurves.GetName(oid);
+ if (name == null)
+ {
+ name = SecNamedCurves.GetName(oid);
+ }
+ if (name == null)
+ {
+ name = NistNamedCurves.GetName(oid);
+ }
+ if (name == null)
+ {
+ name = TeleTrusTNamedCurves.GetName(oid);
+ }
+ if (name == null)
+ {
+ name = AnssiNamedCurves.GetName(oid);
+ }
+ if (name == null)
+ {
+ name = GMNamedCurves.GetName(oid);
+ }
+ return name;
+ }
+
+ /**
+ * return the object identifier signified by the passed in name. Null
+ * if there is no object identifier associated with name.
+ *
+ * @return the object identifier associated with name, if present.
+ */
+ public static DerObjectIdentifier GetOid(string name)
+ {
+ DerObjectIdentifier oid = X962NamedCurves.GetOid(name);
+ if (oid == null)
+ {
+ oid = SecNamedCurves.GetOid(name);
+ }
+ if (oid == null)
+ {
+ oid = NistNamedCurves.GetOid(name);
+ }
+ if (oid == null)
+ {
+ oid = TeleTrusTNamedCurves.GetOid(name);
+ }
+ if (oid == null)
+ {
+ oid = AnssiNamedCurves.GetOid(name);
+ }
+ if (oid == null)
+ {
+ oid = GMNamedCurves.GetOid(name);
+ }
+ return oid;
+ }
+
+ /**
+ * return a X9ECParameters object representing the passed in named
+ * curve.
+ *
+ * @param oid the object id of the curve requested
+ * @return an X9ECParameters object or null if the curve is not available.
+ */
+ public static X9ECParameters GetByOid(DerObjectIdentifier oid)
+ {
+ X9ECParameters ecP = X962NamedCurves.GetByOid(oid);
+ if (ecP == null)
+ {
+ ecP = SecNamedCurves.GetByOid(oid);
+ }
+
+ // NOTE: All the NIST curves are currently from SEC, so no point in redundant OID lookup
+
+ if (ecP == null)
+ {
+ ecP = TeleTrusTNamedCurves.GetByOid(oid);
+ }
+ if (ecP == null)
+ {
+ ecP = AnssiNamedCurves.GetByOid(oid);
+ }
+ if (ecP == null)
+ {
+ ecP = GMNamedCurves.GetByOid(oid);
+ }
+ return ecP;
+ }
+
+ /**
+ * return an enumeration of the names of the available curves.
+ *
+ * @return an enumeration of the names of the available curves.
+ */
+ public static IEnumerable Names
+ {
+ get
+ {
+ IList v = Platform.CreateArrayList();
+ CollectionUtilities.AddRange(v, X962NamedCurves.Names);
+ CollectionUtilities.AddRange(v, SecNamedCurves.Names);
+ CollectionUtilities.AddRange(v, NistNamedCurves.Names);
+ CollectionUtilities.AddRange(v, TeleTrusTNamedCurves.Names);
+ CollectionUtilities.AddRange(v, AnssiNamedCurves.Names);
+ CollectionUtilities.AddRange(v, GMNamedCurves.Names);
+ return v;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x9/KeySpecificInfo.cs b/bc-sharp-crypto/src/asn1/x9/KeySpecificInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..46298646bd4198a0e15ec29ef75b5e656335b9f2
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x9/KeySpecificInfo.cs
@@ -0,0 +1,58 @@
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+ /**
+ * ASN.1 def for Diffie-Hellman key exchange KeySpecificInfo structure. See
+ * RFC 2631, or X9.42, for further details.
+ */
+ public class KeySpecificInfo
+ : Asn1Encodable
+ {
+ private DerObjectIdentifier algorithm;
+ private Asn1OctetString counter;
+
+ public KeySpecificInfo(
+ DerObjectIdentifier algorithm,
+ Asn1OctetString counter)
+ {
+ this.algorithm = algorithm;
+ this.counter = counter;
+ }
+
+ public KeySpecificInfo(
+ Asn1Sequence seq)
+ {
+ IEnumerator e = seq.GetEnumerator();
+
+ e.MoveNext();
+ algorithm = (DerObjectIdentifier)e.Current;
+ e.MoveNext();
+ counter = (Asn1OctetString)e.Current;
+ }
+
+ public DerObjectIdentifier Algorithm
+ {
+ get { return algorithm; }
+ }
+
+ public Asn1OctetString Counter
+ {
+ get { return counter; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * KeySpecificInfo ::= Sequence {
+ * algorithm OBJECT IDENTIFIER,
+ * counter OCTET STRING SIZE (4..4)
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(algorithm, counter);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x9/OtherInfo.cs b/bc-sharp-crypto/src/asn1/x9/OtherInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..21863bd1753aeb9b32e09a40507f0b03d9058b12
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x9/OtherInfo.cs
@@ -0,0 +1,88 @@
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+ /**
+ * ANS.1 def for Diffie-Hellman key exchange OtherInfo structure. See
+ * RFC 2631, or X9.42, for further details.
+ */
+ public class OtherInfo
+ : Asn1Encodable
+ {
+ private KeySpecificInfo keyInfo;
+ private Asn1OctetString partyAInfo;
+ private Asn1OctetString suppPubInfo;
+
+ public OtherInfo(
+ KeySpecificInfo keyInfo,
+ Asn1OctetString partyAInfo,
+ Asn1OctetString suppPubInfo)
+ {
+ this.keyInfo = keyInfo;
+ this.partyAInfo = partyAInfo;
+ this.suppPubInfo = suppPubInfo;
+ }
+
+ public OtherInfo(
+ Asn1Sequence seq)
+ {
+ IEnumerator e = seq.GetEnumerator();
+
+ e.MoveNext();
+ keyInfo = new KeySpecificInfo((Asn1Sequence) e.Current);
+
+ while (e.MoveNext())
+ {
+ DerTaggedObject o = (DerTaggedObject) e.Current;
+
+ if (o.TagNo == 0)
+ {
+ partyAInfo = (Asn1OctetString) o.GetObject();
+ }
+ else if ((int) o.TagNo == 2)
+ {
+ suppPubInfo = (Asn1OctetString) o.GetObject();
+ }
+ }
+ }
+
+ public KeySpecificInfo KeyInfo
+ {
+ get { return keyInfo; }
+ }
+
+ public Asn1OctetString PartyAInfo
+ {
+ get { return partyAInfo; }
+ }
+
+ public Asn1OctetString SuppPubInfo
+ {
+ get { return suppPubInfo; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * OtherInfo ::= Sequence {
+ * keyInfo KeySpecificInfo,
+ * partyAInfo [0] OCTET STRING OPTIONAL,
+ * suppPubInfo [2] OCTET STRING
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(keyInfo);
+
+ if (partyAInfo != null)
+ {
+ v.Add(new DerTaggedObject(0, partyAInfo));
+ }
+
+ v.Add(new DerTaggedObject(2, suppPubInfo));
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x9/X962NamedCurves.cs b/bc-sharp-crypto/src/asn1/x9/X962NamedCurves.cs
new file mode 100644
index 0000000000000000000000000000000000000000..14f7f818a1b4ff7db482c7a9c2d26242380b25dc
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x9/X962NamedCurves.cs
@@ -0,0 +1,751 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+ /**
+ * table of the current named curves defined in X.962 EC-DSA.
+ */
+ public sealed class X962NamedCurves
+ {
+ private X962NamedCurves()
+ {
+ }
+
+ internal class Prime192v1Holder
+ : X9ECParametersHolder
+ {
+ private Prime192v1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Prime192v1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("ffffffffffffffffffffffff99def836146bc9b1b4d22831", 16);
+ BigInteger h = BigInteger.One;
+
+ ECCurve cFp192v1 = new FpCurve(
+ new BigInteger("6277101735386680763835789423207666416083908700390324961279"),
+ new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
+ new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16),
+ n, h);
+
+ return new X9ECParameters(
+ cFp192v1,
+ new X9ECPoint(cFp192v1,
+ Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")),
+ n, h,
+ Hex.Decode("3045AE6FC8422f64ED579528D38120EAE12196D5"));
+ }
+ }
+
+ internal class Prime192v2Holder
+ : X9ECParametersHolder
+ {
+ private Prime192v2Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Prime192v2Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("fffffffffffffffffffffffe5fb1a724dc80418648d8dd31", 16);
+ BigInteger h = BigInteger.One;
+
+ ECCurve cFp192v2 = new FpCurve(
+ new BigInteger("6277101735386680763835789423207666416083908700390324961279"),
+ new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
+ new BigInteger("cc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953", 16),
+ n, h);
+
+ return new X9ECParameters(
+ cFp192v2,
+ new X9ECPoint(cFp192v2,
+ Hex.Decode("03eea2bae7e1497842f2de7769cfe9c989c072ad696f48034a")),
+ n, h,
+ Hex.Decode("31a92ee2029fd10d901b113e990710f0d21ac6b6"));
+ }
+ }
+
+ internal class Prime192v3Holder
+ : X9ECParametersHolder
+ {
+ private Prime192v3Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Prime192v3Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("ffffffffffffffffffffffff7a62d031c83f4294f640ec13", 16);
+ BigInteger h = BigInteger.One;
+
+ ECCurve cFp192v3 = new FpCurve(
+ new BigInteger("6277101735386680763835789423207666416083908700390324961279"),
+ new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
+ new BigInteger("22123dc2395a05caa7423daeccc94760a7d462256bd56916", 16),
+ n, h);
+
+ return new X9ECParameters(
+ cFp192v3,
+ new X9ECPoint(cFp192v3,
+ Hex.Decode("027d29778100c65a1da1783716588dce2b8b4aee8e228f1896")),
+ n, h,
+ Hex.Decode("c469684435deb378c4b65ca9591e2a5763059a2e"));
+ }
+ }
+
+ internal class Prime239v1Holder
+ : X9ECParametersHolder
+ {
+ private Prime239v1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Prime239v1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b", 16);
+ BigInteger h = BigInteger.One;
+
+ ECCurve cFp239v1 = new FpCurve(
+ new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
+ new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16),
+ new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16),
+ n, h);
+
+ return new X9ECParameters(
+ cFp239v1,
+ new X9ECPoint(cFp239v1,
+ Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")),
+ n, h,
+ Hex.Decode("e43bb460f0b80cc0c0b075798e948060f8321b7d"));
+ }
+ }
+
+ internal class Prime239v2Holder
+ : X9ECParametersHolder
+ {
+ private Prime239v2Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Prime239v2Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("7fffffffffffffffffffffff800000cfa7e8594377d414c03821bc582063", 16);
+ BigInteger h = BigInteger.One;
+
+ ECCurve cFp239v2 = new FpCurve(
+ new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
+ new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16),
+ new BigInteger("617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c", 16),
+ n, h);
+
+ return new X9ECParameters(
+ cFp239v2,
+ new X9ECPoint(cFp239v2,
+ Hex.Decode("0238af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7")),
+ n, h,
+ Hex.Decode("e8b4011604095303ca3b8099982be09fcb9ae616"));
+ }
+ }
+
+ internal class Prime239v3Holder
+ : X9ECParametersHolder
+ {
+ private Prime239v3Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Prime239v3Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("7fffffffffffffffffffffff7fffff975deb41b3a6057c3c432146526551", 16);
+ BigInteger h = BigInteger.One;
+
+ ECCurve cFp239v3 = new FpCurve(
+ new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
+ new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16),
+ new BigInteger("255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e", 16),
+ n, h);
+
+ return new X9ECParameters(
+ cFp239v3,
+ new X9ECPoint(cFp239v3,
+ Hex.Decode("036768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a")),
+ n, h,
+ Hex.Decode("7d7374168ffe3471b60a857686a19475d3bfa2ff"));
+ }
+ }
+
+ internal class Prime256v1Holder
+ : X9ECParametersHolder
+ {
+ private Prime256v1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new Prime256v1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16);
+ BigInteger h = BigInteger.One;
+
+ ECCurve cFp256v1 = new FpCurve(
+ new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951"),
+ new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+ new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16),
+ n, h);
+
+ return new X9ECParameters(
+ cFp256v1,
+ new X9ECPoint(cFp256v1,
+ Hex.Decode("036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296")),
+ n, h,
+ Hex.Decode("c49d360886e704936a6678e1139d26b7819f7e90"));
+ }
+ }
+
+ /*
+ * F2m Curves
+ */
+ internal class C2pnb163v1Holder
+ : X9ECParametersHolder
+ {
+ private C2pnb163v1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new C2pnb163v1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("0400000000000000000001E60FC8821CC74DAEAFC1", 16);
+ BigInteger h = BigInteger.Two;
+
+ ECCurve c2m163v1 = new F2mCurve(
+ 163,
+ 1, 2, 8,
+ new BigInteger("072546B5435234A422E0789675F432C89435DE5242", 16),
+ new BigInteger("00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9", 16),
+ n, h);
+
+ return new X9ECParameters(
+ c2m163v1,
+ new X9ECPoint(c2m163v1,
+ Hex.Decode("0307AF69989546103D79329FCC3D74880F33BBE803CB")),
+ n, h,
+ Hex.Decode("D2C0FB15760860DEF1EEF4D696E6768756151754"));
+ }
+ }
+
+ internal class C2pnb163v2Holder
+ : X9ECParametersHolder
+ {
+ private C2pnb163v2Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new C2pnb163v2Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("03FFFFFFFFFFFFFFFFFFFDF64DE1151ADBB78F10A7", 16);
+ BigInteger h = BigInteger.Two;
+
+ ECCurve c2m163v2 = new F2mCurve(
+ 163,
+ 1, 2, 8,
+ new BigInteger("0108B39E77C4B108BED981ED0E890E117C511CF072", 16),
+ new BigInteger("0667ACEB38AF4E488C407433FFAE4F1C811638DF20", 16),
+ n, h);
+
+ return new X9ECParameters(
+ c2m163v2,
+ new X9ECPoint(c2m163v2,
+ Hex.Decode("030024266E4EB5106D0A964D92C4860E2671DB9B6CC5")),
+ n, h,
+ null);
+ }
+ }
+
+ internal class C2pnb163v3Holder
+ : X9ECParametersHolder
+ {
+ private C2pnb163v3Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new C2pnb163v3Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("03FFFFFFFFFFFFFFFFFFFE1AEE140F110AFF961309", 16);
+ BigInteger h = BigInteger.Two;
+
+ ECCurve c2m163v3 = new F2mCurve(
+ 163,
+ 1, 2, 8,
+ new BigInteger("07A526C63D3E25A256A007699F5447E32AE456B50E", 16),
+ new BigInteger("03F7061798EB99E238FD6F1BF95B48FEEB4854252B", 16),
+ n, h);
+
+ return new X9ECParameters(
+ c2m163v3,
+ new X9ECPoint(c2m163v3, Hex.Decode("0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB")),
+ n, h,
+ null);
+ }
+ }
+
+ internal class C2pnb176w1Holder
+ : X9ECParametersHolder
+ {
+ private C2pnb176w1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new C2pnb176w1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("010092537397ECA4F6145799D62B0A19CE06FE26AD", 16);
+ BigInteger h = BigInteger.ValueOf(0xFF6E);
+
+ ECCurve c2m176w1 = new F2mCurve(
+ 176,
+ 1, 2, 43,
+ new BigInteger("00E4E6DB2995065C407D9D39B8D0967B96704BA8E9C90B", 16),
+ new BigInteger("005DDA470ABE6414DE8EC133AE28E9BBD7FCEC0AE0FFF2", 16),
+ n, h);
+
+ return new X9ECParameters(
+ c2m176w1,
+ new X9ECPoint(c2m176w1,
+ Hex.Decode("038D16C2866798B600F9F08BB4A8E860F3298CE04A5798")),
+ n, h,
+ null);
+ }
+ }
+
+ internal class C2tnb191v1Holder
+ : X9ECParametersHolder
+ {
+ private C2tnb191v1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new C2tnb191v1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("40000000000000000000000004A20E90C39067C893BBB9A5", 16);
+ BigInteger h = BigInteger.Two;
+
+ ECCurve c2m191v1 = new F2mCurve(
+ 191,
+ 9,
+ new BigInteger("2866537B676752636A68F56554E12640276B649EF7526267", 16),
+ new BigInteger("2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC", 16),
+ n, h);
+
+ return new X9ECParameters(
+ c2m191v1,
+ new X9ECPoint(c2m191v1,
+ Hex.Decode("0236B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D")),
+ n, h,
+ Hex.Decode("4E13CA542744D696E67687561517552F279A8C84"));
+ }
+ }
+
+ internal class C2tnb191v2Holder
+ : X9ECParametersHolder
+ {
+ private C2tnb191v2Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new C2tnb191v2Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("20000000000000000000000050508CB89F652824E06B8173", 16);
+ BigInteger h = BigInteger.ValueOf(4);
+
+ ECCurve c2m191v2 = new F2mCurve(
+ 191,
+ 9,
+ new BigInteger("401028774D7777C7B7666D1366EA432071274F89FF01E718", 16),
+ new BigInteger("0620048D28BCBD03B6249C99182B7C8CD19700C362C46A01", 16),
+ n, h);
+
+ return new X9ECParameters(
+ c2m191v2,
+ new X9ECPoint(c2m191v2,
+ Hex.Decode("023809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10")),
+ n, h,
+ null);
+ }
+ }
+
+ internal class C2tnb191v3Holder
+ : X9ECParametersHolder
+ {
+ private C2tnb191v3Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new C2tnb191v3Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("155555555555555555555555610C0B196812BFB6288A3EA3", 16);
+ BigInteger h = BigInteger.ValueOf(6);
+
+ ECCurve c2m191v3 = new F2mCurve(
+ 191,
+ 9,
+ new BigInteger("6C01074756099122221056911C77D77E77A777E7E7E77FCB", 16),
+ new BigInteger("71FE1AF926CF847989EFEF8DB459F66394D90F32AD3F15E8", 16),
+ n, h);
+
+ return new X9ECParameters(
+ c2m191v3,
+ new X9ECPoint(c2m191v3,
+ Hex.Decode("03375D4CE24FDE434489DE8746E71786015009E66E38A926DD")),
+ n, h,
+ null);
+ }
+ }
+
+ internal class C2pnb208w1Holder
+ : X9ECParametersHolder
+ {
+ private C2pnb208w1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new C2pnb208w1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("0101BAF95C9723C57B6C21DA2EFF2D5ED588BDD5717E212F9D", 16);
+ BigInteger h = BigInteger.ValueOf(0xFE48);
+
+ ECCurve c2m208w1 = new F2mCurve(
+ 208,
+ 1, 2, 83,
+ new BigInteger("0", 16),
+ new BigInteger("00C8619ED45A62E6212E1160349E2BFA844439FAFC2A3FD1638F9E", 16),
+ n, h);
+
+ return new X9ECParameters(
+ c2m208w1,
+ new X9ECPoint(c2m208w1,
+ Hex.Decode("0289FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A")),
+ n, h,
+ null);
+ }
+ }
+
+ internal class C2tnb239v1Holder
+ : X9ECParametersHolder
+ {
+ private C2tnb239v1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new C2tnb239v1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("2000000000000000000000000000000F4D42FFE1492A4993F1CAD666E447", 16);
+ BigInteger h = BigInteger.ValueOf(4);
+
+ ECCurve c2m239v1 = new F2mCurve(
+ 239,
+ 36,
+ new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16),
+ new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16),
+ n, h);
+
+ return new X9ECParameters(
+ c2m239v1,
+ new X9ECPoint(c2m239v1,
+ Hex.Decode("0257927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D")),
+ n, h,
+ null);
+ }
+ }
+
+ internal class C2tnb239v2Holder
+ : X9ECParametersHolder
+ {
+ private C2tnb239v2Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new C2tnb239v2Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("1555555555555555555555555555553C6F2885259C31E3FCDF154624522D", 16);
+ BigInteger h = BigInteger.ValueOf(6);
+
+ ECCurve c2m239v2 = new F2mCurve(
+ 239,
+ 36,
+ new BigInteger("4230017757A767FAE42398569B746325D45313AF0766266479B75654E65F", 16),
+ new BigInteger("5037EA654196CFF0CD82B2C14A2FCF2E3FF8775285B545722F03EACDB74B", 16),
+ n, h);
+
+ return new X9ECParameters(
+ c2m239v2,
+ new X9ECPoint(c2m239v2,
+ Hex.Decode("0228F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205")),
+ n, h,
+ null);
+ }
+ }
+
+ internal class C2tnb239v3Holder
+ : X9ECParametersHolder
+ {
+ private C2tnb239v3Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new C2tnb239v3Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("0CCCCCCCCCCCCCCCCCCCCCCCCCCCCCAC4912D2D9DF903EF9888B8A0E4CFF", 16);
+ BigInteger h = BigInteger.ValueOf(10);
+
+ ECCurve c2m239v3 = new F2mCurve(
+ 239,
+ 36,
+ new BigInteger("01238774666A67766D6676F778E676B66999176666E687666D8766C66A9F", 16),
+ new BigInteger("6A941977BA9F6A435199ACFC51067ED587F519C5ECB541B8E44111DE1D40", 16),
+ n, h);
+
+ return new X9ECParameters(
+ c2m239v3,
+ new X9ECPoint(c2m239v3,
+ Hex.Decode("0370F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92")),
+ n, h,
+ null);
+ }
+ }
+
+ internal class C2pnb272w1Holder
+ : X9ECParametersHolder
+ {
+ private C2pnb272w1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new C2pnb272w1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("0100FAF51354E0E39E4892DF6E319C72C8161603FA45AA7B998A167B8F1E629521", 16);
+ BigInteger h = BigInteger.ValueOf(0xFF06);
+
+ ECCurve c2m272w1 = new F2mCurve(
+ 272,
+ 1, 3, 56,
+ new BigInteger("0091A091F03B5FBA4AB2CCF49C4EDD220FB028712D42BE752B2C40094DBACDB586FB20", 16),
+ new BigInteger("7167EFC92BB2E3CE7C8AAAFF34E12A9C557003D7C73A6FAF003F99F6CC8482E540F7", 16),
+ n, h);
+
+ return new X9ECParameters(
+ c2m272w1,
+ new X9ECPoint(c2m272w1,
+ Hex.Decode("026108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D")),
+ n, h,
+ null);
+ }
+ }
+
+ internal class C2pnb304w1Holder
+ : X9ECParametersHolder
+ {
+ private C2pnb304w1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new C2pnb304w1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("0101D556572AABAC800101D556572AABAC8001022D5C91DD173F8FB561DA6899164443051D", 16);
+ BigInteger h = BigInteger.ValueOf(0xFE2E);
+
+ ECCurve c2m304w1 = new F2mCurve(
+ 304,
+ 1, 2, 11,
+ new BigInteger("00FD0D693149A118F651E6DCE6802085377E5F882D1B510B44160074C1288078365A0396C8E681", 16),
+ new BigInteger("00BDDB97E555A50A908E43B01C798EA5DAA6788F1EA2794EFCF57166B8C14039601E55827340BE", 16),
+ n, h);
+
+ return new X9ECParameters(
+ c2m304w1,
+ new X9ECPoint(c2m304w1,
+ Hex.Decode("02197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614")),
+ n, h,
+ null);
+ }
+ }
+
+ internal class C2tnb359v1Holder
+ : X9ECParametersHolder
+ {
+ private C2tnb359v1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new C2tnb359v1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("01AF286BCA1AF286BCA1AF286BCA1AF286BCA1AF286BC9FB8F6B85C556892C20A7EB964FE7719E74F490758D3B", 16);
+ BigInteger h = BigInteger.ValueOf(0x4C);
+
+ ECCurve c2m359v1 = new F2mCurve(
+ 359,
+ 68,
+ new BigInteger("5667676A654B20754F356EA92017D946567C46675556F19556A04616B567D223A5E05656FB549016A96656A557", 16),
+ new BigInteger("2472E2D0197C49363F1FE7F5B6DB075D52B6947D135D8CA445805D39BC345626089687742B6329E70680231988", 16),
+ n, h);
+
+ return new X9ECParameters(
+ c2m359v1,
+ new X9ECPoint(c2m359v1,
+ Hex.Decode("033C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097")),
+ n, h,
+ null);
+ }
+ }
+
+ internal class C2pnb368w1Holder
+ : X9ECParametersHolder
+ {
+ private C2pnb368w1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new C2pnb368w1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("010090512DA9AF72B08349D98A5DD4C7B0532ECA51CE03E2D10F3B7AC579BD87E909AE40A6F131E9CFCE5BD967", 16);
+ BigInteger h = BigInteger.ValueOf(0xFF70);
+
+ ECCurve c2m368w1 = new F2mCurve(
+ 368,
+ 1, 2, 85,
+ new BigInteger("00E0D2EE25095206F5E2A4F9ED229F1F256E79A0E2B455970D8D0D865BD94778C576D62F0AB7519CCD2A1A906AE30D", 16),
+ new BigInteger("00FC1217D4320A90452C760A58EDCD30C8DD069B3C34453837A34ED50CB54917E1C2112D84D164F444F8F74786046A", 16),
+ n, h);
+
+ return new X9ECParameters(
+ c2m368w1,
+ new X9ECPoint(c2m368w1,
+ Hex.Decode("021085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F")),
+ n, h,
+ null);
+ }
+ }
+
+ internal class C2tnb431r1Holder
+ : X9ECParametersHolder
+ {
+ private C2tnb431r1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new C2tnb431r1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ BigInteger n = new BigInteger("0340340340340340340340340340340340340340340340340340340323C313FAB50589703B5EC68D3587FEC60D161CC149C1AD4A91", 16);
+ BigInteger h = BigInteger.ValueOf(0x2760);
+
+ ECCurve c2m431r1 = new F2mCurve(
+ 431,
+ 120,
+ new BigInteger("1A827EF00DD6FC0E234CAF046C6A5D8A85395B236CC4AD2CF32A0CADBDC9DDF620B0EB9906D0957F6C6FEACD615468DF104DE296CD8F", 16),
+ new BigInteger("10D9B4A3D9047D8B154359ABFB1B7F5485B04CEB868237DDC9DEDA982A679A5A919B626D4E50A8DD731B107A9962381FB5D807BF2618", 16),
+ n, h);
+
+ return new X9ECParameters(
+ c2m431r1,
+ new X9ECPoint(c2m431r1,
+ Hex.Decode("02120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7")),
+ n, h,
+ null);
+ }
+ }
+
+ private static readonly IDictionary objIds = Platform.CreateHashtable();
+ private static readonly IDictionary curves = Platform.CreateHashtable();
+ private static readonly IDictionary names = Platform.CreateHashtable();
+
+ private static void DefineCurve(
+ string name,
+ DerObjectIdentifier oid,
+ X9ECParametersHolder holder)
+ {
+ objIds.Add(Platform.ToUpperInvariant(name), oid);
+ names.Add(oid, name);
+ curves.Add(oid, holder);
+ }
+
+ static X962NamedCurves()
+ {
+ DefineCurve("prime192v1", X9ObjectIdentifiers.Prime192v1, Prime192v1Holder.Instance);
+ DefineCurve("prime192v2", X9ObjectIdentifiers.Prime192v2, Prime192v2Holder.Instance);
+ DefineCurve("prime192v3", X9ObjectIdentifiers.Prime192v3, Prime192v3Holder.Instance);
+ DefineCurve("prime239v1", X9ObjectIdentifiers.Prime239v1, Prime239v1Holder.Instance);
+ DefineCurve("prime239v2", X9ObjectIdentifiers.Prime239v2, Prime239v2Holder.Instance);
+ DefineCurve("prime239v3", X9ObjectIdentifiers.Prime239v3, Prime239v3Holder.Instance);
+ DefineCurve("prime256v1", X9ObjectIdentifiers.Prime256v1, Prime256v1Holder.Instance);
+ DefineCurve("c2pnb163v1", X9ObjectIdentifiers.C2Pnb163v1, C2pnb163v1Holder.Instance);
+ DefineCurve("c2pnb163v2", X9ObjectIdentifiers.C2Pnb163v2, C2pnb163v2Holder.Instance);
+ DefineCurve("c2pnb163v3", X9ObjectIdentifiers.C2Pnb163v3, C2pnb163v3Holder.Instance);
+ DefineCurve("c2pnb176w1", X9ObjectIdentifiers.C2Pnb176w1, C2pnb176w1Holder.Instance);
+ DefineCurve("c2tnb191v1", X9ObjectIdentifiers.C2Tnb191v1, C2tnb191v1Holder.Instance);
+ DefineCurve("c2tnb191v2", X9ObjectIdentifiers.C2Tnb191v2, C2tnb191v2Holder.Instance);
+ DefineCurve("c2tnb191v3", X9ObjectIdentifiers.C2Tnb191v3, C2tnb191v3Holder.Instance);
+ DefineCurve("c2pnb208w1", X9ObjectIdentifiers.C2Pnb208w1, C2pnb208w1Holder.Instance);
+ DefineCurve("c2tnb239v1", X9ObjectIdentifiers.C2Tnb239v1, C2tnb239v1Holder.Instance);
+ DefineCurve("c2tnb239v2", X9ObjectIdentifiers.C2Tnb239v2, C2tnb239v2Holder.Instance);
+ DefineCurve("c2tnb239v3", X9ObjectIdentifiers.C2Tnb239v3, C2tnb239v3Holder.Instance);
+ DefineCurve("c2pnb272w1", X9ObjectIdentifiers.C2Pnb272w1, C2pnb272w1Holder.Instance);
+ DefineCurve("c2pnb304w1", X9ObjectIdentifiers.C2Pnb304w1, C2pnb304w1Holder.Instance);
+ DefineCurve("c2tnb359v1", X9ObjectIdentifiers.C2Tnb359v1, C2tnb359v1Holder.Instance);
+ DefineCurve("c2pnb368w1", X9ObjectIdentifiers.C2Pnb368w1, C2pnb368w1Holder.Instance);
+ DefineCurve("c2tnb431r1", X9ObjectIdentifiers.C2Tnb431r1, C2tnb431r1Holder.Instance);
+ }
+
+ public static X9ECParameters GetByName(
+ string name)
+ {
+ DerObjectIdentifier oid = GetOid(name);
+ return oid == null ? null : GetByOid(oid);
+ }
+
+ /**
+ * return the X9ECParameters object for the named curve represented by
+ * the passed in object identifier. Null if the curve isn't present.
+ *
+ * @param oid an object identifier representing a named curve, if present.
+ */
+ public static X9ECParameters GetByOid(
+ DerObjectIdentifier oid)
+ {
+ X9ECParametersHolder holder = (X9ECParametersHolder)curves[oid];
+ return holder == null ? null : holder.Parameters;
+ }
+
+ /**
+ * return the object identifier signified by the passed in name. Null
+ * if there is no object identifier associated with name.
+ *
+ * @return the object identifier associated with name, if present.
+ */
+ public static DerObjectIdentifier GetOid(
+ string name)
+ {
+ return (DerObjectIdentifier)objIds[Platform.ToUpperInvariant(name)];
+ }
+
+ /**
+ * return the named curve name represented by the given object identifier.
+ */
+ public static string GetName(
+ DerObjectIdentifier oid)
+ {
+ return (string)names[oid];
+ }
+
+ /**
+ * returns an enumeration containing the name strings for curves
+ * contained in this structure.
+ */
+ public static IEnumerable Names
+ {
+ get { return new EnumerableProxy(names.Values); }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x9/X962Parameters.cs b/bc-sharp-crypto/src/asn1/x9/X962Parameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..04a5c9cbeafa61c384341d262290ce2d9c3970e0
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x9/X962Parameters.cs
@@ -0,0 +1,88 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+ public class X962Parameters
+ : Asn1Encodable, IAsn1Choice
+ {
+ private readonly Asn1Object _params;
+
+ public static X962Parameters GetInstance(
+ object obj)
+ {
+ if (obj == null || obj is X962Parameters)
+ {
+ return (X962Parameters)obj;
+ }
+
+ if (obj is Asn1Object)
+ {
+ return new X962Parameters((Asn1Object)obj);
+ }
+
+ if (obj is byte[])
+ {
+ try
+ {
+ return new X962Parameters(Asn1Object.FromByteArray((byte[])obj));
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("unable to parse encoded data: " + e.Message, e);
+ }
+ }
+
+ throw new ArgumentException("unknown object in getInstance()");
+ }
+
+ public X962Parameters(
+ X9ECParameters ecParameters)
+ {
+ this._params = ecParameters.ToAsn1Object();
+ }
+
+ public X962Parameters(
+ DerObjectIdentifier namedCurve)
+ {
+ this._params = namedCurve;
+ }
+
+ public X962Parameters(
+ Asn1Object obj)
+ {
+ this._params = obj;
+ }
+
+ public bool IsNamedCurve
+ {
+ get { return (_params is DerObjectIdentifier); }
+ }
+
+ public bool IsImplicitlyCA
+ {
+ get { return (_params is Asn1Null); }
+ }
+
+ public Asn1Object Parameters
+ {
+ get { return _params; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Parameters ::= CHOICE {
+ * ecParameters ECParameters,
+ * namedCurve CURVES.&id({CurveNames}),
+ * implicitlyCA Null
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return _params;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x9/X9Curve.cs b/bc-sharp-crypto/src/asn1/x9/X9Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f05a946c24336d7d664df4293f2dfffc2e5b7428
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x9/X9Curve.cs
@@ -0,0 +1,146 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+ /**
+ * ASN.1 def for Elliptic-Curve Curve structure. See
+ * X9.62, for further details.
+ */
+ public class X9Curve
+ : Asn1Encodable
+ {
+ private readonly ECCurve curve;
+ private readonly byte[] seed;
+ private readonly DerObjectIdentifier fieldIdentifier;
+
+ public X9Curve(
+ ECCurve curve)
+ : this(curve, null)
+ {
+ }
+
+ public X9Curve(
+ ECCurve curve,
+ byte[] seed)
+ {
+ if (curve == null)
+ throw new ArgumentNullException("curve");
+
+ this.curve = curve;
+ this.seed = Arrays.Clone(seed);
+
+ if (ECAlgorithms.IsFpCurve(curve))
+ {
+ this.fieldIdentifier = X9ObjectIdentifiers.PrimeField;
+ }
+ else if (ECAlgorithms.IsF2mCurve(curve))
+ {
+ this.fieldIdentifier = X9ObjectIdentifiers.CharacteristicTwoField;
+ }
+ else
+ {
+ throw new ArgumentException("This type of ECCurve is not implemented");
+ }
+ }
+
+ public X9Curve(
+ X9FieldID fieldID,
+ Asn1Sequence seq)
+ {
+ if (fieldID == null)
+ throw new ArgumentNullException("fieldID");
+ if (seq == null)
+ throw new ArgumentNullException("seq");
+
+ this.fieldIdentifier = fieldID.Identifier;
+
+ if (fieldIdentifier.Equals(X9ObjectIdentifiers.PrimeField))
+ {
+ BigInteger q = ((DerInteger) fieldID.Parameters).Value;
+ X9FieldElement x9A = new X9FieldElement(q, (Asn1OctetString) seq[0]);
+ X9FieldElement x9B = new X9FieldElement(q, (Asn1OctetString) seq[1]);
+ curve = new FpCurve(q, x9A.Value.ToBigInteger(), x9B.Value.ToBigInteger());
+ }
+ else
+ {
+ if (fieldIdentifier.Equals(X9ObjectIdentifiers.CharacteristicTwoField))
+ {
+ // Characteristic two field
+ DerSequence parameters = (DerSequence)fieldID.Parameters;
+ int m = ((DerInteger)parameters[0]).Value.IntValue;
+ DerObjectIdentifier representation
+ = (DerObjectIdentifier)parameters[1];
+
+ int k1 = 0;
+ int k2 = 0;
+ int k3 = 0;
+ if (representation.Equals(X9ObjectIdentifiers.TPBasis))
+ {
+ // Trinomial basis representation
+ k1 = ((DerInteger)parameters[2]).Value.IntValue;
+ }
+ else
+ {
+ // Pentanomial basis representation
+ DerSequence pentanomial = (DerSequence) parameters[2];
+ k1 = ((DerInteger) pentanomial[0]).Value.IntValue;
+ k2 = ((DerInteger) pentanomial[1]).Value.IntValue;
+ k3 = ((DerInteger) pentanomial[2]).Value.IntValue;
+ }
+ X9FieldElement x9A = new X9FieldElement(m, k1, k2, k3, (Asn1OctetString)seq[0]);
+ X9FieldElement x9B = new X9FieldElement(m, k1, k2, k3, (Asn1OctetString)seq[1]);
+ // TODO Is it possible to get the order (n) and cofactor(h) too?
+ curve = new F2mCurve(m, k1, k2, k3, x9A.Value.ToBigInteger(), x9B.Value.ToBigInteger());
+ }
+ }
+
+ if (seq.Count == 3)
+ {
+ seed = ((DerBitString) seq[2]).GetBytes();
+ }
+ }
+
+ public ECCurve Curve
+ {
+ get { return curve; }
+ }
+
+ public byte[] GetSeed()
+ {
+ return Arrays.Clone(seed);
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * Curve ::= Sequence {
+ * a FieldElement,
+ * b FieldElement,
+ * seed BIT STRING OPTIONAL
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (fieldIdentifier.Equals(X9ObjectIdentifiers.PrimeField)
+ || fieldIdentifier.Equals(X9ObjectIdentifiers.CharacteristicTwoField))
+ {
+ v.Add(new X9FieldElement(curve.A).ToAsn1Object());
+ v.Add(new X9FieldElement(curve.B).ToAsn1Object());
+ }
+
+ if (seed != null)
+ {
+ v.Add(new DerBitString(seed));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x9/X9ECParameters.cs b/bc-sharp-crypto/src/asn1/x9/X9ECParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0fa3437688e88a858253a73483431e6df3b06684
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x9/X9ECParameters.cs
@@ -0,0 +1,233 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.Field;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+ /**
+ * ASN.1 def for Elliptic-Curve ECParameters structure. See
+ * X9.62, for further details.
+ */
+ public class X9ECParameters
+ : Asn1Encodable
+ {
+ private X9FieldID fieldID;
+ private ECCurve curve;
+ private X9ECPoint g;
+ private BigInteger n;
+ private BigInteger h;
+ private byte[] seed;
+
+ public static X9ECParameters GetInstance(Object obj)
+ {
+ if (obj is X9ECParameters)
+ {
+ return (X9ECParameters)obj;
+ }
+
+ if (obj != null)
+ {
+ return new X9ECParameters(Asn1Sequence.GetInstance(obj));
+ }
+
+ return null;
+ }
+
+ public X9ECParameters(
+ Asn1Sequence seq)
+ {
+ if (!(seq[0] is DerInteger)
+ || !((DerInteger) seq[0]).Value.Equals(BigInteger.One))
+ {
+ throw new ArgumentException("bad version in X9ECParameters");
+ }
+
+ X9Curve x9c = new X9Curve(
+ X9FieldID.GetInstance(seq[1]),
+ Asn1Sequence.GetInstance(seq[2]));
+
+ this.curve = x9c.Curve;
+ object p = seq[3];
+
+ if (p is X9ECPoint)
+ {
+ this.g = ((X9ECPoint)p);
+ }
+ else
+ {
+ this.g = new X9ECPoint(curve, (Asn1OctetString)p);
+ }
+
+ this.n = ((DerInteger)seq[4]).Value;
+ this.seed = x9c.GetSeed();
+
+ if (seq.Count == 6)
+ {
+ this.h = ((DerInteger)seq[5]).Value;
+ }
+ }
+
+ public X9ECParameters(
+ ECCurve curve,
+ ECPoint g,
+ BigInteger n)
+ : this(curve, g, n, null, null)
+ {
+ }
+
+ public X9ECParameters(
+ ECCurve curve,
+ X9ECPoint g,
+ BigInteger n,
+ BigInteger h)
+ : this(curve, g, n, h, null)
+ {
+ }
+
+ public X9ECParameters(
+ ECCurve curve,
+ ECPoint g,
+ BigInteger n,
+ BigInteger h)
+ : this(curve, g, n, h, null)
+ {
+ }
+
+ public X9ECParameters(
+ ECCurve curve,
+ ECPoint g,
+ BigInteger n,
+ BigInteger h,
+ byte[] seed)
+ : this(curve, new X9ECPoint(g), n, h, seed)
+ {
+ }
+
+ public X9ECParameters(
+ ECCurve curve,
+ X9ECPoint g,
+ BigInteger n,
+ BigInteger h,
+ byte[] seed)
+ {
+ this.curve = curve;
+ this.g = g;
+ this.n = n;
+ this.h = h;
+ this.seed = seed;
+
+ if (ECAlgorithms.IsFpCurve(curve))
+ {
+ this.fieldID = new X9FieldID(curve.Field.Characteristic);
+ }
+ else if (ECAlgorithms.IsF2mCurve(curve))
+ {
+ IPolynomialExtensionField field = (IPolynomialExtensionField)curve.Field;
+ int[] exponents = field.MinimalPolynomial.GetExponentsPresent();
+ if (exponents.Length == 3)
+ {
+ this.fieldID = new X9FieldID(exponents[2], exponents[1]);
+ }
+ else if (exponents.Length == 5)
+ {
+ this.fieldID = new X9FieldID(exponents[4], exponents[1], exponents[2], exponents[3]);
+ }
+ else
+ {
+ throw new ArgumentException("Only trinomial and pentomial curves are supported");
+ }
+ }
+ else
+ {
+ throw new ArgumentException("'curve' is of an unsupported type");
+ }
+ }
+
+ public ECCurve Curve
+ {
+ get { return curve; }
+ }
+
+ public ECPoint G
+ {
+ get { return g.Point; }
+ }
+
+ public BigInteger N
+ {
+ get { return n; }
+ }
+
+ public BigInteger H
+ {
+ get { return h; }
+ }
+
+ public byte[] GetSeed()
+ {
+ return seed;
+ }
+
+ /**
+ * Return the ASN.1 entry representing the Curve.
+ *
+ * @return the X9Curve for the curve in these parameters.
+ */
+ public X9Curve CurveEntry
+ {
+ get { return new X9Curve(curve, seed); }
+ }
+
+ /**
+ * Return the ASN.1 entry representing the FieldID.
+ *
+ * @return the X9FieldID for the FieldID in these parameters.
+ */
+ public X9FieldID FieldIDEntry
+ {
+ get { return fieldID; }
+ }
+
+ /**
+ * Return the ASN.1 entry representing the base point G.
+ *
+ * @return the X9ECPoint for the base point in these parameters.
+ */
+ public X9ECPoint BaseEntry
+ {
+ get { return g; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * ECParameters ::= Sequence {
+ * version Integer { ecpVer1(1) } (ecpVer1),
+ * fieldID FieldID {{FieldTypes}},
+ * curve X9Curve,
+ * base X9ECPoint,
+ * order Integer,
+ * cofactor Integer OPTIONAL
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ new DerInteger(BigInteger.One),
+ fieldID,
+ new X9Curve(curve, seed),
+ g,
+ new DerInteger(n));
+
+ if (h != null)
+ {
+ v.Add(new DerInteger(h));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x9/X9ECParametersHolder.cs b/bc-sharp-crypto/src/asn1/x9/X9ECParametersHolder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e802b738c292bd57caa34e6432138758f523a5c6
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x9/X9ECParametersHolder.cs
@@ -0,0 +1,25 @@
+namespace Org.BouncyCastle.Asn1.X9
+{
+ public abstract class X9ECParametersHolder
+ {
+ private X9ECParameters parameters;
+
+ public X9ECParameters Parameters
+ {
+ get
+ {
+ lock (this)
+ {
+ if (parameters == null)
+ {
+ parameters = CreateParameters();
+ }
+
+ return parameters;
+ }
+ }
+ }
+
+ protected abstract X9ECParameters CreateParameters();
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x9/X9ECPoint.cs b/bc-sharp-crypto/src/asn1/x9/X9ECPoint.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7ef4f13bc357f9d2afc175ada120f0311717699c
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x9/X9ECPoint.cs
@@ -0,0 +1,80 @@
+using Org.BouncyCastle.Math.EC;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+ /**
+ * class for describing an ECPoint as a Der object.
+ */
+ public class X9ECPoint
+ : Asn1Encodable
+ {
+ private readonly Asn1OctetString encoding;
+
+ private ECCurve c;
+ private ECPoint p;
+
+ public X9ECPoint(ECPoint p)
+ : this(p, false)
+ {
+ }
+
+ public X9ECPoint(ECPoint p, bool compressed)
+ {
+ this.p = p.Normalize();
+ this.encoding = new DerOctetString(p.GetEncoded(compressed));
+ }
+
+ public X9ECPoint(ECCurve c, byte[] encoding)
+ {
+ this.c = c;
+ this.encoding = new DerOctetString(Arrays.Clone(encoding));
+ }
+
+ public X9ECPoint(ECCurve c, Asn1OctetString s)
+ : this(c, s.GetOctets())
+ {
+ }
+
+ public byte[] GetPointEncoding()
+ {
+ return Arrays.Clone(encoding.GetOctets());
+ }
+
+ public ECPoint Point
+ {
+ get
+ {
+ if (p == null)
+ {
+ p = c.DecodePoint(encoding.GetOctets()).Normalize();
+ }
+
+ return p;
+ }
+ }
+
+ public bool IsPointCompressed
+ {
+ get
+ {
+ byte[] octets = encoding.GetOctets();
+ return octets != null && octets.Length > 0 && (octets[0] == 2 || octets[0] == 3);
+ }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * ECPoint ::= OCTET STRING
+ *
+ *
+ * Octet string produced using ECPoint.GetEncoded().
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return encoding;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x9/X9FieldElement.cs b/bc-sharp-crypto/src/asn1/x9/X9FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..94bd96b24acc6454719860067b7346588b83b1aa
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x9/X9FieldElement.cs
@@ -0,0 +1,69 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+ /**
+ * Class for processing an ECFieldElement as a DER object.
+ */
+ public class X9FieldElement
+ : Asn1Encodable
+ {
+ private ECFieldElement f;
+
+ public X9FieldElement(
+ ECFieldElement f)
+ {
+ this.f = f;
+ }
+
+ public X9FieldElement(
+ BigInteger p,
+ Asn1OctetString s)
+ : this(new FpFieldElement(p, new BigInteger(1, s.GetOctets())))
+ {
+ }
+
+ public X9FieldElement(
+ int m,
+ int k1,
+ int k2,
+ int k3,
+ Asn1OctetString s)
+ : this(new F2mFieldElement(m, k1, k2, k3, new BigInteger(1, s.GetOctets())))
+ {
+ }
+
+ public ECFieldElement Value
+ {
+ get { return f; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ *
+ * FieldElement ::= OCTET STRING
+ *
+ *
+ *
+ * if q is an odd prime then the field element is
+ * processed as an Integer and converted to an octet string
+ * according to x 9.62 4.3.1.
+ * if q is 2m then the bit string
+ * contained in the field element is converted into an octet
+ * string with the same ordering padded at the front if necessary.
+ *
+ *
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ int byteCount = X9IntegerConverter.GetByteLength(f);
+ byte[] paddedBigInteger = X9IntegerConverter.IntegerToBytes(f.ToBigInteger(), byteCount);
+
+ return new DerOctetString(paddedBigInteger);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x9/X9FieldID.cs b/bc-sharp-crypto/src/asn1/x9/X9FieldID.cs
new file mode 100644
index 0000000000000000000000000000000000000000..08d7d71b4dc7cf0334efe09cee8e7469fb3eff30
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x9/X9FieldID.cs
@@ -0,0 +1,132 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+ /**
+ * ASN.1 def for Elliptic-Curve Field ID structure. See
+ * X9.62, for further details.
+ */
+ public class X9FieldID
+ : Asn1Encodable
+ {
+ private readonly DerObjectIdentifier id;
+ private readonly Asn1Object parameters;
+
+ /**
+ * Constructor for elliptic curves over prime fields
+ * F2
.
+ * @param primeP The prime p
defining the prime field.
+ */
+ public X9FieldID(
+ BigInteger primeP)
+ {
+ this.id = X9ObjectIdentifiers.PrimeField;
+ this.parameters = new DerInteger(primeP);
+ }
+
+ /**
+ * Constructor for elliptic curves over binary fields
+ * F2m
.
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k1 The integer k1
where xm +
+ * xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ public X9FieldID(int m, int k1)
+ : this(m, k1, 0, 0)
+ {
+ }
+
+ /**
+ * Constructor for elliptic curves over binary fields
+ * F2m
.
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k1 The integer k1
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k2 The integer k2
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k3 The integer k3
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
..
+ */
+ public X9FieldID(
+ int m,
+ int k1,
+ int k2,
+ int k3)
+ {
+ this.id = X9ObjectIdentifiers.CharacteristicTwoField;
+
+ Asn1EncodableVector fieldIdParams = new Asn1EncodableVector(new DerInteger(m));
+
+ if (k2 == 0)
+ {
+ if (k3 != 0)
+ throw new ArgumentException("inconsistent k values");
+
+ fieldIdParams.Add(
+ X9ObjectIdentifiers.TPBasis,
+ new DerInteger(k1));
+ }
+ else
+ {
+ if (k2 <= k1 || k3 <= k2)
+ throw new ArgumentException("inconsistent k values");
+
+ fieldIdParams.Add(
+ X9ObjectIdentifiers.PPBasis,
+ new DerSequence(
+ new DerInteger(k1),
+ new DerInteger(k2),
+ new DerInteger(k3)));
+ }
+
+ this.parameters = new DerSequence(fieldIdParams);
+ }
+
+ private X9FieldID(Asn1Sequence seq)
+ {
+ this.id = DerObjectIdentifier.GetInstance(seq[0]);
+ this.parameters = seq[1].ToAsn1Object();
+ }
+
+ public static X9FieldID GetInstance(object obj)
+ {
+ if (obj is X9FieldID)
+ return (X9FieldID)obj;
+ if (obj == null)
+ return null;
+ return new X9FieldID(Asn1Sequence.GetInstance(obj));
+ }
+
+ public DerObjectIdentifier Identifier
+ {
+ get { return id; }
+ }
+
+ public Asn1Object Parameters
+ {
+ get { return parameters; }
+ }
+
+ /**
+ * Produce a Der encoding of the following structure.
+ *
+ * FieldID ::= Sequence {
+ * fieldType FIELD-ID.&id({IOSet}),
+ * parameters FIELD-ID.&Type({IOSet}{@fieldType})
+ * }
+ *
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(id, parameters);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x9/X9IntegerConverter.cs b/bc-sharp-crypto/src/asn1/x9/X9IntegerConverter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e8f45711403d9683050fe04bca7d48c7ac74d493
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x9/X9IntegerConverter.cs
@@ -0,0 +1,40 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+ public abstract class X9IntegerConverter
+ {
+ public static int GetByteLength(ECFieldElement fe)
+ {
+ return (fe.FieldSize + 7) / 8;
+ }
+
+ public static int GetByteLength(ECCurve c)
+ {
+ return (c.FieldSize + 7) / 8;
+ }
+
+ public static byte[] IntegerToBytes(BigInteger s, int qLength)
+ {
+ byte[] bytes = s.ToByteArrayUnsigned();
+
+ if (qLength < bytes.Length)
+ {
+ byte[] tmp = new byte[qLength];
+ Array.Copy(bytes, bytes.Length - tmp.Length, tmp, 0, tmp.Length);
+ return tmp;
+ }
+ else if (qLength > bytes.Length)
+ {
+ byte[] tmp = new byte[qLength];
+ Array.Copy(bytes, 0, tmp, tmp.Length - bytes.Length, bytes.Length);
+ return tmp;
+ }
+
+ return bytes;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/asn1/x9/X9ObjectIdentifiers.cs b/bc-sharp-crypto/src/asn1/x9/X9ObjectIdentifiers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9d7ecae6e3c409497d8d45c648dc12d252bf863e
--- /dev/null
+++ b/bc-sharp-crypto/src/asn1/x9/X9ObjectIdentifiers.cs
@@ -0,0 +1,137 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+ public abstract class X9ObjectIdentifiers
+ {
+ //
+ // X9.62
+ //
+ // ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ // us(840) ansi-x962(10045) }
+ //
+
+ internal const string AnsiX962 = "1.2.840.10045";
+
+ public static readonly DerObjectIdentifier ansi_X9_62 = new DerObjectIdentifier(AnsiX962);
+
+ public static readonly DerObjectIdentifier IdFieldType = ansi_X9_62.Branch("1");
+
+ public static readonly DerObjectIdentifier PrimeField = IdFieldType.Branch("1");
+ public static readonly DerObjectIdentifier CharacteristicTwoField = IdFieldType.Branch("2");
+
+ public static readonly DerObjectIdentifier GNBasis = CharacteristicTwoField.Branch("3.1");
+ public static readonly DerObjectIdentifier TPBasis = CharacteristicTwoField.Branch("3.2");
+ public static readonly DerObjectIdentifier PPBasis = CharacteristicTwoField.Branch("3.3");
+
+ [Obsolete("Use 'id_ecSigType' instead")]
+ public const string IdECSigType = AnsiX962 + ".4";
+ public static readonly DerObjectIdentifier id_ecSigType = ansi_X9_62.Branch("4");
+
+ public static readonly DerObjectIdentifier ECDsaWithSha1 = id_ecSigType.Branch("1");
+
+ [Obsolete("Use 'id_publicKeyType' instead")]
+ public const string IdPublicKeyType = AnsiX962 + ".2";
+ public static readonly DerObjectIdentifier id_publicKeyType = ansi_X9_62.Branch("2");
+
+ public static readonly DerObjectIdentifier IdECPublicKey = id_publicKeyType.Branch("1");
+
+ public static readonly DerObjectIdentifier ECDsaWithSha2 = id_ecSigType.Branch("3");
+
+ public static readonly DerObjectIdentifier ECDsaWithSha224 = ECDsaWithSha2.Branch("1");
+ public static readonly DerObjectIdentifier ECDsaWithSha256 = ECDsaWithSha2.Branch("2");
+ public static readonly DerObjectIdentifier ECDsaWithSha384 = ECDsaWithSha2.Branch("3");
+ public static readonly DerObjectIdentifier ECDsaWithSha512 = ECDsaWithSha2.Branch("4");
+
+
+ //
+ // named curves
+ //
+ public static readonly DerObjectIdentifier EllipticCurve = ansi_X9_62.Branch("3");
+
+ //
+ // Two Curves
+ //
+ public static readonly DerObjectIdentifier CTwoCurve = EllipticCurve.Branch("0");
+
+ public static readonly DerObjectIdentifier C2Pnb163v1 = CTwoCurve.Branch("1");
+ public static readonly DerObjectIdentifier C2Pnb163v2 = CTwoCurve.Branch("2");
+ public static readonly DerObjectIdentifier C2Pnb163v3 = CTwoCurve.Branch("3");
+ public static readonly DerObjectIdentifier C2Pnb176w1 = CTwoCurve.Branch("4");
+ public static readonly DerObjectIdentifier C2Tnb191v1 = CTwoCurve.Branch("5");
+ public static readonly DerObjectIdentifier C2Tnb191v2 = CTwoCurve.Branch("6");
+ public static readonly DerObjectIdentifier C2Tnb191v3 = CTwoCurve.Branch("7");
+ public static readonly DerObjectIdentifier C2Onb191v4 = CTwoCurve.Branch("8");
+ public static readonly DerObjectIdentifier C2Onb191v5 = CTwoCurve.Branch("9");
+ public static readonly DerObjectIdentifier C2Pnb208w1 = CTwoCurve.Branch("10");
+ public static readonly DerObjectIdentifier C2Tnb239v1 = CTwoCurve.Branch("11");
+ public static readonly DerObjectIdentifier C2Tnb239v2 = CTwoCurve.Branch("12");
+ public static readonly DerObjectIdentifier C2Tnb239v3 = CTwoCurve.Branch("13");
+ public static readonly DerObjectIdentifier C2Onb239v4 = CTwoCurve.Branch("14");
+ public static readonly DerObjectIdentifier C2Onb239v5 = CTwoCurve.Branch("15");
+ public static readonly DerObjectIdentifier C2Pnb272w1 = CTwoCurve.Branch("16");
+ public static readonly DerObjectIdentifier C2Pnb304w1 = CTwoCurve.Branch("17");
+ public static readonly DerObjectIdentifier C2Tnb359v1 = CTwoCurve.Branch("18");
+ public static readonly DerObjectIdentifier C2Pnb368w1 = CTwoCurve.Branch("19");
+ public static readonly DerObjectIdentifier C2Tnb431r1 = CTwoCurve.Branch("20");
+
+ //
+ // Prime
+ //
+ public static readonly DerObjectIdentifier PrimeCurve = EllipticCurve.Branch("1");
+
+ public static readonly DerObjectIdentifier Prime192v1 = PrimeCurve.Branch("1");
+ public static readonly DerObjectIdentifier Prime192v2 = PrimeCurve.Branch("2");
+ public static readonly DerObjectIdentifier Prime192v3 = PrimeCurve.Branch("3");
+ public static readonly DerObjectIdentifier Prime239v1 = PrimeCurve.Branch("4");
+ public static readonly DerObjectIdentifier Prime239v2 = PrimeCurve.Branch("5");
+ public static readonly DerObjectIdentifier Prime239v3 = PrimeCurve.Branch("6");
+ public static readonly DerObjectIdentifier Prime256v1 = PrimeCurve.Branch("7");
+
+ //
+ // DSA
+ //
+ // dsapublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ // us(840) ansi-x957(10040) number-type(4) 1 }
+ public static readonly DerObjectIdentifier IdDsa = new DerObjectIdentifier("1.2.840.10040.4.1");
+
+ /**
+ * id-dsa-with-sha1 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ * us(840) x9-57 (10040) x9cm(4) 3 }
+ */
+ public static readonly DerObjectIdentifier IdDsaWithSha1 = new DerObjectIdentifier("1.2.840.10040.4.3");
+
+ /**
+ * X9.63
+ */
+ public static readonly DerObjectIdentifier X9x63Scheme = new DerObjectIdentifier("1.3.133.16.840.63.0");
+ public static readonly DerObjectIdentifier DHSinglePassStdDHSha1KdfScheme = X9x63Scheme.Branch("2");
+ public static readonly DerObjectIdentifier DHSinglePassCofactorDHSha1KdfScheme = X9x63Scheme.Branch("3");
+ public static readonly DerObjectIdentifier MqvSinglePassSha1KdfScheme = X9x63Scheme.Branch("16");
+
+ /**
+ * X9.42
+ */
+
+ public static readonly DerObjectIdentifier ansi_x9_42 = new DerObjectIdentifier("1.2.840.10046");
+
+ //
+ // Diffie-Hellman
+ //
+ // dhpublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ // us(840) ansi-x942(10046) number-type(2) 1 }
+ //
+ public static readonly DerObjectIdentifier DHPublicNumber = ansi_x9_42.Branch("2.1");
+
+ public static readonly DerObjectIdentifier X9x42Schemes = ansi_x9_42.Branch("2.3");
+
+ public static readonly DerObjectIdentifier DHStatic = X9x42Schemes.Branch("1");
+ public static readonly DerObjectIdentifier DHEphem = X9x42Schemes.Branch("2");
+ public static readonly DerObjectIdentifier DHOneFlow = X9x42Schemes.Branch("3");
+ public static readonly DerObjectIdentifier DHHybrid1 = X9x42Schemes.Branch("4");
+ public static readonly DerObjectIdentifier DHHybrid2 = X9x42Schemes.Branch("5");
+ public static readonly DerObjectIdentifier DHHybridOneFlow = X9x42Schemes.Branch("6");
+ public static readonly DerObjectIdentifier Mqv2 = X9x42Schemes.Branch("7");
+ public static readonly DerObjectIdentifier Mqv1 = X9x42Schemes.Branch("8");
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/ArmoredInputStream.cs b/bc-sharp-crypto/src/bcpg/ArmoredInputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d5d9f7ffbd5d2ee1b45bcd3384fb7aea665b331c
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/ArmoredInputStream.cs
@@ -0,0 +1,524 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /**
+ * reader for Base64 armored objects - read the headers and then start returning
+ * bytes when the data is reached. An IOException is thrown if the CRC check
+ * fails.
+ */
+ public class ArmoredInputStream
+ : BaseInputStream
+ {
+ /*
+ * set up the decoding table.
+ */
+ private readonly static byte[] decodingTable;
+ static ArmoredInputStream()
+ {
+ decodingTable = new byte[128];
+ for (int i = 'A'; i <= 'Z'; i++)
+ {
+ decodingTable[i] = (byte)(i - 'A');
+ }
+ for (int i = 'a'; i <= 'z'; i++)
+ {
+ decodingTable[i] = (byte)(i - 'a' + 26);
+ }
+ for (int i = '0'; i <= '9'; i++)
+ {
+ decodingTable[i] = (byte)(i - '0' + 52);
+ }
+ decodingTable['+'] = 62;
+ decodingTable['/'] = 63;
+ }
+
+ /**
+ * decode the base 64 encoded input data.
+ *
+ * @return the offset the data starts in out.
+ */
+ private int Decode(
+ int in0,
+ int in1,
+ int in2,
+ int in3,
+ int[] result)
+ {
+ if (in3 < 0)
+ {
+ throw new EndOfStreamException("unexpected end of file in armored stream.");
+ }
+
+ int b1, b2, b3, b4;
+ if (in2 == '=')
+ {
+ b1 = decodingTable[in0] &0xff;
+ b2 = decodingTable[in1] & 0xff;
+ result[2] = ((b1 << 2) | (b2 >> 4)) & 0xff;
+ return 2;
+ }
+ else if (in3 == '=')
+ {
+ b1 = decodingTable[in0];
+ b2 = decodingTable[in1];
+ b3 = decodingTable[in2];
+ result[1] = ((b1 << 2) | (b2 >> 4)) & 0xff;
+ result[2] = ((b2 << 4) | (b3 >> 2)) & 0xff;
+ return 1;
+ }
+ else
+ {
+ b1 = decodingTable[in0];
+ b2 = decodingTable[in1];
+ b3 = decodingTable[in2];
+ b4 = decodingTable[in3];
+ result[0] = ((b1 << 2) | (b2 >> 4)) & 0xff;
+ result[1] = ((b2 << 4) | (b3 >> 2)) & 0xff;
+ result[2] = ((b3 << 6) | b4) & 0xff;
+ return 0;
+ }
+ }
+
+ Stream input;
+ bool start = true;
+ int[] outBuf = new int[3];
+ int bufPtr = 3;
+ Crc24 crc = new Crc24();
+ bool crcFound = false;
+ bool hasHeaders = true;
+ string header = null;
+ bool newLineFound = false;
+ bool clearText = false;
+ bool restart = false;
+ IList headerList= Platform.CreateArrayList();
+ int lastC = 0;
+ bool isEndOfStream;
+
+ /**
+ * Create a stream for reading a PGP armoured message, parsing up to a header
+ * and then reading the data that follows.
+ *
+ * @param input
+ */
+ public ArmoredInputStream(
+ Stream input)
+ : this(input, true)
+ {
+ }
+
+ /**
+ * Create an armoured input stream which will assume the data starts
+ * straight away, or parse for headers first depending on the value of
+ * hasHeaders.
+ *
+ * @param input
+ * @param hasHeaders true if headers are to be looked for, false otherwise.
+ */
+ public ArmoredInputStream(
+ Stream input,
+ bool hasHeaders)
+ {
+ this.input = input;
+ this.hasHeaders = hasHeaders;
+
+ if (hasHeaders)
+ {
+ ParseHeaders();
+ }
+
+ start = false;
+ }
+
+ private bool ParseHeaders()
+ {
+ header = null;
+
+ int c;
+ int last = 0;
+ bool headerFound = false;
+
+ headerList = Platform.CreateArrayList();
+
+ //
+ // if restart we already have a header
+ //
+ if (restart)
+ {
+ headerFound = true;
+ }
+ else
+ {
+ while ((c = input.ReadByte()) >= 0)
+ {
+ if (c == '-' && (last == 0 || last == '\n' || last == '\r'))
+ {
+ headerFound = true;
+ break;
+ }
+
+ last = c;
+ }
+ }
+
+ if (headerFound)
+ {
+ StringBuilder Buffer = new StringBuilder("-");
+ bool eolReached = false;
+ bool crLf = false;
+
+ if (restart) // we've had to look ahead two '-'
+ {
+ Buffer.Append('-');
+ }
+
+ while ((c = input.ReadByte()) >= 0)
+ {
+ if (last == '\r' && c == '\n')
+ {
+ crLf = true;
+ }
+ if (eolReached && (last != '\r' && c == '\n'))
+ {
+ break;
+ }
+ if (eolReached && c == '\r')
+ {
+ break;
+ }
+ if (c == '\r' || (last != '\r' && c == '\n'))
+ {
+ string line = Buffer.ToString();
+ if (line.Trim().Length < 1)
+ break;
+ headerList.Add(line);
+ Buffer.Length = 0;
+ }
+
+ if (c != '\n' && c != '\r')
+ {
+ Buffer.Append((char)c);
+ eolReached = false;
+ }
+ else
+ {
+ if (c == '\r' || (last != '\r' && c == '\n'))
+ {
+ eolReached = true;
+ }
+ }
+
+ last = c;
+ }
+
+ if (crLf)
+ {
+ input.ReadByte(); // skip last \n
+ }
+ }
+
+ if (headerList.Count > 0)
+ {
+ header = (string) headerList[0];
+ }
+
+ clearText = "-----BEGIN PGP SIGNED MESSAGE-----".Equals(header);
+ newLineFound = true;
+
+ return headerFound;
+ }
+
+ /**
+ * @return true if we are inside the clear text section of a PGP
+ * signed message.
+ */
+ public bool IsClearText()
+ {
+ return clearText;
+ }
+
+ /**
+ * @return true if the stream is actually at end of file.
+ */
+ public bool IsEndOfStream()
+ {
+ return isEndOfStream;
+ }
+
+ /**
+ * Return the armor header line (if there is one)
+ * @return the armor header line, null if none present.
+ */
+ public string GetArmorHeaderLine()
+ {
+ return header;
+ }
+
+ /**
+ * Return the armor headers (the lines after the armor header line),
+ * @return an array of armor headers, null if there aren't any.
+ */
+ public string[] GetArmorHeaders()
+ {
+ if (headerList.Count <= 1)
+ {
+ return null;
+ }
+
+ string[] hdrs = new string[headerList.Count - 1];
+ for (int i = 0; i != hdrs.Length; i++)
+ {
+ hdrs[i] = (string) headerList[i + 1];
+ }
+
+ return hdrs;
+ }
+
+ private int ReadIgnoreSpace()
+ {
+ int c;
+ do
+ {
+ c = input.ReadByte();
+ }
+ while (c == ' ' || c == '\t');
+
+ return c;
+ }
+
+ private int ReadIgnoreWhitespace()
+ {
+ int c;
+ do
+ {
+ c = input.ReadByte();
+ }
+ while (c == ' ' || c == '\t' || c == '\r' || c == '\n');
+
+ return c;
+ }
+
+ private int ReadByteClearText()
+ {
+ int c = input.ReadByte();
+
+ if (c == '\r' || (c == '\n' && lastC != '\r'))
+ {
+ newLineFound = true;
+ }
+ else if (newLineFound && c == '-')
+ {
+ c = input.ReadByte();
+ if (c == '-') // a header, not dash escaped
+ {
+ clearText = false;
+ start = true;
+ restart = true;
+ }
+ else // a space - must be a dash escape
+ {
+ c = input.ReadByte();
+ }
+ newLineFound = false;
+ }
+ else
+ {
+ if (c != '\n' && lastC != '\r')
+ {
+ newLineFound = false;
+ }
+ }
+
+ lastC = c;
+
+ if (c < 0)
+ {
+ isEndOfStream = true;
+ }
+
+ return c;
+ }
+
+ private int ReadClearText(byte[] buffer, int offset, int count)
+ {
+ int pos = offset;
+ try
+ {
+ int end = offset + count;
+ while (pos < end)
+ {
+ int c = ReadByteClearText();
+ if (c == -1)
+ {
+ break;
+ }
+ buffer[pos++] = (byte) c;
+ }
+ }
+ catch (IOException ioe)
+ {
+ if (pos == offset) throw ioe;
+ }
+
+ return pos - offset;
+ }
+
+ private int DoReadByte()
+ {
+ if (bufPtr > 2 || crcFound)
+ {
+ int c = ReadIgnoreSpace();
+ if (c == '\n' || c == '\r')
+ {
+ c = ReadIgnoreWhitespace();
+ if (c == '=') // crc reached
+ {
+ bufPtr = Decode(ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf);
+
+ if (bufPtr != 0)
+ {
+ throw new IOException("no crc found in armored message.");
+ }
+
+ crcFound = true;
+
+ int i = ((outBuf[0] & 0xff) << 16)
+ | ((outBuf[1] & 0xff) << 8)
+ | (outBuf[2] & 0xff);
+
+ if (i != crc.Value)
+ {
+ throw new IOException("crc check failed in armored message.");
+ }
+
+ return ReadByte();
+ }
+
+ if (c == '-') // end of record reached
+ {
+ while ((c = input.ReadByte()) >= 0)
+ {
+ if (c == '\n' || c == '\r')
+ {
+ break;
+ }
+ }
+
+ if (!crcFound)
+ {
+ throw new IOException("crc check not found.");
+ }
+
+ crcFound = false;
+ start = true;
+ bufPtr = 3;
+
+ if (c < 0)
+ {
+ isEndOfStream = true;
+ }
+
+ return -1;
+ }
+ }
+
+ if (c < 0)
+ {
+ isEndOfStream = true;
+ return -1;
+ }
+
+ bufPtr = Decode(c, ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf);
+ }
+
+ return outBuf[bufPtr++];
+ }
+
+ public override int ReadByte()
+ {
+ if (start)
+ {
+ if (hasHeaders)
+ {
+ ParseHeaders();
+ }
+
+ crc.Reset();
+ start = false;
+ }
+
+ if (clearText)
+ {
+ return ReadByteClearText();
+ }
+
+ int c = DoReadByte();
+
+ crc.Update(c);
+
+ return c;
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ if (start && count > 0)
+ {
+ if (hasHeaders)
+ {
+ ParseHeaders();
+ }
+ start = false;
+ }
+
+ if (clearText)
+ {
+ return ReadClearText(buffer, offset, count);
+ }
+
+ int pos = offset;
+ try
+ {
+ int end = offset + count;
+ while (pos < end)
+ {
+ int c = DoReadByte();
+ crc.Update(c);
+ if (c == -1)
+ {
+ break;
+ }
+ buffer[pos++] = (byte) c;
+ }
+ }
+ catch (IOException ioe)
+ {
+ if (pos == offset) throw ioe;
+ }
+
+ return pos - offset;
+ }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Platform.Dispose(input);
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ Platform.Dispose(input);
+ base.Close();
+ }
+#endif
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/ArmoredOutputStream.cs b/bc-sharp-crypto/src/bcpg/ArmoredOutputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7b39065d8e4f7bcf48403274b26f9b9b97a357a3
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/ArmoredOutputStream.cs
@@ -0,0 +1,375 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+using System.Text;
+
+#if PORTABLE
+using System.Linq;
+#endif
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /**
+ * Basic output stream.
+ */
+ public class ArmoredOutputStream
+ : BaseOutputStream
+ {
+ public static readonly string HeaderVersion = "Version";
+
+ private static readonly byte[] encodingTable =
+ {
+ (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
+ (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
+ (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
+ (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
+ (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
+ (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+ (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
+ (byte)'v',
+ (byte)'w', (byte)'x', (byte)'y', (byte)'z',
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6',
+ (byte)'7', (byte)'8', (byte)'9',
+ (byte)'+', (byte)'/'
+ };
+
+ /**
+ * encode the input data producing a base 64 encoded byte array.
+ */
+ private static void Encode(
+ Stream outStream,
+ int[] data,
+ int len)
+ {
+ Debug.Assert(len > 0);
+ Debug.Assert(len < 4);
+
+ byte[] bs = new byte[4];
+ int d1 = data[0];
+ bs[0] = encodingTable[(d1 >> 2) & 0x3f];
+
+ switch (len)
+ {
+ case 1:
+ {
+ bs[1] = encodingTable[(d1 << 4) & 0x3f];
+ bs[2] = (byte)'=';
+ bs[3] = (byte)'=';
+ break;
+ }
+ case 2:
+ {
+ int d2 = data[1];
+ bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
+ bs[2] = encodingTable[(d2 << 2) & 0x3f];
+ bs[3] = (byte)'=';
+ break;
+ }
+ case 3:
+ {
+ int d2 = data[1];
+ int d3 = data[2];
+ bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
+ bs[2] = encodingTable[((d2 << 2) | (d3 >> 6)) & 0x3f];
+ bs[3] = encodingTable[d3 & 0x3f];
+ break;
+ }
+ }
+
+ outStream.Write(bs, 0, bs.Length);
+ }
+
+ private readonly Stream outStream;
+ private int[] buf = new int[3];
+ private int bufPtr = 0;
+ private Crc24 crc = new Crc24();
+ private int chunkCount = 0;
+ private int lastb;
+
+ private bool start = true;
+ private bool clearText = false;
+ private bool newLine = false;
+
+ private string type;
+
+ private static readonly string nl = Platform.NewLine;
+ private static readonly string headerStart = "-----BEGIN PGP ";
+ private static readonly string headerTail = "-----";
+ private static readonly string footerStart = "-----END PGP ";
+ private static readonly string footerTail = "-----";
+
+ private static readonly string Version = "BCPG C# v1.8.1";//AssemblyInfo.Version;
+
+ private readonly IDictionary headers;
+
+ public ArmoredOutputStream(Stream outStream)
+ {
+ this.outStream = outStream;
+ this.headers = Platform.CreateHashtable(1);
+ this.headers.Add(HeaderVersion, Version);
+ }
+
+ public ArmoredOutputStream(Stream outStream, IDictionary headers)
+ {
+ this.outStream = outStream;
+ this.headers = Platform.CreateHashtable(headers);
+ if (!this.headers.Contains(HeaderVersion))
+ {
+ this.headers.Add(HeaderVersion, Version);
+ }
+ }
+
+ /**
+ * Set an additional header entry. A null value will clear the entry for name.
+ *
+ * @param name the name of the header entry.
+ * @param v the value of the header entry.
+ */
+ public void SetHeader(string name, string v)
+ {
+ if (v == null)
+ {
+ headers.Remove(name);
+ }
+ else
+ {
+ headers[name] = v;
+ }
+ }
+
+ /**
+ * Reset the headers to only contain a Version string (if one is present).
+ */
+ public void ResetHeaders()
+ {
+ string version = (string)headers[HeaderVersion];
+
+ headers.Clear();
+
+ if (version != null)
+ {
+ headers[HeaderVersion] = Version;
+ }
+ }
+
+ /**
+ * Start a clear text signed message.
+ * @param hashAlgorithm
+ */
+ public void BeginClearText(
+ HashAlgorithmTag hashAlgorithm)
+ {
+ string hash;
+
+ switch (hashAlgorithm)
+ {
+ case HashAlgorithmTag.Sha1:
+ hash = "SHA1";
+ break;
+ case HashAlgorithmTag.Sha256:
+ hash = "SHA256";
+ break;
+ case HashAlgorithmTag.Sha384:
+ hash = "SHA384";
+ break;
+ case HashAlgorithmTag.Sha512:
+ hash = "SHA512";
+ break;
+ case HashAlgorithmTag.MD2:
+ hash = "MD2";
+ break;
+ case HashAlgorithmTag.MD5:
+ hash = "MD5";
+ break;
+ case HashAlgorithmTag.RipeMD160:
+ hash = "RIPEMD160";
+ break;
+ default:
+ throw new IOException("unknown hash algorithm tag in beginClearText: " + hashAlgorithm);
+ }
+
+ DoWrite("-----BEGIN PGP SIGNED MESSAGE-----" + nl);
+ DoWrite("Hash: " + hash + nl + nl);
+
+ clearText = true;
+ newLine = true;
+ lastb = 0;
+ }
+
+ public void EndClearText()
+ {
+ clearText = false;
+ }
+
+ public override void WriteByte(
+ byte b)
+ {
+ if (clearText)
+ {
+ outStream.WriteByte(b);
+
+ if (newLine)
+ {
+ if (!(b == '\n' && lastb == '\r'))
+ {
+ newLine = false;
+ }
+ if (b == '-')
+ {
+ outStream.WriteByte((byte)' ');
+ outStream.WriteByte((byte)'-'); // dash escape
+ }
+ }
+ if (b == '\r' || (b == '\n' && lastb != '\r'))
+ {
+ newLine = true;
+ }
+ lastb = b;
+ return;
+ }
+
+ if (start)
+ {
+ bool newPacket = (b & 0x40) != 0;
+
+ int tag;
+ if (newPacket)
+ {
+ tag = b & 0x3f;
+ }
+ else
+ {
+ tag = (b & 0x3f) >> 2;
+ }
+
+ switch ((PacketTag)tag)
+ {
+ case PacketTag.PublicKey:
+ type = "PUBLIC KEY BLOCK";
+ break;
+ case PacketTag.SecretKey:
+ type = "PRIVATE KEY BLOCK";
+ break;
+ case PacketTag.Signature:
+ type = "SIGNATURE";
+ break;
+ default:
+ type = "MESSAGE";
+ break;
+ }
+
+ DoWrite(headerStart + type + headerTail + nl);
+ if (headers.Contains(HeaderVersion))
+ {
+ WriteHeaderEntry(HeaderVersion, (string)headers[HeaderVersion]);
+ }
+
+ foreach (DictionaryEntry de in headers)
+ {
+ string k = (string)de.Key;
+ if (k != HeaderVersion)
+ {
+ string v = (string)de.Value;
+ WriteHeaderEntry(k, v);
+ }
+ }
+
+ DoWrite(nl);
+
+ start = false;
+ }
+
+ if (bufPtr == 3)
+ {
+ Encode(outStream, buf, bufPtr);
+ bufPtr = 0;
+ if ((++chunkCount & 0xf) == 0)
+ {
+ DoWrite(nl);
+ }
+ }
+
+ crc.Update(b);
+ buf[bufPtr++] = b & 0xff;
+ }
+
+ /**
+ * Note : Close() does not close the underlying stream. So it is possible to write
+ * multiple objects using armoring to a single stream.
+ */
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (type == null)
+ return;
+
+ DoClose();
+
+ type = null;
+ start = true;
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ if (type == null)
+ return;
+
+ DoClose();
+
+ type = null;
+ start = true;
+
+ base.Close();
+ }
+#endif
+
+ private void DoClose()
+ {
+ if (bufPtr > 0)
+ {
+ Encode(outStream, buf, bufPtr);
+ }
+
+ DoWrite(nl + '=');
+
+ int crcV = crc.Value;
+
+ buf[0] = ((crcV >> 16) & 0xff);
+ buf[1] = ((crcV >> 8) & 0xff);
+ buf[2] = (crcV & 0xff);
+
+ Encode(outStream, buf, 3);
+
+ DoWrite(nl);
+ DoWrite(footerStart);
+ DoWrite(type);
+ DoWrite(footerTail);
+ DoWrite(nl);
+
+ outStream.Flush();
+ }
+
+ private void WriteHeaderEntry(
+ string name,
+ string v)
+ {
+ DoWrite(name + ": " + v + nl);
+ }
+
+ private void DoWrite(
+ string s)
+ {
+ byte[] bs = Strings.ToAsciiByteArray(s);
+ outStream.Write(bs, 0, bs.Length);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/BcpgInputStream.cs b/bc-sharp-crypto/src/bcpg/BcpgInputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f9627fde058112af10159557c91045693b123624
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/BcpgInputStream.cs
@@ -0,0 +1,363 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Reader for PGP objects.
+ public class BcpgInputStream
+ : BaseInputStream
+ {
+ private Stream m_in;
+ private bool next = false;
+ private int nextB;
+
+ internal static BcpgInputStream Wrap(
+ Stream inStr)
+ {
+ if (inStr is BcpgInputStream)
+ {
+ return (BcpgInputStream) inStr;
+ }
+
+ return new BcpgInputStream(inStr);
+ }
+
+ private BcpgInputStream(
+ Stream inputStream)
+ {
+ this.m_in = inputStream;
+ }
+
+ public override int ReadByte()
+ {
+ if (next)
+ {
+ next = false;
+ return nextB;
+ }
+
+ return m_in.ReadByte();
+ }
+
+ public override int Read(
+ byte[] buffer,
+ int offset,
+ int count)
+ {
+ // Strangely, when count == 0, we should still attempt to read a byte
+// if (count == 0)
+// return 0;
+
+ if (!next)
+ return m_in.Read(buffer, offset, count);
+
+ // We have next byte waiting, so return it
+
+ if (nextB < 0)
+ return 0; // EndOfStream
+
+ if (buffer == null)
+ throw new ArgumentNullException("buffer");
+
+ buffer[offset] = (byte) nextB;
+ next = false;
+
+ return 1;
+ }
+
+ public byte[] ReadAll()
+ {
+ return Streams.ReadAll(this);
+ }
+
+ public void ReadFully(
+ byte[] buffer,
+ int off,
+ int len)
+ {
+ if (Streams.ReadFully(this, buffer, off, len) < len)
+ throw new EndOfStreamException();
+ }
+
+ public void ReadFully(
+ byte[] buffer)
+ {
+ ReadFully(buffer, 0, buffer.Length);
+ }
+
+ /// Returns the next packet tag in the stream.
+ public PacketTag NextPacketTag()
+ {
+ if (!next)
+ {
+ try
+ {
+ nextB = m_in.ReadByte();
+ }
+ catch (EndOfStreamException)
+ {
+ nextB = -1;
+ }
+
+ next = true;
+ }
+
+ if (nextB < 0)
+ return (PacketTag)nextB;
+
+ int maskB = nextB & 0x3f;
+ if ((nextB & 0x40) == 0) // old
+ {
+ maskB >>= 2;
+ }
+ return (PacketTag)maskB;
+ }
+
+ public Packet ReadPacket()
+ {
+ int hdr = this.ReadByte();
+
+ if (hdr < 0)
+ {
+ return null;
+ }
+
+ if ((hdr & 0x80) == 0)
+ {
+ throw new IOException("invalid header encountered");
+ }
+
+ bool newPacket = (hdr & 0x40) != 0;
+ PacketTag tag = 0;
+ int bodyLen = 0;
+ bool partial = false;
+
+ if (newPacket)
+ {
+ tag = (PacketTag)(hdr & 0x3f);
+
+ int l = this.ReadByte();
+
+ if (l < 192)
+ {
+ bodyLen = l;
+ }
+ else if (l <= 223)
+ {
+ int b = m_in.ReadByte();
+ bodyLen = ((l - 192) << 8) + (b) + 192;
+ }
+ else if (l == 255)
+ {
+ bodyLen = (m_in.ReadByte() << 24) | (m_in.ReadByte() << 16)
+ | (m_in.ReadByte() << 8) | m_in.ReadByte();
+ }
+ else
+ {
+ partial = true;
+ bodyLen = 1 << (l & 0x1f);
+ }
+ }
+ else
+ {
+ int lengthType = hdr & 0x3;
+
+ tag = (PacketTag)((hdr & 0x3f) >> 2);
+
+ switch (lengthType)
+ {
+ case 0:
+ bodyLen = this.ReadByte();
+ break;
+ case 1:
+ bodyLen = (this.ReadByte() << 8) | this.ReadByte();
+ break;
+ case 2:
+ bodyLen = (this.ReadByte() << 24) | (this.ReadByte() << 16)
+ | (this.ReadByte() << 8) | this.ReadByte();
+ break;
+ case 3:
+ partial = true;
+ break;
+ default:
+ throw new IOException("unknown length type encountered");
+ }
+ }
+
+ BcpgInputStream objStream;
+ if (bodyLen == 0 && partial)
+ {
+ objStream = this;
+ }
+ else
+ {
+ PartialInputStream pis = new PartialInputStream(this, partial, bodyLen);
+ objStream = new BcpgInputStream(pis);
+ }
+
+ switch (tag)
+ {
+ case PacketTag.Reserved:
+ return new InputStreamPacket(objStream);
+ case PacketTag.PublicKeyEncryptedSession:
+ return new PublicKeyEncSessionPacket(objStream);
+ case PacketTag.Signature:
+ return new SignaturePacket(objStream);
+ case PacketTag.SymmetricKeyEncryptedSessionKey:
+ return new SymmetricKeyEncSessionPacket(objStream);
+ case PacketTag.OnePassSignature:
+ return new OnePassSignaturePacket(objStream);
+ case PacketTag.SecretKey:
+ return new SecretKeyPacket(objStream);
+ case PacketTag.PublicKey:
+ return new PublicKeyPacket(objStream);
+ case PacketTag.SecretSubkey:
+ return new SecretSubkeyPacket(objStream);
+ case PacketTag.CompressedData:
+ return new CompressedDataPacket(objStream);
+ case PacketTag.SymmetricKeyEncrypted:
+ return new SymmetricEncDataPacket(objStream);
+ case PacketTag.Marker:
+ return new MarkerPacket(objStream);
+ case PacketTag.LiteralData:
+ return new LiteralDataPacket(objStream);
+ case PacketTag.Trust:
+ return new TrustPacket(objStream);
+ case PacketTag.UserId:
+ return new UserIdPacket(objStream);
+ case PacketTag.UserAttribute:
+ return new UserAttributePacket(objStream);
+ case PacketTag.PublicSubkey:
+ return new PublicSubkeyPacket(objStream);
+ case PacketTag.SymmetricEncryptedIntegrityProtected:
+ return new SymmetricEncIntegrityPacket(objStream);
+ case PacketTag.ModificationDetectionCode:
+ return new ModDetectionCodePacket(objStream);
+ case PacketTag.Experimental1:
+ case PacketTag.Experimental2:
+ case PacketTag.Experimental3:
+ case PacketTag.Experimental4:
+ return new ExperimentalPacket(tag, objStream);
+ default:
+ throw new IOException("unknown packet type encountered: " + tag);
+ }
+ }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Platform.Dispose(m_in);
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ Platform.Dispose(m_in);
+ base.Close();
+ }
+#endif
+
+ ///
+ /// A stream that overlays our input stream, allowing the user to only read a segment of it.
+ /// NB: dataLength will be negative if the segment length is in the upper range above 2**31.
+ ///
+ private class PartialInputStream
+ : BaseInputStream
+ {
+ private BcpgInputStream m_in;
+ private bool partial;
+ private int dataLength;
+
+ internal PartialInputStream(
+ BcpgInputStream bcpgIn,
+ bool partial,
+ int dataLength)
+ {
+ this.m_in = bcpgIn;
+ this.partial = partial;
+ this.dataLength = dataLength;
+ }
+
+ public override int ReadByte()
+ {
+ do
+ {
+ if (dataLength != 0)
+ {
+ int ch = m_in.ReadByte();
+ if (ch < 0)
+ {
+ throw new EndOfStreamException("Premature end of stream in PartialInputStream");
+ }
+ dataLength--;
+ return ch;
+ }
+ }
+ while (partial && ReadPartialDataLength() >= 0);
+
+ return -1;
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ do
+ {
+ if (dataLength != 0)
+ {
+ int readLen = (dataLength > count || dataLength < 0) ? count : dataLength;
+ int len = m_in.Read(buffer, offset, readLen);
+ if (len < 1)
+ {
+ throw new EndOfStreamException("Premature end of stream in PartialInputStream");
+ }
+ dataLength -= len;
+ return len;
+ }
+ }
+ while (partial && ReadPartialDataLength() >= 0);
+
+ return 0;
+ }
+
+ private int ReadPartialDataLength()
+ {
+ int l = m_in.ReadByte();
+
+ if (l < 0)
+ {
+ return -1;
+ }
+
+ partial = false;
+
+ if (l < 192)
+ {
+ dataLength = l;
+ }
+ else if (l <= 223)
+ {
+ dataLength = ((l - 192) << 8) + (m_in.ReadByte()) + 192;
+ }
+ else if (l == 255)
+ {
+ dataLength = (m_in.ReadByte() << 24) | (m_in.ReadByte() << 16)
+ | (m_in.ReadByte() << 8) | m_in.ReadByte();
+ }
+ else
+ {
+ partial = true;
+ dataLength = 1 << (l & 0x1f);
+ }
+
+ return 0;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/BcpgObject.cs b/bc-sharp-crypto/src/bcpg/BcpgObject.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4807ad46e818232360eba049c7a4e51a5ea019b0
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/BcpgObject.cs
@@ -0,0 +1,22 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Base class for a PGP object.
+ public abstract class BcpgObject
+ {
+ public virtual byte[] GetEncoded()
+ {
+ MemoryStream bOut = new MemoryStream();
+ BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+ pOut.WriteObject(this);
+
+ return bOut.ToArray();
+ }
+
+ public abstract void Encode(BcpgOutputStream bcpgOut);
+ }
+}
+
diff --git a/bc-sharp-crypto/src/bcpg/BcpgOutputStream.cs b/bc-sharp-crypto/src/bcpg/BcpgOutputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7ab661edb023a6b82eddb9c85254edb08d2f2918
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/BcpgOutputStream.cs
@@ -0,0 +1,404 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Basic output stream.
+ public class BcpgOutputStream
+ : BaseOutputStream
+ {
+ internal static BcpgOutputStream Wrap(
+ Stream outStr)
+ {
+ if (outStr is BcpgOutputStream)
+ {
+ return (BcpgOutputStream) outStr;
+ }
+
+ return new BcpgOutputStream(outStr);
+ }
+
+ private Stream outStr;
+ private byte[] partialBuffer;
+ private int partialBufferLength;
+ private int partialPower;
+ private int partialOffset;
+ private const int BufferSizePower = 16; // 2^16 size buffer on long files
+
+ /// Create a stream representing a general packet.
+ /// Output stream to write to.
+ public BcpgOutputStream(
+ Stream outStr)
+ {
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
+
+ this.outStr = outStr;
+ }
+
+ /// Create a stream representing an old style partial object.
+ /// Output stream to write to.
+ /// The packet tag for the object.
+ public BcpgOutputStream(
+ Stream outStr,
+ PacketTag tag)
+ {
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
+
+ this.outStr = outStr;
+ this.WriteHeader(tag, true, true, 0);
+ }
+
+ /// Create a stream representing a general packet.
+ /// Output stream to write to.
+ /// Packet tag.
+ /// Size of chunks making up the packet.
+ /// If true, the header is written out in old format.
+ public BcpgOutputStream(
+ Stream outStr,
+ PacketTag tag,
+ long length,
+ bool oldFormat)
+ {
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
+
+ this.outStr = outStr;
+
+ if (length > 0xFFFFFFFFL)
+ {
+ this.WriteHeader(tag, false, true, 0);
+ this.partialBufferLength = 1 << BufferSizePower;
+ this.partialBuffer = new byte[partialBufferLength];
+ this.partialPower = BufferSizePower;
+ this.partialOffset = 0;
+ }
+ else
+ {
+ this.WriteHeader(tag, oldFormat, false, length);
+ }
+ }
+
+ /// Create a new style partial input stream buffered into chunks.
+ /// Output stream to write to.
+ /// Packet tag.
+ /// Size of chunks making up the packet.
+ public BcpgOutputStream(
+ Stream outStr,
+ PacketTag tag,
+ long length)
+ {
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
+
+ this.outStr = outStr;
+ this.WriteHeader(tag, false, false, length);
+ }
+
+ /// Create a new style partial input stream buffered into chunks.
+ /// Output stream to write to.
+ /// Packet tag.
+ /// Buffer to use for collecting chunks.
+ public BcpgOutputStream(
+ Stream outStr,
+ PacketTag tag,
+ byte[] buffer)
+ {
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
+
+ this.outStr = outStr;
+ this.WriteHeader(tag, false, true, 0);
+
+ this.partialBuffer = buffer;
+
+ uint length = (uint) partialBuffer.Length;
+ for (partialPower = 0; length != 1; partialPower++)
+ {
+ length >>= 1;
+ }
+
+ if (partialPower > 30)
+ {
+ throw new IOException("Buffer cannot be greater than 2^30 in length.");
+ }
+ this.partialBufferLength = 1 << partialPower;
+ this.partialOffset = 0;
+ }
+
+ private void WriteNewPacketLength(
+ long bodyLen)
+ {
+ if (bodyLen < 192)
+ {
+ outStr.WriteByte((byte)bodyLen);
+ }
+ else if (bodyLen <= 8383)
+ {
+ bodyLen -= 192;
+
+ outStr.WriteByte((byte)(((bodyLen >> 8) & 0xff) + 192));
+ outStr.WriteByte((byte)bodyLen);
+ }
+ else
+ {
+ outStr.WriteByte(0xff);
+ outStr.WriteByte((byte)(bodyLen >> 24));
+ outStr.WriteByte((byte)(bodyLen >> 16));
+ outStr.WriteByte((byte)(bodyLen >> 8));
+ outStr.WriteByte((byte)bodyLen);
+ }
+ }
+
+ private void WriteHeader(
+ PacketTag tag,
+ bool oldPackets,
+ bool partial,
+ long bodyLen)
+ {
+ int hdr = 0x80;
+
+ if (partialBuffer != null)
+ {
+ PartialFlush(true);
+ partialBuffer = null;
+ }
+
+ if (oldPackets)
+ {
+ hdr |= ((int) tag) << 2;
+
+ if (partial)
+ {
+ this.WriteByte((byte)(hdr | 0x03));
+ }
+ else
+ {
+ if (bodyLen <= 0xff)
+ {
+ this.WriteByte((byte) hdr);
+ this.WriteByte((byte)bodyLen);
+ }
+ else if (bodyLen <= 0xffff)
+ {
+ this.WriteByte((byte)(hdr | 0x01));
+ this.WriteByte((byte)(bodyLen >> 8));
+ this.WriteByte((byte)(bodyLen));
+ }
+ else
+ {
+ this.WriteByte((byte)(hdr | 0x02));
+ this.WriteByte((byte)(bodyLen >> 24));
+ this.WriteByte((byte)(bodyLen >> 16));
+ this.WriteByte((byte)(bodyLen >> 8));
+ this.WriteByte((byte)bodyLen);
+ }
+ }
+ }
+ else
+ {
+ hdr |= 0x40 | (int) tag;
+ this.WriteByte((byte) hdr);
+
+ if (partial)
+ {
+ partialOffset = 0;
+ }
+ else
+ {
+ this.WriteNewPacketLength(bodyLen);
+ }
+ }
+ }
+
+ private void PartialFlush(
+ bool isLast)
+ {
+ if (isLast)
+ {
+ WriteNewPacketLength(partialOffset);
+ outStr.Write(partialBuffer, 0, partialOffset);
+ }
+ else
+ {
+ outStr.WriteByte((byte)(0xE0 | partialPower));
+ outStr.Write(partialBuffer, 0, partialBufferLength);
+ }
+
+ partialOffset = 0;
+ }
+
+ private void WritePartial(
+ byte b)
+ {
+ if (partialOffset == partialBufferLength)
+ {
+ PartialFlush(false);
+ }
+
+ partialBuffer[partialOffset++] = b;
+ }
+
+ private void WritePartial(
+ byte[] buffer,
+ int off,
+ int len)
+ {
+ if (partialOffset == partialBufferLength)
+ {
+ PartialFlush(false);
+ }
+
+ if (len <= (partialBufferLength - partialOffset))
+ {
+ Array.Copy(buffer, off, partialBuffer, partialOffset, len);
+ partialOffset += len;
+ }
+ else
+ {
+ int diff = partialBufferLength - partialOffset;
+ Array.Copy(buffer, off, partialBuffer, partialOffset, diff);
+ off += diff;
+ len -= diff;
+ PartialFlush(false);
+ while (len > partialBufferLength)
+ {
+ Array.Copy(buffer, off, partialBuffer, 0, partialBufferLength);
+ off += partialBufferLength;
+ len -= partialBufferLength;
+ PartialFlush(false);
+ }
+ Array.Copy(buffer, off, partialBuffer, 0, len);
+ partialOffset += len;
+ }
+ }
+ public override void WriteByte(
+ byte value)
+ {
+ if (partialBuffer != null)
+ {
+ WritePartial(value);
+ }
+ else
+ {
+ outStr.WriteByte(value);
+ }
+ }
+ public override void Write(
+ byte[] buffer,
+ int offset,
+ int count)
+ {
+ if (partialBuffer != null)
+ {
+ WritePartial(buffer, offset, count);
+ }
+ else
+ {
+ outStr.Write(buffer, offset, count);
+ }
+ }
+
+ // Additional helper methods to write primitive types
+ internal virtual void WriteShort(
+ short n)
+ {
+ this.Write(
+ (byte)(n >> 8),
+ (byte)n);
+ }
+ internal virtual void WriteInt(
+ int n)
+ {
+ this.Write(
+ (byte)(n >> 24),
+ (byte)(n >> 16),
+ (byte)(n >> 8),
+ (byte)n);
+ }
+ internal virtual void WriteLong(
+ long n)
+ {
+ this.Write(
+ (byte)(n >> 56),
+ (byte)(n >> 48),
+ (byte)(n >> 40),
+ (byte)(n >> 32),
+ (byte)(n >> 24),
+ (byte)(n >> 16),
+ (byte)(n >> 8),
+ (byte)n);
+ }
+
+ public void WritePacket(
+ ContainedPacket p)
+ {
+ p.Encode(this);
+ }
+
+ internal void WritePacket(
+ PacketTag tag,
+ byte[] body,
+ bool oldFormat)
+ {
+ this.WriteHeader(tag, oldFormat, false, body.Length);
+ this.Write(body);
+ }
+
+ public void WriteObject(
+ BcpgObject bcpgObject)
+ {
+ bcpgObject.Encode(this);
+ }
+
+ public void WriteObjects(
+ params BcpgObject[] v)
+ {
+ foreach (BcpgObject o in v)
+ {
+ o.Encode(this);
+ }
+ }
+
+ /// Flush the underlying stream.
+ public override void Flush()
+ {
+ outStr.Flush();
+ }
+
+ /// Finish writing out the current packet without closing the underlying stream.
+ public void Finish()
+ {
+ if (partialBuffer != null)
+ {
+ PartialFlush(true);
+ partialBuffer = null;
+ }
+ }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ this.Finish();
+ outStr.Flush();
+ Platform.Dispose(outStr);
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ this.Finish();
+ outStr.Flush();
+ Platform.Dispose(outStr);
+ base.Close();
+ }
+#endif
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/CompressedDataPacket.cs b/bc-sharp-crypto/src/bcpg/CompressedDataPacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2432825ebac67fc2e9cea42d310a5a5a3bcbe432
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/CompressedDataPacket.cs
@@ -0,0 +1,24 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Generic compressed data object.
+ public class CompressedDataPacket
+ : InputStreamPacket
+ {
+ private readonly CompressionAlgorithmTag algorithm;
+
+ internal CompressedDataPacket(
+ BcpgInputStream bcpgIn)
+ : base(bcpgIn)
+ {
+ this.algorithm = (CompressionAlgorithmTag) bcpgIn.ReadByte();
+ }
+
+ /// The algorithm tag value.
+ public CompressionAlgorithmTag Algorithm
+ {
+ get { return algorithm; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/CompressionAlgorithmTags.cs b/bc-sharp-crypto/src/bcpg/CompressionAlgorithmTags.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0e452298e175521788092817364489177a5ae3bd
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/CompressionAlgorithmTags.cs
@@ -0,0 +1,11 @@
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Basic tags for compression algorithms.
+ public enum CompressionAlgorithmTag
+ {
+ Uncompressed = 0, // Uncompressed
+ Zip = 1, // ZIP (RFC 1951)
+ ZLib = 2, // ZLIB (RFC 1950)
+ BZip2 = 3, // BZ2
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/ContainedPacket.cs b/bc-sharp-crypto/src/bcpg/ContainedPacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e8f387ca45cb4af13934d623a66ce513fe6cdd9e
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/ContainedPacket.cs
@@ -0,0 +1,22 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Basic type for a PGP packet.
+ public abstract class ContainedPacket
+ : Packet
+ {
+ public byte[] GetEncoded()
+ {
+ MemoryStream bOut = new MemoryStream();
+ BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+ pOut.WritePacket(this);
+
+ return bOut.ToArray();
+ }
+
+ public abstract void Encode(BcpgOutputStream bcpgOut);
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/Crc24.cs b/bc-sharp-crypto/src/bcpg/Crc24.cs
new file mode 100644
index 0000000000000000000000000000000000000000..97846f4fb574f6a5368298f7c16d57e9ce28d44d
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/Crc24.cs
@@ -0,0 +1,46 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ public class Crc24
+ {
+ private const int Crc24Init = 0x0b704ce;
+ private const int Crc24Poly = 0x1864cfb;
+
+ private int crc = Crc24Init;
+
+ public Crc24()
+ {
+ }
+
+ public void Update(
+ int b)
+ {
+ crc ^= b << 16;
+ for (int i = 0; i < 8; i++)
+ {
+ crc <<= 1;
+ if ((crc & 0x1000000) != 0)
+ {
+ crc ^= Crc24Poly;
+ }
+ }
+ }
+
+ [Obsolete("Use 'Value' property instead")]
+ public int GetValue()
+ {
+ return crc;
+ }
+
+ public int Value
+ {
+ get { return crc; }
+ }
+
+ public void Reset()
+ {
+ crc = Crc24Init;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/DsaPublicBcpgKey.cs b/bc-sharp-crypto/src/bcpg/DsaPublicBcpgKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..11294cc227f82471b4862b77177b49d68c4f81a6
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/DsaPublicBcpgKey.cs
@@ -0,0 +1,80 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Base class for a DSA public key.
+ public class DsaPublicBcpgKey
+ : BcpgObject, IBcpgKey
+ {
+ private readonly MPInteger p, q, g, y;
+
+ /// The stream to read the packet from.
+ public DsaPublicBcpgKey(
+ BcpgInputStream bcpgIn)
+ {
+ this.p = new MPInteger(bcpgIn);
+ this.q = new MPInteger(bcpgIn);
+ this.g = new MPInteger(bcpgIn);
+ this.y = new MPInteger(bcpgIn);
+ }
+
+ public DsaPublicBcpgKey(
+ BigInteger p,
+ BigInteger q,
+ BigInteger g,
+ BigInteger y)
+ {
+ this.p = new MPInteger(p);
+ this.q = new MPInteger(q);
+ this.g = new MPInteger(g);
+ this.y = new MPInteger(y);
+ }
+
+ /// The format, as a string, always "PGP".
+ public string Format
+ {
+ get { return "PGP"; }
+ }
+
+ /// Return the standard PGP encoding of the key.
+ public override byte[] GetEncoded()
+ {
+ try
+ {
+ return base.GetEncoded();
+ }
+ catch (Exception)
+ {
+ return null;
+ }
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WriteObjects(p, q, g, y);
+ }
+
+ public BigInteger G
+ {
+ get { return g.Value; }
+ }
+
+ public BigInteger P
+ {
+ get { return p.Value; }
+ }
+
+ public BigInteger Q
+ {
+ get { return q.Value; }
+ }
+
+ public BigInteger Y
+ {
+ get { return y.Value; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/DsaSecretBcpgKey.cs b/bc-sharp-crypto/src/bcpg/DsaSecretBcpgKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..41835d41980a68648e24dc94f5aacee87cbc695e
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/DsaSecretBcpgKey.cs
@@ -0,0 +1,61 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Base class for a DSA secret key.
+ public class DsaSecretBcpgKey
+ : BcpgObject, IBcpgKey
+ {
+ internal MPInteger x;
+
+ /**
+ * @param in
+ */
+ public DsaSecretBcpgKey(
+ BcpgInputStream bcpgIn)
+ {
+ this.x = new MPInteger(bcpgIn);
+ }
+
+ public DsaSecretBcpgKey(
+ BigInteger x)
+ {
+ this.x = new MPInteger(x);
+ }
+
+ /// The format, as a string, always "PGP".
+ public string Format
+ {
+ get { return "PGP"; }
+ }
+
+ /// Return the standard PGP encoding of the key.
+ public override byte[] GetEncoded()
+ {
+ try
+ {
+ return base.GetEncoded();
+ }
+ catch (Exception)
+ {
+ return null;
+ }
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WriteObject(x);
+ }
+
+ /**
+ * @return x
+ */
+ public BigInteger X
+ {
+ get { return x.Value; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/ECDHPublicBCPGKey.cs b/bc-sharp-crypto/src/bcpg/ECDHPublicBCPGKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..dc225e31e185f0325c1b01529913342c84dc1b6e
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/ECDHPublicBCPGKey.cs
@@ -0,0 +1,102 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Base class for an ECDH Public Key.
+ public class ECDHPublicBcpgKey
+ : ECPublicBcpgKey
+ {
+ private byte reserved;
+ private HashAlgorithmTag hashFunctionId;
+ private SymmetricKeyAlgorithmTag symAlgorithmId;
+
+ /// The stream to read the packet from.
+ public ECDHPublicBcpgKey(
+ BcpgInputStream bcpgIn)
+ : base(bcpgIn)
+ {
+ int length = bcpgIn.ReadByte();
+ byte[] kdfParameters = new byte[length];
+ if (kdfParameters.Length != 3)
+ throw new InvalidOperationException("kdf parameters size of 3 expected.");
+
+ bcpgIn.ReadFully(kdfParameters);
+
+ reserved = kdfParameters[0];
+ hashFunctionId = (HashAlgorithmTag)kdfParameters[1];
+ symAlgorithmId = (SymmetricKeyAlgorithmTag)kdfParameters[2];
+
+ VerifyHashAlgorithm();
+ VerifySymmetricKeyAlgorithm();
+ }
+
+ public ECDHPublicBcpgKey(
+ DerObjectIdentifier oid,
+ ECPoint point,
+ HashAlgorithmTag hashAlgorithm,
+ SymmetricKeyAlgorithmTag symmetricKeyAlgorithm)
+ : base(oid, point)
+ {
+ reserved = 1;
+ hashFunctionId = hashAlgorithm;
+ symAlgorithmId = symmetricKeyAlgorithm;
+
+ VerifyHashAlgorithm();
+ VerifySymmetricKeyAlgorithm();
+ }
+
+ public virtual byte Reserved
+ {
+ get { return reserved; }
+ }
+
+ public virtual HashAlgorithmTag HashAlgorithm
+ {
+ get { return hashFunctionId; }
+ }
+
+ public virtual SymmetricKeyAlgorithmTag SymmetricKeyAlgorithm
+ {
+ get { return symAlgorithmId; }
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ base.Encode(bcpgOut);
+ bcpgOut.WriteByte(0x3);
+ bcpgOut.WriteByte(reserved);
+ bcpgOut.WriteByte((byte)hashFunctionId);
+ bcpgOut.WriteByte((byte)symAlgorithmId);
+ }
+
+ private void VerifyHashAlgorithm()
+ {
+ switch ((HashAlgorithmTag)hashFunctionId)
+ {
+ case HashAlgorithmTag.Sha256:
+ case HashAlgorithmTag.Sha384:
+ case HashAlgorithmTag.Sha512:
+ break;
+ default:
+ throw new InvalidOperationException("Hash algorithm must be SHA-256 or stronger.");
+ }
+ }
+
+ private void VerifySymmetricKeyAlgorithm()
+ {
+ switch ((SymmetricKeyAlgorithmTag)symAlgorithmId)
+ {
+ case SymmetricKeyAlgorithmTag.Aes128:
+ case SymmetricKeyAlgorithmTag.Aes192:
+ case SymmetricKeyAlgorithmTag.Aes256:
+ break;
+ default:
+ throw new InvalidOperationException("Symmetric key algorithm must be AES-128 or stronger.");
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/ECDsaPublicBCPGKey.cs b/bc-sharp-crypto/src/bcpg/ECDsaPublicBCPGKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5f0c8ac55a558c9e0efc583a82ba87524b273d3c
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/ECDsaPublicBCPGKey.cs
@@ -0,0 +1,34 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Base class for an ECDSA Public Key.
+ public class ECDsaPublicBcpgKey
+ : ECPublicBcpgKey
+ {
+ /// The stream to read the packet from.
+ protected internal ECDsaPublicBcpgKey(
+ BcpgInputStream bcpgIn)
+ : base(bcpgIn)
+ {
+ }
+
+ public ECDsaPublicBcpgKey(
+ DerObjectIdentifier oid,
+ ECPoint point)
+ : base(oid, point)
+ {
+ }
+
+ public ECDsaPublicBcpgKey(
+ DerObjectIdentifier oid,
+ BigInteger encodedPoint)
+ : base(oid, encodedPoint)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/ECPublicBCPGKey.cs b/bc-sharp-crypto/src/bcpg/ECPublicBCPGKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f328f9dc3f8d46b7d7268017a4c97ef890914ae4
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/ECPublicBCPGKey.cs
@@ -0,0 +1,97 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Base class for an EC Public Key.
+ public abstract class ECPublicBcpgKey
+ : BcpgObject, IBcpgKey
+ {
+ internal DerObjectIdentifier oid;
+ internal BigInteger point;
+
+ /// The stream to read the packet from.
+ protected ECPublicBcpgKey(
+ BcpgInputStream bcpgIn)
+ {
+ this.oid = DerObjectIdentifier.GetInstance(Asn1Object.FromByteArray(ReadBytesOfEncodedLength(bcpgIn)));
+ this.point = new MPInteger(bcpgIn).Value;
+ }
+
+ protected ECPublicBcpgKey(
+ DerObjectIdentifier oid,
+ ECPoint point)
+ {
+ this.point = new BigInteger(1, point.GetEncoded());
+ this.oid = oid;
+ }
+
+ protected ECPublicBcpgKey(
+ DerObjectIdentifier oid,
+ BigInteger encodedPoint)
+ {
+ this.point = encodedPoint;
+ this.oid = oid;
+ }
+
+ /// The format, as a string, always "PGP".
+ public string Format
+ {
+ get { return "PGP"; }
+ }
+
+ /// Return the standard PGP encoding of the key.
+ public override byte[] GetEncoded()
+ {
+ try
+ {
+ return base.GetEncoded();
+ }
+ catch (IOException)
+ {
+ return null;
+ }
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ byte[] oid = this.oid.GetEncoded();
+ bcpgOut.Write(oid, 1, oid.Length - 1);
+
+ MPInteger point = new MPInteger(this.point);
+ bcpgOut.WriteObject(point);
+ }
+
+ public virtual BigInteger EncodedPoint
+ {
+ get { return point; }
+ }
+
+ public virtual DerObjectIdentifier CurveOid
+ {
+ get { return oid; }
+ }
+
+ protected static byte[] ReadBytesOfEncodedLength(
+ BcpgInputStream bcpgIn)
+ {
+ int length = bcpgIn.ReadByte();
+ if (length == 0 || length == 0xFF)
+ {
+ throw new IOException("future extensions not yet implemented.");
+ }
+
+ byte[] buffer = new byte[length + 2];
+ bcpgIn.ReadFully(buffer, 2, buffer.Length - 2);
+ buffer[0] = (byte)0x06;
+ buffer[1] = (byte)length;
+
+ return buffer;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/ECSecretBCPGKey.cs b/bc-sharp-crypto/src/bcpg/ECSecretBCPGKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..22e0a3473877921e870ab54ed02a759bb05c9f7c
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/ECSecretBCPGKey.cs
@@ -0,0 +1,56 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Base class for an EC Secret Key.
+ public class ECSecretBcpgKey
+ : BcpgObject, IBcpgKey
+ {
+ internal MPInteger x;
+
+ public ECSecretBcpgKey(
+ BcpgInputStream bcpgIn)
+ {
+ this.x = new MPInteger(bcpgIn);
+ }
+
+ public ECSecretBcpgKey(
+ BigInteger x)
+ {
+ this.x = new MPInteger(x);
+ }
+
+ /// The format, as a string, always "PGP".
+ public string Format
+ {
+ get { return "PGP"; }
+ }
+
+ /// Return the standard PGP encoding of the key.
+ public override byte[] GetEncoded()
+ {
+ try
+ {
+ return base.GetEncoded();
+ }
+ catch (Exception)
+ {
+ return null;
+ }
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WriteObject(x);
+ }
+
+ public virtual BigInteger X
+ {
+ get { return x.Value; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/ElGamalPublicBcpgKey.cs b/bc-sharp-crypto/src/bcpg/ElGamalPublicBcpgKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..808e427b2ac5467e52e26ae424f4811e2a8f0c3b
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/ElGamalPublicBcpgKey.cs
@@ -0,0 +1,71 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Base class for an ElGamal public key.
+ public class ElGamalPublicBcpgKey
+ : BcpgObject, IBcpgKey
+ {
+ internal MPInteger p, g, y;
+
+ public ElGamalPublicBcpgKey(
+ BcpgInputStream bcpgIn)
+ {
+ this.p = new MPInteger(bcpgIn);
+ this.g = new MPInteger(bcpgIn);
+ this.y = new MPInteger(bcpgIn);
+ }
+
+ public ElGamalPublicBcpgKey(
+ BigInteger p,
+ BigInteger g,
+ BigInteger y)
+ {
+ this.p = new MPInteger(p);
+ this.g = new MPInteger(g);
+ this.y = new MPInteger(y);
+ }
+
+ /// The format, as a string, always "PGP".
+ public string Format
+ {
+ get { return "PGP"; }
+ }
+
+ /// Return the standard PGP encoding of the key.
+ public override byte[] GetEncoded()
+ {
+ try
+ {
+ return base.GetEncoded();
+ }
+ catch (Exception)
+ {
+ return null;
+ }
+ }
+
+ public BigInteger P
+ {
+ get { return p.Value; }
+ }
+
+ public BigInteger G
+ {
+ get { return g.Value; }
+ }
+
+ public BigInteger Y
+ {
+ get { return y.Value; }
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WriteObjects(p, g, y);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/ElGamalSecretBcpgKey.cs b/bc-sharp-crypto/src/bcpg/ElGamalSecretBcpgKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2d95b29b1a58b02350b861fe81a44f744e46dad4
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/ElGamalSecretBcpgKey.cs
@@ -0,0 +1,61 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Base class for an ElGamal secret key.
+ public class ElGamalSecretBcpgKey
+ : BcpgObject, IBcpgKey
+ {
+ internal MPInteger x;
+
+ /**
+ * @param in
+ */
+ public ElGamalSecretBcpgKey(
+ BcpgInputStream bcpgIn)
+ {
+ this.x = new MPInteger(bcpgIn);
+ }
+
+ /**
+ * @param x
+ */
+ public ElGamalSecretBcpgKey(
+ BigInteger x)
+ {
+ this.x = new MPInteger(x);
+ }
+
+ /// The format, as a string, always "PGP".
+ public string Format
+ {
+ get { return "PGP"; }
+ }
+
+ public BigInteger X
+ {
+ get { return x.Value; }
+ }
+
+ /// Return the standard PGP encoding of the key.
+ public override byte[] GetEncoded()
+ {
+ try
+ {
+ return base.GetEncoded();
+ }
+ catch (Exception)
+ {
+ return null;
+ }
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WriteObject(x);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/ExperimentalPacket.cs b/bc-sharp-crypto/src/bcpg/ExperimentalPacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..36a254be16d95d6ef93697b57fa95edc2668edf6
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/ExperimentalPacket.cs
@@ -0,0 +1,38 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Basic packet for an experimental packet.
+ public class ExperimentalPacket
+ : ContainedPacket //, PublicKeyAlgorithmTag
+ {
+ private readonly PacketTag tag;
+ private readonly byte[] contents;
+
+ internal ExperimentalPacket(
+ PacketTag tag,
+ BcpgInputStream bcpgIn)
+ {
+ this.tag = tag;
+
+ this.contents = bcpgIn.ReadAll();
+ }
+
+ public PacketTag Tag
+ {
+ get { return tag; }
+ }
+
+ public byte[] GetContents()
+ {
+ return (byte[]) contents.Clone();
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WritePacket(tag, contents, true);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/HashAlgorithmTags.cs b/bc-sharp-crypto/src/bcpg/HashAlgorithmTags.cs
new file mode 100644
index 0000000000000000000000000000000000000000..96c009153c04dd7a45cefbdfc6c06c04f0316e39
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/HashAlgorithmTags.cs
@@ -0,0 +1,19 @@
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Basic tags for hash algorithms.
+ public enum HashAlgorithmTag
+ {
+ MD5 = 1, // MD5
+ Sha1 = 2, // SHA-1
+ RipeMD160 = 3, // RIPE-MD/160
+ DoubleSha = 4, // Reserved for double-width SHA (experimental)
+ MD2 = 5, // MD2
+ Tiger192 = 6, // Reserved for TIGER/192
+ Haval5pass160 = 7, // Reserved for HAVAL (5 pass, 160-bit)
+
+ Sha256 = 8, // SHA-256
+ Sha384 = 9, // SHA-384
+ Sha512 = 10, // SHA-512
+ Sha224 = 11, // SHA-224
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/IBcpgKey.cs b/bc-sharp-crypto/src/bcpg/IBcpgKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..275461772be1f35a224b963db9be460933dd8616
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/IBcpgKey.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Base interface for a PGP key.
+ public interface IBcpgKey
+ {
+ ///
+ /// The base format for this key - in the case of the symmetric keys it will generally
+ /// be raw indicating that the key is just a straight byte representation, for an asymmetric
+ /// key the format will be PGP, indicating the key is a string of MPIs encoded in PGP format.
+ ///
+ /// "RAW" or "PGP".
+ string Format { get; }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/InputStreamPacket.cs b/bc-sharp-crypto/src/bcpg/InputStreamPacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c45efab7bdde7d8a659ade6abb848d9ec0bfc350
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/InputStreamPacket.cs
@@ -0,0 +1,20 @@
+namespace Org.BouncyCastle.Bcpg
+{
+ public class InputStreamPacket
+ : Packet
+ {
+ private readonly BcpgInputStream bcpgIn;
+
+ public InputStreamPacket(
+ BcpgInputStream bcpgIn)
+ {
+ this.bcpgIn = bcpgIn;
+ }
+
+ /// Note: you can only read from this once...
+ public BcpgInputStream GetInputStream()
+ {
+ return bcpgIn;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/LiteralDataPacket.cs b/bc-sharp-crypto/src/bcpg/LiteralDataPacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..63a2c6d448d39958bc9337f05e21d27de33e6cfd
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/LiteralDataPacket.cs
@@ -0,0 +1,57 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Generic literal data packet.
+ public class LiteralDataPacket
+ : InputStreamPacket
+ {
+ private int format;
+ private byte[] fileName;
+ private long modDate;
+
+ internal LiteralDataPacket(
+ BcpgInputStream bcpgIn)
+ : base(bcpgIn)
+ {
+ format = bcpgIn.ReadByte();
+ int len = bcpgIn.ReadByte();
+
+ fileName = new byte[len];
+ for (int i = 0; i != len; ++i)
+ {
+ fileName[i] = (byte)bcpgIn.ReadByte();
+ }
+
+ modDate = (((uint)bcpgIn.ReadByte() << 24)
+ | ((uint)bcpgIn.ReadByte() << 16)
+ | ((uint)bcpgIn.ReadByte() << 8)
+ | (uint)bcpgIn.ReadByte()) * 1000L;
+ }
+
+ /// The format tag value.
+ public int Format
+ {
+ get { return format; }
+ }
+
+ /// The modification time of the file in milli-seconds (since Jan 1, 1970 UTC)
+ public long ModificationTime
+ {
+ get { return modDate; }
+ }
+
+ public string FileName
+ {
+ get { return Strings.FromUtf8ByteArray(fileName); }
+ }
+
+ public byte[] GetRawFileName()
+ {
+ return Arrays.Clone(fileName);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/MPInteger.cs b/bc-sharp-crypto/src/bcpg/MPInteger.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4414072441f7460ec86b66682ce02ce40358e9d0
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/MPInteger.cs
@@ -0,0 +1,59 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// A multiple precision integer
+ public class MPInteger
+ : BcpgObject
+ {
+ private readonly BigInteger val;
+
+ public MPInteger(
+ BcpgInputStream bcpgIn)
+ {
+ if (bcpgIn == null)
+ throw new ArgumentNullException("bcpgIn");
+
+ int length = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte();
+ byte[] bytes = new byte[(length + 7) / 8];
+
+ bcpgIn.ReadFully(bytes);
+
+ this.val = new BigInteger(1, bytes);
+ }
+
+ public MPInteger(
+ BigInteger val)
+ {
+ if (val == null)
+ throw new ArgumentNullException("val");
+ if (val.SignValue < 0)
+ throw new ArgumentException("Values must be positive", "val");
+
+ this.val = val;
+ }
+
+ public BigInteger Value
+ {
+ get { return val; }
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WriteShort((short) val.BitLength);
+ bcpgOut.Write(val.ToByteArrayUnsigned());
+ }
+
+ internal static void Encode(
+ BcpgOutputStream bcpgOut,
+ BigInteger val)
+ {
+ bcpgOut.WriteShort((short) val.BitLength);
+ bcpgOut.Write(val.ToByteArrayUnsigned());
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/MarkerPacket.cs b/bc-sharp-crypto/src/bcpg/MarkerPacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4dc4b5a83a506a206df8ac030560c99cc7b8483b
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/MarkerPacket.cs
@@ -0,0 +1,24 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Basic type for a marker packet.
+ public class MarkerPacket
+ : ContainedPacket
+ {
+ // "PGP"
+ byte[] marker = { (byte)0x50, (byte)0x47, (byte)0x50 };
+
+ public MarkerPacket(
+ BcpgInputStream bcpgIn)
+ {
+ bcpgIn.ReadFully(marker);
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WritePacket(PacketTag.Marker, marker, true);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/ModDetectionCodePacket.cs b/bc-sharp-crypto/src/bcpg/ModDetectionCodePacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6bb23645a2fec6f6d93f55b2739678c51895dd9f
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/ModDetectionCodePacket.cs
@@ -0,0 +1,42 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Basic packet for a modification detection code packet.
+ public class ModDetectionCodePacket
+ : ContainedPacket
+ {
+ private readonly byte[] digest;
+
+ internal ModDetectionCodePacket(
+ BcpgInputStream bcpgIn)
+ {
+ if (bcpgIn == null)
+ throw new ArgumentNullException("bcpgIn");
+
+ this.digest = new byte[20];
+ bcpgIn.ReadFully(this.digest);
+ }
+
+ public ModDetectionCodePacket(
+ byte[] digest)
+ {
+ if (digest == null)
+ throw new ArgumentNullException("digest");
+
+ this.digest = (byte[]) digest.Clone();
+ }
+
+ public byte[] GetDigest()
+ {
+ return (byte[]) digest.Clone();
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WritePacket(PacketTag.ModificationDetectionCode, digest, false);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/OnePassSignaturePacket.cs b/bc-sharp-crypto/src/bcpg/OnePassSignaturePacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b67df0a529c4e09acd4da2ca3b534fb88492c733
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/OnePassSignaturePacket.cs
@@ -0,0 +1,93 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Generic signature object
+ public class OnePassSignaturePacket
+ : ContainedPacket
+ {
+ private int version;
+ private int sigType;
+ private HashAlgorithmTag hashAlgorithm;
+ private PublicKeyAlgorithmTag keyAlgorithm;
+ private long keyId;
+ private int nested;
+
+ internal OnePassSignaturePacket(
+ BcpgInputStream bcpgIn)
+ {
+ version = bcpgIn.ReadByte();
+ sigType = bcpgIn.ReadByte();
+ hashAlgorithm = (HashAlgorithmTag) bcpgIn.ReadByte();
+ keyAlgorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte();
+
+ keyId |= (long)bcpgIn.ReadByte() << 56;
+ keyId |= (long)bcpgIn.ReadByte() << 48;
+ keyId |= (long)bcpgIn.ReadByte() << 40;
+ keyId |= (long)bcpgIn.ReadByte() << 32;
+ keyId |= (long)bcpgIn.ReadByte() << 24;
+ keyId |= (long)bcpgIn.ReadByte() << 16;
+ keyId |= (long)bcpgIn.ReadByte() << 8;
+ keyId |= (uint)bcpgIn.ReadByte();
+
+ nested = bcpgIn.ReadByte();
+ }
+
+ public OnePassSignaturePacket(
+ int sigType,
+ HashAlgorithmTag hashAlgorithm,
+ PublicKeyAlgorithmTag keyAlgorithm,
+ long keyId,
+ bool isNested)
+ {
+ this.version = 3;
+ this.sigType = sigType;
+ this.hashAlgorithm = hashAlgorithm;
+ this.keyAlgorithm = keyAlgorithm;
+ this.keyId = keyId;
+ this.nested = (isNested) ? 0 : 1;
+ }
+
+ public int SignatureType
+ {
+ get { return sigType; }
+ }
+
+ /// The encryption algorithm tag.
+ public PublicKeyAlgorithmTag KeyAlgorithm
+ {
+ get { return keyAlgorithm; }
+ }
+
+ /// The hash algorithm tag.
+ public HashAlgorithmTag HashAlgorithm
+ {
+ get { return hashAlgorithm; }
+ }
+
+ public long KeyId
+ {
+ get { return keyId; }
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ MemoryStream bOut = new MemoryStream();
+ BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+ pOut.Write(
+ (byte) version,
+ (byte) sigType,
+ (byte) hashAlgorithm,
+ (byte) keyAlgorithm);
+
+ pOut.WriteLong(keyId);
+
+ pOut.WriteByte((byte) nested);
+
+ bcpgOut.WritePacket(PacketTag.OnePassSignature, bOut.ToArray(), true);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/OutputStreamPacket.cs b/bc-sharp-crypto/src/bcpg/OutputStreamPacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..aa8316dcb83b03799f63f8e563fbaf9ce6bbeeb7
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/OutputStreamPacket.cs
@@ -0,0 +1,24 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ public abstract class OutputStreamPacket
+ {
+ private readonly BcpgOutputStream bcpgOut;
+
+ internal OutputStreamPacket(
+ BcpgOutputStream bcpgOut)
+ {
+ if (bcpgOut == null)
+ throw new ArgumentNullException("bcpgOut");
+
+ this.bcpgOut = bcpgOut;
+ }
+
+ public abstract BcpgOutputStream Open();
+
+ public abstract void Close();
+ }
+}
+
diff --git a/bc-sharp-crypto/src/bcpg/Packet.cs b/bc-sharp-crypto/src/bcpg/Packet.cs
new file mode 100644
index 0000000000000000000000000000000000000000..83f6d1f74fd5591cb75f3c74eaba3a49cbd46074
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/Packet.cs
@@ -0,0 +1,7 @@
+namespace Org.BouncyCastle.Bcpg
+{
+ public class Packet
+ //: PacketTag
+ {
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/PacketTags.cs b/bc-sharp-crypto/src/bcpg/PacketTags.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5a53d4e95752595ab0da72456f35f550f020919a
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/PacketTags.cs
@@ -0,0 +1,30 @@
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Basic PGP packet tag types.
+ public enum PacketTag
+ {
+ Reserved = 0, // Reserved - a packet tag must not have this value
+ PublicKeyEncryptedSession = 1, // Public-Key Encrypted Session Key Packet
+ Signature = 2, // Signature Packet
+ SymmetricKeyEncryptedSessionKey = 3, // Symmetric-Key Encrypted Session Key Packet
+ OnePassSignature = 4, // One-Pass Signature Packet
+ SecretKey = 5, // Secret Key Packet
+ PublicKey = 6, // Public Key Packet
+ SecretSubkey = 7, // Secret Subkey Packet
+ CompressedData = 8, // Compressed Data Packet
+ SymmetricKeyEncrypted = 9, // Symmetrically Encrypted Data Packet
+ Marker = 10, // Marker Packet
+ LiteralData = 11, // Literal Data Packet
+ Trust = 12, // Trust Packet
+ UserId = 13, // User ID Packet
+ PublicSubkey = 14, // Public Subkey Packet
+ UserAttribute = 17, // User attribute
+ SymmetricEncryptedIntegrityProtected = 18, // Symmetric encrypted, integrity protected
+ ModificationDetectionCode = 19, // Modification detection code
+
+ Experimental1 = 60, // Private or Experimental Values
+ Experimental2 = 61,
+ Experimental3 = 62,
+ Experimental4 = 63
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/PublicKeyAlgorithmTags.cs b/bc-sharp-crypto/src/bcpg/PublicKeyAlgorithmTags.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9e30b54f7bb69b1bb7debedef45a5c677a889861
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/PublicKeyAlgorithmTags.cs
@@ -0,0 +1,32 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Public Key Algorithm tag numbers.
+ public enum PublicKeyAlgorithmTag
+ {
+ RsaGeneral = 1, // RSA (Encrypt or Sign)
+ RsaEncrypt = 2, // RSA Encrypt-Only
+ RsaSign = 3, // RSA Sign-Only
+ ElGamalEncrypt = 16, // Elgamal (Encrypt-Only), see [ELGAMAL]
+ Dsa = 17, // DSA (Digital Signature Standard)
+ [Obsolete("Use 'ECDH' instead")]
+ EC = 18, // Reserved for Elliptic Curve
+ ECDH = 18, // Reserved for Elliptic Curve (actual algorithm name)
+ ECDsa = 19, // Reserved for ECDSA
+ ElGamalGeneral = 20, // Elgamal (Encrypt or Sign)
+ DiffieHellman = 21, // Reserved for Diffie-Hellman (X9.42, as defined for IETF-S/MIME)
+
+ Experimental_1 = 100,
+ Experimental_2 = 101,
+ Experimental_3 = 102,
+ Experimental_4 = 103,
+ Experimental_5 = 104,
+ Experimental_6 = 105,
+ Experimental_7 = 106,
+ Experimental_8 = 107,
+ Experimental_9 = 108,
+ Experimental_10 = 109,
+ Experimental_11 = 110,
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/PublicKeyEncSessionPacket.cs b/bc-sharp-crypto/src/bcpg/PublicKeyEncSessionPacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..831b5a189fee75e3bd6e420f4466829f6db76e58
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/PublicKeyEncSessionPacket.cs
@@ -0,0 +1,115 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Basic packet for a PGP public key.
+ public class PublicKeyEncSessionPacket
+ : ContainedPacket //, PublicKeyAlgorithmTag
+ {
+ private int version;
+ private long keyId;
+ private PublicKeyAlgorithmTag algorithm;
+ private byte[][] data;
+
+ internal PublicKeyEncSessionPacket(
+ BcpgInputStream bcpgIn)
+ {
+ version = bcpgIn.ReadByte();
+
+ keyId |= (long)bcpgIn.ReadByte() << 56;
+ keyId |= (long)bcpgIn.ReadByte() << 48;
+ keyId |= (long)bcpgIn.ReadByte() << 40;
+ keyId |= (long)bcpgIn.ReadByte() << 32;
+ keyId |= (long)bcpgIn.ReadByte() << 24;
+ keyId |= (long)bcpgIn.ReadByte() << 16;
+ keyId |= (long)bcpgIn.ReadByte() << 8;
+ keyId |= (uint)bcpgIn.ReadByte();
+
+ algorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte();
+
+ switch ((PublicKeyAlgorithmTag) algorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaEncrypt:
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ data = new byte[][]{ new MPInteger(bcpgIn).GetEncoded() };
+ break;
+ case PublicKeyAlgorithmTag.ElGamalEncrypt:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ MPInteger p = new MPInteger(bcpgIn);
+ MPInteger g = new MPInteger(bcpgIn);
+ data = new byte[][]{
+ p.GetEncoded(),
+ g.GetEncoded(),
+ };
+ break;
+ case PublicKeyAlgorithmTag.ECDH:
+ data = new byte[][]{ Streams.ReadAll(bcpgIn) };
+ break;
+ default:
+ throw new IOException("unknown PGP public key algorithm encountered");
+ }
+ }
+
+ public PublicKeyEncSessionPacket(
+ long keyId,
+ PublicKeyAlgorithmTag algorithm,
+ byte[][] data)
+ {
+ this.version = 3;
+ this.keyId = keyId;
+ this.algorithm = algorithm;
+ this.data = new byte[data.Length][];
+ for (int i = 0; i < data.Length; ++i)
+ {
+ this.data[i] = Arrays.Clone(data[i]);
+ }
+ }
+
+ public int Version
+ {
+ get { return version; }
+ }
+
+ public long KeyId
+ {
+ get { return keyId; }
+ }
+
+ public PublicKeyAlgorithmTag Algorithm
+ {
+ get { return algorithm; }
+ }
+
+ public byte[][] GetEncSessionKey()
+ {
+ return data;
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ MemoryStream bOut = new MemoryStream();
+ BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+ pOut.WriteByte((byte) version);
+
+ pOut.WriteLong(keyId);
+
+ pOut.WriteByte((byte)algorithm);
+
+ for (int i = 0; i < data.Length; ++i)
+ {
+ pOut.Write(data[i]);
+ }
+
+ Platform.Dispose(pOut);
+
+ bcpgOut.WritePacket(PacketTag.PublicKeyEncryptedSession , bOut.ToArray(), true);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/PublicKeyPacket.cs b/bc-sharp-crypto/src/bcpg/PublicKeyPacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bbed941dc71df1e8d43004d257a4653360f854be
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/PublicKeyPacket.cs
@@ -0,0 +1,121 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Basic packet for a PGP public key.
+ public class PublicKeyPacket
+ : ContainedPacket //, PublicKeyAlgorithmTag
+ {
+ private int version;
+ private long time;
+ private int validDays;
+ private PublicKeyAlgorithmTag algorithm;
+ private IBcpgKey key;
+
+ internal PublicKeyPacket(
+ BcpgInputStream bcpgIn)
+ {
+ version = bcpgIn.ReadByte();
+
+ time = ((uint)bcpgIn.ReadByte() << 24) | ((uint)bcpgIn.ReadByte() << 16)
+ | ((uint)bcpgIn.ReadByte() << 8) | (uint)bcpgIn.ReadByte();
+
+ if (version <= 3)
+ {
+ validDays = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte();
+ }
+
+ algorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte();
+
+ switch ((PublicKeyAlgorithmTag) algorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaEncrypt:
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ case PublicKeyAlgorithmTag.RsaSign:
+ key = new RsaPublicBcpgKey(bcpgIn);
+ break;
+ case PublicKeyAlgorithmTag.Dsa:
+ key = new DsaPublicBcpgKey(bcpgIn);
+ break;
+ case PublicKeyAlgorithmTag.ElGamalEncrypt:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ key = new ElGamalPublicBcpgKey(bcpgIn);
+ break;
+ case PublicKeyAlgorithmTag.ECDH:
+ key = new ECDHPublicBcpgKey(bcpgIn);
+ break;
+ case PublicKeyAlgorithmTag.ECDsa:
+ key = new ECDsaPublicBcpgKey(bcpgIn);
+ break;
+ default:
+ throw new IOException("unknown PGP public key algorithm encountered");
+ }
+ }
+
+ /// Construct a version 4 public key packet.
+ public PublicKeyPacket(
+ PublicKeyAlgorithmTag algorithm,
+ DateTime time,
+ IBcpgKey key)
+ {
+ this.version = 4;
+ this.time = DateTimeUtilities.DateTimeToUnixMs(time) / 1000L;
+ this.algorithm = algorithm;
+ this.key = key;
+ }
+
+ public virtual int Version
+ {
+ get { return version; }
+ }
+
+ public virtual PublicKeyAlgorithmTag Algorithm
+ {
+ get { return algorithm; }
+ }
+
+ public virtual int ValidDays
+ {
+ get { return validDays; }
+ }
+
+ public virtual DateTime GetTime()
+ {
+ return DateTimeUtilities.UnixMsToDateTime(time * 1000L);
+ }
+
+ public virtual IBcpgKey Key
+ {
+ get { return key; }
+ }
+
+ public virtual byte[] GetEncodedContents()
+ {
+ MemoryStream bOut = new MemoryStream();
+ BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+ pOut.WriteByte((byte) version);
+ pOut.WriteInt((int) time);
+
+ if (version <= 3)
+ {
+ pOut.WriteShort((short) validDays);
+ }
+
+ pOut.WriteByte((byte) algorithm);
+
+ pOut.WriteObject((BcpgObject)key);
+
+ return bOut.ToArray();
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WritePacket(PacketTag.PublicKey, GetEncodedContents(), true);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/PublicSubkeyPacket.cs b/bc-sharp-crypto/src/bcpg/PublicSubkeyPacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6e1aeda98251fe1aaed3b3a0d3a5bf136797fb78
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/PublicSubkeyPacket.cs
@@ -0,0 +1,30 @@
+using System;
+using System.IO;
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Basic packet for a PGP public subkey
+ public class PublicSubkeyPacket
+ : PublicKeyPacket
+ {
+ internal PublicSubkeyPacket(
+ BcpgInputStream bcpgIn)
+ : base(bcpgIn)
+ {
+ }
+
+ /// Construct a version 4 public subkey packet.
+ public PublicSubkeyPacket(
+ PublicKeyAlgorithmTag algorithm,
+ DateTime time,
+ IBcpgKey key)
+ : base(algorithm, time, key)
+ {
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WritePacket(PacketTag.PublicSubkey, GetEncodedContents(), true);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/RsaPublicBcpgKey.cs b/bc-sharp-crypto/src/bcpg/RsaPublicBcpgKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fd2313c89cd1edbeb99f2a2b967b2e9f356b9b24
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/RsaPublicBcpgKey.cs
@@ -0,0 +1,66 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Base class for an RSA public key.
+ public class RsaPublicBcpgKey
+ : BcpgObject, IBcpgKey
+ {
+ private readonly MPInteger n, e;
+
+ /// Construct an RSA public key from the passed in stream.
+ public RsaPublicBcpgKey(
+ BcpgInputStream bcpgIn)
+ {
+ this.n = new MPInteger(bcpgIn);
+ this.e = new MPInteger(bcpgIn);
+ }
+
+ /// The modulus.
+ /// The public exponent.
+ public RsaPublicBcpgKey(
+ BigInteger n,
+ BigInteger e)
+ {
+ this.n = new MPInteger(n);
+ this.e = new MPInteger(e);
+ }
+
+ public BigInteger PublicExponent
+ {
+ get { return e.Value; }
+ }
+
+ public BigInteger Modulus
+ {
+ get { return n.Value; }
+ }
+
+ /// The format, as a string, always "PGP".
+ public string Format
+ {
+ get { return "PGP"; }
+ }
+
+ /// Return the standard PGP encoding of the key.
+ public override byte[] GetEncoded()
+ {
+ try
+ {
+ return base.GetEncoded();
+ }
+ catch (Exception)
+ {
+ return null;
+ }
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WriteObjects(n, e);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/RsaSecretBcpgKey.cs b/bc-sharp-crypto/src/bcpg/RsaSecretBcpgKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5c04d9f85cb1da15daca8f3875c4d1a5ac5a998a
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/RsaSecretBcpgKey.cs
@@ -0,0 +1,114 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Base class for an RSA secret (or priate) key.
+ public class RsaSecretBcpgKey
+ : BcpgObject, IBcpgKey
+ {
+ private readonly MPInteger d, p, q, u;
+ private readonly BigInteger expP, expQ, crt;
+
+ public RsaSecretBcpgKey(
+ BcpgInputStream bcpgIn)
+ {
+ this.d = new MPInteger(bcpgIn);
+ this.p = new MPInteger(bcpgIn);
+ this.q = new MPInteger(bcpgIn);
+ this.u = new MPInteger(bcpgIn);
+
+ this.expP = d.Value.Remainder(p.Value.Subtract(BigInteger.One));
+ this.expQ = d.Value.Remainder(q.Value.Subtract(BigInteger.One));
+ this.crt = q.Value.ModInverse(p.Value);
+ }
+
+ public RsaSecretBcpgKey(
+ BigInteger d,
+ BigInteger p,
+ BigInteger q)
+ {
+ // PGP requires (p < q)
+ int cmp = p.CompareTo(q);
+ if (cmp >= 0)
+ {
+ if (cmp == 0)
+ throw new ArgumentException("p and q cannot be equal");
+
+ BigInteger tmp = p;
+ p = q;
+ q = tmp;
+ }
+
+ this.d = new MPInteger(d);
+ this.p = new MPInteger(p);
+ this.q = new MPInteger(q);
+ this.u = new MPInteger(p.ModInverse(q));
+
+ this.expP = d.Remainder(p.Subtract(BigInteger.One));
+ this.expQ = d.Remainder(q.Subtract(BigInteger.One));
+ this.crt = q.ModInverse(p);
+ }
+
+ public BigInteger Modulus
+ {
+ get { return p.Value.Multiply(q.Value); }
+ }
+
+ public BigInteger PrivateExponent
+ {
+ get { return d.Value; }
+ }
+
+ public BigInteger PrimeP
+ {
+ get { return p.Value; }
+ }
+
+ public BigInteger PrimeQ
+ {
+ get { return q.Value; }
+ }
+
+ public BigInteger PrimeExponentP
+ {
+ get { return expP; }
+ }
+
+ public BigInteger PrimeExponentQ
+ {
+ get { return expQ; }
+ }
+
+ public BigInteger CrtCoefficient
+ {
+ get { return crt; }
+ }
+
+ /// The format, as a string, always "PGP".
+ public string Format
+ {
+ get { return "PGP"; }
+ }
+
+ /// Return the standard PGP encoding of the key.
+ public override byte[] GetEncoded()
+ {
+ try
+ {
+ return base.GetEncoded();
+ }
+ catch (Exception)
+ {
+ return null;
+ }
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WriteObjects(d, p, q, u);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/S2k.cs b/bc-sharp-crypto/src/bcpg/S2k.cs
new file mode 100644
index 0000000000000000000000000000000000000000..33fd792feb4e459483547cd260e330dddcfc5933
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/S2k.cs
@@ -0,0 +1,149 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// The string to key specifier class.
+ public class S2k
+ : BcpgObject
+ {
+ private const int ExpBias = 6;
+
+ public const int Simple = 0;
+ public const int Salted = 1;
+ public const int SaltedAndIterated = 3;
+ public const int GnuDummyS2K = 101;
+ public const int GnuProtectionModeNoPrivateKey = 1;
+ public const int GnuProtectionModeDivertToCard = 2;
+
+ internal int type;
+ internal HashAlgorithmTag algorithm;
+ internal byte[] iv;
+ internal int itCount = -1;
+ internal int protectionMode = -1;
+
+ internal S2k(
+ Stream inStr)
+ {
+ type = inStr.ReadByte();
+ algorithm = (HashAlgorithmTag) inStr.ReadByte();
+
+ //
+ // if this happens we have a dummy-S2k packet.
+ //
+ if (type != GnuDummyS2K)
+ {
+ if (type != 0)
+ {
+ iv = new byte[8];
+ if (Streams.ReadFully(inStr, iv, 0, iv.Length) < iv.Length)
+ throw new EndOfStreamException();
+
+ if (type == 3)
+ {
+ itCount = inStr.ReadByte();
+ }
+ }
+ }
+ else
+ {
+ inStr.ReadByte(); // G
+ inStr.ReadByte(); // N
+ inStr.ReadByte(); // U
+ protectionMode = inStr.ReadByte(); // protection mode
+ }
+ }
+
+ public S2k(
+ HashAlgorithmTag algorithm)
+ {
+ this.type = 0;
+ this.algorithm = algorithm;
+ }
+
+ public S2k(
+ HashAlgorithmTag algorithm,
+ byte[] iv)
+ {
+ this.type = 1;
+ this.algorithm = algorithm;
+ this.iv = iv;
+ }
+
+ public S2k(
+ HashAlgorithmTag algorithm,
+ byte[] iv,
+ int itCount)
+ {
+ this.type = 3;
+ this.algorithm = algorithm;
+ this.iv = iv;
+ this.itCount = itCount;
+ }
+
+ public virtual int Type
+ {
+ get { return type; }
+ }
+
+ /// The hash algorithm.
+ public virtual HashAlgorithmTag HashAlgorithm
+ {
+ get { return algorithm; }
+ }
+
+ /// The IV for the key generation algorithm.
+ public virtual byte[] GetIV()
+ {
+ return Arrays.Clone(iv);
+ }
+
+ [Obsolete("Use 'IterationCount' property instead")]
+ public long GetIterationCount()
+ {
+ return IterationCount;
+ }
+
+ /// The iteration count
+ public virtual long IterationCount
+ {
+ get { return (16 + (itCount & 15)) << ((itCount >> 4) + ExpBias); }
+ }
+
+ /// The protection mode - only if GnuDummyS2K
+ public virtual int ProtectionMode
+ {
+ get { return protectionMode; }
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WriteByte((byte) type);
+ bcpgOut.WriteByte((byte) algorithm);
+
+ if (type != GnuDummyS2K)
+ {
+ if (type != 0)
+ {
+ bcpgOut.Write(iv);
+ }
+
+ if (type == 3)
+ {
+ bcpgOut.WriteByte((byte) itCount);
+ }
+ }
+ else
+ {
+ bcpgOut.WriteByte((byte) 'G');
+ bcpgOut.WriteByte((byte) 'N');
+ bcpgOut.WriteByte((byte) 'U');
+ bcpgOut.WriteByte((byte) protectionMode);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/SecretKeyPacket.cs b/bc-sharp-crypto/src/bcpg/SecretKeyPacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d9ceab4f14b07b8f133e8d86718ec1f8e054281f
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/SecretKeyPacket.cs
@@ -0,0 +1,170 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Basic packet for a PGP secret key.
+ public class SecretKeyPacket
+ : ContainedPacket //, PublicKeyAlgorithmTag
+ {
+ public const int UsageNone = 0x00;
+ public const int UsageChecksum = 0xff;
+ public const int UsageSha1 = 0xfe;
+
+ private PublicKeyPacket pubKeyPacket;
+ private readonly byte[] secKeyData;
+ private int s2kUsage;
+ private SymmetricKeyAlgorithmTag encAlgorithm;
+ private S2k s2k;
+ private byte[] iv;
+
+ internal SecretKeyPacket(
+ BcpgInputStream bcpgIn)
+ {
+ if (this is SecretSubkeyPacket)
+ {
+ pubKeyPacket = new PublicSubkeyPacket(bcpgIn);
+ }
+ else
+ {
+ pubKeyPacket = new PublicKeyPacket(bcpgIn);
+ }
+
+ s2kUsage = bcpgIn.ReadByte();
+
+ if (s2kUsage == UsageChecksum || s2kUsage == UsageSha1)
+ {
+ encAlgorithm = (SymmetricKeyAlgorithmTag) bcpgIn.ReadByte();
+ s2k = new S2k(bcpgIn);
+ }
+ else
+ {
+ encAlgorithm = (SymmetricKeyAlgorithmTag) s2kUsage;
+ }
+
+ if (!(s2k != null && s2k.Type == S2k.GnuDummyS2K && s2k.ProtectionMode == 0x01))
+ {
+ if (s2kUsage != 0)
+ {
+ if (((int) encAlgorithm) < 7)
+ {
+ iv = new byte[8];
+ }
+ else
+ {
+ iv = new byte[16];
+ }
+ bcpgIn.ReadFully(iv);
+ }
+ }
+
+ secKeyData = bcpgIn.ReadAll();
+ }
+
+ public SecretKeyPacket(
+ PublicKeyPacket pubKeyPacket,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ S2k s2k,
+ byte[] iv,
+ byte[] secKeyData)
+ {
+ this.pubKeyPacket = pubKeyPacket;
+ this.encAlgorithm = encAlgorithm;
+
+ if (encAlgorithm != SymmetricKeyAlgorithmTag.Null)
+ {
+ this.s2kUsage = UsageChecksum;
+ }
+ else
+ {
+ this.s2kUsage = UsageNone;
+ }
+
+ this.s2k = s2k;
+ this.iv = Arrays.Clone(iv);
+ this.secKeyData = secKeyData;
+ }
+
+ public SecretKeyPacket(
+ PublicKeyPacket pubKeyPacket,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ int s2kUsage,
+ S2k s2k,
+ byte[] iv,
+ byte[] secKeyData)
+ {
+ this.pubKeyPacket = pubKeyPacket;
+ this.encAlgorithm = encAlgorithm;
+ this.s2kUsage = s2kUsage;
+ this.s2k = s2k;
+ this.iv = Arrays.Clone(iv);
+ this.secKeyData = secKeyData;
+ }
+
+ public SymmetricKeyAlgorithmTag EncAlgorithm
+ {
+ get { return encAlgorithm; }
+ }
+
+ public int S2kUsage
+ {
+ get { return s2kUsage; }
+ }
+
+ public byte[] GetIV()
+ {
+ return Arrays.Clone(iv);
+ }
+
+ public S2k S2k
+ {
+ get { return s2k; }
+ }
+
+ public PublicKeyPacket PublicKeyPacket
+ {
+ get { return pubKeyPacket; }
+ }
+
+ public byte[] GetSecretKeyData()
+ {
+ return secKeyData;
+ }
+
+ public byte[] GetEncodedContents()
+ {
+ MemoryStream bOut = new MemoryStream();
+ BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+ pOut.Write(pubKeyPacket.GetEncodedContents());
+
+ pOut.WriteByte((byte) s2kUsage);
+
+ if (s2kUsage == UsageChecksum || s2kUsage == UsageSha1)
+ {
+ pOut.WriteByte((byte) encAlgorithm);
+ pOut.WriteObject(s2k);
+ }
+
+ if (iv != null)
+ {
+ pOut.Write(iv);
+ }
+
+ if (secKeyData != null && secKeyData.Length > 0)
+ {
+ pOut.Write(secKeyData);
+ }
+
+ return bOut.ToArray();
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WritePacket(PacketTag.SecretKey, GetEncodedContents(), true);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/SecretSubkeyPacket.cs b/bc-sharp-crypto/src/bcpg/SecretSubkeyPacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8f1746942920346e28675e20bb1878b84c03ddde
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/SecretSubkeyPacket.cs
@@ -0,0 +1,43 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Basic packet for a PGP secret key.
+ public class SecretSubkeyPacket
+ : SecretKeyPacket
+ {
+ internal SecretSubkeyPacket(
+ BcpgInputStream bcpgIn)
+ : base(bcpgIn)
+ {
+ }
+
+ public SecretSubkeyPacket(
+ PublicKeyPacket pubKeyPacket,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ S2k s2k,
+ byte[] iv,
+ byte[] secKeyData)
+ : base(pubKeyPacket, encAlgorithm, s2k, iv, secKeyData)
+ {
+ }
+
+ public SecretSubkeyPacket(
+ PublicKeyPacket pubKeyPacket,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ int s2kUsage,
+ S2k s2k,
+ byte[] iv,
+ byte[] secKeyData)
+ : base(pubKeyPacket, encAlgorithm, s2kUsage, s2k, iv, secKeyData)
+ {
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WritePacket(PacketTag.SecretSubkey, GetEncodedContents(), true);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/SignaturePacket.cs b/bc-sharp-crypto/src/bcpg/SignaturePacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5b91c15a328060b85b5466332a42fe86ea7ae28f
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/SignaturePacket.cs
@@ -0,0 +1,477 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Bcpg.Sig;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Generic signature packet.
+ public class SignaturePacket
+ : ContainedPacket //, PublicKeyAlgorithmTag
+ {
+ private int version;
+ private int signatureType;
+ private long creationTime;
+ private long keyId;
+ private PublicKeyAlgorithmTag keyAlgorithm;
+ private HashAlgorithmTag hashAlgorithm;
+ private MPInteger[] signature;
+ private byte[] fingerprint;
+ private SignatureSubpacket[] hashedData;
+ private SignatureSubpacket[] unhashedData;
+ private byte[] signatureEncoding;
+
+ internal SignaturePacket(
+ BcpgInputStream bcpgIn)
+ {
+ version = bcpgIn.ReadByte();
+
+ if (version == 3 || version == 2)
+ {
+// int l =
+ bcpgIn.ReadByte();
+
+ signatureType = bcpgIn.ReadByte();
+ creationTime = (((long)bcpgIn.ReadByte() << 24) | ((long)bcpgIn.ReadByte() << 16)
+ | ((long)bcpgIn.ReadByte() << 8) | (uint)bcpgIn.ReadByte()) * 1000L;
+
+ keyId |= (long)bcpgIn.ReadByte() << 56;
+ keyId |= (long)bcpgIn.ReadByte() << 48;
+ keyId |= (long)bcpgIn.ReadByte() << 40;
+ keyId |= (long)bcpgIn.ReadByte() << 32;
+ keyId |= (long)bcpgIn.ReadByte() << 24;
+ keyId |= (long)bcpgIn.ReadByte() << 16;
+ keyId |= (long)bcpgIn.ReadByte() << 8;
+ keyId |= (uint)bcpgIn.ReadByte();
+
+ keyAlgorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte();
+ hashAlgorithm = (HashAlgorithmTag) bcpgIn.ReadByte();
+ }
+ else if (version == 4)
+ {
+ signatureType = bcpgIn.ReadByte();
+ keyAlgorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte();
+ hashAlgorithm = (HashAlgorithmTag) bcpgIn.ReadByte();
+
+ int hashedLength = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte();
+ byte[] hashed = new byte[hashedLength];
+
+ bcpgIn.ReadFully(hashed);
+
+ //
+ // read the signature sub packet data.
+ //
+ SignatureSubpacketsParser sIn = new SignatureSubpacketsParser(
+ new MemoryStream(hashed, false));
+
+ IList v = Platform.CreateArrayList();
+ SignatureSubpacket sub;
+ while ((sub = sIn.ReadPacket()) != null)
+ {
+ v.Add(sub);
+ }
+
+ hashedData = new SignatureSubpacket[v.Count];
+
+ for (int i = 0; i != hashedData.Length; i++)
+ {
+ SignatureSubpacket p = (SignatureSubpacket)v[i];
+ if (p is IssuerKeyId)
+ {
+ keyId = ((IssuerKeyId)p).KeyId;
+ }
+ else if (p is SignatureCreationTime)
+ {
+ creationTime = DateTimeUtilities.DateTimeToUnixMs(
+ ((SignatureCreationTime)p).GetTime());
+ }
+
+ hashedData[i] = p;
+ }
+
+ int unhashedLength = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte();
+ byte[] unhashed = new byte[unhashedLength];
+
+ bcpgIn.ReadFully(unhashed);
+
+ sIn = new SignatureSubpacketsParser(new MemoryStream(unhashed, false));
+
+ v.Clear();
+
+ while ((sub = sIn.ReadPacket()) != null)
+ {
+ v.Add(sub);
+ }
+
+ unhashedData = new SignatureSubpacket[v.Count];
+
+ for (int i = 0; i != unhashedData.Length; i++)
+ {
+ SignatureSubpacket p = (SignatureSubpacket)v[i];
+ if (p is IssuerKeyId)
+ {
+ keyId = ((IssuerKeyId)p).KeyId;
+ }
+
+ unhashedData[i] = p;
+ }
+ }
+ else
+ {
+ throw new Exception("unsupported version: " + version);
+ }
+
+ fingerprint = new byte[2];
+ bcpgIn.ReadFully(fingerprint);
+
+ switch (keyAlgorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ case PublicKeyAlgorithmTag.RsaSign:
+ MPInteger v = new MPInteger(bcpgIn);
+ signature = new MPInteger[]{ v };
+ break;
+ case PublicKeyAlgorithmTag.Dsa:
+ MPInteger r = new MPInteger(bcpgIn);
+ MPInteger s = new MPInteger(bcpgIn);
+ signature = new MPInteger[]{ r, s };
+ break;
+ case PublicKeyAlgorithmTag.ElGamalEncrypt: // yep, this really does happen sometimes.
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ MPInteger p = new MPInteger(bcpgIn);
+ MPInteger g = new MPInteger(bcpgIn);
+ MPInteger y = new MPInteger(bcpgIn);
+ signature = new MPInteger[]{ p, g, y };
+ break;
+ case PublicKeyAlgorithmTag.ECDsa:
+ MPInteger ecR = new MPInteger(bcpgIn);
+ MPInteger ecS = new MPInteger(bcpgIn);
+ signature = new MPInteger[]{ ecR, ecS };
+ break;
+ default:
+ if (keyAlgorithm >= PublicKeyAlgorithmTag.Experimental_1 && keyAlgorithm <= PublicKeyAlgorithmTag.Experimental_11)
+ {
+ signature = null;
+ MemoryStream bOut = new MemoryStream();
+ int ch;
+ while ((ch = bcpgIn.ReadByte()) >= 0)
+ {
+ bOut.WriteByte((byte) ch);
+ }
+ signatureEncoding = bOut.ToArray();
+ }
+ else
+ {
+ throw new IOException("unknown signature key algorithm: " + keyAlgorithm);
+ }
+ break;
+ }
+ }
+
+ /**
+ * Generate a version 4 signature packet.
+ *
+ * @param signatureType
+ * @param keyAlgorithm
+ * @param hashAlgorithm
+ * @param hashedData
+ * @param unhashedData
+ * @param fingerprint
+ * @param signature
+ */
+ public SignaturePacket(
+ int signatureType,
+ long keyId,
+ PublicKeyAlgorithmTag keyAlgorithm,
+ HashAlgorithmTag hashAlgorithm,
+ SignatureSubpacket[] hashedData,
+ SignatureSubpacket[] unhashedData,
+ byte[] fingerprint,
+ MPInteger[] signature)
+ : this(4, signatureType, keyId, keyAlgorithm, hashAlgorithm, hashedData, unhashedData, fingerprint, signature)
+ {
+ }
+
+ /**
+ * Generate a version 2/3 signature packet.
+ *
+ * @param signatureType
+ * @param keyAlgorithm
+ * @param hashAlgorithm
+ * @param fingerprint
+ * @param signature
+ */
+ public SignaturePacket(
+ int version,
+ int signatureType,
+ long keyId,
+ PublicKeyAlgorithmTag keyAlgorithm,
+ HashAlgorithmTag hashAlgorithm,
+ long creationTime,
+ byte[] fingerprint,
+ MPInteger[] signature)
+ : this(version, signatureType, keyId, keyAlgorithm, hashAlgorithm, null, null, fingerprint, signature)
+ {
+ this.creationTime = creationTime;
+ }
+
+ public SignaturePacket(
+ int version,
+ int signatureType,
+ long keyId,
+ PublicKeyAlgorithmTag keyAlgorithm,
+ HashAlgorithmTag hashAlgorithm,
+ SignatureSubpacket[] hashedData,
+ SignatureSubpacket[] unhashedData,
+ byte[] fingerprint,
+ MPInteger[] signature)
+ {
+ this.version = version;
+ this.signatureType = signatureType;
+ this.keyId = keyId;
+ this.keyAlgorithm = keyAlgorithm;
+ this.hashAlgorithm = hashAlgorithm;
+ this.hashedData = hashedData;
+ this.unhashedData = unhashedData;
+ this.fingerprint = fingerprint;
+ this.signature = signature;
+
+ if (hashedData != null)
+ {
+ setCreationTime();
+ }
+ }
+
+ public int Version
+ {
+ get { return version; }
+ }
+
+ public int SignatureType
+ {
+ get { return signatureType; }
+ }
+
+ /**
+ * return the keyId
+ * @return the keyId that created the signature.
+ */
+ public long KeyId
+ {
+ get { return keyId; }
+ }
+
+ /**
+ * return the signature trailer that must be included with the data
+ * to reconstruct the signature
+ *
+ * @return byte[]
+ */
+ public byte[] GetSignatureTrailer()
+ {
+ byte[] trailer = null;
+
+ if (version == 3)
+ {
+ trailer = new byte[5];
+
+ long time = creationTime / 1000L;
+
+ trailer[0] = (byte)signatureType;
+ trailer[1] = (byte)(time >> 24);
+ trailer[2] = (byte)(time >> 16);
+ trailer[3] = (byte)(time >> 8);
+ trailer[4] = (byte)(time);
+ }
+ else
+ {
+ MemoryStream sOut = new MemoryStream();
+
+ sOut.WriteByte((byte)this.Version);
+ sOut.WriteByte((byte)this.SignatureType);
+ sOut.WriteByte((byte)this.KeyAlgorithm);
+ sOut.WriteByte((byte)this.HashAlgorithm);
+
+ MemoryStream hOut = new MemoryStream();
+ SignatureSubpacket[] hashed = this.GetHashedSubPackets();
+
+ for (int i = 0; i != hashed.Length; i++)
+ {
+ hashed[i].Encode(hOut);
+ }
+
+ byte[] data = hOut.ToArray();
+
+ sOut.WriteByte((byte)(data.Length >> 8));
+ sOut.WriteByte((byte)data.Length);
+ sOut.Write(data, 0, data.Length);
+
+ byte[] hData = sOut.ToArray();
+
+ sOut.WriteByte((byte)this.Version);
+ sOut.WriteByte((byte)0xff);
+ sOut.WriteByte((byte)(hData.Length>> 24));
+ sOut.WriteByte((byte)(hData.Length >> 16));
+ sOut.WriteByte((byte)(hData.Length >> 8));
+ sOut.WriteByte((byte)(hData.Length));
+
+ trailer = sOut.ToArray();
+ }
+
+ return trailer;
+ }
+
+ public PublicKeyAlgorithmTag KeyAlgorithm
+ {
+ get { return keyAlgorithm; }
+ }
+
+ public HashAlgorithmTag HashAlgorithm
+ {
+ get { return hashAlgorithm; }
+ }
+
+ /**
+ * return the signature as a set of integers - note this is normalised to be the
+ * ASN.1 encoding of what appears in the signature packet.
+ */
+ public MPInteger[] GetSignature()
+ {
+ return signature;
+ }
+
+ /**
+ * Return the byte encoding of the signature section.
+ * @return uninterpreted signature bytes.
+ */
+ public byte[] GetSignatureBytes()
+ {
+ if (signatureEncoding != null)
+ {
+ return (byte[]) signatureEncoding.Clone();
+ }
+
+ MemoryStream bOut = new MemoryStream();
+ BcpgOutputStream bcOut = new BcpgOutputStream(bOut);
+
+ foreach (MPInteger sigObj in signature)
+ {
+ try
+ {
+ bcOut.WriteObject(sigObj);
+ }
+ catch (IOException e)
+ {
+ throw new Exception("internal error: " + e);
+ }
+ }
+
+ return bOut.ToArray();
+ }
+
+ public SignatureSubpacket[] GetHashedSubPackets()
+ {
+ return hashedData;
+ }
+
+ public SignatureSubpacket[] GetUnhashedSubPackets()
+ {
+ return unhashedData;
+ }
+
+ /// Return the creation time in milliseconds since 1 Jan., 1970 UTC.
+ public long CreationTime
+ {
+ get { return creationTime; }
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ MemoryStream bOut = new MemoryStream();
+ BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+ pOut.WriteByte((byte) version);
+
+ if (version == 3 || version == 2)
+ {
+ pOut.Write(
+ 5, // the length of the next block
+ (byte) signatureType);
+
+ pOut.WriteInt((int)(creationTime / 1000L));
+
+ pOut.WriteLong(keyId);
+
+ pOut.Write(
+ (byte) keyAlgorithm,
+ (byte) hashAlgorithm);
+ }
+ else if (version == 4)
+ {
+ pOut.Write(
+ (byte) signatureType,
+ (byte) keyAlgorithm,
+ (byte) hashAlgorithm);
+
+ EncodeLengthAndData(pOut, GetEncodedSubpackets(hashedData));
+
+ EncodeLengthAndData(pOut, GetEncodedSubpackets(unhashedData));
+ }
+ else
+ {
+ throw new IOException("unknown version: " + version);
+ }
+
+ pOut.Write(fingerprint);
+
+ if (signature != null)
+ {
+ pOut.WriteObjects(signature);
+ }
+ else
+ {
+ pOut.Write(signatureEncoding);
+ }
+
+ bcpgOut.WritePacket(PacketTag.Signature, bOut.ToArray(), true);
+ }
+
+ private static void EncodeLengthAndData(
+ BcpgOutputStream pOut,
+ byte[] data)
+ {
+ pOut.WriteShort((short) data.Length);
+ pOut.Write(data);
+ }
+
+ private static byte[] GetEncodedSubpackets(
+ SignatureSubpacket[] ps)
+ {
+ MemoryStream sOut = new MemoryStream();
+
+ foreach (SignatureSubpacket p in ps)
+ {
+ p.Encode(sOut);
+ }
+
+ return sOut.ToArray();
+ }
+
+ private void setCreationTime()
+ {
+ foreach (SignatureSubpacket p in hashedData)
+ {
+ if (p is SignatureCreationTime)
+ {
+ creationTime = DateTimeUtilities.DateTimeToUnixMs(
+ ((SignatureCreationTime)p).GetTime());
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/SignatureSubpacket.cs b/bc-sharp-crypto/src/bcpg/SignatureSubpacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d993155998b9c68a5190eab51c3af4959c20a55b
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/SignatureSubpacket.cs
@@ -0,0 +1,94 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Basic type for a PGP Signature sub-packet.
+ public class SignatureSubpacket
+ {
+ private readonly SignatureSubpacketTag type;
+ private readonly bool critical;
+ private readonly bool isLongLength;
+ internal byte[] data;
+
+ protected internal SignatureSubpacket(
+ SignatureSubpacketTag type,
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ {
+ this.type = type;
+ this.critical = critical;
+ this.isLongLength = isLongLength;
+ this.data = data;
+ }
+
+ public SignatureSubpacketTag SubpacketType
+ {
+ get { return type; }
+ }
+
+ public bool IsCritical()
+ {
+ return critical;
+ }
+
+ public bool IsLongLength()
+ {
+ return isLongLength;
+ }
+
+ /// Return the generic data making up the packet.
+ public byte[] GetData()
+ {
+ return (byte[]) data.Clone();
+ }
+
+ public void Encode(
+ Stream os)
+ {
+ int bodyLen = data.Length + 1;
+
+ if (isLongLength)
+ {
+ os.WriteByte(0xff);
+ os.WriteByte((byte)(bodyLen >> 24));
+ os.WriteByte((byte)(bodyLen >> 16));
+ os.WriteByte((byte)(bodyLen >> 8));
+ os.WriteByte((byte)bodyLen);
+ }
+ else
+ {
+ if (bodyLen < 192)
+ {
+ os.WriteByte((byte)bodyLen);
+ }
+ else if (bodyLen <= 8383)
+ {
+ bodyLen -= 192;
+
+ os.WriteByte((byte)(((bodyLen >> 8) & 0xff) + 192));
+ os.WriteByte((byte)bodyLen);
+ }
+ else
+ {
+ os.WriteByte(0xff);
+ os.WriteByte((byte)(bodyLen >> 24));
+ os.WriteByte((byte)(bodyLen >> 16));
+ os.WriteByte((byte)(bodyLen >> 8));
+ os.WriteByte((byte)bodyLen);
+ }
+ }
+
+ if (critical)
+ {
+ os.WriteByte((byte)(0x80 | (int) type));
+ }
+ else
+ {
+ os.WriteByte((byte) type);
+ }
+
+ os.Write(data, 0, data.Length);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/SignatureSubpacketTags.cs b/bc-sharp-crypto/src/bcpg/SignatureSubpacketTags.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1a8e254c091adcd6039cf2a5648ea29e225bfffa
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/SignatureSubpacketTags.cs
@@ -0,0 +1,33 @@
+namespace Org.BouncyCastle.Bcpg
+{
+ /**
+ * Basic PGP signature sub-packet tag types.
+ */
+ public enum SignatureSubpacketTag
+ {
+ CreationTime = 2, // signature creation time
+ ExpireTime = 3, // signature expiration time
+ Exportable = 4, // exportable certification
+ TrustSig = 5, // trust signature
+ RegExp = 6, // regular expression
+ Revocable = 7, // revocable
+ KeyExpireTime = 9, // key expiration time
+ Placeholder = 10, // placeholder for backward compatibility
+ PreferredSymmetricAlgorithms = 11, // preferred symmetric algorithms
+ RevocationKey = 12, // revocation key
+ IssuerKeyId = 16, // issuer key ID
+ NotationData = 20, // notation data
+ PreferredHashAlgorithms = 21, // preferred hash algorithms
+ PreferredCompressionAlgorithms = 22, // preferred compression algorithms
+ KeyServerPreferences = 23, // key server preferences
+ PreferredKeyServer = 24, // preferred key server
+ PrimaryUserId = 25, // primary user id
+ PolicyUrl = 26, // policy URL
+ KeyFlags = 27, // key flags
+ SignerUserId = 28, // signer's user id
+ RevocationReason = 29, // reason for revocation
+ Features = 30, // features
+ SignatureTarget = 31, // signature target
+ EmbeddedSignature = 32 // embedded signature
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/SignatureSubpacketsReader.cs b/bc-sharp-crypto/src/bcpg/SignatureSubpacketsReader.cs
new file mode 100644
index 0000000000000000000000000000000000000000..80bedb07cf0aeb279a087fa45fe0e5fc1a955139
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/SignatureSubpacketsReader.cs
@@ -0,0 +1,128 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Bcpg.Sig;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /**
+ * reader for signature sub-packets
+ */
+ public class SignatureSubpacketsParser
+ {
+ private readonly Stream input;
+
+ public SignatureSubpacketsParser(
+ Stream input)
+ {
+ this.input = input;
+ }
+
+ public SignatureSubpacket ReadPacket()
+ {
+ int l = input.ReadByte();
+ if (l < 0)
+ return null;
+
+ int bodyLen = 0;
+ bool isLongLength = false;
+
+ if (l < 192)
+ {
+ bodyLen = l;
+ }
+ else if (l <= 223)
+ {
+ bodyLen = ((l - 192) << 8) + (input.ReadByte()) + 192;
+ }
+ else if (l == 255)
+ {
+ isLongLength = true;
+ bodyLen = (input.ReadByte() << 24) | (input.ReadByte() << 16)
+ | (input.ReadByte() << 8) | input.ReadByte();
+ }
+ else
+ {
+ throw new IOException("unexpected length header");
+ }
+
+ int tag = input.ReadByte();
+ if (tag < 0)
+ throw new EndOfStreamException("unexpected EOF reading signature sub packet");
+
+ byte[] data = new byte[bodyLen - 1];
+
+ //
+ // this may seem a bit strange but it turns out some applications miscode the length
+ // in fixed length fields, so we check the length we do get, only throwing an exception if
+ // we really cannot continue
+ //
+ int bytesRead = Streams.ReadFully(input, data);
+
+ bool isCritical = ((tag & 0x80) != 0);
+ SignatureSubpacketTag type = (SignatureSubpacketTag)(tag & 0x7f);
+
+ if (bytesRead != data.Length)
+ {
+ switch (type)
+ {
+ case SignatureSubpacketTag.CreationTime:
+ data = CheckData(data, 4, bytesRead, "Signature Creation Time");
+ break;
+ case SignatureSubpacketTag.IssuerKeyId:
+ data = CheckData(data, 8, bytesRead, "Issuer");
+ break;
+ case SignatureSubpacketTag.KeyExpireTime:
+ data = CheckData(data, 4, bytesRead, "Signature Key Expiration Time");
+ break;
+ case SignatureSubpacketTag.ExpireTime:
+ data = CheckData(data, 4, bytesRead, "Signature Expiration Time");
+ break;
+ default:
+ throw new EndOfStreamException("truncated subpacket data.");
+ }
+ }
+
+ switch (type)
+ {
+ case SignatureSubpacketTag.CreationTime:
+ return new SignatureCreationTime(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.KeyExpireTime:
+ return new KeyExpirationTime(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.ExpireTime:
+ return new SignatureExpirationTime(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.Revocable:
+ return new Revocable(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.Exportable:
+ return new Exportable(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.IssuerKeyId:
+ return new IssuerKeyId(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.TrustSig:
+ return new TrustSignature(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.PreferredCompressionAlgorithms:
+ case SignatureSubpacketTag.PreferredHashAlgorithms:
+ case SignatureSubpacketTag.PreferredSymmetricAlgorithms:
+ return new PreferredAlgorithms(type, isCritical, isLongLength, data);
+ case SignatureSubpacketTag.KeyFlags:
+ return new KeyFlags(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.PrimaryUserId:
+ return new PrimaryUserId(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.SignerUserId:
+ return new SignerUserId(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.NotationData:
+ return new NotationData(isCritical, isLongLength, data);
+ }
+ return new SignatureSubpacket(type, isCritical, isLongLength, data);
+ }
+
+ private byte[] CheckData(byte[] data, int expected, int bytesRead, string name)
+ {
+ if (bytesRead != expected)
+ throw new EndOfStreamException("truncated " + name + " subpacket data.");
+
+ return Arrays.CopyOfRange(data, 0, expected);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/SymmetricEncDataPacket.cs b/bc-sharp-crypto/src/bcpg/SymmetricEncDataPacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..17ee55bb73167b52b6cc790d0e12ebfef42f84cb
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/SymmetricEncDataPacket.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Basic type for a symmetric key encrypted packet.
+ public class SymmetricEncDataPacket
+ : InputStreamPacket
+ {
+ public SymmetricEncDataPacket(
+ BcpgInputStream bcpgIn)
+ : base(bcpgIn)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/SymmetricEncIntegrityPacket.cs b/bc-sharp-crypto/src/bcpg/SymmetricEncIntegrityPacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a9b6d06782c248f8ac37c9bb87bc519611d3fbcb
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/SymmetricEncIntegrityPacket.cs
@@ -0,0 +1,18 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ public class SymmetricEncIntegrityPacket
+ : InputStreamPacket
+ {
+ internal readonly int version;
+
+ internal SymmetricEncIntegrityPacket(
+ BcpgInputStream bcpgIn)
+ : base(bcpgIn)
+ {
+ version = bcpgIn.ReadByte();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/SymmetricKeyAlgorithmTags.cs b/bc-sharp-crypto/src/bcpg/SymmetricKeyAlgorithmTags.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e05a486163bebb43b202fda4fcab994ecfb35244
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/SymmetricKeyAlgorithmTags.cs
@@ -0,0 +1,23 @@
+namespace Org.BouncyCastle.Bcpg
+{
+ /**
+ * Basic tags for symmetric key algorithms
+ */
+ public enum SymmetricKeyAlgorithmTag
+ {
+ Null = 0, // Plaintext or unencrypted data
+ Idea = 1, // IDEA [IDEA]
+ TripleDes = 2, // Triple-DES (DES-EDE, as per spec -168 bit key derived from 192)
+ Cast5 = 3, // Cast5 (128 bit key, as per RFC 2144)
+ Blowfish = 4, // Blowfish (128 bit key, 16 rounds) [Blowfish]
+ Safer = 5, // Safer-SK128 (13 rounds) [Safer]
+ Des = 6, // Reserved for DES/SK
+ Aes128 = 7, // Reserved for AES with 128-bit key
+ Aes192 = 8, // Reserved for AES with 192-bit key
+ Aes256 = 9, // Reserved for AES with 256-bit key
+ Twofish = 10, // Reserved for Twofish
+ Camellia128 = 11, // Reserved for AES with 128-bit key
+ Camellia192 = 12, // Reserved for AES with 192-bit key
+ Camellia256 = 13 // Reserved for AES with 256-bit key
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/SymmetricKeyEncSessionPacket.cs b/bc-sharp-crypto/src/bcpg/SymmetricKeyEncSessionPacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0381fa38654c8d3121b08f32b078c40029ffbccb
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/SymmetricKeyEncSessionPacket.cs
@@ -0,0 +1,91 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /**
+ * Basic type for a symmetric encrypted session key packet
+ */
+ public class SymmetricKeyEncSessionPacket
+ : ContainedPacket
+ {
+ private int version;
+ private SymmetricKeyAlgorithmTag encAlgorithm;
+ private S2k s2k;
+ private readonly byte[] secKeyData;
+
+ public SymmetricKeyEncSessionPacket(
+ BcpgInputStream bcpgIn)
+ {
+ version = bcpgIn.ReadByte();
+ encAlgorithm = (SymmetricKeyAlgorithmTag) bcpgIn.ReadByte();
+
+ s2k = new S2k(bcpgIn);
+
+ secKeyData = bcpgIn.ReadAll();
+ }
+
+ public SymmetricKeyEncSessionPacket(
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ S2k s2k,
+ byte[] secKeyData)
+ {
+ this.version = 4;
+ this.encAlgorithm = encAlgorithm;
+ this.s2k = s2k;
+ this.secKeyData = secKeyData;
+ }
+
+ /**
+ * @return int
+ */
+ public SymmetricKeyAlgorithmTag EncAlgorithm
+ {
+ get { return encAlgorithm; }
+ }
+
+ /**
+ * @return S2k
+ */
+ public S2k S2k
+ {
+ get { return s2k; }
+ }
+
+ /**
+ * @return byte[]
+ */
+ public byte[] GetSecKeyData()
+ {
+ return secKeyData;
+ }
+
+ /**
+ * @return int
+ */
+ public int Version
+ {
+ get { return version; }
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ MemoryStream bOut = new MemoryStream();
+ BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+ pOut.Write(
+ (byte) version,
+ (byte) encAlgorithm);
+
+ pOut.WriteObject(s2k);
+
+ if (secKeyData != null && secKeyData.Length > 0)
+ {
+ pOut.Write(secKeyData);
+ }
+
+ bcpgOut.WritePacket(PacketTag.SymmetricKeyEncryptedSessionKey, bOut.ToArray(), true);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/TrustPacket.cs b/bc-sharp-crypto/src/bcpg/TrustPacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6f1969c2a70c028a74eaa457341931e7fcca9999
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/TrustPacket.cs
@@ -0,0 +1,43 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /// Basic type for a trust packet.
+ public class TrustPacket
+ : ContainedPacket
+ {
+ private readonly byte[] levelAndTrustAmount;
+
+ public TrustPacket(
+ BcpgInputStream bcpgIn)
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ int ch;
+ while ((ch = bcpgIn.ReadByte()) >= 0)
+ {
+ bOut.WriteByte((byte) ch);
+ }
+
+ levelAndTrustAmount = bOut.ToArray();
+ }
+
+ public TrustPacket(
+ int trustCode)
+ {
+ this.levelAndTrustAmount = new byte[]{ (byte) trustCode };
+ }
+
+ public byte[] GetLevelAndTrustAmount()
+ {
+ return (byte[]) levelAndTrustAmount.Clone();
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WritePacket(PacketTag.Trust, levelAndTrustAmount, true);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/UserAttributePacket.cs b/bc-sharp-crypto/src/bcpg/UserAttributePacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..20e3598ab6f11967f390a957715f7def8aa9056e
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/UserAttributePacket.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /**
+ * Basic type for a user attribute packet.
+ */
+ public class UserAttributePacket
+ : ContainedPacket
+ {
+ private readonly UserAttributeSubpacket[] subpackets;
+
+ public UserAttributePacket(
+ BcpgInputStream bcpgIn)
+ {
+ UserAttributeSubpacketsParser sIn = new UserAttributeSubpacketsParser(bcpgIn);
+ UserAttributeSubpacket sub;
+
+ IList v = Platform.CreateArrayList();
+ while ((sub = sIn.ReadPacket()) != null)
+ {
+ v.Add(sub);
+ }
+
+ subpackets = new UserAttributeSubpacket[v.Count];
+
+ for (int i = 0; i != subpackets.Length; i++)
+ {
+ subpackets[i] = (UserAttributeSubpacket)v[i];
+ }
+ }
+
+ public UserAttributePacket(
+ UserAttributeSubpacket[] subpackets)
+ {
+ this.subpackets = subpackets;
+ }
+
+ public UserAttributeSubpacket[] GetSubpackets()
+ {
+ return subpackets;
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ for (int i = 0; i != subpackets.Length; i++)
+ {
+ subpackets[i].Encode(bOut);
+ }
+
+ bcpgOut.WritePacket(PacketTag.UserAttribute, bOut.ToArray(), false);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/UserAttributeSubpacket.cs b/bc-sharp-crypto/src/bcpg/UserAttributeSubpacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..05f60ac1711af3b4fbb592de0e5f0f977799a290
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/UserAttributeSubpacket.cs
@@ -0,0 +1,90 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /**
+ * Basic type for a user attribute sub-packet.
+ */
+ public class UserAttributeSubpacket
+ {
+ internal readonly UserAttributeSubpacketTag type;
+ private readonly bool longLength; // we preserve this as not everyone encodes length properly.
+ protected readonly byte[] data;
+
+ protected internal UserAttributeSubpacket(UserAttributeSubpacketTag type, byte[] data)
+ : this(type, false, data)
+ {
+ }
+
+ protected internal UserAttributeSubpacket(UserAttributeSubpacketTag type, bool forceLongLength, byte[] data)
+ {
+ this.type = type;
+ this.longLength = forceLongLength;
+ this.data = data;
+ }
+
+ public virtual UserAttributeSubpacketTag SubpacketType
+ {
+ get { return type; }
+ }
+
+ /**
+ * return the generic data making up the packet.
+ */
+ public virtual byte[] GetData()
+ {
+ return data;
+ }
+
+ public virtual void Encode(Stream os)
+ {
+ int bodyLen = data.Length + 1;
+
+ if (bodyLen < 192 && !longLength)
+ {
+ os.WriteByte((byte)bodyLen);
+ }
+ else if (bodyLen <= 8383 && !longLength)
+ {
+ bodyLen -= 192;
+
+ os.WriteByte((byte)(((bodyLen >> 8) & 0xff) + 192));
+ os.WriteByte((byte)bodyLen);
+ }
+ else
+ {
+ os.WriteByte(0xff);
+ os.WriteByte((byte)(bodyLen >> 24));
+ os.WriteByte((byte)(bodyLen >> 16));
+ os.WriteByte((byte)(bodyLen >> 8));
+ os.WriteByte((byte)bodyLen);
+ }
+
+ os.WriteByte((byte) type);
+ os.Write(data, 0, data.Length);
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ UserAttributeSubpacket other = obj as UserAttributeSubpacket;
+
+ if (other == null)
+ return false;
+
+ return type == other.type
+ && Arrays.AreEqual(data, other.data);
+ }
+
+ public override int GetHashCode()
+ {
+ return type.GetHashCode() ^ Arrays.GetHashCode(data);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/UserAttributeSubpacketTags.cs b/bc-sharp-crypto/src/bcpg/UserAttributeSubpacketTags.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7a9cd1d5d62c332fa60cf53fa158f35b17005598
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/UserAttributeSubpacketTags.cs
@@ -0,0 +1,10 @@
+namespace Org.BouncyCastle.Bcpg
+{
+ /**
+ * Basic PGP user attribute sub-packet tag types.
+ */
+ public enum UserAttributeSubpacketTag
+ {
+ ImageAttribute = 1
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/UserAttributeSubpacketsReader.cs b/bc-sharp-crypto/src/bcpg/UserAttributeSubpacketsReader.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f0cc1b8e41413eb6ff947d4401bba86f8e1e7200
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/UserAttributeSubpacketsReader.cs
@@ -0,0 +1,65 @@
+using System;
+using System.IO;
+using Org.BouncyCastle.Bcpg.Attr;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /**
+ * reader for user attribute sub-packets
+ */
+ public class UserAttributeSubpacketsParser
+ {
+ private readonly Stream input;
+
+ public UserAttributeSubpacketsParser(
+ Stream input)
+ {
+ this.input = input;
+ }
+
+ public virtual UserAttributeSubpacket ReadPacket()
+ {
+ int l = input.ReadByte();
+ if (l < 0)
+ return null;
+
+ int bodyLen = 0;
+ bool longLength = false;
+ if (l < 192)
+ {
+ bodyLen = l;
+ }
+ else if (l <= 223)
+ {
+ bodyLen = ((l - 192) << 8) + (input.ReadByte()) + 192;
+ }
+ else if (l == 255)
+ {
+ bodyLen = (input.ReadByte() << 24) | (input.ReadByte() << 16)
+ | (input.ReadByte() << 8) | input.ReadByte();
+ longLength = true;
+ }
+ else
+ {
+ throw new IOException("unrecognised length reading user attribute sub packet");
+ }
+
+ int tag = input.ReadByte();
+ if (tag < 0)
+ throw new EndOfStreamException("unexpected EOF reading user attribute sub packet");
+
+ byte[] data = new byte[bodyLen - 1];
+ if (Streams.ReadFully(input, data) < data.Length)
+ throw new EndOfStreamException();
+
+ UserAttributeSubpacketTag type = (UserAttributeSubpacketTag) tag;
+ switch (type)
+ {
+ case UserAttributeSubpacketTag.ImageAttribute:
+ return new ImageAttrib(longLength, data);
+ }
+ return new UserAttributeSubpacket(type, longLength, data);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/UserIdPacket.cs b/bc-sharp-crypto/src/bcpg/UserIdPacket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a175e74a618cc4ed5ab871b77d8ce336ffc07e77
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/UserIdPacket.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ /**
+ * Basic type for a user ID packet.
+ */
+ public class UserIdPacket
+ : ContainedPacket
+ {
+ private readonly byte[] idData;
+
+ public UserIdPacket(
+ BcpgInputStream bcpgIn)
+ {
+ this.idData = bcpgIn.ReadAll();
+ }
+
+ public UserIdPacket(
+ string id)
+ {
+ this.idData = Encoding.UTF8.GetBytes(id);
+ }
+
+ public string GetId()
+ {
+ return Encoding.UTF8.GetString(idData, 0, idData.Length);
+ }
+
+ public override void Encode(
+ BcpgOutputStream bcpgOut)
+ {
+ bcpgOut.WritePacket(PacketTag.UserId, idData, true);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/attr/ImageAttrib.cs b/bc-sharp-crypto/src/bcpg/attr/ImageAttrib.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2d0fef8b832306b3088199a7b805641e457e0cbd
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/attr/ImageAttrib.cs
@@ -0,0 +1,72 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg.Attr
+{
+ /// Basic type for a image attribute packet.
+ public class ImageAttrib
+ : UserAttributeSubpacket
+ {
+ public enum Format : byte
+ {
+ Jpeg = 1
+ }
+
+ private static readonly byte[] Zeroes = new byte[12];
+
+ private int hdrLength;
+ private int _version;
+ private int _encoding;
+ private byte[] imageData;
+
+ public ImageAttrib(byte[] data)
+ : this(false, data)
+ {
+ }
+
+ public ImageAttrib(bool forceLongLength, byte[] data)
+ : base(UserAttributeSubpacketTag.ImageAttribute, forceLongLength, data)
+ {
+ hdrLength = ((data[1] & 0xff) << 8) | (data[0] & 0xff);
+ _version = data[2] & 0xff;
+ _encoding = data[3] & 0xff;
+
+ imageData = new byte[data.Length - hdrLength];
+ Array.Copy(data, hdrLength, imageData, 0, imageData.Length);
+ }
+
+ public ImageAttrib(
+ Format imageType,
+ byte[] imageData)
+ : this(ToByteArray(imageType, imageData))
+ {
+ }
+
+ private static byte[] ToByteArray(
+ Format imageType,
+ byte[] imageData)
+ {
+ MemoryStream bOut = new MemoryStream();
+ bOut.WriteByte(0x10); bOut.WriteByte(0x00); bOut.WriteByte(0x01);
+ bOut.WriteByte((byte) imageType);
+ bOut.Write(Zeroes, 0, Zeroes.Length);
+ bOut.Write(imageData, 0, imageData.Length);
+ return bOut.ToArray();
+ }
+
+ public virtual int Version
+ {
+ get { return _version; }
+ }
+
+ public virtual int Encoding
+ {
+ get { return _encoding; }
+ }
+
+ public virtual byte[] GetImageData()
+ {
+ return imageData;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/sig/EmbeddedSignature.cs b/bc-sharp-crypto/src/bcpg/sig/EmbeddedSignature.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fffdaef73f5bfe0091db4d74503fbfcb53dbc4dc
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/sig/EmbeddedSignature.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+ /**
+ * Packet embedded signature
+ */
+ public class EmbeddedSignature
+ : SignatureSubpacket
+ {
+ public EmbeddedSignature(
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.EmbeddedSignature, critical, isLongLength, data)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/sig/Exportable.cs b/bc-sharp-crypto/src/bcpg/sig/Exportable.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4d030346f13a83b44615f7366d7e79da1e52e1e0
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/sig/Exportable.cs
@@ -0,0 +1,46 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+ /**
+ * packet giving signature creation time.
+ */
+ public class Exportable
+ : SignatureSubpacket
+ {
+ private static byte[] BooleanToByteArray(bool val)
+ {
+ byte[] data = new byte[1];
+
+ if (val)
+ {
+ data[0] = 1;
+ return data;
+ }
+ else
+ {
+ return data;
+ }
+ }
+
+ public Exportable(
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.Exportable, critical, isLongLength, data)
+ {
+ }
+
+ public Exportable(
+ bool critical,
+ bool isExportable)
+ : base(SignatureSubpacketTag.Exportable, critical, false, BooleanToByteArray(isExportable))
+ {
+ }
+
+ public bool IsExportable()
+ {
+ return data[0] != 0;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/sig/Features.cs b/bc-sharp-crypto/src/bcpg/sig/Features.cs
new file mode 100644
index 0000000000000000000000000000000000000000..29584239a52043783c043caffe688346541e4d81
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/sig/Features.cs
@@ -0,0 +1,75 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+ /**
+ * packet giving signature expiration time.
+ */
+ public class Features
+ : SignatureSubpacket
+ {
+ /** Identifier for the modification detection feature */
+ public static readonly byte FEATURE_MODIFICATION_DETECTION = 1;
+
+ private static byte[] FeatureToByteArray(byte feature)
+ {
+ return new byte[]{ feature };
+ }
+
+ public Features(
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.Features, critical, isLongLength, data)
+ {
+ }
+
+ public Features(bool critical, byte feature)
+ : base(SignatureSubpacketTag.Features, critical, false, FeatureToByteArray(feature))
+ {
+ }
+
+ /**
+ * Returns if modification detection is supported.
+ */
+ public bool SupportsModificationDetection
+ {
+ get { return SupportsFeature(FEATURE_MODIFICATION_DETECTION); }
+ }
+
+ /**
+ * Returns if a particular feature is supported.
+ */
+ public bool SupportsFeature(byte feature)
+ {
+ return Array.IndexOf(data, feature) >= 0;
+ }
+
+ /**
+ * Sets support for a particular feature.
+ */
+ private void SetSupportsFeature(byte feature, bool support)
+ {
+ if (feature == 0)
+ throw new ArgumentException("cannot be 0", "feature");
+
+ int i = Array.IndexOf(data, feature);
+ if ((i >= 0) == support)
+ return;
+
+ if (support)
+ {
+ data = Arrays.Append(data, feature);
+ }
+ else
+ {
+ byte[] temp = new byte[data.Length - 1];
+ Array.Copy(data, 0, temp, 0, i);
+ Array.Copy(data, i + 1, temp, i, temp.Length - i);
+ data = temp;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/sig/IssuerKeyId.cs b/bc-sharp-crypto/src/bcpg/sig/IssuerKeyId.cs
new file mode 100644
index 0000000000000000000000000000000000000000..627ea3ecf361fbea9d213e7f948ced838be79019
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/sig/IssuerKeyId.cs
@@ -0,0 +1,62 @@
+using System;
+
+
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+ /**
+ * packet giving signature creation time.
+ */
+ public class IssuerKeyId
+ : SignatureSubpacket
+ {
+ protected static byte[] KeyIdToBytes(
+ long keyId)
+ {
+ byte[] data = new byte[8];
+
+ data[0] = (byte)(keyId >> 56);
+ data[1] = (byte)(keyId >> 48);
+ data[2] = (byte)(keyId >> 40);
+ data[3] = (byte)(keyId >> 32);
+ data[4] = (byte)(keyId >> 24);
+ data[5] = (byte)(keyId >> 16);
+ data[6] = (byte)(keyId >> 8);
+ data[7] = (byte)keyId;
+
+ return data;
+ }
+
+ public IssuerKeyId(
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.IssuerKeyId, critical, isLongLength, data)
+ {
+ }
+
+ public IssuerKeyId(
+ bool critical,
+ long keyId)
+ : base(SignatureSubpacketTag.IssuerKeyId, critical, false, KeyIdToBytes(keyId))
+ {
+ }
+
+ public long KeyId
+ {
+ get
+ {
+ long keyId = ((long)(data[0] & 0xff) << 56)
+ | ((long)(data[1] & 0xff) << 48)
+ | ((long)(data[2] & 0xff) << 40)
+ | ((long)(data[3] & 0xff) << 32)
+ | ((long)(data[4] & 0xff) << 24)
+ | ((long)(data[5] & 0xff) << 16)
+ | ((long)(data[6] & 0xff) << 8)
+ | ((long)data[7] & 0xff);
+
+ return keyId;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/sig/KeyExpirationTime.cs b/bc-sharp-crypto/src/bcpg/sig/KeyExpirationTime.cs
new file mode 100644
index 0000000000000000000000000000000000000000..dfd3e76fdd14a661a4312d4d6274b30457bfa6e8
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/sig/KeyExpirationTime.cs
@@ -0,0 +1,55 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+ /**
+ * packet giving time after creation at which the key expires.
+ */
+ public class KeyExpirationTime
+ : SignatureSubpacket
+ {
+ protected static byte[] TimeToBytes(
+ long t)
+ {
+ byte[] data = new byte[4];
+
+ data[0] = (byte)(t >> 24);
+ data[1] = (byte)(t >> 16);
+ data[2] = (byte)(t >> 8);
+ data[3] = (byte)t;
+
+ return data;
+ }
+
+ public KeyExpirationTime(
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.KeyExpireTime, critical, isLongLength, data)
+ {
+ }
+
+ public KeyExpirationTime(
+ bool critical,
+ long seconds)
+ : base(SignatureSubpacketTag.KeyExpireTime, critical, false, TimeToBytes(seconds))
+ {
+ }
+
+ /**
+ * Return the number of seconds after creation time a key is valid for.
+ *
+ * @return second count for key validity.
+ */
+ public long Time
+ {
+ get
+ {
+ long time = ((long)(data[0] & 0xff) << 24) | ((long)(data[1] & 0xff) << 16)
+ | ((long)(data[2] & 0xff) << 8) | ((long)data[3] & 0xff);
+
+ return time;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/sig/KeyFlags.cs b/bc-sharp-crypto/src/bcpg/sig/KeyFlags.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5b5d85a72072cd69b92f70c70fb26aa286be58b7
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/sig/KeyFlags.cs
@@ -0,0 +1,75 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+ /**
+ * Packet holding the key flag values.
+ */
+ public class KeyFlags
+ : SignatureSubpacket
+ {
+ public const int CertifyOther = 0x01;
+ public const int SignData = 0x02;
+ public const int EncryptComms = 0x04;
+ public const int EncryptStorage = 0x08;
+ public const int Split = 0x10;
+ public const int Authentication = 0x20;
+ public const int Shared = 0x80;
+
+ private static byte[] IntToByteArray(
+ int v)
+ {
+ byte[] tmp = new byte[4];
+ int size = 0;
+
+ for (int i = 0; i != 4; i++)
+ {
+ tmp[i] = (byte)(v >> (i * 8));
+ if (tmp[i] != 0)
+ {
+ size = i;
+ }
+ }
+
+ byte[] data = new byte[size + 1];
+ Array.Copy(tmp, 0, data, 0, data.Length);
+ return data;
+ }
+
+ public KeyFlags(
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.KeyFlags, critical, isLongLength, data)
+ {
+ }
+
+ public KeyFlags(
+ bool critical,
+ int flags)
+ : base(SignatureSubpacketTag.KeyFlags, critical, false, IntToByteArray(flags))
+ {
+ }
+
+ ///
+ /// Return the flag values contained in the first 4 octets (note: at the moment
+ /// the standard only uses the first one).
+ ///
+ public int Flags
+ {
+ get
+ {
+ int flags = 0;
+
+ for (int i = 0; i != data.Length; i++)
+ {
+ flags |= (data[i] & 0xff) << (i * 8);
+ }
+
+ return flags;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/sig/NotationData.cs b/bc-sharp-crypto/src/bcpg/sig/NotationData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9ac6f89cfddf1827b60beada28ab0c7ddf6dd19e
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/sig/NotationData.cs
@@ -0,0 +1,113 @@
+using System;
+using System.IO;
+using System.Text;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+ /**
+ * Class provided a NotationData object according to
+ * RFC2440, Chapter 5.2.3.15. Notation Data
+ */
+ public class NotationData
+ : SignatureSubpacket
+ {
+ public const int HeaderFlagLength = 4;
+ public const int HeaderNameLength = 2;
+ public const int HeaderValueLength = 2;
+
+ public NotationData(
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.NotationData, critical, isLongLength, data)
+ {
+ }
+
+ public NotationData(
+ bool critical,
+ bool humanReadable,
+ string notationName,
+ string notationValue)
+ : base(SignatureSubpacketTag.NotationData, critical, false,
+ CreateData(humanReadable, notationName, notationValue))
+ {
+ }
+
+ private static byte[] CreateData(
+ bool humanReadable,
+ string notationName,
+ string notationValue)
+ {
+ MemoryStream os = new MemoryStream();
+
+ // (4 octets of flags, 2 octets of name length (M),
+ // 2 octets of value length (N),
+ // M octets of name data,
+ // N octets of value data)
+
+ // flags
+ os.WriteByte(humanReadable ? (byte)0x80 : (byte)0x00);
+ os.WriteByte(0x0);
+ os.WriteByte(0x0);
+ os.WriteByte(0x0);
+
+ byte[] nameData, valueData = null;
+ int nameLength, valueLength;
+
+ nameData = Encoding.UTF8.GetBytes(notationName);
+ nameLength = System.Math.Min(nameData.Length, 0xFF);
+
+ valueData = Encoding.UTF8.GetBytes(notationValue);
+ valueLength = System.Math.Min(valueData.Length, 0xFF);
+
+ // name length
+ os.WriteByte((byte)(nameLength >> 8));
+ os.WriteByte((byte)(nameLength >> 0));
+
+ // value length
+ os.WriteByte((byte)(valueLength >> 8));
+ os.WriteByte((byte)(valueLength >> 0));
+
+ // name
+ os.Write(nameData, 0, nameLength);
+
+ // value
+ os.Write(valueData, 0, valueLength);
+
+ return os.ToArray();
+ }
+
+ public bool IsHumanReadable
+ {
+ get { return data[0] == (byte)0x80; }
+ }
+
+ public string GetNotationName()
+ {
+ int nameLength = ((data[HeaderFlagLength] << 8) + (data[HeaderFlagLength + 1] << 0));
+ int namePos = HeaderFlagLength + HeaderNameLength + HeaderValueLength;
+
+ return Encoding.UTF8.GetString(data, namePos, nameLength);
+ }
+
+ public string GetNotationValue()
+ {
+ int nameLength = ((data[HeaderFlagLength] << 8) + (data[HeaderFlagLength + 1] << 0));
+ int valueLength = ((data[HeaderFlagLength + HeaderNameLength] << 8) + (data[HeaderFlagLength + HeaderNameLength + 1] << 0));
+ int valuePos = HeaderFlagLength + HeaderNameLength + HeaderValueLength + nameLength;
+
+ return Encoding.UTF8.GetString(data, valuePos, valueLength);
+ }
+
+ public byte[] GetNotationValueBytes()
+ {
+ int nameLength = ((data[HeaderFlagLength] << 8) + (data[HeaderFlagLength + 1] << 0));
+ int valueLength = ((data[HeaderFlagLength + HeaderNameLength] << 8) + (data[HeaderFlagLength + HeaderNameLength + 1] << 0));
+ int valuePos = HeaderFlagLength + HeaderNameLength + HeaderValueLength + nameLength;
+
+ byte[] bytes = new byte[valueLength];
+ Array.Copy(data, valuePos, bytes, 0, valueLength);
+ return bytes;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/sig/PreferredAlgorithms.cs b/bc-sharp-crypto/src/bcpg/sig/PreferredAlgorithms.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9514bed2b8adc7a46f4ab8c09c11620cad9fc491
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/sig/PreferredAlgorithms.cs
@@ -0,0 +1,53 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+ /**
+ * packet giving signature creation time.
+ */
+ public class PreferredAlgorithms
+ : SignatureSubpacket
+ {
+ private static byte[] IntToByteArray(
+ int[] v)
+ {
+ byte[] data = new byte[v.Length];
+
+ for (int i = 0; i != v.Length; i++)
+ {
+ data[i] = (byte)v[i];
+ }
+
+ return data;
+ }
+
+ public PreferredAlgorithms(
+ SignatureSubpacketTag type,
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ : base(type, critical, isLongLength, data)
+ {
+ }
+
+ public PreferredAlgorithms(
+ SignatureSubpacketTag type,
+ bool critical,
+ int[] preferences)
+ : base(type, critical, false, IntToByteArray(preferences))
+ {
+ }
+
+ public int[] GetPreferences()
+ {
+ int[] v = new int[data.Length];
+
+ for (int i = 0; i != v.Length; i++)
+ {
+ v[i] = data[i] & 0xff;
+ }
+
+ return v;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/sig/PrimaryUserId.cs b/bc-sharp-crypto/src/bcpg/sig/PrimaryUserId.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1f16f40eb589e999046d09badccea64ca5c077f1
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/sig/PrimaryUserId.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+ /**
+ * packet giving whether or not the signature is signed using the primary user ID for the key.
+ */
+ public class PrimaryUserId
+ : SignatureSubpacket
+ {
+ private static byte[] BooleanToByteArray(
+ bool val)
+ {
+ byte[] data = new byte[1];
+
+ if (val)
+ {
+ data[0] = 1;
+ return data;
+ }
+ else
+ {
+ return data;
+ }
+ }
+
+ public PrimaryUserId(
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.PrimaryUserId, critical, isLongLength, data)
+ {
+ }
+
+ public PrimaryUserId(
+ bool critical,
+ bool isPrimaryUserId)
+ : base(SignatureSubpacketTag.PrimaryUserId, critical, false, BooleanToByteArray(isPrimaryUserId))
+ {
+ }
+
+ public bool IsPrimaryUserId()
+ {
+ return data[0] != 0;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/sig/Revocable.cs b/bc-sharp-crypto/src/bcpg/sig/Revocable.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7aa91391f9cee9d5fbbb3c35885fc49f4f2ba072
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/sig/Revocable.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+ /**
+ * packet giving whether or not is revocable.
+ */
+ public class Revocable
+ : SignatureSubpacket
+ {
+ private static byte[] BooleanToByteArray(
+ bool value)
+ {
+ byte[] data = new byte[1];
+
+ if (value)
+ {
+ data[0] = 1;
+ return data;
+ }
+ else
+ {
+ return data;
+ }
+ }
+
+ public Revocable(
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.Revocable, critical, isLongLength, data)
+ {
+ }
+
+ public Revocable(
+ bool critical,
+ bool isRevocable)
+ : base(SignatureSubpacketTag.Revocable, critical, false, BooleanToByteArray(isRevocable))
+ {
+ }
+
+ public bool IsRevocable()
+ {
+ return data[0] != 0;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/sig/RevocationKey.cs b/bc-sharp-crypto/src/bcpg/sig/RevocationKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..11467d2afc450d67af2b2a4e49849865d58254e9
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/sig/RevocationKey.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ ///
+ /// Represents revocation key OpenPGP signature sub packet.
+ ///
+ public class RevocationKey
+ : SignatureSubpacket
+ {
+ // 1 octet of class,
+ // 1 octet of public-key algorithm ID,
+ // 20 octets of fingerprint
+ public RevocationKey(
+ bool isCritical,
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.RevocationKey, isCritical, isLongLength, data)
+ {
+ }
+
+ public RevocationKey(
+ bool isCritical,
+ RevocationKeyTag signatureClass,
+ PublicKeyAlgorithmTag keyAlgorithm,
+ byte[] fingerprint)
+ : base(SignatureSubpacketTag.RevocationKey, isCritical, false,
+ CreateData(signatureClass, keyAlgorithm, fingerprint))
+ {
+ }
+
+ private static byte[] CreateData(
+ RevocationKeyTag signatureClass,
+ PublicKeyAlgorithmTag keyAlgorithm,
+ byte[] fingerprint)
+ {
+ byte[] data = new byte[2 + fingerprint.Length];
+ data[0] = (byte)signatureClass;
+ data[1] = (byte)keyAlgorithm;
+ Array.Copy(fingerprint, 0, data, 2, fingerprint.Length);
+ return data;
+ }
+
+ public virtual RevocationKeyTag SignatureClass
+ {
+ get { return (RevocationKeyTag)this.GetData()[0]; }
+ }
+
+ public virtual PublicKeyAlgorithmTag Algorithm
+ {
+ get { return (PublicKeyAlgorithmTag)this.GetData()[1]; }
+ }
+
+ public virtual byte[] GetFingerprint()
+ {
+ byte[] data = this.GetData();
+ byte[] fingerprint = new byte[data.Length - 2];
+ Array.Copy(data, 2, fingerprint, 0, fingerprint.Length);
+ return fingerprint;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/sig/RevocationKeyTags.cs b/bc-sharp-crypto/src/bcpg/sig/RevocationKeyTags.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d76d1dcf4d4b1a8302923432dc1c8ecc73f80f91
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/sig/RevocationKeyTags.cs
@@ -0,0 +1,9 @@
+namespace Org.BouncyCastle.Bcpg
+{
+ public enum RevocationKeyTag
+ : byte
+ {
+ ClassDefault = 0x80,
+ ClassSensitive = 0x40
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/sig/RevocationReason.cs b/bc-sharp-crypto/src/bcpg/sig/RevocationReason.cs
new file mode 100644
index 0000000000000000000000000000000000000000..42afd5f5b5173f3397a372ecccec7bdadcb7b503
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/sig/RevocationReason.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg
+{
+ ///
+ /// Represents revocation reason OpenPGP signature sub packet.
+ ///
+ public class RevocationReason
+ : SignatureSubpacket
+ {
+ public RevocationReason(bool isCritical, bool isLongLength, byte[] data)
+ : base(SignatureSubpacketTag.RevocationReason, isCritical, isLongLength, data)
+ {
+ }
+
+ public RevocationReason(
+ bool isCritical,
+ RevocationReasonTag reason,
+ string description)
+ : base(SignatureSubpacketTag.RevocationReason, isCritical, false, CreateData(reason, description))
+ {
+ }
+
+ private static byte[] CreateData(
+ RevocationReasonTag reason,
+ string description)
+ {
+ byte[] descriptionBytes = Strings.ToUtf8ByteArray(description);
+ byte[] data = new byte[1 + descriptionBytes.Length];
+
+ data[0] = (byte)reason;
+ Array.Copy(descriptionBytes, 0, data, 1, descriptionBytes.Length);
+
+ return data;
+ }
+
+ public virtual RevocationReasonTag GetRevocationReason()
+ {
+ return (RevocationReasonTag)GetData()[0];
+ }
+
+ public virtual string GetRevocationDescription()
+ {
+ byte[] data = GetData();
+ if (data.Length == 1)
+ {
+ return string.Empty;
+ }
+
+ byte[] description = new byte[data.Length - 1];
+ Array.Copy(data, 1, description, 0, description.Length);
+
+ return Strings.FromUtf8ByteArray(description);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/sig/RevocationReasonTags.cs b/bc-sharp-crypto/src/bcpg/sig/RevocationReasonTags.cs
new file mode 100644
index 0000000000000000000000000000000000000000..524a58c49a5d867a0f694026143697387e00b320
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/sig/RevocationReasonTags.cs
@@ -0,0 +1,14 @@
+namespace Org.BouncyCastle.Bcpg
+{
+ public enum RevocationReasonTag
+ : byte
+ {
+ NoReason = 0, // No reason specified (key revocations or cert revocations)
+ KeySuperseded = 1, // Key is superseded (key revocations)
+ KeyCompromised = 2, // Key material has been compromised (key revocations)
+ KeyRetired = 3, // Key is retired and no longer used (key revocations)
+ UserNoLongerValid = 32, // User ID information is no longer valid (cert revocations)
+
+ // 100-110 - Private Use
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/sig/SignatureCreationTime.cs b/bc-sharp-crypto/src/bcpg/sig/SignatureCreationTime.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d172e5d52a29a3110f0d4ff08e4a922d527238c0
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/sig/SignatureCreationTime.cs
@@ -0,0 +1,51 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+ /**
+ * packet giving signature creation time.
+ */
+ public class SignatureCreationTime
+ : SignatureSubpacket
+ {
+ protected static byte[] TimeToBytes(
+ DateTime time)
+ {
+ long t = DateTimeUtilities.DateTimeToUnixMs(time) / 1000L;
+ byte[] data = new byte[4];
+ data[0] = (byte)(t >> 24);
+ data[1] = (byte)(t >> 16);
+ data[2] = (byte)(t >> 8);
+ data[3] = (byte)t;
+ return data;
+ }
+
+ public SignatureCreationTime(
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.CreationTime, critical, isLongLength, data)
+ {
+ }
+
+ public SignatureCreationTime(
+ bool critical,
+ DateTime date)
+ : base(SignatureSubpacketTag.CreationTime, critical, false, TimeToBytes(date))
+ {
+ }
+
+ public DateTime GetTime()
+ {
+ long time = (long)(
+ ((uint)data[0] << 24)
+ | ((uint)data[1] << 16)
+ | ((uint)data[2] << 8)
+ | ((uint)data[3])
+ );
+ return DateTimeUtilities.UnixMsToDateTime(time * 1000L);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/sig/SignatureExpirationTime.cs b/bc-sharp-crypto/src/bcpg/sig/SignatureExpirationTime.cs
new file mode 100644
index 0000000000000000000000000000000000000000..24f0a9f8a96e4c1a16955b5bb56dc207a50f80be
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/sig/SignatureExpirationTime.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+ /**
+ * packet giving signature expiration time.
+ */
+ public class SignatureExpirationTime
+ : SignatureSubpacket
+ {
+ protected static byte[] TimeToBytes(
+ long t)
+ {
+ byte[] data = new byte[4];
+ data[0] = (byte)(t >> 24);
+ data[1] = (byte)(t >> 16);
+ data[2] = (byte)(t >> 8);
+ data[3] = (byte)t;
+ return data;
+ }
+
+ public SignatureExpirationTime(
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.ExpireTime, critical, isLongLength, data)
+ {
+ }
+
+ public SignatureExpirationTime(
+ bool critical,
+ long seconds)
+ : base(SignatureSubpacketTag.ExpireTime, critical, false, TimeToBytes(seconds))
+ {
+ }
+
+ /**
+ * return time in seconds before signature expires after creation time.
+ */
+ public long Time
+ {
+ get
+ {
+ long time = ((long)(data[0] & 0xff) << 24) | ((long)(data[1] & 0xff) << 16)
+ | ((long)(data[2] & 0xff) << 8) | ((long)data[3] & 0xff);
+
+ return time;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/sig/SignerUserId.cs b/bc-sharp-crypto/src/bcpg/sig/SignerUserId.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8ab62ed2ec6357dc8dd8b3cf511a8b1c9842a296
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/sig/SignerUserId.cs
@@ -0,0 +1,53 @@
+using System;
+
+
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+ /**
+ * packet giving the User ID of the signer.
+ */
+ public class SignerUserId
+ : SignatureSubpacket
+ {
+ private static byte[] UserIdToBytes(
+ string id)
+ {
+ byte[] idData = new byte[id.Length];
+
+ for (int i = 0; i != id.Length; i++)
+ {
+ idData[i] = (byte)id[i];
+ }
+
+ return idData;
+ }
+
+ public SignerUserId(
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.SignerUserId, critical, isLongLength, data)
+ {
+ }
+
+ public SignerUserId(
+ bool critical,
+ string userId)
+ : base(SignatureSubpacketTag.SignerUserId, critical, false, UserIdToBytes(userId))
+ {
+ }
+
+ public string GetId()
+ {
+ char[] chars = new char[data.Length];
+
+ for (int i = 0; i != chars.Length; i++)
+ {
+ chars[i] = (char)(data[i] & 0xff);
+ }
+
+ return new string(chars);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/bcpg/sig/TrustSignature.cs b/bc-sharp-crypto/src/bcpg/sig/TrustSignature.cs
new file mode 100644
index 0000000000000000000000000000000000000000..91458826df49b96b8fcb4b2acdf8eab3be88fafb
--- /dev/null
+++ b/bc-sharp-crypto/src/bcpg/sig/TrustSignature.cs
@@ -0,0 +1,44 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+ /**
+ * packet giving trust.
+ */
+ public class TrustSignature
+ : SignatureSubpacket
+ {
+ private static byte[] IntToByteArray(
+ int v1,
+ int v2)
+ {
+ return new byte[]{ (byte)v1, (byte)v2 };
+ }
+
+ public TrustSignature(
+ bool critical,
+ bool isLongLength,
+ byte[] data)
+ : base(SignatureSubpacketTag.TrustSig, critical, isLongLength, data)
+ {
+ }
+
+ public TrustSignature(
+ bool critical,
+ int depth,
+ int trustAmount)
+ : base(SignatureSubpacketTag.TrustSig, critical, false, IntToByteArray(depth, trustAmount))
+ {
+ }
+
+ public int Depth
+ {
+ get { return data[0] & 0xff; }
+ }
+
+ public int TrustAmount
+ {
+ get { return data[1] & 0xff; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/BaseDigestCalculator.cs b/bc-sharp-crypto/src/cms/BaseDigestCalculator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3dcbca75383ca576fac9a3feb3df7494369a79a9
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/BaseDigestCalculator.cs
@@ -0,0 +1,23 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Cms
+{
+ internal class BaseDigestCalculator
+ : IDigestCalculator
+ {
+ private readonly byte[] digest;
+
+ internal BaseDigestCalculator(
+ byte[] digest)
+ {
+ this.digest = digest;
+ }
+
+ public byte[] GetDigest()
+ {
+ return Arrays.Clone(digest);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSAttributeTableGenerationException.cs b/bc-sharp-crypto/src/cms/CMSAttributeTableGenerationException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..87dad99298dace0554828a0252203743ef60ee40
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSAttributeTableGenerationException.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Org.BouncyCastle.Cms
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class CmsAttributeTableGenerationException
+ : CmsException
+ {
+ public CmsAttributeTableGenerationException()
+ {
+ }
+
+ public CmsAttributeTableGenerationException(
+ string name)
+ : base(name)
+ {
+ }
+
+ public CmsAttributeTableGenerationException(
+ string name,
+ Exception e)
+ : base(name, e)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSAttributeTableGenerator.cs b/bc-sharp-crypto/src/cms/CMSAttributeTableGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..92c9a29d9fc382320e82c111f864188d78090f39
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSAttributeTableGenerator.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.Cms;
+
+namespace Org.BouncyCastle.Cms
+{
+ ///
+ /// The 'Signature' parameter is only available when generating unsigned attributes.
+ ///
+ public enum CmsAttributeTableParameter
+ {
+// const string ContentType = "contentType";
+// const string Digest = "digest";
+// const string Signature = "encryptedDigest";
+// const string DigestAlgorithmIdentifier = "digestAlgID";
+
+ ContentType, Digest, Signature, DigestAlgorithmIdentifier
+ }
+
+ public interface CmsAttributeTableGenerator
+ {
+ AttributeTable GetAttributes(IDictionary parameters);
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSAuthEnvelopedData.cs b/bc-sharp-crypto/src/cms/CMSAuthEnvelopedData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d35e946ae0eabb6d7fa0c0c5f38e7acbf00ed739
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSAuthEnvelopedData.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * containing class for an CMS AuthEnveloped Data object
+ */
+ internal class CmsAuthEnvelopedData
+ {
+ internal RecipientInformationStore recipientInfoStore;
+ internal ContentInfo contentInfo;
+
+ private OriginatorInfo originator;
+ private AlgorithmIdentifier authEncAlg;
+ private Asn1Set authAttrs;
+ private byte[] mac;
+ private Asn1Set unauthAttrs;
+
+ public CmsAuthEnvelopedData(
+ byte[] authEnvData)
+ : this(CmsUtilities.ReadContentInfo(authEnvData))
+ {
+ }
+
+ public CmsAuthEnvelopedData(
+ Stream authEnvData)
+ : this(CmsUtilities.ReadContentInfo(authEnvData))
+ {
+ }
+
+ public CmsAuthEnvelopedData(
+ ContentInfo contentInfo)
+ {
+ this.contentInfo = contentInfo;
+
+ AuthEnvelopedData authEnvData = AuthEnvelopedData.GetInstance(contentInfo.Content);
+
+ this.originator = authEnvData.OriginatorInfo;
+
+ //
+ // read the recipients
+ //
+ Asn1Set recipientInfos = authEnvData.RecipientInfos;
+
+ //
+ // read the auth-encrypted content info
+ //
+ EncryptedContentInfo authEncInfo = authEnvData.AuthEncryptedContentInfo;
+ this.authEncAlg = authEncInfo.ContentEncryptionAlgorithm;
+ CmsSecureReadable secureReadable = new AuthEnvelopedSecureReadable(this);
+
+ //
+ // build the RecipientInformationStore
+ //
+ this.recipientInfoStore = CmsEnvelopedHelper.BuildRecipientInformationStore(
+ recipientInfos, secureReadable);
+
+ // FIXME These need to be passed to the AEAD cipher as AAD (Additional Authenticated Data)
+ this.authAttrs = authEnvData.AuthAttrs;
+ this.mac = authEnvData.Mac.GetOctets();
+ this.unauthAttrs = authEnvData.UnauthAttrs;
+ }
+
+ private class AuthEnvelopedSecureReadable : CmsSecureReadable
+ {
+ private readonly CmsAuthEnvelopedData parent;
+
+ internal AuthEnvelopedSecureReadable(CmsAuthEnvelopedData parent)
+ {
+ this.parent = parent;
+ }
+
+ public AlgorithmIdentifier Algorithm
+ {
+ get { return parent.authEncAlg; }
+ }
+
+ public object CryptoObject
+ {
+ get { return null; }
+ }
+
+ public CmsReadable GetReadable(KeyParameter key)
+ {
+ // TODO Create AEAD cipher instance to decrypt and calculate tag ( MAC)
+ throw new CmsException("AuthEnveloped data decryption not yet implemented");
+
+// RFC 5084 ASN.1 Module
+// -- Parameters for AlgorithmIdentifier
+//
+// CCMParameters ::= SEQUENCE {
+// aes-nonce OCTET STRING (SIZE(7..13)),
+// aes-ICVlen AES-CCM-ICVlen DEFAULT 12 }
+//
+// AES-CCM-ICVlen ::= INTEGER (4 | 6 | 8 | 10 | 12 | 14 | 16)
+//
+// GCMParameters ::= SEQUENCE {
+// aes-nonce OCTET STRING, -- recommended size is 12 octets
+// aes-ICVlen AES-GCM-ICVlen DEFAULT 12 }
+//
+// AES-GCM-ICVlen ::= INTEGER (12 | 13 | 14 | 15 | 16)
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSAuthEnvelopedGenerator.cs b/bc-sharp-crypto/src/cms/CMSAuthEnvelopedGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4273cff293dce29e73c8311fed72936c97400e26
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSAuthEnvelopedGenerator.cs
@@ -0,0 +1,16 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Nist;
+
+namespace Org.BouncyCastle.Cms
+{
+ internal class CmsAuthEnvelopedGenerator
+ {
+ public static readonly string Aes128Ccm = NistObjectIdentifiers.IdAes128Ccm.Id;
+ public static readonly string Aes192Ccm = NistObjectIdentifiers.IdAes192Ccm.Id;
+ public static readonly string Aes256Ccm = NistObjectIdentifiers.IdAes256Ccm.Id;
+ public static readonly string Aes128Gcm = NistObjectIdentifiers.IdAes128Gcm.Id;
+ public static readonly string Aes192Gcm = NistObjectIdentifiers.IdAes192Gcm.Id;
+ public static readonly string Aes256Gcm = NistObjectIdentifiers.IdAes256Gcm.Id;
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSAuthenticatedData.cs b/bc-sharp-crypto/src/cms/CMSAuthenticatedData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..33b4cc22cf6926c36280546c36e8ef2bfc8bd606
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSAuthenticatedData.cs
@@ -0,0 +1,137 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * containing class for an CMS Authenticated Data object
+ */
+ public class CmsAuthenticatedData
+ {
+ internal RecipientInformationStore recipientInfoStore;
+ internal ContentInfo contentInfo;
+
+ private AlgorithmIdentifier macAlg;
+ private Asn1Set authAttrs;
+ private Asn1Set unauthAttrs;
+ private byte[] mac;
+
+ public CmsAuthenticatedData(
+ byte[] authData)
+ : this(CmsUtilities.ReadContentInfo(authData))
+ {
+ }
+
+ public CmsAuthenticatedData(
+ Stream authData)
+ : this(CmsUtilities.ReadContentInfo(authData))
+ {
+ }
+
+ public CmsAuthenticatedData(
+ ContentInfo contentInfo)
+ {
+ this.contentInfo = contentInfo;
+
+ AuthenticatedData authData = AuthenticatedData.GetInstance(contentInfo.Content);
+
+ //
+ // read the recipients
+ //
+ Asn1Set recipientInfos = authData.RecipientInfos;
+
+ this.macAlg = authData.MacAlgorithm;
+
+ //
+ // read the authenticated content info
+ //
+ ContentInfo encInfo = authData.EncapsulatedContentInfo;
+ CmsReadable readable = new CmsProcessableByteArray(
+ Asn1OctetString.GetInstance(encInfo.Content).GetOctets());
+ CmsSecureReadable secureReadable = new CmsEnvelopedHelper.CmsAuthenticatedSecureReadable(
+ this.macAlg, readable);
+
+ //
+ // build the RecipientInformationStore
+ //
+ this.recipientInfoStore = CmsEnvelopedHelper.BuildRecipientInformationStore(
+ recipientInfos, secureReadable);
+
+ this.authAttrs = authData.AuthAttrs;
+ this.mac = authData.Mac.GetOctets();
+ this.unauthAttrs = authData.UnauthAttrs;
+ }
+
+ public byte[] GetMac()
+ {
+ return Arrays.Clone(mac);
+ }
+
+ public AlgorithmIdentifier MacAlgorithmID
+ {
+ get { return macAlg; }
+ }
+
+ /**
+ * return the object identifier for the content MAC algorithm.
+ */
+ public string MacAlgOid
+ {
+ get { return macAlg.Algorithm.Id; }
+ }
+
+ /**
+ * return a store of the intended recipients for this message
+ */
+ public RecipientInformationStore GetRecipientInfos()
+ {
+ return recipientInfoStore;
+ }
+
+ /**
+ * return the ContentInfo
+ */
+ public ContentInfo ContentInfo
+ {
+ get { return contentInfo; }
+ }
+
+ /**
+ * return a table of the digested attributes indexed by
+ * the OID of the attribute.
+ */
+ public Asn1.Cms.AttributeTable GetAuthAttrs()
+ {
+ if (authAttrs == null)
+ return null;
+
+ return new Asn1.Cms.AttributeTable(authAttrs);
+ }
+
+ /**
+ * return a table of the undigested attributes indexed by
+ * the OID of the attribute.
+ */
+ public Asn1.Cms.AttributeTable GetUnauthAttrs()
+ {
+ if (unauthAttrs == null)
+ return null;
+
+ return new Asn1.Cms.AttributeTable(unauthAttrs);
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] GetEncoded()
+ {
+ return contentInfo.GetEncoded();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSAuthenticatedDataGenerator.cs b/bc-sharp-crypto/src/cms/CMSAuthenticatedDataGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..131a4753f93fcacfc66675d62ede3c253464b722
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSAuthenticatedDataGenerator.cs
@@ -0,0 +1,156 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * General class for generating a CMS authenticated-data message.
+ *
+ * A simple example of usage.
+ *
+ *
+ * CMSAuthenticatedDataGenerator fact = new CMSAuthenticatedDataGenerator();
+ *
+ * fact.addKeyTransRecipient(cert);
+ *
+ * CMSAuthenticatedData data = fact.generate(content, algorithm, "BC");
+ *
+ */
+ public class CmsAuthenticatedDataGenerator
+ : CmsAuthenticatedGenerator
+ {
+ /**
+ * base constructor
+ */
+ public CmsAuthenticatedDataGenerator()
+ {
+ }
+
+ /**
+ * constructor allowing specific source of randomness
+ * @param rand instance of SecureRandom to use
+ */
+ public CmsAuthenticatedDataGenerator(
+ SecureRandom rand)
+ : base(rand)
+ {
+ }
+
+ /**
+ * generate an enveloped object that contains an CMS Enveloped Data
+ * object using the given provider and the passed in key generator.
+ */
+ private CmsAuthenticatedData Generate(
+ CmsProcessable content,
+ string macOid,
+ CipherKeyGenerator keyGen)
+ {
+ AlgorithmIdentifier macAlgId;
+ KeyParameter encKey;
+ Asn1OctetString encContent;
+ Asn1OctetString macResult;
+
+ try
+ {
+ // FIXME Will this work for macs?
+ byte[] encKeyBytes = keyGen.GenerateKey();
+ encKey = ParameterUtilities.CreateKeyParameter(macOid, encKeyBytes);
+
+ Asn1Encodable asn1Params = GenerateAsn1Parameters(macOid, encKeyBytes);
+
+ ICipherParameters cipherParameters;
+ macAlgId = GetAlgorithmIdentifier(
+ macOid, encKey, asn1Params, out cipherParameters);
+
+ IMac mac = MacUtilities.GetMac(macOid);
+ // TODO Confirm no ParametersWithRandom needed
+ // FIXME Only passing key at the moment
+// mac.Init(cipherParameters);
+ mac.Init(encKey);
+
+ MemoryStream bOut = new MemoryStream();
+ Stream mOut = new TeeOutputStream(bOut, new MacOutputStream(mac));
+
+ content.Write(mOut);
+
+ Platform.Dispose(mOut);
+
+ encContent = new BerOctetString(bOut.ToArray());
+
+ byte[] macOctets = MacUtilities.DoFinal(mac);
+ macResult = new DerOctetString(macOctets);
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw new CmsException("couldn't create cipher.", e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CmsException("key invalid in message.", e);
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("exception decoding algorithm parameters.", e);
+ }
+
+ Asn1EncodableVector recipientInfos = new Asn1EncodableVector();
+
+ foreach (RecipientInfoGenerator rig in recipientInfoGenerators)
+ {
+ try
+ {
+ recipientInfos.Add(rig.Generate(encKey, rand));
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CmsException("key inappropriate for algorithm.", e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CmsException("error making encrypted content.", e);
+ }
+ }
+
+ ContentInfo eci = new ContentInfo(CmsObjectIdentifiers.Data, encContent);
+
+ ContentInfo contentInfo = new ContentInfo(
+ CmsObjectIdentifiers.AuthenticatedData,
+ new AuthenticatedData(null, new DerSet(recipientInfos), macAlgId, null, eci, null, macResult, null));
+
+ return new CmsAuthenticatedData(contentInfo);
+ }
+
+ /**
+ * generate an authenticated object that contains an CMS Authenticated Data object
+ */
+ public CmsAuthenticatedData Generate(
+ CmsProcessable content,
+ string encryptionOid)
+ {
+ try
+ {
+ // FIXME Will this work for macs?
+ CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
+
+ keyGen.Init(new KeyGenerationParameters(rand, keyGen.DefaultStrength));
+
+ return Generate(content, encryptionOid, keyGen);
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw new CmsException("can't find key generation algorithm.", e);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSAuthenticatedDataParser.cs b/bc-sharp-crypto/src/cms/CMSAuthenticatedDataParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7defafc0731e91cc15f03a71c1f850bbc991675a
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSAuthenticatedDataParser.cs
@@ -0,0 +1,214 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * Parsing class for an CMS Authenticated Data object from an input stream.
+ *
+ * Note: that because we are in a streaming mode only one recipient can be tried and it is important
+ * that the methods on the parser are called in the appropriate order.
+ *
+ *
+ * Example of use - assuming the first recipient matches the private key we have.
+ *
+ * CMSAuthenticatedDataParser ad = new CMSAuthenticatedDataParser(inputStream);
+ *
+ * RecipientInformationStore recipients = ad.getRecipientInfos();
+ *
+ * Collection c = recipients.getRecipients();
+ * Iterator it = c.iterator();
+ *
+ * if (it.hasNext())
+ * {
+ * RecipientInformation recipient = (RecipientInformation)it.next();
+ *
+ * CMSTypedStream recData = recipient.getContentStream(privateKey, "BC");
+ *
+ * processDataStream(recData.getContentStream());
+ *
+ * if (!Arrays.equals(ad.getMac(), recipient.getMac())
+ * {
+ * System.err.println("Data corrupted!!!!");
+ * }
+ * }
+ *
+ * Note: this class does not introduce buffering - if you are processing large files you should create
+ * the parser with:
+ *
+ * CMSAuthenticatedDataParser ep = new CMSAuthenticatedDataParser(new BufferedInputStream(inputStream, bufSize));
+ *
+ * where bufSize is a suitably large buffer size.
+ *
+ */
+ public class CmsAuthenticatedDataParser
+ : CmsContentInfoParser
+ {
+ internal RecipientInformationStore _recipientInfoStore;
+ internal AuthenticatedDataParser authData;
+
+ private AlgorithmIdentifier macAlg;
+ private byte[] mac;
+ private Asn1.Cms.AttributeTable authAttrs;
+ private Asn1.Cms.AttributeTable unauthAttrs;
+
+ private bool authAttrNotRead;
+ private bool unauthAttrNotRead;
+
+ public CmsAuthenticatedDataParser(
+ byte[] envelopedData)
+ : this(new MemoryStream(envelopedData, false))
+ {
+ }
+
+ public CmsAuthenticatedDataParser(
+ Stream envelopedData)
+ : base(envelopedData)
+ {
+ this.authAttrNotRead = true;
+ this.authData = new AuthenticatedDataParser(
+ (Asn1SequenceParser)contentInfo.GetContent(Asn1Tags.Sequence));
+
+ // TODO Validate version?
+ //DerInteger version = this.authData.getVersion();
+
+ //
+ // read the recipients
+ //
+ Asn1Set recipientInfos = Asn1Set.GetInstance(authData.GetRecipientInfos().ToAsn1Object());
+
+ this.macAlg = authData.GetMacAlgorithm();
+
+ //
+ // read the authenticated content info
+ //
+ ContentInfoParser data = authData.GetEnapsulatedContentInfo();
+ CmsReadable readable = new CmsProcessableInputStream(
+ ((Asn1OctetStringParser)data.GetContent(Asn1Tags.OctetString)).GetOctetStream());
+ CmsSecureReadable secureReadable = new CmsEnvelopedHelper.CmsAuthenticatedSecureReadable(
+ this.macAlg, readable);
+
+ //
+ // build the RecipientInformationStore
+ //
+ this._recipientInfoStore = CmsEnvelopedHelper.BuildRecipientInformationStore(
+ recipientInfos, secureReadable);
+ }
+
+ public AlgorithmIdentifier MacAlgorithmID
+ {
+ get { return macAlg; }
+ }
+
+ /**
+ * return the object identifier for the mac algorithm.
+ */
+ public string MacAlgOid
+ {
+ get { return macAlg.Algorithm.Id; }
+ }
+
+
+ /**
+ * return the ASN.1 encoded encryption algorithm parameters, or null if
+ * there aren't any.
+ */
+ public Asn1Object MacAlgParams
+ {
+ get
+ {
+ Asn1Encodable ae = macAlg.Parameters;
+
+ return ae == null ? null : ae.ToAsn1Object();
+ }
+ }
+
+ /**
+ * return a store of the intended recipients for this message
+ */
+ public RecipientInformationStore GetRecipientInfos()
+ {
+ return _recipientInfoStore;
+ }
+
+ public byte[] GetMac()
+ {
+ if (mac == null)
+ {
+ GetAuthAttrs();
+ mac = authData.GetMac().GetOctets();
+ }
+ return Arrays.Clone(mac);
+ }
+
+ /**
+ * return a table of the unauthenticated attributes indexed by
+ * the OID of the attribute.
+ * @exception java.io.IOException
+ */
+ public Asn1.Cms.AttributeTable GetAuthAttrs()
+ {
+ if (authAttrs == null && authAttrNotRead)
+ {
+ Asn1SetParser s = authData.GetAuthAttrs();
+
+ authAttrNotRead = false;
+
+ if (s != null)
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ IAsn1Convertible o;
+ while ((o = s.ReadObject()) != null)
+ {
+ Asn1SequenceParser seq = (Asn1SequenceParser)o;
+
+ v.Add(seq.ToAsn1Object());
+ }
+
+ authAttrs = new Asn1.Cms.AttributeTable(new DerSet(v));
+ }
+ }
+
+ return authAttrs;
+ }
+
+ /**
+ * return a table of the unauthenticated attributes indexed by
+ * the OID of the attribute.
+ * @exception java.io.IOException
+ */
+ public Asn1.Cms.AttributeTable GetUnauthAttrs()
+ {
+ if (unauthAttrs == null && unauthAttrNotRead)
+ {
+ Asn1SetParser s = authData.GetUnauthAttrs();
+
+ unauthAttrNotRead = false;
+
+ if (s != null)
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ IAsn1Convertible o;
+ while ((o = s.ReadObject()) != null)
+ {
+ Asn1SequenceParser seq = (Asn1SequenceParser)o;
+
+ v.Add(seq.ToAsn1Object());
+ }
+
+ unauthAttrs = new Asn1.Cms.AttributeTable(new DerSet(v));
+ }
+ }
+
+ return unauthAttrs;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs b/bc-sharp-crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4d18d10d4646b46cf1d259d7e24e4a4db25a8289
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs
@@ -0,0 +1,297 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * General class for generating a CMS authenticated-data message stream.
+ *
+ * A simple example of usage.
+ *
+ * CMSAuthenticatedDataStreamGenerator edGen = new CMSAuthenticatedDataStreamGenerator();
+ *
+ * edGen.addKeyTransRecipient(cert);
+ *
+ * ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ *
+ * OutputStream out = edGen.open(
+ * bOut, CMSAuthenticatedDataGenerator.AES128_CBC, "BC");*
+ * out.write(data);
+ *
+ * out.close();
+ *
+ *
+ */
+ public class CmsAuthenticatedDataStreamGenerator
+ : CmsAuthenticatedGenerator
+ {
+ // TODO Add support
+// private object _originatorInfo = null;
+// private object _unprotectedAttributes = null;
+ private int _bufferSize;
+ private bool _berEncodeRecipientSet;
+
+ /**
+ * base constructor
+ */
+ public CmsAuthenticatedDataStreamGenerator()
+ {
+ }
+
+ /**
+ * constructor allowing specific source of randomness
+ * @param rand instance of SecureRandom to use
+ */
+ public CmsAuthenticatedDataStreamGenerator(
+ SecureRandom rand)
+ : base(rand)
+ {
+ }
+
+ /**
+ * Set the underlying string size for encapsulated data
+ *
+ * @param bufferSize length of octet strings to buffer the data.
+ */
+ public void SetBufferSize(
+ int bufferSize)
+ {
+ _bufferSize = bufferSize;
+ }
+
+ /**
+ * Use a BER Set to store the recipient information
+ */
+ public void SetBerEncodeRecipients(
+ bool berEncodeRecipientSet)
+ {
+ _berEncodeRecipientSet = berEncodeRecipientSet;
+ }
+
+ /**
+ * generate an enveloped object that contains an CMS Enveloped Data
+ * object using the given provider and the passed in key generator.
+ * @throws java.io.IOException
+ */
+ private Stream Open(
+ Stream outStr,
+ string macOid,
+ CipherKeyGenerator keyGen)
+ {
+ // FIXME Will this work for macs?
+ byte[] encKeyBytes = keyGen.GenerateKey();
+ KeyParameter encKey = ParameterUtilities.CreateKeyParameter(macOid, encKeyBytes);
+
+ Asn1Encodable asn1Params = GenerateAsn1Parameters(macOid, encKeyBytes);
+
+ ICipherParameters cipherParameters;
+ AlgorithmIdentifier macAlgId = GetAlgorithmIdentifier(
+ macOid, encKey, asn1Params, out cipherParameters);
+
+ Asn1EncodableVector recipientInfos = new Asn1EncodableVector();
+
+ foreach (RecipientInfoGenerator rig in recipientInfoGenerators)
+ {
+ try
+ {
+ recipientInfos.Add(rig.Generate(encKey, rand));
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CmsException("key inappropriate for algorithm.", e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CmsException("error making encrypted content.", e);
+ }
+ }
+
+ // FIXME Only passing key at the moment
+// return Open(outStr, macAlgId, cipherParameters, recipientInfos);
+ return Open(outStr, macAlgId, encKey, recipientInfos);
+ }
+
+ protected Stream Open(
+ Stream outStr,
+ AlgorithmIdentifier macAlgId,
+ ICipherParameters cipherParameters,
+ Asn1EncodableVector recipientInfos)
+ {
+ try
+ {
+ //
+ // ContentInfo
+ //
+ BerSequenceGenerator cGen = new BerSequenceGenerator(outStr);
+
+ cGen.AddObject(CmsObjectIdentifiers.AuthenticatedData);
+
+ //
+ // Authenticated Data
+ //
+ BerSequenceGenerator authGen = new BerSequenceGenerator(
+ cGen.GetRawOutputStream(), 0, true);
+
+ authGen.AddObject(new DerInteger(AuthenticatedData.CalculateVersion(null)));
+
+ Stream authRaw = authGen.GetRawOutputStream();
+ Asn1Generator recipGen = _berEncodeRecipientSet
+ ? (Asn1Generator) new BerSetGenerator(authRaw)
+ : new DerSetGenerator(authRaw);
+
+ foreach (Asn1Encodable ae in recipientInfos)
+ {
+ recipGen.AddObject(ae);
+ }
+
+ recipGen.Close();
+
+ authGen.AddObject(macAlgId);
+
+ BerSequenceGenerator eiGen = new BerSequenceGenerator(authRaw);
+ eiGen.AddObject(CmsObjectIdentifiers.Data);
+
+ Stream octetOutputStream = CmsUtilities.CreateBerOctetOutputStream(
+ eiGen.GetRawOutputStream(), 0, false, _bufferSize);
+
+ IMac mac = MacUtilities.GetMac(macAlgId.Algorithm);
+ // TODO Confirm no ParametersWithRandom needed
+ mac.Init(cipherParameters);
+ Stream mOut = new TeeOutputStream(octetOutputStream, new MacOutputStream(mac));
+
+ return new CmsAuthenticatedDataOutputStream(mOut, mac, cGen, authGen, eiGen);
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw new CmsException("couldn't create cipher.", e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CmsException("key invalid in message.", e);
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("exception decoding algorithm parameters.", e);
+ }
+ }
+
+ /**
+ * generate an enveloped object that contains an CMS Enveloped Data object
+ */
+ public Stream Open(
+ Stream outStr,
+ string encryptionOid)
+ {
+ CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
+
+ keyGen.Init(new KeyGenerationParameters(rand, keyGen.DefaultStrength));
+
+ return Open(outStr, encryptionOid, keyGen);
+ }
+
+ /**
+ * generate an enveloped object that contains an CMS Enveloped Data object
+ */
+ public Stream Open(
+ Stream outStr,
+ string encryptionOid,
+ int keySize)
+ {
+ CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
+
+ keyGen.Init(new KeyGenerationParameters(rand, keySize));
+
+ return Open(outStr, encryptionOid, keyGen);
+ }
+
+ private class CmsAuthenticatedDataOutputStream
+ : BaseOutputStream
+ {
+ private readonly Stream macStream;
+ private readonly IMac mac;
+ private readonly BerSequenceGenerator cGen;
+ private readonly BerSequenceGenerator authGen;
+ private readonly BerSequenceGenerator eiGen;
+
+ public CmsAuthenticatedDataOutputStream(
+ Stream macStream,
+ IMac mac,
+ BerSequenceGenerator cGen,
+ BerSequenceGenerator authGen,
+ BerSequenceGenerator eiGen)
+ {
+ this.macStream = macStream;
+ this.mac = mac;
+ this.cGen = cGen;
+ this.authGen = authGen;
+ this.eiGen = eiGen;
+ }
+
+ public override void WriteByte(
+ byte b)
+ {
+ macStream.WriteByte(b);
+ }
+
+ public override void Write(
+ byte[] bytes,
+ int off,
+ int len)
+ {
+ macStream.Write(bytes, off, len);
+ }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Platform.Dispose(macStream);
+
+ // TODO Parent context(s) should really be be closed explicitly
+
+ eiGen.Close();
+
+ // [TODO] auth attributes go here
+ byte[] macOctets = MacUtilities.DoFinal(mac);
+ authGen.AddObject(new DerOctetString(macOctets));
+ // [TODO] unauth attributes go here
+
+ authGen.Close();
+ cGen.Close();
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ Platform.Dispose(macStream);
+
+ // TODO Parent context(s) should really be be closed explicitly
+
+ eiGen.Close();
+
+ // [TODO] auth attributes go here
+ byte[] macOctets = MacUtilities.DoFinal(mac);
+ authGen.AddObject(new DerOctetString(macOctets));
+ // [TODO] unauth attributes go here
+
+ authGen.Close();
+ cGen.Close();
+ base.Close();
+ }
+#endif
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSAuthenticatedGenerator.cs b/bc-sharp-crypto/src/cms/CMSAuthenticatedGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8824d19132d03d74d4a618b1a74ad5057e43cf77
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSAuthenticatedGenerator.cs
@@ -0,0 +1,35 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+ public class CmsAuthenticatedGenerator
+ : CmsEnvelopedGenerator
+ {
+ /**
+ * base constructor
+ */
+ public CmsAuthenticatedGenerator()
+ {
+ }
+
+ /**
+ * constructor allowing specific source of randomness
+ *
+ * @param rand instance of SecureRandom to use
+ */
+ public CmsAuthenticatedGenerator(
+ SecureRandom rand)
+ : base(rand)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSCompressedData.cs b/bc-sharp-crypto/src/cms/CMSCompressedData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..21651f0414d6b8ea375d9c764ba47327a0ecddd2
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSCompressedData.cs
@@ -0,0 +1,108 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Zlib;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * containing class for an CMS Compressed Data object
+ */
+ public class CmsCompressedData
+ {
+ internal ContentInfo contentInfo;
+
+ public CmsCompressedData(
+ byte[] compressedData)
+ : this(CmsUtilities.ReadContentInfo(compressedData))
+ {
+ }
+
+ public CmsCompressedData(
+ Stream compressedDataStream)
+ : this(CmsUtilities.ReadContentInfo(compressedDataStream))
+ {
+ }
+
+ public CmsCompressedData(
+ ContentInfo contentInfo)
+ {
+ this.contentInfo = contentInfo;
+ }
+
+ /**
+ * Return the uncompressed content.
+ *
+ * @return the uncompressed content
+ * @throws CmsException if there is an exception uncompressing the data.
+ */
+ public byte[] GetContent()
+ {
+ CompressedData comData = CompressedData.GetInstance(contentInfo.Content);
+ ContentInfo content = comData.EncapContentInfo;
+
+ Asn1OctetString bytes = (Asn1OctetString) content.Content;
+ ZInputStream zIn = new ZInputStream(bytes.GetOctetStream());
+
+ try
+ {
+ return CmsUtilities.StreamToByteArray(zIn);
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("exception reading compressed stream.", e);
+ }
+ finally
+ {
+ Platform.Dispose(zIn);
+ }
+ }
+
+ /**
+ * Return the uncompressed content, throwing an exception if the data size
+ * is greater than the passed in limit. If the content is exceeded getCause()
+ * on the CMSException will contain a StreamOverflowException
+ *
+ * @param limit maximum number of bytes to read
+ * @return the content read
+ * @throws CMSException if there is an exception uncompressing the data.
+ */
+ public byte[] GetContent(int limit)
+ {
+ CompressedData comData = CompressedData.GetInstance(contentInfo.Content);
+ ContentInfo content = comData.EncapContentInfo;
+
+ Asn1OctetString bytes = (Asn1OctetString)content.Content;
+
+ ZInputStream zIn = new ZInputStream(new MemoryStream(bytes.GetOctets(), false));
+
+ try
+ {
+ return CmsUtilities.StreamToByteArray(zIn, limit);
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("exception reading compressed stream.", e);
+ }
+ }
+
+ /**
+ * return the ContentInfo
+ */
+ public ContentInfo ContentInfo
+ {
+ get { return contentInfo; }
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] GetEncoded()
+ {
+ return contentInfo.GetEncoded();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSCompressedDataGenerator.cs b/bc-sharp-crypto/src/cms/CMSCompressedDataGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d51de1026380e3fd1d5247f1c036328483172a55
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSCompressedDataGenerator.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Zlib;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * General class for generating a compressed CMS message.
+ *
+ * A simple example of usage.
+ *
+ *
+ * CMSCompressedDataGenerator fact = new CMSCompressedDataGenerator();
+ * CMSCompressedData data = fact.Generate(content, algorithm);
+ *
+ *
+ */
+ public class CmsCompressedDataGenerator
+ {
+ public const string ZLib = "1.2.840.113549.1.9.16.3.8";
+
+ public CmsCompressedDataGenerator()
+ {
+ }
+
+ /**
+ * Generate an object that contains an CMS Compressed Data
+ */
+ public CmsCompressedData Generate(
+ CmsProcessable content,
+ string compressionOid)
+ {
+ AlgorithmIdentifier comAlgId;
+ Asn1OctetString comOcts;
+
+ try
+ {
+ MemoryStream bOut = new MemoryStream();
+ ZOutputStream zOut = new ZOutputStream(bOut, JZlib.Z_DEFAULT_COMPRESSION);
+
+ content.Write(zOut);
+
+ Platform.Dispose(zOut);
+
+ comAlgId = new AlgorithmIdentifier(new DerObjectIdentifier(compressionOid));
+ comOcts = new BerOctetString(bOut.ToArray());
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("exception encoding data.", e);
+ }
+
+ ContentInfo comContent = new ContentInfo(CmsObjectIdentifiers.Data, comOcts);
+ ContentInfo contentInfo = new ContentInfo(
+ CmsObjectIdentifiers.CompressedData,
+ new CompressedData(comAlgId, comContent));
+
+ return new CmsCompressedData(contentInfo);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSCompressedDataParser.cs b/bc-sharp-crypto/src/cms/CMSCompressedDataParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..93dfa1286e895ecc96060d78e3c6ce805c0aaa95
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSCompressedDataParser.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Utilities.Zlib;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * Class for reading a CMS Compressed Data stream.
+ *
+ * CMSCompressedDataParser cp = new CMSCompressedDataParser(inputStream);
+ *
+ * process(cp.GetContent().GetContentStream());
+ *
+ * Note: this class does not introduce buffering - if you are processing large files you should create
+ * the parser with:
+ *
+ * CMSCompressedDataParser ep = new CMSCompressedDataParser(new BufferedInputStream(inputStream, bufSize));
+ *
+ * where bufSize is a suitably large buffer size.
+ */
+ public class CmsCompressedDataParser
+ : CmsContentInfoParser
+ {
+ public CmsCompressedDataParser(
+ byte[] compressedData)
+ : this(new MemoryStream(compressedData, false))
+ {
+ }
+
+ public CmsCompressedDataParser(
+ Stream compressedData)
+ : base(compressedData)
+ {
+ }
+
+ public CmsTypedStream GetContent()
+ {
+ try
+ {
+ CompressedDataParser comData = new CompressedDataParser((Asn1SequenceParser)this.contentInfo.GetContent(Asn1Tags.Sequence));
+ ContentInfoParser content = comData.GetEncapContentInfo();
+
+ Asn1OctetStringParser bytes = (Asn1OctetStringParser)content.GetContent(Asn1Tags.OctetString);
+
+ return new CmsTypedStream(content.ContentType.ToString(), new ZInputStream(bytes.GetOctetStream()));
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("IOException reading compressed content.", e);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSCompressedDataStreamGenerator.cs b/bc-sharp-crypto/src/cms/CMSCompressedDataStreamGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0cb1bb6414a0cfe1a9f3b5e0f6bb644ffc85d1ba
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSCompressedDataStreamGenerator.cs
@@ -0,0 +1,158 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.Utilities.Zlib;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * General class for generating a compressed CMS message stream.
+ *
+ * A simple example of usage.
+ *
+ *
+ * CMSCompressedDataStreamGenerator gen = new CMSCompressedDataStreamGenerator();
+ *
+ * Stream cOut = gen.Open(outputStream, CMSCompressedDataStreamGenerator.ZLIB);
+ *
+ * cOut.Write(data);
+ *
+ * cOut.Close();
+ *
+ */
+ public class CmsCompressedDataStreamGenerator
+ {
+ public const string ZLib = "1.2.840.113549.1.9.16.3.8";
+
+ private int _bufferSize;
+
+ /**
+ * base constructor
+ */
+ public CmsCompressedDataStreamGenerator()
+ {
+ }
+
+ /**
+ * Set the underlying string size for encapsulated data
+ *
+ * @param bufferSize length of octet strings to buffer the data.
+ */
+ public void SetBufferSize(
+ int bufferSize)
+ {
+ _bufferSize = bufferSize;
+ }
+
+ public Stream Open(
+ Stream outStream,
+ string compressionOID)
+ {
+ return Open(outStream, CmsObjectIdentifiers.Data.Id, compressionOID);
+ }
+
+ public Stream Open(
+ Stream outStream,
+ string contentOID,
+ string compressionOID)
+ {
+ BerSequenceGenerator sGen = new BerSequenceGenerator(outStream);
+
+ sGen.AddObject(CmsObjectIdentifiers.CompressedData);
+
+ //
+ // Compressed Data
+ //
+ BerSequenceGenerator cGen = new BerSequenceGenerator(
+ sGen.GetRawOutputStream(), 0, true);
+
+ // CMSVersion
+ cGen.AddObject(new DerInteger(0));
+
+ // CompressionAlgorithmIdentifier
+ cGen.AddObject(new AlgorithmIdentifier(new DerObjectIdentifier(ZLib)));
+
+ //
+ // Encapsulated ContentInfo
+ //
+ BerSequenceGenerator eiGen = new BerSequenceGenerator(cGen.GetRawOutputStream());
+
+ eiGen.AddObject(new DerObjectIdentifier(contentOID));
+
+ Stream octetStream = CmsUtilities.CreateBerOctetOutputStream(
+ eiGen.GetRawOutputStream(), 0, true, _bufferSize);
+
+ return new CmsCompressedOutputStream(
+ new ZOutputStream(octetStream, JZlib.Z_DEFAULT_COMPRESSION), sGen, cGen, eiGen);
+ }
+
+ private class CmsCompressedOutputStream
+ : BaseOutputStream
+ {
+ private ZOutputStream _out;
+ private BerSequenceGenerator _sGen;
+ private BerSequenceGenerator _cGen;
+ private BerSequenceGenerator _eiGen;
+
+ internal CmsCompressedOutputStream(
+ ZOutputStream outStream,
+ BerSequenceGenerator sGen,
+ BerSequenceGenerator cGen,
+ BerSequenceGenerator eiGen)
+ {
+ _out = outStream;
+ _sGen = sGen;
+ _cGen = cGen;
+ _eiGen = eiGen;
+ }
+
+ public override void WriteByte(
+ byte b)
+ {
+ _out.WriteByte(b);
+ }
+
+ public override void Write(
+ byte[] bytes,
+ int off,
+ int len)
+ {
+ _out.Write(bytes, off, len);
+ }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Platform.Dispose(_out);
+
+ // TODO Parent context(s) should really be be closed explicitly
+
+ _eiGen.Close();
+ _cGen.Close();
+ _sGen.Close();
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ Platform.Dispose(_out);
+
+ // TODO Parent context(s) should really be be closed explicitly
+
+ _eiGen.Close();
+ _cGen.Close();
+ _sGen.Close();
+ base.Close();
+ }
+#endif
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSContentInfoParser.cs b/bc-sharp-crypto/src/cms/CMSContentInfoParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a7b43f295a233ad5e289d6be11c65a093e28eaab
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSContentInfoParser.cs
@@ -0,0 +1,48 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Cms
+{
+ public class CmsContentInfoParser
+ {
+ protected ContentInfoParser contentInfo;
+ protected Stream data;
+
+ protected CmsContentInfoParser(
+ Stream data)
+ {
+ if (data == null)
+ throw new ArgumentNullException("data");
+
+ this.data = data;
+
+ try
+ {
+ Asn1StreamParser inStream = new Asn1StreamParser(data);
+
+ this.contentInfo = new ContentInfoParser((Asn1SequenceParser)inStream.ReadObject());
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("IOException reading content.", e);
+ }
+ catch (InvalidCastException e)
+ {
+ throw new CmsException("Unexpected object reading content.", e);
+ }
+ }
+
+ /**
+ * Close the underlying data stream.
+ * @throws IOException if the close fails.
+ */
+ public void Close()
+ {
+ Platform.Dispose(this.data);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSEnvelopedData.cs b/bc-sharp-crypto/src/cms/CMSEnvelopedData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..223d0ca7392f589c1de609c38a1f3ea00ed1582f
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSEnvelopedData.cs
@@ -0,0 +1,115 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * containing class for an CMS Enveloped Data object
+ */
+ public class CmsEnvelopedData
+ {
+ internal RecipientInformationStore recipientInfoStore;
+ internal ContentInfo contentInfo;
+
+ private AlgorithmIdentifier encAlg;
+ private Asn1Set unprotectedAttributes;
+
+ public CmsEnvelopedData(
+ byte[] envelopedData)
+ : this(CmsUtilities.ReadContentInfo(envelopedData))
+ {
+ }
+
+ public CmsEnvelopedData(
+ Stream envelopedData)
+ : this(CmsUtilities.ReadContentInfo(envelopedData))
+ {
+ }
+
+ public CmsEnvelopedData(
+ ContentInfo contentInfo)
+ {
+ this.contentInfo = contentInfo;
+
+ EnvelopedData envData = EnvelopedData.GetInstance(contentInfo.Content);
+
+ //
+ // read the recipients
+ //
+ Asn1Set recipientInfos = envData.RecipientInfos;
+
+ //
+ // read the encrypted content info
+ //
+ EncryptedContentInfo encInfo = envData.EncryptedContentInfo;
+ this.encAlg = encInfo.ContentEncryptionAlgorithm;
+ CmsReadable readable = new CmsProcessableByteArray(encInfo.EncryptedContent.GetOctets());
+ CmsSecureReadable secureReadable = new CmsEnvelopedHelper.CmsEnvelopedSecureReadable(
+ this.encAlg, readable);
+
+ //
+ // build the RecipientInformationStore
+ //
+ this.recipientInfoStore = CmsEnvelopedHelper.BuildRecipientInformationStore(
+ recipientInfos, secureReadable);
+
+ this.unprotectedAttributes = envData.UnprotectedAttrs;
+ }
+
+ public AlgorithmIdentifier EncryptionAlgorithmID
+ {
+ get { return encAlg; }
+ }
+
+ /**
+ * return the object identifier for the content encryption algorithm.
+ */
+ public string EncryptionAlgOid
+ {
+ get { return encAlg.Algorithm.Id; }
+ }
+
+ /**
+ * return a store of the intended recipients for this message
+ */
+ public RecipientInformationStore GetRecipientInfos()
+ {
+ return recipientInfoStore;
+ }
+
+ /**
+ * return the ContentInfo
+ */
+ public ContentInfo ContentInfo
+ {
+ get { return contentInfo; }
+ }
+
+ /**
+ * return a table of the unprotected attributes indexed by
+ * the OID of the attribute.
+ */
+ public Asn1.Cms.AttributeTable GetUnprotectedAttributes()
+ {
+ if (unprotectedAttributes == null)
+ return null;
+
+ return new Asn1.Cms.AttributeTable(unprotectedAttributes);
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] GetEncoded()
+ {
+ return contentInfo.GetEncoded();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSEnvelopedDataGenerator.cs b/bc-sharp-crypto/src/cms/CMSEnvelopedDataGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d260e998aa3e3bbd23dbc1a40bff38f573a42ff5
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSEnvelopedDataGenerator.cs
@@ -0,0 +1,178 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+ ///
+ /// General class for generating a CMS enveloped-data message.
+ ///
+ /// A simple example of usage.
+ ///
+ ///
+ /// CmsEnvelopedDataGenerator fact = new CmsEnvelopedDataGenerator();
+ ///
+ /// fact.AddKeyTransRecipient(cert);
+ ///
+ /// CmsEnvelopedData data = fact.Generate(content, algorithm);
+ ///
+ ///
+ public class CmsEnvelopedDataGenerator
+ : CmsEnvelopedGenerator
+ {
+ public CmsEnvelopedDataGenerator()
+ {
+ }
+
+ /// Constructor allowing specific source of randomness
+ /// Instance of SecureRandom to use.
+ public CmsEnvelopedDataGenerator(
+ SecureRandom rand)
+ : base(rand)
+ {
+ }
+
+ ///
+ /// Generate an enveloped object that contains a CMS Enveloped Data
+ /// object using the passed in key generator.
+ ///
+ private CmsEnvelopedData Generate(
+ CmsProcessable content,
+ string encryptionOid,
+ CipherKeyGenerator keyGen)
+ {
+ AlgorithmIdentifier encAlgId = null;
+ KeyParameter encKey;
+ Asn1OctetString encContent;
+
+ try
+ {
+ byte[] encKeyBytes = keyGen.GenerateKey();
+ encKey = ParameterUtilities.CreateKeyParameter(encryptionOid, encKeyBytes);
+
+ Asn1Encodable asn1Params = GenerateAsn1Parameters(encryptionOid, encKeyBytes);
+
+ ICipherParameters cipherParameters;
+ encAlgId = GetAlgorithmIdentifier(
+ encryptionOid, encKey, asn1Params, out cipherParameters);
+
+ IBufferedCipher cipher = CipherUtilities.GetCipher(encryptionOid);
+ cipher.Init(true, new ParametersWithRandom(cipherParameters, rand));
+
+ MemoryStream bOut = new MemoryStream();
+ CipherStream cOut = new CipherStream(bOut, null, cipher);
+
+ content.Write(cOut);
+
+ Platform.Dispose(cOut);
+
+ encContent = new BerOctetString(bOut.ToArray());
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw new CmsException("couldn't create cipher.", e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CmsException("key invalid in message.", e);
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("exception decoding algorithm parameters.", e);
+ }
+
+
+ Asn1EncodableVector recipientInfos = new Asn1EncodableVector();
+
+ foreach (RecipientInfoGenerator rig in recipientInfoGenerators)
+ {
+ try
+ {
+ recipientInfos.Add(rig.Generate(encKey, rand));
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CmsException("key inappropriate for algorithm.", e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CmsException("error making encrypted content.", e);
+ }
+ }
+
+ EncryptedContentInfo eci = new EncryptedContentInfo(
+ CmsObjectIdentifiers.Data,
+ encAlgId,
+ encContent);
+
+ Asn1Set unprotectedAttrSet = null;
+ if (unprotectedAttributeGenerator != null)
+ {
+ Asn1.Cms.AttributeTable attrTable = unprotectedAttributeGenerator.GetAttributes(Platform.CreateHashtable());
+
+ unprotectedAttrSet = new BerSet(attrTable.ToAsn1EncodableVector());
+ }
+
+ ContentInfo contentInfo = new ContentInfo(
+ CmsObjectIdentifiers.EnvelopedData,
+ new EnvelopedData(null, new DerSet(recipientInfos), eci, unprotectedAttrSet));
+
+ return new CmsEnvelopedData(contentInfo);
+ }
+
+ /// Generate an enveloped object that contains an CMS Enveloped Data object.
+ public CmsEnvelopedData Generate(
+ CmsProcessable content,
+ string encryptionOid)
+ {
+ try
+ {
+ CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
+
+ keyGen.Init(new KeyGenerationParameters(rand, keyGen.DefaultStrength));
+
+ return Generate(content, encryptionOid, keyGen);
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw new CmsException("can't find key generation algorithm.", e);
+ }
+ }
+
+ /// Generate an enveloped object that contains an CMS Enveloped Data object.
+ public CmsEnvelopedData Generate(
+ CmsProcessable content,
+ string encryptionOid,
+ int keySize)
+ {
+ try
+ {
+ CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
+
+ keyGen.Init(new KeyGenerationParameters(rand, keySize));
+
+ return Generate(content, encryptionOid, keyGen);
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw new CmsException("can't find key generation algorithm.", e);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSEnvelopedDataParser.cs b/bc-sharp-crypto/src/cms/CMSEnvelopedDataParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d5dfaf53d19cd7160fbcdb52866f79dbffc38280
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSEnvelopedDataParser.cs
@@ -0,0 +1,161 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * Parsing class for an CMS Enveloped Data object from an input stream.
+ *
+ * Note: that because we are in a streaming mode only one recipient can be tried and it is important
+ * that the methods on the parser are called in the appropriate order.
+ *
+ *
+ * Example of use - assuming the first recipient matches the private key we have.
+ *
+ * CmsEnvelopedDataParser ep = new CmsEnvelopedDataParser(inputStream);
+ *
+ * RecipientInformationStore recipients = ep.GetRecipientInfos();
+ *
+ * Collection c = recipients.getRecipients();
+ * Iterator it = c.iterator();
+ *
+ * if (it.hasNext())
+ * {
+ * RecipientInformation recipient = (RecipientInformation)it.next();
+ *
+ * CMSTypedStream recData = recipient.getContentStream(privateKey);
+ *
+ * processDataStream(recData.getContentStream());
+ * }
+ *
+ * Note: this class does not introduce buffering - if you are processing large files you should create
+ * the parser with:
+ *
+ * CmsEnvelopedDataParser ep = new CmsEnvelopedDataParser(new BufferedInputStream(inputStream, bufSize));
+ *
+ * where bufSize is a suitably large buffer size.
+ *
+ */
+ public class CmsEnvelopedDataParser
+ : CmsContentInfoParser
+ {
+ internal RecipientInformationStore recipientInfoStore;
+ internal EnvelopedDataParser envelopedData;
+
+ private AlgorithmIdentifier _encAlg;
+ private Asn1.Cms.AttributeTable _unprotectedAttributes;
+ private bool _attrNotRead;
+
+ public CmsEnvelopedDataParser(
+ byte[] envelopedData)
+ : this(new MemoryStream(envelopedData, false))
+ {
+ }
+
+ public CmsEnvelopedDataParser(
+ Stream envelopedData)
+ : base(envelopedData)
+ {
+ this._attrNotRead = true;
+ this.envelopedData = new EnvelopedDataParser(
+ (Asn1SequenceParser)this.contentInfo.GetContent(Asn1Tags.Sequence));
+
+ // TODO Validate version?
+ //DerInteger version = this.envelopedData.Version;
+
+ //
+ // read the recipients
+ //
+ Asn1Set recipientInfos = Asn1Set.GetInstance(this.envelopedData.GetRecipientInfos().ToAsn1Object());
+
+ //
+ // read the encrypted content info
+ //
+ EncryptedContentInfoParser encInfo = this.envelopedData.GetEncryptedContentInfo();
+ this._encAlg = encInfo.ContentEncryptionAlgorithm;
+ CmsReadable readable = new CmsProcessableInputStream(
+ ((Asn1OctetStringParser)encInfo.GetEncryptedContent(Asn1Tags.OctetString)).GetOctetStream());
+ CmsSecureReadable secureReadable = new CmsEnvelopedHelper.CmsEnvelopedSecureReadable(
+ this._encAlg, readable);
+
+ //
+ // build the RecipientInformationStore
+ //
+ this.recipientInfoStore = CmsEnvelopedHelper.BuildRecipientInformationStore(
+ recipientInfos, secureReadable);
+ }
+
+ public AlgorithmIdentifier EncryptionAlgorithmID
+ {
+ get { return _encAlg; }
+ }
+
+ /**
+ * return the object identifier for the content encryption algorithm.
+ */
+ public string EncryptionAlgOid
+ {
+ get { return _encAlg.Algorithm.Id; }
+ }
+
+ /**
+ * return the ASN.1 encoded encryption algorithm parameters, or null if
+ * there aren't any.
+ */
+ public Asn1Object EncryptionAlgParams
+ {
+ get
+ {
+ Asn1Encodable ae = _encAlg.Parameters;
+
+ return ae == null ? null : ae.ToAsn1Object();
+ }
+ }
+
+ /**
+ * return a store of the intended recipients for this message
+ */
+ public RecipientInformationStore GetRecipientInfos()
+ {
+ return this.recipientInfoStore;
+ }
+
+ /**
+ * return a table of the unprotected attributes indexed by
+ * the OID of the attribute.
+ * @throws IOException
+ */
+ public Asn1.Cms.AttributeTable GetUnprotectedAttributes()
+ {
+ if (_unprotectedAttributes == null && _attrNotRead)
+ {
+ Asn1SetParser asn1Set = this.envelopedData.GetUnprotectedAttrs();
+
+ _attrNotRead = false;
+
+ if (asn1Set != null)
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+ IAsn1Convertible o;
+
+ while ((o = asn1Set.ReadObject()) != null)
+ {
+ Asn1SequenceParser seq = (Asn1SequenceParser)o;
+
+ v.Add(seq.ToAsn1Object());
+ }
+
+ _unprotectedAttributes = new Asn1.Cms.AttributeTable(new DerSet(v));
+ }
+ }
+
+ return _unprotectedAttributes;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs b/bc-sharp-crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8e6d2729b73518c3777ece1338af0602ee286695
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs
@@ -0,0 +1,308 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * General class for generating a CMS enveloped-data message stream.
+ *
+ * A simple example of usage.
+ *
+ * CmsEnvelopedDataStreamGenerator edGen = new CmsEnvelopedDataStreamGenerator();
+ *
+ * edGen.AddKeyTransRecipient(cert);
+ *
+ * MemoryStream bOut = new MemoryStream();
+ *
+ * Stream out = edGen.Open(
+ * bOut, CMSEnvelopedDataGenerator.AES128_CBC);*
+ * out.Write(data);
+ *
+ * out.Close();
+ *
+ *
+ */
+ public class CmsEnvelopedDataStreamGenerator
+ : CmsEnvelopedGenerator
+ {
+ private object _originatorInfo = null;
+ private object _unprotectedAttributes = null;
+ private int _bufferSize;
+ private bool _berEncodeRecipientSet;
+
+ public CmsEnvelopedDataStreamGenerator()
+ {
+ }
+
+ /// Constructor allowing specific source of randomness
+ /// Instance of SecureRandom to use.
+ public CmsEnvelopedDataStreamGenerator(
+ SecureRandom rand)
+ : base(rand)
+ {
+ }
+
+ /// Set the underlying string size for encapsulated data.
+ /// Length of octet strings to buffer the data.
+ public void SetBufferSize(
+ int bufferSize)
+ {
+ _bufferSize = bufferSize;
+ }
+
+ /// Use a BER Set to store the recipient information.
+ public void SetBerEncodeRecipients(
+ bool berEncodeRecipientSet)
+ {
+ _berEncodeRecipientSet = berEncodeRecipientSet;
+ }
+
+ private DerInteger Version
+ {
+ get
+ {
+ int version = (_originatorInfo != null || _unprotectedAttributes != null)
+ ? 2
+ : 0;
+
+ return new DerInteger(version);
+ }
+ }
+
+ ///
+ /// Generate an enveloped object that contains an CMS Enveloped Data
+ /// object using the passed in key generator.
+ ///
+ private Stream Open(
+ Stream outStream,
+ string encryptionOid,
+ CipherKeyGenerator keyGen)
+ {
+ byte[] encKeyBytes = keyGen.GenerateKey();
+ KeyParameter encKey = ParameterUtilities.CreateKeyParameter(encryptionOid, encKeyBytes);
+
+ Asn1Encodable asn1Params = GenerateAsn1Parameters(encryptionOid, encKeyBytes);
+
+ ICipherParameters cipherParameters;
+ AlgorithmIdentifier encAlgID = GetAlgorithmIdentifier(
+ encryptionOid, encKey, asn1Params, out cipherParameters);
+
+ Asn1EncodableVector recipientInfos = new Asn1EncodableVector();
+
+ foreach (RecipientInfoGenerator rig in recipientInfoGenerators)
+ {
+ try
+ {
+ recipientInfos.Add(rig.Generate(encKey, rand));
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CmsException("key inappropriate for algorithm.", e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CmsException("error making encrypted content.", e);
+ }
+ }
+
+ return Open(outStream, encAlgID, cipherParameters, recipientInfos);
+ }
+
+ private Stream Open(
+ Stream outStream,
+ AlgorithmIdentifier encAlgID,
+ ICipherParameters cipherParameters,
+ Asn1EncodableVector recipientInfos)
+ {
+ try
+ {
+ //
+ // ContentInfo
+ //
+ BerSequenceGenerator cGen = new BerSequenceGenerator(outStream);
+
+ cGen.AddObject(CmsObjectIdentifiers.EnvelopedData);
+
+ //
+ // Encrypted Data
+ //
+ BerSequenceGenerator envGen = new BerSequenceGenerator(
+ cGen.GetRawOutputStream(), 0, true);
+
+ envGen.AddObject(this.Version);
+
+ Stream envRaw = envGen.GetRawOutputStream();
+ Asn1Generator recipGen = _berEncodeRecipientSet
+ ? (Asn1Generator) new BerSetGenerator(envRaw)
+ : new DerSetGenerator(envRaw);
+
+ foreach (Asn1Encodable ae in recipientInfos)
+ {
+ recipGen.AddObject(ae);
+ }
+
+ recipGen.Close();
+
+ BerSequenceGenerator eiGen = new BerSequenceGenerator(envRaw);
+ eiGen.AddObject(CmsObjectIdentifiers.Data);
+ eiGen.AddObject(encAlgID);
+
+ Stream octetOutputStream = CmsUtilities.CreateBerOctetOutputStream(
+ eiGen.GetRawOutputStream(), 0, false, _bufferSize);
+
+ IBufferedCipher cipher = CipherUtilities.GetCipher(encAlgID.Algorithm);
+ cipher.Init(true, new ParametersWithRandom(cipherParameters, rand));
+ CipherStream cOut = new CipherStream(octetOutputStream, null, cipher);
+
+ return new CmsEnvelopedDataOutputStream(this, cOut, cGen, envGen, eiGen);
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw new CmsException("couldn't create cipher.", e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CmsException("key invalid in message.", e);
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("exception decoding algorithm parameters.", e);
+ }
+ }
+
+ /**
+ * generate an enveloped object that contains an CMS Enveloped Data object
+ * @throws IOException
+ */
+ public Stream Open(
+ Stream outStream,
+ string encryptionOid)
+ {
+ CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
+
+ keyGen.Init(new KeyGenerationParameters(rand, keyGen.DefaultStrength));
+
+ return Open(outStream, encryptionOid, keyGen);
+ }
+
+ /**
+ * generate an enveloped object that contains an CMS Enveloped Data object
+ * @throws IOException
+ */
+ public Stream Open(
+ Stream outStream,
+ string encryptionOid,
+ int keySize)
+ {
+ CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
+
+ keyGen.Init(new KeyGenerationParameters(rand, keySize));
+
+ return Open(outStream, encryptionOid, keyGen);
+ }
+
+ private class CmsEnvelopedDataOutputStream
+ : BaseOutputStream
+ {
+ private readonly CmsEnvelopedGenerator _outer;
+
+ private readonly CipherStream _out;
+ private readonly BerSequenceGenerator _cGen;
+ private readonly BerSequenceGenerator _envGen;
+ private readonly BerSequenceGenerator _eiGen;
+
+ public CmsEnvelopedDataOutputStream(
+ CmsEnvelopedGenerator outer,
+ CipherStream outStream,
+ BerSequenceGenerator cGen,
+ BerSequenceGenerator envGen,
+ BerSequenceGenerator eiGen)
+ {
+ _outer = outer;
+ _out = outStream;
+ _cGen = cGen;
+ _envGen = envGen;
+ _eiGen = eiGen;
+ }
+
+ public override void WriteByte(
+ byte b)
+ {
+ _out.WriteByte(b);
+ }
+
+ public override void Write(
+ byte[] bytes,
+ int off,
+ int len)
+ {
+ _out.Write(bytes, off, len);
+ }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Platform.Dispose(_out);
+
+ // TODO Parent context(s) should really be closed explicitly
+
+ _eiGen.Close();
+
+ if (_outer.unprotectedAttributeGenerator != null)
+ {
+ Asn1.Cms.AttributeTable attrTable = _outer.unprotectedAttributeGenerator.GetAttributes(Platform.CreateHashtable());
+
+ Asn1Set unprotectedAttrs = new BerSet(attrTable.ToAsn1EncodableVector());
+
+ _envGen.AddObject(new DerTaggedObject(false, 1, unprotectedAttrs));
+ }
+
+ _envGen.Close();
+ _cGen.Close();
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ Platform.Dispose(_out);
+
+ // TODO Parent context(s) should really be closed explicitly
+
+ _eiGen.Close();
+
+ if (_outer.unprotectedAttributeGenerator != null)
+ {
+ Asn1.Cms.AttributeTable attrTable = _outer.unprotectedAttributeGenerator.GetAttributes(Platform.CreateHashtable());
+
+ Asn1Set unprotectedAttrs = new BerSet(attrTable.ToAsn1EncodableVector());
+
+ _envGen.AddObject(new DerTaggedObject(false, 1, unprotectedAttrs));
+ }
+
+ _envGen.Close();
+ _cGen.Close();
+ base.Close();
+ }
+#endif
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSEnvelopedGenerator.cs b/bc-sharp-crypto/src/cms/CMSEnvelopedGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f92ae3824ef479599fa8cb5261ac7798eb7a2867
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSEnvelopedGenerator.cs
@@ -0,0 +1,331 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Kisa;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Ntt;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * General class for generating a CMS enveloped-data message.
+ *
+ * A simple example of usage.
+ *
+ *
+ * CMSEnvelopedDataGenerator fact = new CMSEnvelopedDataGenerator();
+ *
+ * fact.addKeyTransRecipient(cert);
+ *
+ * CMSEnvelopedData data = fact.generate(content, algorithm, "BC");
+ *
+ */
+ public class CmsEnvelopedGenerator
+ {
+ // Note: These tables are complementary: If rc2Table[i]==j, then rc2Ekb[j]==i
+ internal static readonly short[] rc2Table =
+ {
+ 0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0,
+ 0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a,
+ 0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36,
+ 0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c,
+ 0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60,
+ 0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa,
+ 0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e,
+ 0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf,
+ 0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6,
+ 0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3,
+ 0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c,
+ 0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2,
+ 0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5,
+ 0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5,
+ 0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f,
+ 0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab
+ };
+
+// internal static readonly short[] rc2Ekb =
+// {
+// 0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5,
+// 0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5,
+// 0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef,
+// 0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d,
+// 0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb,
+// 0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d,
+// 0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3,
+// 0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61,
+// 0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1,
+// 0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21,
+// 0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42,
+// 0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f,
+// 0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7,
+// 0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15,
+// 0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7,
+// 0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd
+// };
+
+
+ // TODO Create named constants for all of these
+ public static readonly string DesEde3Cbc = PkcsObjectIdentifiers.DesEde3Cbc.Id;
+ public static readonly string RC2Cbc = PkcsObjectIdentifiers.RC2Cbc.Id;
+ public const string IdeaCbc = "1.3.6.1.4.1.188.7.1.1.2";
+ public const string Cast5Cbc = "1.2.840.113533.7.66.10";
+ public static readonly string Aes128Cbc = NistObjectIdentifiers.IdAes128Cbc.Id;
+ public static readonly string Aes192Cbc = NistObjectIdentifiers.IdAes192Cbc.Id;
+ public static readonly string Aes256Cbc = NistObjectIdentifiers.IdAes256Cbc.Id;
+ public static readonly string Camellia128Cbc = NttObjectIdentifiers.IdCamellia128Cbc.Id;
+ public static readonly string Camellia192Cbc = NttObjectIdentifiers.IdCamellia192Cbc.Id;
+ public static readonly string Camellia256Cbc = NttObjectIdentifiers.IdCamellia256Cbc.Id;
+ public static readonly string SeedCbc = KisaObjectIdentifiers.IdSeedCbc.Id;
+
+ public static readonly string DesEde3Wrap = PkcsObjectIdentifiers.IdAlgCms3DesWrap.Id;
+ public static readonly string Aes128Wrap = NistObjectIdentifiers.IdAes128Wrap.Id;
+ public static readonly string Aes192Wrap = NistObjectIdentifiers.IdAes192Wrap.Id;
+ public static readonly string Aes256Wrap = NistObjectIdentifiers.IdAes256Wrap.Id;
+ public static readonly string Camellia128Wrap = NttObjectIdentifiers.IdCamellia128Wrap.Id;
+ public static readonly string Camellia192Wrap = NttObjectIdentifiers.IdCamellia192Wrap.Id;
+ public static readonly string Camellia256Wrap = NttObjectIdentifiers.IdCamellia256Wrap.Id;
+ public static readonly string SeedWrap = KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap.Id;
+
+ public static readonly string ECDHSha1Kdf = X9ObjectIdentifiers.DHSinglePassStdDHSha1KdfScheme.Id;
+ public static readonly string ECMqvSha1Kdf = X9ObjectIdentifiers.MqvSinglePassSha1KdfScheme.Id;
+
+ internal readonly IList recipientInfoGenerators = Platform.CreateArrayList();
+ internal readonly SecureRandom rand;
+
+ internal CmsAttributeTableGenerator unprotectedAttributeGenerator = null;
+
+ public CmsEnvelopedGenerator()
+ : this(new SecureRandom())
+ {
+ }
+
+ /// Constructor allowing specific source of randomness
+ /// Instance of SecureRandom to use.
+ public CmsEnvelopedGenerator(
+ SecureRandom rand)
+ {
+ this.rand = rand;
+ }
+
+ public CmsAttributeTableGenerator UnprotectedAttributeGenerator
+ {
+ get { return this.unprotectedAttributeGenerator; }
+ set { this.unprotectedAttributeGenerator = value; }
+ }
+
+ /**
+ * add a recipient.
+ *
+ * @param cert recipient's public key certificate
+ * @exception ArgumentException if there is a problem with the certificate
+ */
+ public void AddKeyTransRecipient(
+ X509Certificate cert)
+ {
+ KeyTransRecipientInfoGenerator ktrig = new KeyTransRecipientInfoGenerator();
+ ktrig.RecipientCert = cert;
+
+ recipientInfoGenerators.Add(ktrig);
+ }
+
+ /**
+ * add a recipient
+ *
+ * @param key the public key used by the recipient
+ * @param subKeyId the identifier for the recipient's public key
+ * @exception ArgumentException if there is a problem with the key
+ */
+ public void AddKeyTransRecipient(
+ AsymmetricKeyParameter pubKey,
+ byte[] subKeyId)
+ {
+ KeyTransRecipientInfoGenerator ktrig = new KeyTransRecipientInfoGenerator();
+ ktrig.RecipientPublicKey = pubKey;
+ ktrig.SubjectKeyIdentifier = new DerOctetString(subKeyId);
+
+ recipientInfoGenerators.Add(ktrig);
+ }
+
+ /**
+ * add a KEK recipient.
+ * @param key the secret key to use for wrapping
+ * @param keyIdentifier the byte string that identifies the key
+ */
+ public void AddKekRecipient(
+ string keyAlgorithm, // TODO Remove need for this parameter
+ KeyParameter key,
+ byte[] keyIdentifier)
+ {
+ AddKekRecipient(keyAlgorithm, key, new KekIdentifier(keyIdentifier, null, null));
+ }
+
+ /**
+ * add a KEK recipient.
+ * @param key the secret key to use for wrapping
+ * @param keyIdentifier the byte string that identifies the key
+ */
+ public void AddKekRecipient(
+ string keyAlgorithm, // TODO Remove need for this parameter
+ KeyParameter key,
+ KekIdentifier kekIdentifier)
+ {
+ KekRecipientInfoGenerator kekrig = new KekRecipientInfoGenerator();
+ kekrig.KekIdentifier = kekIdentifier;
+ kekrig.KeyEncryptionKeyOID = keyAlgorithm;
+ kekrig.KeyEncryptionKey = key;
+
+ recipientInfoGenerators.Add(kekrig);
+ }
+
+ public void AddPasswordRecipient(
+ CmsPbeKey pbeKey,
+ string kekAlgorithmOid)
+ {
+ Pbkdf2Params p = new Pbkdf2Params(pbeKey.Salt, pbeKey.IterationCount);
+
+ PasswordRecipientInfoGenerator prig = new PasswordRecipientInfoGenerator();
+ prig.KeyDerivationAlgorithm = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdPbkdf2, p);
+ prig.KeyEncryptionKeyOID = kekAlgorithmOid;
+ prig.KeyEncryptionKey = pbeKey.GetEncoded(kekAlgorithmOid);
+
+ recipientInfoGenerators.Add(prig);
+ }
+
+ /**
+ * Add a key agreement based recipient.
+ *
+ * @param agreementAlgorithm key agreement algorithm to use.
+ * @param senderPrivateKey private key to initialise sender side of agreement with.
+ * @param senderPublicKey sender public key to include with message.
+ * @param recipientCert recipient's public key certificate.
+ * @param cekWrapAlgorithm OID for key wrapping algorithm to use.
+ * @exception SecurityUtilityException if the algorithm requested cannot be found
+ * @exception InvalidKeyException if the keys are inappropriate for the algorithm specified
+ */
+ public void AddKeyAgreementRecipient(
+ string agreementAlgorithm,
+ AsymmetricKeyParameter senderPrivateKey,
+ AsymmetricKeyParameter senderPublicKey,
+ X509Certificate recipientCert,
+ string cekWrapAlgorithm)
+ {
+ IList recipientCerts = Platform.CreateArrayList(1);
+ recipientCerts.Add(recipientCert);
+
+ AddKeyAgreementRecipients(agreementAlgorithm, senderPrivateKey, senderPublicKey,
+ recipientCerts, cekWrapAlgorithm);
+ }
+
+ /**
+ * Add multiple key agreement based recipients (sharing a single KeyAgreeRecipientInfo structure).
+ *
+ * @param agreementAlgorithm key agreement algorithm to use.
+ * @param senderPrivateKey private key to initialise sender side of agreement with.
+ * @param senderPublicKey sender public key to include with message.
+ * @param recipientCerts recipients' public key certificates.
+ * @param cekWrapAlgorithm OID for key wrapping algorithm to use.
+ * @exception SecurityUtilityException if the algorithm requested cannot be found
+ * @exception InvalidKeyException if the keys are inappropriate for the algorithm specified
+ */
+ public void AddKeyAgreementRecipients(
+ string agreementAlgorithm,
+ AsymmetricKeyParameter senderPrivateKey,
+ AsymmetricKeyParameter senderPublicKey,
+ ICollection recipientCerts,
+ string cekWrapAlgorithm)
+ {
+ if (!senderPrivateKey.IsPrivate)
+ throw new ArgumentException("Expected private key", "senderPrivateKey");
+ if (senderPublicKey.IsPrivate)
+ throw new ArgumentException("Expected public key", "senderPublicKey");
+
+ /* TODO
+ * "a recipient X.509 version 3 certificate that contains a key usage extension MUST
+ * assert the keyAgreement bit."
+ */
+
+ KeyAgreeRecipientInfoGenerator karig = new KeyAgreeRecipientInfoGenerator();
+ karig.KeyAgreementOID = new DerObjectIdentifier(agreementAlgorithm);
+ karig.KeyEncryptionOID = new DerObjectIdentifier(cekWrapAlgorithm);
+ karig.RecipientCerts = recipientCerts;
+ karig.SenderKeyPair = new AsymmetricCipherKeyPair(senderPublicKey, senderPrivateKey);
+
+ recipientInfoGenerators.Add(karig);
+ }
+
+ protected internal virtual AlgorithmIdentifier GetAlgorithmIdentifier(
+ string encryptionOid,
+ KeyParameter encKey,
+ Asn1Encodable asn1Params,
+ out ICipherParameters cipherParameters)
+ {
+ Asn1Object asn1Object;
+ if (asn1Params != null)
+ {
+ asn1Object = asn1Params.ToAsn1Object();
+ cipherParameters = ParameterUtilities.GetCipherParameters(
+ encryptionOid, encKey, asn1Object);
+ }
+ else
+ {
+ asn1Object = DerNull.Instance;
+ cipherParameters = encKey;
+ }
+
+ return new AlgorithmIdentifier(
+ new DerObjectIdentifier(encryptionOid),
+ asn1Object);
+ }
+
+ protected internal virtual Asn1Encodable GenerateAsn1Parameters(
+ string encryptionOid,
+ byte[] encKeyBytes)
+ {
+ Asn1Encodable asn1Params = null;
+
+ try
+ {
+ if (encryptionOid.Equals(RC2Cbc))
+ {
+ byte[] iv = new byte[8];
+ rand.NextBytes(iv);
+
+ // TODO Is this detailed repeat of Java version really necessary?
+ int effKeyBits = encKeyBytes.Length * 8;
+ int parameterVersion;
+
+ if (effKeyBits < 256)
+ {
+ parameterVersion = rc2Table[effKeyBits];
+ }
+ else
+ {
+ parameterVersion = effKeyBits;
+ }
+
+ asn1Params = new RC2CbcParameter(parameterVersion, iv);
+ }
+ else
+ {
+ asn1Params = ParameterUtilities.GenerateParameters(encryptionOid, rand);
+ }
+ }
+ catch (SecurityUtilityException)
+ {
+ // No problem... no parameters generated
+ }
+
+ return asn1Params;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSEnvelopedHelper.cs b/bc-sharp-crypto/src/cms/CMSEnvelopedHelper.cs
new file mode 100644
index 0000000000000000000000000000000000000000..77d2da47a7d753d62069b0ae7c054ec560a38a5b
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSEnvelopedHelper.cs
@@ -0,0 +1,311 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+ class CmsEnvelopedHelper
+ {
+ internal static readonly CmsEnvelopedHelper Instance = new CmsEnvelopedHelper();
+
+ private static readonly IDictionary KeySizes = Platform.CreateHashtable();
+ private static readonly IDictionary BaseCipherNames = Platform.CreateHashtable();
+
+ static CmsEnvelopedHelper()
+ {
+ KeySizes.Add(CmsEnvelopedGenerator.DesEde3Cbc, 192);
+ KeySizes.Add(CmsEnvelopedGenerator.Aes128Cbc, 128);
+ KeySizes.Add(CmsEnvelopedGenerator.Aes192Cbc, 192);
+ KeySizes.Add(CmsEnvelopedGenerator.Aes256Cbc, 256);
+
+ BaseCipherNames.Add(CmsEnvelopedGenerator.DesEde3Cbc, "DESEDE");
+ BaseCipherNames.Add(CmsEnvelopedGenerator.Aes128Cbc, "AES");
+ BaseCipherNames.Add(CmsEnvelopedGenerator.Aes192Cbc, "AES");
+ BaseCipherNames.Add(CmsEnvelopedGenerator.Aes256Cbc, "AES");
+ }
+
+ private string GetAsymmetricEncryptionAlgName(
+ string encryptionAlgOid)
+ {
+ if (Asn1.Pkcs.PkcsObjectIdentifiers.RsaEncryption.Id.Equals(encryptionAlgOid))
+ {
+ return "RSA/ECB/PKCS1Padding";
+ }
+
+ return encryptionAlgOid;
+ }
+
+ internal IBufferedCipher CreateAsymmetricCipher(
+ string encryptionOid)
+ {
+ string asymName = GetAsymmetricEncryptionAlgName(encryptionOid);
+ if (!asymName.Equals(encryptionOid))
+ {
+ try
+ {
+ return CipherUtilities.GetCipher(asymName);
+ }
+ catch (SecurityUtilityException)
+ {
+ // Ignore
+ }
+ }
+ return CipherUtilities.GetCipher(encryptionOid);
+ }
+
+ internal IWrapper CreateWrapper(
+ string encryptionOid)
+ {
+ try
+ {
+ return WrapperUtilities.GetWrapper(encryptionOid);
+ }
+ catch (SecurityUtilityException)
+ {
+ return WrapperUtilities.GetWrapper(GetAsymmetricEncryptionAlgName(encryptionOid));
+ }
+ }
+
+ internal string GetRfc3211WrapperName(
+ string oid)
+ {
+ if (oid == null)
+ throw new ArgumentNullException("oid");
+
+ string alg = (string) BaseCipherNames[oid];
+
+ if (alg == null)
+ throw new ArgumentException("no name for " + oid, "oid");
+
+ return alg + "RFC3211Wrap";
+ }
+
+ internal int GetKeySize(
+ string oid)
+ {
+ if (!KeySizes.Contains(oid))
+ {
+ throw new ArgumentException("no keysize for " + oid, "oid");
+ }
+
+ return (int) KeySizes[oid];
+ }
+
+ internal static RecipientInformationStore BuildRecipientInformationStore(
+ Asn1Set recipientInfos, CmsSecureReadable secureReadable)
+ {
+ IList infos = Platform.CreateArrayList();
+ for (int i = 0; i != recipientInfos.Count; i++)
+ {
+ RecipientInfo info = RecipientInfo.GetInstance(recipientInfos[i]);
+
+ ReadRecipientInfo(infos, info, secureReadable);
+ }
+ return new RecipientInformationStore(infos);
+ }
+
+ private static void ReadRecipientInfo(
+ IList infos, RecipientInfo info, CmsSecureReadable secureReadable)
+ {
+ Asn1Encodable recipInfo = info.Info;
+ if (recipInfo is KeyTransRecipientInfo)
+ {
+ infos.Add(new KeyTransRecipientInformation((KeyTransRecipientInfo)recipInfo, secureReadable));
+ }
+ else if (recipInfo is KekRecipientInfo)
+ {
+ infos.Add(new KekRecipientInformation((KekRecipientInfo)recipInfo, secureReadable));
+ }
+ else if (recipInfo is KeyAgreeRecipientInfo)
+ {
+ KeyAgreeRecipientInformation.ReadRecipientInfo(infos, (KeyAgreeRecipientInfo)recipInfo, secureReadable);
+ }
+ else if (recipInfo is PasswordRecipientInfo)
+ {
+ infos.Add(new PasswordRecipientInformation((PasswordRecipientInfo)recipInfo, secureReadable));
+ }
+ }
+
+ internal class CmsAuthenticatedSecureReadable : CmsSecureReadable
+ {
+ private AlgorithmIdentifier algorithm;
+ private IMac mac;
+ private CmsReadable readable;
+
+ internal CmsAuthenticatedSecureReadable(AlgorithmIdentifier algorithm, CmsReadable readable)
+ {
+ this.algorithm = algorithm;
+ this.readable = readable;
+ }
+
+ public AlgorithmIdentifier Algorithm
+ {
+ get { return this.algorithm; }
+ }
+
+ public object CryptoObject
+ {
+ get { return this.mac; }
+ }
+
+ public CmsReadable GetReadable(KeyParameter sKey)
+ {
+ string macAlg = this.algorithm.Algorithm.Id;
+// Asn1Object sParams = this.algorithm.Parameters.ToAsn1Object();
+
+ try
+ {
+ this.mac = MacUtilities.GetMac(macAlg);
+
+ // FIXME Support for MAC algorithm parameters similar to cipher parameters
+// ASN1Object sParams = (ASN1Object)macAlg.getParameters();
+//
+// if (sParams != null && !(sParams instanceof ASN1Null))
+// {
+// AlgorithmParameters params = CMSEnvelopedHelper.INSTANCE.createAlgorithmParameters(macAlg.getObjectId().getId(), provider);
+//
+// params.init(sParams.getEncoded(), "ASN.1");
+//
+// mac.init(sKey, params.getParameterSpec(IvParameterSpec.class));
+// }
+// else
+ {
+ mac.Init(sKey);
+ }
+
+// Asn1Object asn1Params = asn1Enc == null ? null : asn1Enc.ToAsn1Object();
+//
+// ICipherParameters cipherParameters = sKey;
+//
+// if (asn1Params != null && !(asn1Params is Asn1Null))
+// {
+// cipherParameters = ParameterUtilities.GetCipherParameters(
+// macAlg.Algorithm, cipherParameters, asn1Params);
+// }
+// else
+// {
+// string alg = macAlg.Algorithm.Id;
+// if (alg.Equals(CmsEnvelopedDataGenerator.DesEde3Cbc)
+// || alg.Equals(CmsEnvelopedDataGenerator.IdeaCbc)
+// || alg.Equals(CmsEnvelopedDataGenerator.Cast5Cbc))
+// {
+// cipherParameters = new ParametersWithIV(cipherParameters, new byte[8]);
+// }
+// }
+//
+// mac.Init(cipherParameters);
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw new CmsException("couldn't create cipher.", e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CmsException("key invalid in message.", e);
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("error decoding algorithm parameters.", e);
+ }
+
+ try
+ {
+ return new CmsProcessableInputStream(
+ new TeeInputStream(
+ readable.GetInputStream(),
+ new MacOutputStream(this.mac)));
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("error reading content.", e);
+ }
+ }
+ }
+
+ internal class CmsEnvelopedSecureReadable : CmsSecureReadable
+ {
+ private AlgorithmIdentifier algorithm;
+ private IBufferedCipher cipher;
+ private CmsReadable readable;
+
+ internal CmsEnvelopedSecureReadable(AlgorithmIdentifier algorithm, CmsReadable readable)
+ {
+ this.algorithm = algorithm;
+ this.readable = readable;
+ }
+
+ public AlgorithmIdentifier Algorithm
+ {
+ get { return this.algorithm; }
+ }
+
+ public object CryptoObject
+ {
+ get { return this.cipher; }
+ }
+
+ public CmsReadable GetReadable(KeyParameter sKey)
+ {
+ try
+ {
+ this.cipher = CipherUtilities.GetCipher(this.algorithm.Algorithm);
+
+ Asn1Encodable asn1Enc = this.algorithm.Parameters;
+ Asn1Object asn1Params = asn1Enc == null ? null : asn1Enc.ToAsn1Object();
+
+ ICipherParameters cipherParameters = sKey;
+
+ if (asn1Params != null && !(asn1Params is Asn1Null))
+ {
+ cipherParameters = ParameterUtilities.GetCipherParameters(
+ this.algorithm.Algorithm, cipherParameters, asn1Params);
+ }
+ else
+ {
+ string alg = this.algorithm.Algorithm.Id;
+ if (alg.Equals(CmsEnvelopedDataGenerator.DesEde3Cbc)
+ || alg.Equals(CmsEnvelopedDataGenerator.IdeaCbc)
+ || alg.Equals(CmsEnvelopedDataGenerator.Cast5Cbc))
+ {
+ cipherParameters = new ParametersWithIV(cipherParameters, new byte[8]);
+ }
+ }
+
+ cipher.Init(false, cipherParameters);
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw new CmsException("couldn't create cipher.", e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CmsException("key invalid in message.", e);
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("error decoding algorithm parameters.", e);
+ }
+
+ try
+ {
+ return new CmsProcessableInputStream(
+ new CipherStream(readable.GetInputStream(), cipher, null));
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("error reading content.", e);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/cms/CMSException.cs b/bc-sharp-crypto/src/cms/CMSException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..29fe0a6c0b9acf43f3626a64f691103e181c4404
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSException.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Org.BouncyCastle.Cms
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class CmsException
+ : Exception
+ {
+ public CmsException()
+ {
+ }
+
+ public CmsException(
+ string msg)
+ : base(msg)
+ {
+ }
+
+ public CmsException(
+ string msg,
+ Exception e)
+ : base(msg, e)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSPBEKey.cs b/bc-sharp-crypto/src/cms/CMSPBEKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e03307e571f8d35b74637466471af4d3767ca767
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSPBEKey.cs
@@ -0,0 +1,109 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+//import javax.crypto.interfaces.PBEKey;
+
+namespace Org.BouncyCastle.Cms
+{
+ public abstract class CmsPbeKey
+ // TODO Create an equivalent interface somewhere?
+ // : PBEKey
+ : ICipherParameters
+ {
+ internal readonly char[] password;
+ internal readonly byte[] salt;
+ internal readonly int iterationCount;
+
+ [Obsolete("Use version taking 'char[]' instead")]
+ public CmsPbeKey(
+ string password,
+ byte[] salt,
+ int iterationCount)
+ : this(password.ToCharArray(), salt, iterationCount)
+ {
+ }
+
+ [Obsolete("Use version taking 'char[]' instead")]
+ public CmsPbeKey(
+ string password,
+ AlgorithmIdentifier keyDerivationAlgorithm)
+ : this(password.ToCharArray(), keyDerivationAlgorithm)
+ {
+ }
+
+ public CmsPbeKey(
+ char[] password,
+ byte[] salt,
+ int iterationCount)
+ {
+ this.password = (char[])password.Clone();
+ this.salt = Arrays.Clone(salt);
+ this.iterationCount = iterationCount;
+ }
+
+ public CmsPbeKey(
+ char[] password,
+ AlgorithmIdentifier keyDerivationAlgorithm)
+ {
+ if (!keyDerivationAlgorithm.Algorithm.Equals(PkcsObjectIdentifiers.IdPbkdf2))
+ throw new ArgumentException("Unsupported key derivation algorithm: "
+ + keyDerivationAlgorithm.Algorithm);
+
+ Pbkdf2Params kdfParams = Pbkdf2Params.GetInstance(
+ keyDerivationAlgorithm.Parameters.ToAsn1Object());
+
+ this.password = (char[])password.Clone();
+ this.salt = kdfParams.GetSalt();
+ this.iterationCount = kdfParams.IterationCount.IntValue;
+ }
+
+ ~CmsPbeKey()
+ {
+ Array.Clear(this.password, 0, this.password.Length);
+ }
+
+ [Obsolete("Will be removed")]
+ public string Password
+ {
+ get { return new string(password); }
+ }
+
+ public byte[] Salt
+ {
+ get { return Arrays.Clone(salt); }
+ }
+
+ [Obsolete("Use 'Salt' property instead")]
+ public byte[] GetSalt()
+ {
+ return Salt;
+ }
+
+ public int IterationCount
+ {
+ get { return iterationCount; }
+ }
+
+ public string Algorithm
+ {
+ get { return "PKCS5S2"; }
+ }
+
+ public string Format
+ {
+ get { return "RAW"; }
+ }
+
+ public byte[] GetEncoded()
+ {
+ return null;
+ }
+
+ internal abstract KeyParameter GetEncoded(string algorithmOid);
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSProcessable.cs b/bc-sharp-crypto/src/cms/CMSProcessable.cs
new file mode 100644
index 0000000000000000000000000000000000000000..41018d12b6d87d2be5b1760b34000a01b90d3b6e
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSProcessable.cs
@@ -0,0 +1,19 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+ public interface CmsProcessable
+ {
+ ///
+ /// Generic routine to copy out the data we want processed.
+ ///
+ ///
+ /// This routine may be called multiple times.
+ ///
+ void Write(Stream outStream);
+
+ [Obsolete]
+ object GetContent();
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSProcessableByteArray.cs b/bc-sharp-crypto/src/cms/CMSProcessableByteArray.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a6ab9b6a27bd6b8da40401782ab802b098e6921f
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSProcessableByteArray.cs
@@ -0,0 +1,36 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * a holding class for a byte array of data to be processed.
+ */
+ public class CmsProcessableByteArray
+ : CmsProcessable, CmsReadable
+ {
+ private readonly byte[] bytes;
+
+ public CmsProcessableByteArray(byte[] bytes)
+ {
+ this.bytes = bytes;
+ }
+
+ public virtual Stream GetInputStream()
+ {
+ return new MemoryStream(bytes, false);
+ }
+
+ public virtual void Write(Stream zOut)
+ {
+ zOut.Write(bytes, 0, bytes.Length);
+ }
+
+ /// A clone of the byte array
+ [Obsolete]
+ public virtual object GetContent()
+ {
+ return bytes.Clone();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSProcessableFile.cs b/bc-sharp-crypto/src/cms/CMSProcessableFile.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c74d2a84655135c50a0cc24308f9121bd4aeb3ae
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSProcessableFile.cs
@@ -0,0 +1,52 @@
+#if !PORTABLE || DOTNET
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * a holding class for a file of data to be processed.
+ */
+ public class CmsProcessableFile
+ : CmsProcessable, CmsReadable
+ {
+ private const int DefaultBufSize = 32 * 1024;
+
+ private readonly FileInfo _file;
+ private readonly int _bufSize;
+
+ public CmsProcessableFile(FileInfo file)
+ : this(file, DefaultBufSize)
+ {
+ }
+
+ public CmsProcessableFile(FileInfo file, int bufSize)
+ {
+ _file = file;
+ _bufSize = bufSize;
+ }
+
+ public virtual Stream GetInputStream()
+ {
+ return new FileStream(_file.FullName, FileMode.Open, FileAccess.Read, FileShare.Read, _bufSize);
+ }
+
+ public virtual void Write(Stream zOut)
+ {
+ Stream inStr = GetInputStream();
+ Streams.PipeAll(inStr, zOut);
+ Platform.Dispose(inStr);
+ }
+
+ /// The file handle
+ [Obsolete]
+ public virtual object GetContent()
+ {
+ return _file;
+ }
+ }
+}
+#endif
diff --git a/bc-sharp-crypto/src/cms/CMSProcessableInputStream.cs b/bc-sharp-crypto/src/cms/CMSProcessableInputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b2abd6f7157fc042366bd644f64fc79516e21d88
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSProcessableInputStream.cs
@@ -0,0 +1,53 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+ public class CmsProcessableInputStream
+ : CmsProcessable, CmsReadable
+ {
+ private readonly Stream input;
+
+ private bool used = false;
+
+ public CmsProcessableInputStream(Stream input)
+ {
+ this.input = input;
+ }
+
+ public virtual Stream GetInputStream()
+ {
+ CheckSingleUsage();
+
+ return input;
+ }
+
+ public virtual void Write(Stream output)
+ {
+ CheckSingleUsage();
+
+ Streams.PipeAll(input, output);
+ Platform.Dispose(input);
+ }
+
+ [Obsolete]
+ public virtual object GetContent()
+ {
+ return GetInputStream();
+ }
+
+ protected virtual void CheckSingleUsage()
+ {
+ lock (this)
+ {
+ if (used)
+ throw new InvalidOperationException("CmsProcessableInputStream can only be used once");
+
+ used = true;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSReadable.cs b/bc-sharp-crypto/src/cms/CMSReadable.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ad83ba068846f43322a5dad0c0f638bf14571b01
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSReadable.cs
@@ -0,0 +1,10 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+ public interface CmsReadable
+ {
+ Stream GetInputStream();
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSSecureReadable.cs b/bc-sharp-crypto/src/cms/CMSSecureReadable.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5ceac24fd2cd8f959137702560575072bb7033e8
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSSecureReadable.cs
@@ -0,0 +1,14 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Cms
+{
+ internal interface CmsSecureReadable
+ {
+ AlgorithmIdentifier Algorithm { get; }
+ object CryptoObject { get; }
+ CmsReadable GetReadable(KeyParameter key);
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSSignedData.cs b/bc-sharp-crypto/src/cms/CMSSignedData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..237c1528ec306720fad0255c68b3e4482dd06484
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSSignedData.cs
@@ -0,0 +1,425 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * general class for handling a pkcs7-signature message.
+ *
+ * A simple example of usage - note, in the example below the validity of
+ * the certificate isn't verified, just the fact that one of the certs
+ * matches the given signer...
+ *
+ *
+ * IX509Store certs = s.GetCertificates();
+ * SignerInformationStore signers = s.GetSignerInfos();
+ *
+ * foreach (SignerInformation signer in signers.GetSigners())
+ * {
+ * ArrayList certList = new ArrayList(certs.GetMatches(signer.SignerID));
+ * X509Certificate cert = (X509Certificate) certList[0];
+ *
+ * if (signer.Verify(cert.GetPublicKey()))
+ * {
+ * verified++;
+ * }
+ * }
+ *
+ */
+ public class CmsSignedData
+ {
+ private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance;
+
+ private readonly CmsProcessable signedContent;
+ private SignedData signedData;
+ private ContentInfo contentInfo;
+ private SignerInformationStore signerInfoStore;
+ private IX509Store attrCertStore;
+ private IX509Store certificateStore;
+ private IX509Store crlStore;
+ private IDictionary hashes;
+
+ private CmsSignedData(
+ CmsSignedData c)
+ {
+ this.signedData = c.signedData;
+ this.contentInfo = c.contentInfo;
+ this.signedContent = c.signedContent;
+ this.signerInfoStore = c.signerInfoStore;
+ }
+
+ public CmsSignedData(
+ byte[] sigBlock)
+ : this(CmsUtilities.ReadContentInfo(new MemoryStream(sigBlock, false)))
+ {
+ }
+
+ public CmsSignedData(
+ CmsProcessable signedContent,
+ byte[] sigBlock)
+ : this(signedContent, CmsUtilities.ReadContentInfo(new MemoryStream(sigBlock, false)))
+ {
+ }
+
+ /**
+ * Content with detached signature, digests precomputed
+ *
+ * @param hashes a map of precomputed digests for content indexed by name of hash.
+ * @param sigBlock the signature object.
+ */
+ public CmsSignedData(
+ IDictionary hashes,
+ byte[] sigBlock)
+ : this(hashes, CmsUtilities.ReadContentInfo(sigBlock))
+ {
+ }
+
+ /**
+ * base constructor - content with detached signature.
+ *
+ * @param signedContent the content that was signed.
+ * @param sigData the signature object.
+ */
+ public CmsSignedData(
+ CmsProcessable signedContent,
+ Stream sigData)
+ : this(signedContent, CmsUtilities.ReadContentInfo(sigData))
+ {
+ }
+
+ /**
+ * base constructor - with encapsulated content
+ */
+ public CmsSignedData(
+ Stream sigData)
+ : this(CmsUtilities.ReadContentInfo(sigData))
+ {
+ }
+
+ public CmsSignedData(
+ CmsProcessable signedContent,
+ ContentInfo sigData)
+ {
+ this.signedContent = signedContent;
+ this.contentInfo = sigData;
+ this.signedData = SignedData.GetInstance(contentInfo.Content);
+ }
+
+ public CmsSignedData(
+ IDictionary hashes,
+ ContentInfo sigData)
+ {
+ this.hashes = hashes;
+ this.contentInfo = sigData;
+ this.signedData = SignedData.GetInstance(contentInfo.Content);
+ }
+
+ public CmsSignedData(
+ ContentInfo sigData)
+ {
+ this.contentInfo = sigData;
+ this.signedData = SignedData.GetInstance(contentInfo.Content);
+
+ //
+ // this can happen if the signed message is sent simply to send a
+ // certificate chain.
+ //
+ if (signedData.EncapContentInfo.Content != null)
+ {
+ this.signedContent = new CmsProcessableByteArray(
+ ((Asn1OctetString)(signedData.EncapContentInfo.Content)).GetOctets());
+ }
+// else
+// {
+// this.signedContent = null;
+// }
+ }
+
+ /// Return the version number for this object.
+ public int Version
+ {
+ get { return signedData.Version.Value.IntValue; }
+ }
+
+ /**
+ * return the collection of signers that are associated with the
+ * signatures for the message.
+ */
+ public SignerInformationStore GetSignerInfos()
+ {
+ if (signerInfoStore == null)
+ {
+ IList signerInfos = Platform.CreateArrayList();
+ Asn1Set s = signedData.SignerInfos;
+
+ foreach (object obj in s)
+ {
+ SignerInfo info = SignerInfo.GetInstance(obj);
+ DerObjectIdentifier contentType = signedData.EncapContentInfo.ContentType;
+
+ if (hashes == null)
+ {
+ signerInfos.Add(new SignerInformation(info, contentType, signedContent, null));
+ }
+ else
+ {
+ byte[] hash = (byte[])hashes[info.DigestAlgorithm.Algorithm.Id];
+
+ signerInfos.Add(new SignerInformation(info, contentType, null, new BaseDigestCalculator(hash)));
+ }
+ }
+
+ signerInfoStore = new SignerInformationStore(signerInfos);
+ }
+
+ return signerInfoStore;
+ }
+
+ /**
+ * return a X509Store containing the attribute certificates, if any, contained
+ * in this message.
+ *
+ * @param type type of store to create
+ * @return a store of attribute certificates
+ * @exception NoSuchStoreException if the store type isn't available.
+ * @exception CmsException if a general exception prevents creation of the X509Store
+ */
+ public IX509Store GetAttributeCertificates(
+ string type)
+ {
+ if (attrCertStore == null)
+ {
+ attrCertStore = Helper.CreateAttributeStore(type, signedData.Certificates);
+ }
+
+ return attrCertStore;
+ }
+
+ /**
+ * return a X509Store containing the public key certificates, if any, contained
+ * in this message.
+ *
+ * @param type type of store to create
+ * @return a store of public key certificates
+ * @exception NoSuchStoreException if the store type isn't available.
+ * @exception CmsException if a general exception prevents creation of the X509Store
+ */
+ public IX509Store GetCertificates(
+ string type)
+ {
+ if (certificateStore == null)
+ {
+ certificateStore = Helper.CreateCertificateStore(type, signedData.Certificates);
+ }
+
+ return certificateStore;
+ }
+
+ /**
+ * return a X509Store containing CRLs, if any, contained
+ * in this message.
+ *
+ * @param type type of store to create
+ * @return a store of CRLs
+ * @exception NoSuchStoreException if the store type isn't available.
+ * @exception CmsException if a general exception prevents creation of the X509Store
+ */
+ public IX509Store GetCrls(
+ string type)
+ {
+ if (crlStore == null)
+ {
+ crlStore = Helper.CreateCrlStore(type, signedData.CRLs);
+ }
+
+ return crlStore;
+ }
+
+ [Obsolete("Use 'SignedContentType' property instead.")]
+ public string SignedContentTypeOid
+ {
+ get { return signedData.EncapContentInfo.ContentType.Id; }
+ }
+
+ ///
+ /// Return the DerObjectIdentifier associated with the encapsulated
+ /// content info structure carried in the signed data.
+ ///
+ public DerObjectIdentifier SignedContentType
+ {
+ get { return signedData.EncapContentInfo.ContentType; }
+ }
+
+ public CmsProcessable SignedContent
+ {
+ get { return signedContent; }
+ }
+
+ /**
+ * return the ContentInfo
+ */
+ public ContentInfo ContentInfo
+ {
+ get { return contentInfo; }
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] GetEncoded()
+ {
+ return contentInfo.GetEncoded();
+ }
+
+ /**
+ * Replace the signerinformation store associated with this
+ * CmsSignedData object with the new one passed in. You would
+ * probably only want to do this if you wanted to change the unsigned
+ * attributes associated with a signer, or perhaps delete one.
+ *
+ * @param signedData the signed data object to be used as a base.
+ * @param signerInformationStore the new signer information store to use.
+ * @return a new signed data object.
+ */
+ public static CmsSignedData ReplaceSigners(
+ CmsSignedData signedData,
+ SignerInformationStore signerInformationStore)
+ {
+ //
+ // copy
+ //
+ CmsSignedData cms = new CmsSignedData(signedData);
+
+ //
+ // replace the store
+ //
+ cms.signerInfoStore = signerInformationStore;
+
+ //
+ // replace the signers in the SignedData object
+ //
+ Asn1EncodableVector digestAlgs = new Asn1EncodableVector();
+ Asn1EncodableVector vec = new Asn1EncodableVector();
+
+ foreach (SignerInformation signer in signerInformationStore.GetSigners())
+ {
+ digestAlgs.Add(Helper.FixAlgID(signer.DigestAlgorithmID));
+ vec.Add(signer.ToSignerInfo());
+ }
+
+ Asn1Set digests = new DerSet(digestAlgs);
+ Asn1Set signers = new DerSet(vec);
+ Asn1Sequence sD = (Asn1Sequence)signedData.signedData.ToAsn1Object();
+
+ //
+ // signers are the last item in the sequence.
+ //
+ vec = new Asn1EncodableVector(
+ sD[0], // version
+ digests);
+
+ for (int i = 2; i != sD.Count - 1; i++)
+ {
+ vec.Add(sD[i]);
+ }
+
+ vec.Add(signers);
+
+ cms.signedData = SignedData.GetInstance(new BerSequence(vec));
+
+ //
+ // replace the contentInfo with the new one
+ //
+ cms.contentInfo = new ContentInfo(cms.contentInfo.ContentType, cms.signedData);
+
+ return cms;
+ }
+
+ /**
+ * Replace the certificate and CRL information associated with this
+ * CmsSignedData object with the new one passed in.
+ *
+ * @param signedData the signed data object to be used as a base.
+ * @param x509Certs the new certificates to be used.
+ * @param x509Crls the new CRLs to be used.
+ * @return a new signed data object.
+ * @exception CmsException if there is an error processing the stores
+ */
+ public static CmsSignedData ReplaceCertificatesAndCrls(
+ CmsSignedData signedData,
+ IX509Store x509Certs,
+ IX509Store x509Crls,
+ IX509Store x509AttrCerts)
+ {
+ if (x509AttrCerts != null)
+ throw Platform.CreateNotImplementedException("Currently can't replace attribute certificates");
+
+ //
+ // copy
+ //
+ CmsSignedData cms = new CmsSignedData(signedData);
+
+ //
+ // replace the certs and crls in the SignedData object
+ //
+ Asn1Set certs = null;
+ try
+ {
+ Asn1Set asn1Set = CmsUtilities.CreateBerSetFromList(
+ CmsUtilities.GetCertificatesFromStore(x509Certs));
+
+ if (asn1Set.Count != 0)
+ {
+ certs = asn1Set;
+ }
+ }
+ catch (X509StoreException e)
+ {
+ throw new CmsException("error getting certificates from store", e);
+ }
+
+ Asn1Set crls = null;
+ try
+ {
+ Asn1Set asn1Set = CmsUtilities.CreateBerSetFromList(
+ CmsUtilities.GetCrlsFromStore(x509Crls));
+
+ if (asn1Set.Count != 0)
+ {
+ crls = asn1Set;
+ }
+ }
+ catch (X509StoreException e)
+ {
+ throw new CmsException("error getting CRLs from store", e);
+ }
+
+ //
+ // replace the CMS structure.
+ //
+ SignedData old = signedData.signedData;
+ cms.signedData = new SignedData(
+ old.DigestAlgorithms,
+ old.EncapContentInfo,
+ certs,
+ crls,
+ old.SignerInfos);
+
+ //
+ // replace the contentInfo with the new one
+ //
+ cms.contentInfo = new ContentInfo(cms.contentInfo.ContentType, cms.signedData);
+
+ return cms;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSSignedDataGenerator.cs b/bc-sharp-crypto/src/cms/CMSSignedDataGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f63ed874e92f47f1c55e33fc494436c197058944
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSSignedDataGenerator.cs
@@ -0,0 +1,585 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.Crypto.Operators;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * general class for generating a pkcs7-signature message.
+ *
+ * A simple example of usage.
+ *
+ *
+ * IX509Store certs...
+ * IX509Store crls...
+ * CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+ *
+ * gen.AddSigner(privKey, cert, CmsSignedGenerator.DigestSha1);
+ * gen.AddCertificates(certs);
+ * gen.AddCrls(crls);
+ *
+ * CmsSignedData data = gen.Generate(content);
+ *
+ *
+ */
+ public class CmsSignedDataGenerator
+ : CmsSignedGenerator
+ {
+ private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance;
+
+ private readonly IList signerInfs = Platform.CreateArrayList();
+
+ private class SignerInf
+ {
+ private readonly CmsSignedGenerator outer;
+
+ private readonly ISignatureFactory sigCalc;
+ private readonly SignerIdentifier signerIdentifier;
+ private readonly string digestOID;
+ private readonly string encOID;
+ private readonly CmsAttributeTableGenerator sAttr;
+ private readonly CmsAttributeTableGenerator unsAttr;
+ private readonly Asn1.Cms.AttributeTable baseSignedTable;
+
+ internal SignerInf(
+ CmsSignedGenerator outer,
+ AsymmetricKeyParameter key,
+ SignerIdentifier signerIdentifier,
+ string digestOID,
+ string encOID,
+ CmsAttributeTableGenerator sAttr,
+ CmsAttributeTableGenerator unsAttr,
+ Asn1.Cms.AttributeTable baseSignedTable)
+ {
+ string digestName = Helper.GetDigestAlgName(digestOID);
+
+ string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(encOID);
+
+ this.outer = outer;
+ this.sigCalc = new Asn1SignatureFactory(signatureName, key);
+ this.signerIdentifier = signerIdentifier;
+ this.digestOID = digestOID;
+ this.encOID = encOID;
+ this.sAttr = sAttr;
+ this.unsAttr = unsAttr;
+ this.baseSignedTable = baseSignedTable;
+ }
+
+ internal SignerInf(
+ CmsSignedGenerator outer,
+ ISignatureFactory sigCalc,
+ SignerIdentifier signerIdentifier,
+ CmsAttributeTableGenerator sAttr,
+ CmsAttributeTableGenerator unsAttr,
+ Asn1.Cms.AttributeTable baseSignedTable)
+ {
+ this.outer = outer;
+ this.sigCalc = sigCalc;
+ this.signerIdentifier = signerIdentifier;
+ this.digestOID = new DefaultDigestAlgorithmIdentifierFinder().find((AlgorithmIdentifier)sigCalc.AlgorithmDetails).Algorithm.Id;
+ this.encOID = ((AlgorithmIdentifier)sigCalc.AlgorithmDetails).Algorithm.Id;
+ this.sAttr = sAttr;
+ this.unsAttr = unsAttr;
+ this.baseSignedTable = baseSignedTable;
+ }
+
+ internal AlgorithmIdentifier DigestAlgorithmID
+ {
+ get { return new AlgorithmIdentifier(new DerObjectIdentifier(digestOID), DerNull.Instance); }
+ }
+
+ internal CmsAttributeTableGenerator SignedAttributes
+ {
+ get { return sAttr; }
+ }
+
+ internal CmsAttributeTableGenerator UnsignedAttributes
+ {
+ get { return unsAttr; }
+ }
+
+ internal SignerInfo ToSignerInfo(
+ DerObjectIdentifier contentType,
+ CmsProcessable content,
+ SecureRandom random)
+ {
+ AlgorithmIdentifier digAlgId = DigestAlgorithmID;
+ string digestName = Helper.GetDigestAlgName(digestOID);
+
+ string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(encOID);
+
+ byte[] hash;
+ if (outer._digests.Contains(digestOID))
+ {
+ hash = (byte[])outer._digests[digestOID];
+ }
+ else
+ {
+ IDigest dig = Helper.GetDigestInstance(digestName);
+ if (content != null)
+ {
+ content.Write(new DigOutputStream(dig));
+ }
+ hash = DigestUtilities.DoFinal(dig);
+ outer._digests.Add(digestOID, hash.Clone());
+ }
+
+ IStreamCalculator calculator = sigCalc.CreateCalculator();
+
+#if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE
+ Stream sigStr = calculator.Stream;
+#else
+ Stream sigStr = new BufferedStream(calculator.Stream);
+#endif
+
+ Asn1Set signedAttr = null;
+ if (sAttr != null)
+ {
+ IDictionary parameters = outer.GetBaseParameters(contentType, digAlgId, hash);
+
+// Asn1.Cms.AttributeTable signed = sAttr.GetAttributes(Collections.unmodifiableMap(parameters));
+ Asn1.Cms.AttributeTable signed = sAttr.GetAttributes(parameters);
+
+ if (contentType == null) //counter signature
+ {
+ if (signed != null && signed[CmsAttributes.ContentType] != null)
+ {
+ IDictionary tmpSigned = signed.ToDictionary();
+ tmpSigned.Remove(CmsAttributes.ContentType);
+ signed = new Asn1.Cms.AttributeTable(tmpSigned);
+ }
+ }
+
+ // TODO Validate proposed signed attributes
+
+ signedAttr = outer.GetAttributeSet(signed);
+
+ // sig must be composed from the DER encoding.
+ new DerOutputStream(sigStr).WriteObject(signedAttr);
+ }
+ else if (content != null)
+ {
+ // TODO Use raw signature of the hash value instead
+ content.Write(sigStr);
+ }
+
+ Platform.Dispose(sigStr);
+ byte[] sigBytes = ((IBlockResult)calculator.GetResult()).Collect();
+
+ Asn1Set unsignedAttr = null;
+ if (unsAttr != null)
+ {
+ IDictionary baseParameters = outer.GetBaseParameters(contentType, digAlgId, hash);
+ baseParameters[CmsAttributeTableParameter.Signature] = sigBytes.Clone();
+
+// Asn1.Cms.AttributeTable unsigned = unsAttr.GetAttributes(Collections.unmodifiableMap(baseParameters));
+ Asn1.Cms.AttributeTable unsigned = unsAttr.GetAttributes(baseParameters);
+
+ // TODO Validate proposed unsigned attributes
+
+ unsignedAttr = outer.GetAttributeSet(unsigned);
+ }
+
+ // TODO[RSAPSS] Need the ability to specify non-default parameters
+ Asn1Encodable sigX509Parameters = SignerUtilities.GetDefaultX509Parameters(signatureName);
+ AlgorithmIdentifier encAlgId = Helper.GetEncAlgorithmIdentifier(
+ new DerObjectIdentifier(encOID), sigX509Parameters);
+
+ return new SignerInfo(signerIdentifier, digAlgId,
+ signedAttr, encAlgId, new DerOctetString(sigBytes), unsignedAttr);
+ }
+ }
+
+ public CmsSignedDataGenerator()
+ {
+ }
+
+ /// Constructor allowing specific source of randomness
+ /// Instance of SecureRandom to use.
+ public CmsSignedDataGenerator(
+ SecureRandom rand)
+ : base(rand)
+ {
+ }
+
+ /**
+ * add a signer - no attributes other than the default ones will be
+ * provided here.
+ *
+ * @param key signing key to use
+ * @param cert certificate containing corresponding public key
+ * @param digestOID digest algorithm OID
+ */
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ X509Certificate cert,
+ string digestOID)
+ {
+ AddSigner(privateKey, cert, Helper.GetEncOid(privateKey, digestOID), digestOID);
+ }
+
+ /**
+ * add a signer, specifying the digest encryption algorithm to use - no attributes other than the default ones will be
+ * provided here.
+ *
+ * @param key signing key to use
+ * @param cert certificate containing corresponding public key
+ * @param encryptionOID digest encryption algorithm OID
+ * @param digestOID digest algorithm OID
+ */
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ X509Certificate cert,
+ string encryptionOID,
+ string digestOID)
+ {
+ doAddSigner(privateKey, GetSignerIdentifier(cert), encryptionOID, digestOID,
+ new DefaultSignedAttributeTableGenerator(), null, null);
+ }
+
+ /**
+ * add a signer - no attributes other than the default ones will be
+ * provided here.
+ */
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ byte[] subjectKeyID,
+ string digestOID)
+ {
+ AddSigner(privateKey, subjectKeyID, Helper.GetEncOid(privateKey, digestOID), digestOID);
+ }
+
+ /**
+ * add a signer, specifying the digest encryption algorithm to use - no attributes other than the default ones will be
+ * provided here.
+ */
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ byte[] subjectKeyID,
+ string encryptionOID,
+ string digestOID)
+ {
+ doAddSigner(privateKey, GetSignerIdentifier(subjectKeyID), encryptionOID, digestOID,
+ new DefaultSignedAttributeTableGenerator(), null, null);
+ }
+
+ /**
+ * add a signer with extra signed/unsigned attributes.
+ *
+ * @param key signing key to use
+ * @param cert certificate containing corresponding public key
+ * @param digestOID digest algorithm OID
+ * @param signedAttr table of attributes to be included in signature
+ * @param unsignedAttr table of attributes to be included as unsigned
+ */
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ X509Certificate cert,
+ string digestOID,
+ Asn1.Cms.AttributeTable signedAttr,
+ Asn1.Cms.AttributeTable unsignedAttr)
+ {
+ AddSigner(privateKey, cert, Helper.GetEncOid(privateKey, digestOID), digestOID,
+ signedAttr, unsignedAttr);
+ }
+
+ /**
+ * add a signer, specifying the digest encryption algorithm, with extra signed/unsigned attributes.
+ *
+ * @param key signing key to use
+ * @param cert certificate containing corresponding public key
+ * @param encryptionOID digest encryption algorithm OID
+ * @param digestOID digest algorithm OID
+ * @param signedAttr table of attributes to be included in signature
+ * @param unsignedAttr table of attributes to be included as unsigned
+ */
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ X509Certificate cert,
+ string encryptionOID,
+ string digestOID,
+ Asn1.Cms.AttributeTable signedAttr,
+ Asn1.Cms.AttributeTable unsignedAttr)
+ {
+ doAddSigner(privateKey, GetSignerIdentifier(cert), encryptionOID, digestOID,
+ new DefaultSignedAttributeTableGenerator(signedAttr),
+ new SimpleAttributeTableGenerator(unsignedAttr),
+ signedAttr);
+ }
+
+ /**
+ * add a signer with extra signed/unsigned attributes.
+ *
+ * @param key signing key to use
+ * @param subjectKeyID subjectKeyID of corresponding public key
+ * @param digestOID digest algorithm OID
+ * @param signedAttr table of attributes to be included in signature
+ * @param unsignedAttr table of attributes to be included as unsigned
+ */
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ byte[] subjectKeyID,
+ string digestOID,
+ Asn1.Cms.AttributeTable signedAttr,
+ Asn1.Cms.AttributeTable unsignedAttr)
+ {
+ AddSigner(privateKey, subjectKeyID, Helper.GetEncOid(privateKey, digestOID), digestOID,
+ signedAttr, unsignedAttr);
+ }
+
+ /**
+ * add a signer, specifying the digest encryption algorithm, with extra signed/unsigned attributes.
+ *
+ * @param key signing key to use
+ * @param subjectKeyID subjectKeyID of corresponding public key
+ * @param encryptionOID digest encryption algorithm OID
+ * @param digestOID digest algorithm OID
+ * @param signedAttr table of attributes to be included in signature
+ * @param unsignedAttr table of attributes to be included as unsigned
+ */
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ byte[] subjectKeyID,
+ string encryptionOID,
+ string digestOID,
+ Asn1.Cms.AttributeTable signedAttr,
+ Asn1.Cms.AttributeTable unsignedAttr)
+ {
+ doAddSigner(privateKey, GetSignerIdentifier(subjectKeyID), encryptionOID, digestOID,
+ new DefaultSignedAttributeTableGenerator(signedAttr),
+ new SimpleAttributeTableGenerator(unsignedAttr),
+ signedAttr);
+ }
+
+ /**
+ * add a signer with extra signed/unsigned attributes based on generators.
+ */
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ X509Certificate cert,
+ string digestOID,
+ CmsAttributeTableGenerator signedAttrGen,
+ CmsAttributeTableGenerator unsignedAttrGen)
+ {
+ AddSigner(privateKey, cert, Helper.GetEncOid(privateKey, digestOID), digestOID,
+ signedAttrGen, unsignedAttrGen);
+ }
+
+ /**
+ * add a signer, specifying the digest encryption algorithm, with extra signed/unsigned attributes based on generators.
+ */
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ X509Certificate cert,
+ string encryptionOID,
+ string digestOID,
+ CmsAttributeTableGenerator signedAttrGen,
+ CmsAttributeTableGenerator unsignedAttrGen)
+ {
+ doAddSigner(privateKey, GetSignerIdentifier(cert), encryptionOID, digestOID, signedAttrGen,
+ unsignedAttrGen, null);
+ }
+
+ /**
+ * add a signer with extra signed/unsigned attributes based on generators.
+ */
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ byte[] subjectKeyID,
+ string digestOID,
+ CmsAttributeTableGenerator signedAttrGen,
+ CmsAttributeTableGenerator unsignedAttrGen)
+ {
+ AddSigner(privateKey, subjectKeyID, Helper.GetEncOid(privateKey, digestOID), digestOID,
+ signedAttrGen, unsignedAttrGen);
+ }
+
+ /**
+ * add a signer, including digest encryption algorithm, with extra signed/unsigned attributes based on generators.
+ */
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ byte[] subjectKeyID,
+ string encryptionOID,
+ string digestOID,
+ CmsAttributeTableGenerator signedAttrGen,
+ CmsAttributeTableGenerator unsignedAttrGen)
+ {
+ doAddSigner(privateKey, GetSignerIdentifier(subjectKeyID), encryptionOID, digestOID,
+ signedAttrGen, unsignedAttrGen, null);
+ }
+
+ public void AddSignerInfoGenerator(SignerInfoGenerator signerInfoGenerator)
+ {
+ signerInfs.Add(new SignerInf(this, signerInfoGenerator.contentSigner, signerInfoGenerator.sigId,
+ signerInfoGenerator.signedGen, signerInfoGenerator.unsignedGen, null));
+ }
+
+ private void doAddSigner(
+ AsymmetricKeyParameter privateKey,
+ SignerIdentifier signerIdentifier,
+ string encryptionOID,
+ string digestOID,
+ CmsAttributeTableGenerator signedAttrGen,
+ CmsAttributeTableGenerator unsignedAttrGen,
+ Asn1.Cms.AttributeTable baseSignedTable)
+ {
+ signerInfs.Add(new SignerInf(this, privateKey, signerIdentifier, digestOID, encryptionOID,
+ signedAttrGen, unsignedAttrGen, baseSignedTable));
+ }
+
+ /**
+ * generate a signed object that for a CMS Signed Data object
+ */
+ public CmsSignedData Generate(
+ CmsProcessable content)
+ {
+ return Generate(content, false);
+ }
+
+ /**
+ * generate a signed object that for a CMS Signed Data
+ * object - if encapsulate is true a copy
+ * of the message will be included in the signature. The content type
+ * is set according to the OID represented by the string signedContentType.
+ */
+ public CmsSignedData Generate(
+ string signedContentType,
+ // FIXME Avoid accessing more than once to support CmsProcessableInputStream
+ CmsProcessable content,
+ bool encapsulate)
+ {
+ Asn1EncodableVector digestAlgs = new Asn1EncodableVector();
+ Asn1EncodableVector signerInfos = new Asn1EncodableVector();
+
+ _digests.Clear(); // clear the current preserved digest state
+
+ //
+ // add the precalculated SignerInfo objects.
+ //
+ foreach (SignerInformation signer in _signers)
+ {
+ digestAlgs.Add(Helper.FixAlgID(signer.DigestAlgorithmID));
+
+ // TODO Verify the content type and calculated digest match the precalculated SignerInfo
+ signerInfos.Add(signer.ToSignerInfo());
+ }
+
+ //
+ // add the SignerInfo objects
+ //
+ bool isCounterSignature = (signedContentType == null);
+
+ DerObjectIdentifier contentTypeOid = isCounterSignature
+ ? null
+ : new DerObjectIdentifier(signedContentType);
+
+ foreach (SignerInf signer in signerInfs)
+ {
+ try
+ {
+ digestAlgs.Add(signer.DigestAlgorithmID);
+ signerInfos.Add(signer.ToSignerInfo(contentTypeOid, content, rand));
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("encoding error.", e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CmsException("key inappropriate for signature.", e);
+ }
+ catch (SignatureException e)
+ {
+ throw new CmsException("error creating signature.", e);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new CmsException("error creating sid.", e);
+ }
+ }
+
+ Asn1Set certificates = null;
+
+ if (_certs.Count != 0)
+ {
+ certificates = CmsUtilities.CreateBerSetFromList(_certs);
+ }
+
+ Asn1Set certrevlist = null;
+
+ if (_crls.Count != 0)
+ {
+ certrevlist = CmsUtilities.CreateBerSetFromList(_crls);
+ }
+
+ Asn1OctetString octs = null;
+ if (encapsulate)
+ {
+ MemoryStream bOut = new MemoryStream();
+ if (content != null)
+ {
+ try
+ {
+ content.Write(bOut);
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("encapsulation error.", e);
+ }
+ }
+ octs = new BerOctetString(bOut.ToArray());
+ }
+
+ ContentInfo encInfo = new ContentInfo(contentTypeOid, octs);
+
+ SignedData sd = new SignedData(
+ new DerSet(digestAlgs),
+ encInfo,
+ certificates,
+ certrevlist,
+ new DerSet(signerInfos));
+
+ ContentInfo contentInfo = new ContentInfo(CmsObjectIdentifiers.SignedData, sd);
+
+ return new CmsSignedData(content, contentInfo);
+ }
+
+ /**
+ * generate a signed object that for a CMS Signed Data
+ * object - if encapsulate is true a copy
+ * of the message will be included in the signature with the
+ * default content type "data".
+ */
+ public CmsSignedData Generate(
+ CmsProcessable content,
+ bool encapsulate)
+ {
+ return this.Generate(Data, content, encapsulate);
+ }
+
+ /**
+ * generate a set of one or more SignerInformation objects representing counter signatures on
+ * the passed in SignerInformation object.
+ *
+ * @param signer the signer to be countersigned
+ * @param sigProvider the provider to be used for counter signing.
+ * @return a store containing the signers.
+ */
+ public SignerInformationStore GenerateCounterSigners(
+ SignerInformation signer)
+ {
+ return this.Generate(null, new CmsProcessableByteArray(signer.GetSignature()), false).GetSignerInfos();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSSignedDataParser.cs b/bc-sharp-crypto/src/cms/CMSSignedDataParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fb51ab1199b079d455fa9463def302c3915bb472
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSSignedDataParser.cs
@@ -0,0 +1,450 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * Parsing class for an CMS Signed Data object from an input stream.
+ *
+ * Note: that because we are in a streaming mode only one signer can be tried and it is important
+ * that the methods on the parser are called in the appropriate order.
+ *
+ *
+ * A simple example of usage for an encapsulated signature.
+ *
+ *
+ * Two notes: first, in the example below the validity of
+ * the certificate isn't verified, just the fact that one of the certs
+ * matches the given signer, and, second, because we are in a streaming
+ * mode the order of the operations is important.
+ *
+ *
+ * CmsSignedDataParser sp = new CmsSignedDataParser(encapSigData);
+ *
+ * sp.GetSignedContent().Drain();
+ *
+ * IX509Store certs = sp.GetCertificates();
+ * SignerInformationStore signers = sp.GetSignerInfos();
+ *
+ * foreach (SignerInformation signer in signers.GetSigners())
+ * {
+ * ArrayList certList = new ArrayList(certs.GetMatches(signer.SignerID));
+ * X509Certificate cert = (X509Certificate) certList[0];
+ *
+ * Console.WriteLine("verify returns: " + signer.Verify(cert));
+ * }
+ *
+ * Note also: this class does not introduce buffering - if you are processing large files you should create
+ * the parser with:
+ *
+ * CmsSignedDataParser ep = new CmsSignedDataParser(new BufferedInputStream(encapSigData, bufSize));
+ *
+ * where bufSize is a suitably large buffer size.
+ */
+ public class CmsSignedDataParser
+ : CmsContentInfoParser
+ {
+ private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance;
+
+ private SignedDataParser _signedData;
+ private DerObjectIdentifier _signedContentType;
+ private CmsTypedStream _signedContent;
+ private IDictionary _digests;
+ private ISet _digestOids;
+
+ private SignerInformationStore _signerInfoStore;
+ private Asn1Set _certSet, _crlSet;
+ private bool _isCertCrlParsed;
+ private IX509Store _attributeStore;
+ private IX509Store _certificateStore;
+ private IX509Store _crlStore;
+
+ public CmsSignedDataParser(
+ byte[] sigBlock)
+ : this(new MemoryStream(sigBlock, false))
+ {
+ }
+
+ public CmsSignedDataParser(
+ CmsTypedStream signedContent,
+ byte[] sigBlock)
+ : this(signedContent, new MemoryStream(sigBlock, false))
+ {
+ }
+
+ /**
+ * base constructor - with encapsulated content
+ */
+ public CmsSignedDataParser(
+ Stream sigData)
+ : this(null, sigData)
+ {
+ }
+
+ /**
+ * base constructor
+ *
+ * @param signedContent the content that was signed.
+ * @param sigData the signature object.
+ */
+ public CmsSignedDataParser(
+ CmsTypedStream signedContent,
+ Stream sigData)
+ : base(sigData)
+ {
+ try
+ {
+ this._signedContent = signedContent;
+ this._signedData = SignedDataParser.GetInstance(this.contentInfo.GetContent(Asn1Tags.Sequence));
+ this._digests = Platform.CreateHashtable();
+ this._digestOids = new HashSet();
+
+ Asn1SetParser digAlgs = _signedData.GetDigestAlgorithms();
+ IAsn1Convertible o;
+
+ while ((o = digAlgs.ReadObject()) != null)
+ {
+ AlgorithmIdentifier id = AlgorithmIdentifier.GetInstance(o.ToAsn1Object());
+
+ try
+ {
+ string digestOid = id.Algorithm.Id;
+ string digestName = Helper.GetDigestAlgName(digestOid);
+
+ if (!this._digests.Contains(digestName))
+ {
+ this._digests[digestName] = Helper.GetDigestInstance(digestName);
+ this._digestOids.Add(digestOid);
+ }
+ }
+ catch (SecurityUtilityException)
+ {
+ // TODO Should do something other than ignore it
+ }
+ }
+
+ //
+ // If the message is simply a certificate chain message GetContent() may return null.
+ //
+ ContentInfoParser cont = _signedData.GetEncapContentInfo();
+ Asn1OctetStringParser octs = (Asn1OctetStringParser)
+ cont.GetContent(Asn1Tags.OctetString);
+
+ if (octs != null)
+ {
+ CmsTypedStream ctStr = new CmsTypedStream(
+ cont.ContentType.Id, octs.GetOctetStream());
+
+ if (_signedContent == null)
+ {
+ this._signedContent = ctStr;
+ }
+ else
+ {
+ //
+ // content passed in, need to read past empty encapsulated content info object if present
+ //
+ ctStr.Drain();
+ }
+ }
+
+ _signedContentType = _signedContent == null
+ ? cont.ContentType
+ : new DerObjectIdentifier(_signedContent.ContentType);
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("io exception: " + e.Message, e);
+ }
+ }
+
+ /**
+ * Return the version number for the SignedData object
+ *
+ * @return the version number
+ */
+ public int Version
+ {
+ get { return _signedData.Version.Value.IntValue; }
+ }
+
+ public ISet DigestOids
+ {
+ get { return new HashSet(_digestOids); }
+ }
+
+ /**
+ * return the collection of signers that are associated with the
+ * signatures for the message.
+ * @throws CmsException
+ */
+ public SignerInformationStore GetSignerInfos()
+ {
+ if (_signerInfoStore == null)
+ {
+ PopulateCertCrlSets();
+
+ IList signerInfos = Platform.CreateArrayList();
+ IDictionary hashes = Platform.CreateHashtable();
+
+ foreach (object digestKey in _digests.Keys)
+ {
+ hashes[digestKey] = DigestUtilities.DoFinal(
+ (IDigest)_digests[digestKey]);
+ }
+
+ try
+ {
+ Asn1SetParser s = _signedData.GetSignerInfos();
+ IAsn1Convertible o;
+
+ while ((o = s.ReadObject()) != null)
+ {
+ SignerInfo info = SignerInfo.GetInstance(o.ToAsn1Object());
+ string digestName = Helper.GetDigestAlgName(
+ info.DigestAlgorithm.Algorithm.Id);
+
+ byte[] hash = (byte[]) hashes[digestName];
+
+ signerInfos.Add(new SignerInformation(info, _signedContentType, null, new BaseDigestCalculator(hash)));
+ }
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("io exception: " + e.Message, e);
+ }
+
+ _signerInfoStore = new SignerInformationStore(signerInfos);
+ }
+
+ return _signerInfoStore;
+ }
+
+ /**
+ * return a X509Store containing the attribute certificates, if any, contained
+ * in this message.
+ *
+ * @param type type of store to create
+ * @return a store of attribute certificates
+ * @exception org.bouncycastle.x509.NoSuchStoreException if the store type isn't available.
+ * @exception CmsException if a general exception prevents creation of the X509Store
+ */
+ public IX509Store GetAttributeCertificates(
+ string type)
+ {
+ if (_attributeStore == null)
+ {
+ PopulateCertCrlSets();
+
+ _attributeStore = Helper.CreateAttributeStore(type, _certSet);
+ }
+
+ return _attributeStore;
+ }
+
+ /**
+ * return a X509Store containing the public key certificates, if any, contained
+ * in this message.
+ *
+ * @param type type of store to create
+ * @return a store of public key certificates
+ * @exception NoSuchStoreException if the store type isn't available.
+ * @exception CmsException if a general exception prevents creation of the X509Store
+ */
+ public IX509Store GetCertificates(
+ string type)
+ {
+ if (_certificateStore == null)
+ {
+ PopulateCertCrlSets();
+
+ _certificateStore = Helper.CreateCertificateStore(type, _certSet);
+ }
+
+ return _certificateStore;
+ }
+
+ /**
+ * return a X509Store containing CRLs, if any, contained
+ * in this message.
+ *
+ * @param type type of store to create
+ * @return a store of CRLs
+ * @exception NoSuchStoreException if the store type isn't available.
+ * @exception CmsException if a general exception prevents creation of the X509Store
+ */
+ public IX509Store GetCrls(
+ string type)
+ {
+ if (_crlStore == null)
+ {
+ PopulateCertCrlSets();
+
+ _crlStore = Helper.CreateCrlStore(type, _crlSet);
+ }
+
+ return _crlStore;
+ }
+
+ private void PopulateCertCrlSets()
+ {
+ if (_isCertCrlParsed)
+ return;
+
+ _isCertCrlParsed = true;
+
+ try
+ {
+ // care! Streaming - Must process the GetCertificates() result before calling GetCrls()
+ _certSet = GetAsn1Set(_signedData.GetCertificates());
+ _crlSet = GetAsn1Set(_signedData.GetCrls());
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("problem parsing cert/crl sets", e);
+ }
+ }
+
+ ///
+ /// Return the DerObjectIdentifier associated with the encapsulated
+ /// content info structure carried in the signed data.
+ ///
+ public DerObjectIdentifier SignedContentType
+ {
+ get { return _signedContentType; }
+ }
+
+ public CmsTypedStream GetSignedContent()
+ {
+ if (_signedContent == null)
+ {
+ return null;
+ }
+
+ Stream digStream = _signedContent.ContentStream;
+
+ foreach (IDigest digest in _digests.Values)
+ {
+ digStream = new DigestStream(digStream, digest, null);
+ }
+
+ return new CmsTypedStream(_signedContent.ContentType, digStream);
+ }
+
+ /**
+ * Replace the signerinformation store associated with the passed
+ * in message contained in the stream original with the new one passed in.
+ * You would probably only want to do this if you wanted to change the unsigned
+ * attributes associated with a signer, or perhaps delete one.
+ *
+ * The output stream is returned unclosed.
+ *
+ * @param original the signed data stream to be used as a base.
+ * @param signerInformationStore the new signer information store to use.
+ * @param out the stream to Write the new signed data object to.
+ * @return out.
+ */
+ public static Stream ReplaceSigners(
+ Stream original,
+ SignerInformationStore signerInformationStore,
+ Stream outStr)
+ {
+ // NB: SecureRandom would be ignored since using existing signatures only
+ CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+ CmsSignedDataParser parser = new CmsSignedDataParser(original);
+
+// gen.AddDigests(parser.DigestOids);
+ gen.AddSigners(signerInformationStore);
+
+ CmsTypedStream signedContent = parser.GetSignedContent();
+ bool encapsulate = (signedContent != null);
+ Stream contentOut = gen.Open(outStr, parser.SignedContentType.Id, encapsulate);
+ if (encapsulate)
+ {
+ Streams.PipeAll(signedContent.ContentStream, contentOut);
+ }
+
+ gen.AddAttributeCertificates(parser.GetAttributeCertificates("Collection"));
+ gen.AddCertificates(parser.GetCertificates("Collection"));
+ gen.AddCrls(parser.GetCrls("Collection"));
+
+// gen.AddSigners(parser.GetSignerInfos());
+
+ Platform.Dispose(contentOut);
+
+ return outStr;
+ }
+
+ /**
+ * Replace the certificate and CRL information associated with this
+ * CMSSignedData object with the new one passed in.
+ *
+ * The output stream is returned unclosed.
+ *
+ * @param original the signed data stream to be used as a base.
+ * @param certsAndCrls the new certificates and CRLs to be used.
+ * @param out the stream to Write the new signed data object to.
+ * @return out.
+ * @exception CmsException if there is an error processing the CertStore
+ */
+ public static Stream ReplaceCertificatesAndCrls(
+ Stream original,
+ IX509Store x509Certs,
+ IX509Store x509Crls,
+ IX509Store x509AttrCerts,
+ Stream outStr)
+ {
+ // NB: SecureRandom would be ignored since using existing signatures only
+ CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+ CmsSignedDataParser parser = new CmsSignedDataParser(original);
+
+ gen.AddDigests(parser.DigestOids);
+
+ CmsTypedStream signedContent = parser.GetSignedContent();
+ bool encapsulate = (signedContent != null);
+ Stream contentOut = gen.Open(outStr, parser.SignedContentType.Id, encapsulate);
+ if (encapsulate)
+ {
+ Streams.PipeAll(signedContent.ContentStream, contentOut);
+ }
+
+// gen.AddAttributeCertificates(parser.GetAttributeCertificates("Collection"));
+// gen.AddCertificates(parser.GetCertificates("Collection"));
+// gen.AddCrls(parser.GetCrls("Collection"));
+ if (x509AttrCerts != null)
+ gen.AddAttributeCertificates(x509AttrCerts);
+ if (x509Certs != null)
+ gen.AddCertificates(x509Certs);
+ if (x509Crls != null)
+ gen.AddCrls(x509Crls);
+
+ gen.AddSigners(parser.GetSignerInfos());
+
+ Platform.Dispose(contentOut);
+
+ return outStr;
+ }
+
+ private static Asn1Set GetAsn1Set(
+ Asn1SetParser asn1SetParser)
+ {
+ return asn1SetParser == null
+ ? null
+ : Asn1Set.GetInstance(asn1SetParser.ToAsn1Object());
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSSignedDataStreamGenerator.cs b/bc-sharp-crypto/src/cms/CMSSignedDataStreamGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d0ab7428a84146b36362c45fe3141464e47fa119
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSSignedDataStreamGenerator.cs
@@ -0,0 +1,929 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * General class for generating a pkcs7-signature message stream.
+ *
+ * A simple example of usage.
+ *
+ *
+ * IX509Store certs...
+ * CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+ *
+ * gen.AddSigner(privateKey, cert, CmsSignedDataStreamGenerator.DIGEST_SHA1);
+ *
+ * gen.AddCertificates(certs);
+ *
+ * Stream sigOut = gen.Open(bOut);
+ *
+ * sigOut.Write(Encoding.UTF8.GetBytes("Hello World!"));
+ *
+ * sigOut.Close();
+ *
+ */
+ public class CmsSignedDataStreamGenerator
+ : CmsSignedGenerator
+ {
+ private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance;
+
+ private readonly IList _signerInfs = Platform.CreateArrayList();
+ private readonly ISet _messageDigestOids = new HashSet();
+ private readonly IDictionary _messageDigests = Platform.CreateHashtable();
+ private readonly IDictionary _messageHashes = Platform.CreateHashtable();
+ private bool _messageDigestsLocked;
+ private int _bufferSize;
+
+ private class DigestAndSignerInfoGeneratorHolder
+ {
+ internal readonly ISignerInfoGenerator signerInf;
+ internal readonly string digestOID;
+
+ internal DigestAndSignerInfoGeneratorHolder(ISignerInfoGenerator signerInf, String digestOID)
+ {
+ this.signerInf = signerInf;
+ this.digestOID = digestOID;
+ }
+
+ internal AlgorithmIdentifier DigestAlgorithm
+ {
+ get { return new AlgorithmIdentifier(new DerObjectIdentifier(this.digestOID), DerNull.Instance); }
+ }
+ }
+
+ private class SignerInfoGeneratorImpl : ISignerInfoGenerator
+ {
+ private readonly CmsSignedDataStreamGenerator outer;
+
+ private readonly SignerIdentifier _signerIdentifier;
+ private readonly string _digestOID;
+ private readonly string _encOID;
+ private readonly CmsAttributeTableGenerator _sAttr;
+ private readonly CmsAttributeTableGenerator _unsAttr;
+ private readonly string _encName;
+ private readonly ISigner _sig;
+
+ internal SignerInfoGeneratorImpl(
+ CmsSignedDataStreamGenerator outer,
+ AsymmetricKeyParameter key,
+ SignerIdentifier signerIdentifier,
+ string digestOID,
+ string encOID,
+ CmsAttributeTableGenerator sAttr,
+ CmsAttributeTableGenerator unsAttr)
+ {
+ this.outer = outer;
+
+ _signerIdentifier = signerIdentifier;
+ _digestOID = digestOID;
+ _encOID = encOID;
+ _sAttr = sAttr;
+ _unsAttr = unsAttr;
+ _encName = Helper.GetEncryptionAlgName(_encOID);
+
+ string digestName = Helper.GetDigestAlgName(_digestOID);
+ string signatureName = digestName + "with" + _encName;
+
+ if (_sAttr != null)
+ {
+ _sig = Helper.GetSignatureInstance(signatureName);
+ }
+ else
+ {
+ // Note: Need to use raw signatures here since we have already calculated the digest
+ if (_encName.Equals("RSA"))
+ {
+ _sig = Helper.GetSignatureInstance("RSA");
+ }
+ else if (_encName.Equals("DSA"))
+ {
+ _sig = Helper.GetSignatureInstance("NONEwithDSA");
+ }
+ // TODO Add support for raw PSS
+// else if (_encName.equals("RSAandMGF1"))
+// {
+// _sig = CMSSignedHelper.INSTANCE.getSignatureInstance("NONEWITHRSAPSS", _sigProvider);
+// try
+// {
+// // Init the params this way to avoid having a 'raw' version of each PSS algorithm
+// Signature sig2 = CMSSignedHelper.INSTANCE.getSignatureInstance(signatureName, _sigProvider);
+// PSSParameterSpec spec = (PSSParameterSpec)sig2.getParameters().getParameterSpec(PSSParameterSpec.class);
+// _sig.setParameter(spec);
+// }
+// catch (Exception e)
+// {
+// throw new SignatureException("algorithm: " + _encName + " could not be configured.");
+// }
+// }
+ else
+ {
+ throw new SignatureException("algorithm: " + _encName + " not supported in base signatures.");
+ }
+ }
+
+ _sig.Init(true, new ParametersWithRandom(key, outer.rand));
+ }
+
+ public SignerInfo Generate(DerObjectIdentifier contentType, AlgorithmIdentifier digestAlgorithm,
+ byte[] calculatedDigest)
+ {
+ try
+ {
+ string digestName = Helper.GetDigestAlgName(_digestOID);
+ string signatureName = digestName + "with" + _encName;
+
+// AlgorithmIdentifier digAlgId = DigestAlgorithmID;
+//
+// byte[] hash = (byte[])outer._messageHashes[Helper.GetDigestAlgName(this._digestOID)];
+// outer._digests[_digestOID] = hash.Clone();
+
+ byte[] bytesToSign = calculatedDigest;
+
+ /* RFC 3852 5.4
+ * The result of the message digest calculation process depends on
+ * whether the signedAttrs field is present. When the field is absent,
+ * the result is just the message digest of the content as described
+ *
+ * above. When the field is present, however, the result is the message
+ * digest of the complete DER encoding of the SignedAttrs value
+ * contained in the signedAttrs field.
+ */
+ Asn1Set signedAttr = null;
+ if (_sAttr != null)
+ {
+ IDictionary parameters = outer.GetBaseParameters(contentType, digestAlgorithm, calculatedDigest);
+
+// Asn1.Cms.AttributeTable signed = _sAttr.GetAttributes(Collections.unmodifiableMap(parameters));
+ Asn1.Cms.AttributeTable signed = _sAttr.GetAttributes(parameters);
+
+ if (contentType == null) //counter signature
+ {
+ if (signed != null && signed[CmsAttributes.ContentType] != null)
+ {
+ IDictionary tmpSigned = signed.ToDictionary();
+ tmpSigned.Remove(CmsAttributes.ContentType);
+ signed = new Asn1.Cms.AttributeTable(tmpSigned);
+ }
+ }
+
+ signedAttr = outer.GetAttributeSet(signed);
+
+ // sig must be composed from the DER encoding.
+ bytesToSign = signedAttr.GetEncoded(Asn1Encodable.Der);
+ }
+ else
+ {
+ // Note: Need to use raw signatures here since we have already calculated the digest
+ if (_encName.Equals("RSA"))
+ {
+ DigestInfo dInfo = new DigestInfo(digestAlgorithm, calculatedDigest);
+ bytesToSign = dInfo.GetEncoded(Asn1Encodable.Der);
+ }
+ }
+
+ _sig.BlockUpdate(bytesToSign, 0, bytesToSign.Length);
+ byte[] sigBytes = _sig.GenerateSignature();
+
+ Asn1Set unsignedAttr = null;
+ if (_unsAttr != null)
+ {
+ IDictionary parameters = outer.GetBaseParameters(
+ contentType, digestAlgorithm, calculatedDigest);
+ parameters[CmsAttributeTableParameter.Signature] = sigBytes.Clone();
+
+// Asn1.Cms.AttributeTable unsigned = _unsAttr.getAttributes(Collections.unmodifiableMap(parameters));
+ Asn1.Cms.AttributeTable unsigned = _unsAttr.GetAttributes(parameters);
+
+ unsignedAttr = outer.GetAttributeSet(unsigned);
+ }
+
+ // TODO[RSAPSS] Need the ability to specify non-default parameters
+ Asn1Encodable sigX509Parameters = SignerUtilities.GetDefaultX509Parameters(signatureName);
+ AlgorithmIdentifier digestEncryptionAlgorithm = Helper.GetEncAlgorithmIdentifier(
+ new DerObjectIdentifier(_encOID), sigX509Parameters);
+
+ return new SignerInfo(_signerIdentifier, digestAlgorithm,
+ signedAttr, digestEncryptionAlgorithm, new DerOctetString(sigBytes), unsignedAttr);
+ }
+ catch (IOException e)
+ {
+ throw new CmsStreamException("encoding error.", e);
+ }
+ catch (SignatureException e)
+ {
+ throw new CmsStreamException("error creating signature.", e);
+ }
+ }
+ }
+
+ public CmsSignedDataStreamGenerator()
+ {
+ }
+
+ /// Constructor allowing specific source of randomness
+ /// Instance of SecureRandom to use.
+ public CmsSignedDataStreamGenerator(
+ SecureRandom rand)
+ : base(rand)
+ {
+ }
+
+ /**
+ * Set the underlying string size for encapsulated data
+ *
+ * @param bufferSize length of octet strings to buffer the data.
+ */
+ public void SetBufferSize(
+ int bufferSize)
+ {
+ _bufferSize = bufferSize;
+ }
+
+ public void AddDigests(
+ params string[] digestOids)
+ {
+ AddDigests((IEnumerable) digestOids);
+ }
+
+ public void AddDigests(
+ IEnumerable digestOids)
+ {
+ foreach (string digestOid in digestOids)
+ {
+ ConfigureDigest(digestOid);
+ }
+ }
+
+ /**
+ * add a signer - no attributes other than the default ones will be
+ * provided here.
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidKeyException
+ */
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ X509Certificate cert,
+ string digestOid)
+ {
+ AddSigner(privateKey, cert, digestOid,
+ new DefaultSignedAttributeTableGenerator(), null);
+ }
+
+ /**
+ * add a signer, specifying the digest encryption algorithm - no attributes other than the default ones will be
+ * provided here.
+ * @throws NoSuchProviderException
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidKeyException
+ */
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ X509Certificate cert,
+ string encryptionOid,
+ string digestOid)
+ {
+ AddSigner(privateKey, cert, encryptionOid, digestOid,
+ new DefaultSignedAttributeTableGenerator(),
+ (CmsAttributeTableGenerator)null);
+ }
+
+ /**
+ * add a signer with extra signed/unsigned attributes.
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidKeyException
+ */
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ X509Certificate cert,
+ string digestOid,
+ Asn1.Cms.AttributeTable signedAttr,
+ Asn1.Cms.AttributeTable unsignedAttr)
+ {
+ AddSigner(privateKey, cert, digestOid,
+ new DefaultSignedAttributeTableGenerator(signedAttr),
+ new SimpleAttributeTableGenerator(unsignedAttr));
+ }
+
+ /**
+ * add a signer with extra signed/unsigned attributes - specifying digest
+ * encryption algorithm.
+ * @throws NoSuchProviderException
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidKeyException
+ */
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ X509Certificate cert,
+ string encryptionOid,
+ string digestOid,
+ Asn1.Cms.AttributeTable signedAttr,
+ Asn1.Cms.AttributeTable unsignedAttr)
+ {
+ AddSigner(privateKey, cert, encryptionOid, digestOid,
+ new DefaultSignedAttributeTableGenerator(signedAttr),
+ new SimpleAttributeTableGenerator(unsignedAttr));
+ }
+
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ X509Certificate cert,
+ string digestOid,
+ CmsAttributeTableGenerator signedAttrGenerator,
+ CmsAttributeTableGenerator unsignedAttrGenerator)
+ {
+ AddSigner(privateKey, cert, Helper.GetEncOid(privateKey, digestOid), digestOid,
+ signedAttrGenerator, unsignedAttrGenerator);
+ }
+
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ X509Certificate cert,
+ string encryptionOid,
+ string digestOid,
+ CmsAttributeTableGenerator signedAttrGenerator,
+ CmsAttributeTableGenerator unsignedAttrGenerator)
+ {
+ DoAddSigner(privateKey, GetSignerIdentifier(cert), encryptionOid, digestOid,
+ signedAttrGenerator, unsignedAttrGenerator);
+ }
+
+ /**
+ * add a signer - no attributes other than the default ones will be
+ * provided here.
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidKeyException
+ */
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ byte[] subjectKeyID,
+ string digestOid)
+ {
+ AddSigner(privateKey, subjectKeyID, digestOid, new DefaultSignedAttributeTableGenerator(),
+ (CmsAttributeTableGenerator)null);
+ }
+
+ /**
+ * add a signer - no attributes other than the default ones will be
+ * provided here.
+ * @throws NoSuchProviderException
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidKeyException
+ */
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ byte[] subjectKeyID,
+ string encryptionOid,
+ string digestOid)
+ {
+ AddSigner(privateKey, subjectKeyID, encryptionOid, digestOid,
+ new DefaultSignedAttributeTableGenerator(),
+ (CmsAttributeTableGenerator)null);
+ }
+
+ /**
+ * add a signer with extra signed/unsigned attributes.
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidKeyException
+ */
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ byte[] subjectKeyID,
+ string digestOid,
+ Asn1.Cms.AttributeTable signedAttr,
+ Asn1.Cms.AttributeTable unsignedAttr)
+ {
+ AddSigner(privateKey, subjectKeyID, digestOid,
+ new DefaultSignedAttributeTableGenerator(signedAttr),
+ new SimpleAttributeTableGenerator(unsignedAttr));
+ }
+
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ byte[] subjectKeyID,
+ string digestOid,
+ CmsAttributeTableGenerator signedAttrGenerator,
+ CmsAttributeTableGenerator unsignedAttrGenerator)
+ {
+ AddSigner(privateKey, subjectKeyID, Helper.GetEncOid(privateKey, digestOid),
+ digestOid, signedAttrGenerator, unsignedAttrGenerator);
+ }
+
+ public void AddSigner(
+ AsymmetricKeyParameter privateKey,
+ byte[] subjectKeyID,
+ string encryptionOid,
+ string digestOid,
+ CmsAttributeTableGenerator signedAttrGenerator,
+ CmsAttributeTableGenerator unsignedAttrGenerator)
+ {
+ DoAddSigner(privateKey, GetSignerIdentifier(subjectKeyID), encryptionOid, digestOid,
+ signedAttrGenerator, unsignedAttrGenerator);
+ }
+
+ private void DoAddSigner(
+ AsymmetricKeyParameter privateKey,
+ SignerIdentifier signerIdentifier,
+ string encryptionOid,
+ string digestOid,
+ CmsAttributeTableGenerator signedAttrGenerator,
+ CmsAttributeTableGenerator unsignedAttrGenerator)
+ {
+ ConfigureDigest(digestOid);
+
+ SignerInfoGeneratorImpl signerInf = new SignerInfoGeneratorImpl(this, privateKey,
+ signerIdentifier, digestOid, encryptionOid, signedAttrGenerator, unsignedAttrGenerator);
+
+ _signerInfs.Add(new DigestAndSignerInfoGeneratorHolder(signerInf, digestOid));
+ }
+
+ internal override void AddSignerCallback(
+ SignerInformation si)
+ {
+ // FIXME If there were parameters in si.DigestAlgorithmID.Parameters, they are lost
+ // NB: Would need to call FixAlgID on the DigestAlgorithmID
+
+ // For precalculated signers, just need to register the algorithm, not configure a digest
+ RegisterDigestOid(si.DigestAlgorithmID.Algorithm.Id);
+ }
+
+ /**
+ * generate a signed object that for a CMS Signed Data object
+ */
+ public Stream Open(
+ Stream outStream)
+ {
+ return Open(outStream, false);
+ }
+
+ /**
+ * generate a signed object that for a CMS Signed Data
+ * object - if encapsulate is true a copy
+ * of the message will be included in the signature with the
+ * default content type "data".
+ */
+ public Stream Open(
+ Stream outStream,
+ bool encapsulate)
+ {
+ return Open(outStream, Data, encapsulate);
+ }
+
+ /**
+ * generate a signed object that for a CMS Signed Data
+ * object using the given provider - if encapsulate is true a copy
+ * of the message will be included in the signature with the
+ * default content type "data". If dataOutputStream is non null the data
+ * being signed will be written to the stream as it is processed.
+ * @param out stream the CMS object is to be written to.
+ * @param encapsulate true if data should be encapsulated.
+ * @param dataOutputStream output stream to copy the data being signed to.
+ */
+ public Stream Open(
+ Stream outStream,
+ bool encapsulate,
+ Stream dataOutputStream)
+ {
+ return Open(outStream, Data, encapsulate, dataOutputStream);
+ }
+
+ /**
+ * generate a signed object that for a CMS Signed Data
+ * object - if encapsulate is true a copy
+ * of the message will be included in the signature. The content type
+ * is set according to the OID represented by the string signedContentType.
+ */
+ public Stream Open(
+ Stream outStream,
+ string signedContentType,
+ bool encapsulate)
+ {
+ return Open(outStream, signedContentType, encapsulate, null);
+ }
+
+ /**
+ * generate a signed object that for a CMS Signed Data
+ * object using the given provider - if encapsulate is true a copy
+ * of the message will be included in the signature. The content type
+ * is set according to the OID represented by the string signedContentType.
+ * @param out stream the CMS object is to be written to.
+ * @param signedContentType OID for data to be signed.
+ * @param encapsulate true if data should be encapsulated.
+ * @param dataOutputStream output stream to copy the data being signed to.
+ */
+ public Stream Open(
+ Stream outStream,
+ string signedContentType,
+ bool encapsulate,
+ Stream dataOutputStream)
+ {
+ if (outStream == null)
+ throw new ArgumentNullException("outStream");
+ if (!outStream.CanWrite)
+ throw new ArgumentException("Expected writeable stream", "outStream");
+ if (dataOutputStream != null && !dataOutputStream.CanWrite)
+ throw new ArgumentException("Expected writeable stream", "dataOutputStream");
+
+ _messageDigestsLocked = true;
+
+ //
+ // ContentInfo
+ //
+ BerSequenceGenerator sGen = new BerSequenceGenerator(outStream);
+
+ sGen.AddObject(CmsObjectIdentifiers.SignedData);
+
+ //
+ // Signed Data
+ //
+ BerSequenceGenerator sigGen = new BerSequenceGenerator(
+ sGen.GetRawOutputStream(), 0, true);
+
+ bool isCounterSignature = (signedContentType == null);
+
+ DerObjectIdentifier contentTypeOid = isCounterSignature
+ ? null
+ : new DerObjectIdentifier(signedContentType);
+
+ sigGen.AddObject(CalculateVersion(contentTypeOid));
+
+ Asn1EncodableVector digestAlgs = new Asn1EncodableVector();
+
+ foreach (string digestOid in _messageDigestOids)
+ {
+ digestAlgs.Add(
+ new AlgorithmIdentifier(new DerObjectIdentifier(digestOid), DerNull.Instance));
+ }
+
+ {
+ byte[] tmp = new DerSet(digestAlgs).GetEncoded();
+ sigGen.GetRawOutputStream().Write(tmp, 0, tmp.Length);
+ }
+
+ BerSequenceGenerator eiGen = new BerSequenceGenerator(sigGen.GetRawOutputStream());
+ eiGen.AddObject(contentTypeOid);
+
+ // If encapsulating, add the data as an octet string in the sequence
+ Stream encapStream = encapsulate
+ ? CmsUtilities.CreateBerOctetOutputStream(eiGen.GetRawOutputStream(), 0, true, _bufferSize)
+ : null;
+
+ // Also send the data to 'dataOutputStream' if necessary
+ Stream teeStream = GetSafeTeeOutputStream(dataOutputStream, encapStream);
+
+ // Let all the digests see the data as it is written
+ Stream digStream = AttachDigestsToOutputStream(_messageDigests.Values, teeStream);
+
+ return new CmsSignedDataOutputStream(this, digStream, signedContentType, sGen, sigGen, eiGen);
+ }
+
+ private void RegisterDigestOid(
+ string digestOid)
+ {
+ if (_messageDigestsLocked)
+ {
+ if (!_messageDigestOids.Contains(digestOid))
+ throw new InvalidOperationException("Cannot register new digest OIDs after the data stream is opened");
+ }
+ else
+ {
+ _messageDigestOids.Add(digestOid);
+ }
+ }
+
+ private void ConfigureDigest(
+ string digestOid)
+ {
+ RegisterDigestOid(digestOid);
+
+ string digestName = Helper.GetDigestAlgName(digestOid);
+ IDigest dig = (IDigest)_messageDigests[digestName];
+ if (dig == null)
+ {
+ if (_messageDigestsLocked)
+ throw new InvalidOperationException("Cannot configure new digests after the data stream is opened");
+
+ dig = Helper.GetDigestInstance(digestName);
+ _messageDigests[digestName] = dig;
+ }
+ }
+
+ // TODO Make public?
+ internal void Generate(
+ Stream outStream,
+ string eContentType,
+ bool encapsulate,
+ Stream dataOutputStream,
+ CmsProcessable content)
+ {
+ Stream signedOut = Open(outStream, eContentType, encapsulate, dataOutputStream);
+ if (content != null)
+ {
+ content.Write(signedOut);
+ }
+ Platform.Dispose(signedOut);
+ }
+
+ // RFC3852, section 5.1:
+ // IF ((certificates is present) AND
+ // (any certificates with a type of other are present)) OR
+ // ((crls is present) AND
+ // (any crls with a type of other are present))
+ // THEN version MUST be 5
+ // ELSE
+ // IF (certificates is present) AND
+ // (any version 2 attribute certificates are present)
+ // THEN version MUST be 4
+ // ELSE
+ // IF ((certificates is present) AND
+ // (any version 1 attribute certificates are present)) OR
+ // (any SignerInfo structures are version 3) OR
+ // (encapContentInfo eContentType is other than id-data)
+ // THEN version MUST be 3
+ // ELSE version MUST be 1
+ //
+ private DerInteger CalculateVersion(
+ DerObjectIdentifier contentOid)
+ {
+ bool otherCert = false;
+ bool otherCrl = false;
+ bool attrCertV1Found = false;
+ bool attrCertV2Found = false;
+
+ if (_certs != null)
+ {
+ foreach (object obj in _certs)
+ {
+ if (obj is Asn1TaggedObject)
+ {
+ Asn1TaggedObject tagged = (Asn1TaggedObject) obj;
+
+ if (tagged.TagNo == 1)
+ {
+ attrCertV1Found = true;
+ }
+ else if (tagged.TagNo == 2)
+ {
+ attrCertV2Found = true;
+ }
+ else if (tagged.TagNo == 3)
+ {
+ otherCert = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (otherCert)
+ {
+ return new DerInteger(5);
+ }
+
+ if (_crls != null)
+ {
+ foreach (object obj in _crls)
+ {
+ if (obj is Asn1TaggedObject)
+ {
+ otherCrl = true;
+ break;
+ }
+ }
+ }
+
+ if (otherCrl)
+ {
+ return new DerInteger(5);
+ }
+
+ if (attrCertV2Found)
+ {
+ return new DerInteger(4);
+ }
+
+ if (attrCertV1Found || !CmsObjectIdentifiers.Data.Equals(contentOid) || CheckForVersion3(_signers))
+ {
+ return new DerInteger(3);
+ }
+
+ return new DerInteger(1);
+ }
+
+ private bool CheckForVersion3(
+ IList signerInfos)
+ {
+ foreach (SignerInformation si in signerInfos)
+ {
+ SignerInfo s = SignerInfo.GetInstance(si.ToSignerInfo());
+
+ if (s.Version.Value.IntValue == 3)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static Stream AttachDigestsToOutputStream(ICollection digests, Stream s)
+ {
+ Stream result = s;
+ foreach (IDigest digest in digests)
+ {
+ result = GetSafeTeeOutputStream(result, new DigOutputStream(digest));
+ }
+ return result;
+ }
+
+ private static Stream GetSafeOutputStream(Stream s)
+ {
+ if (s == null)
+ return new NullOutputStream();
+ return s;
+ }
+
+ private static Stream GetSafeTeeOutputStream(Stream s1, Stream s2)
+ {
+ if (s1 == null)
+ return GetSafeOutputStream(s2);
+ if (s2 == null)
+ return GetSafeOutputStream(s1);
+ return new TeeOutputStream(s1, s2);
+ }
+
+ private class CmsSignedDataOutputStream
+ : BaseOutputStream
+ {
+ private readonly CmsSignedDataStreamGenerator outer;
+
+ private Stream _out;
+ private DerObjectIdentifier _contentOID;
+ private BerSequenceGenerator _sGen;
+ private BerSequenceGenerator _sigGen;
+ private BerSequenceGenerator _eiGen;
+
+ public CmsSignedDataOutputStream(
+ CmsSignedDataStreamGenerator outer,
+ Stream outStream,
+ string contentOID,
+ BerSequenceGenerator sGen,
+ BerSequenceGenerator sigGen,
+ BerSequenceGenerator eiGen)
+ {
+ this.outer = outer;
+
+ _out = outStream;
+ _contentOID = new DerObjectIdentifier(contentOID);
+ _sGen = sGen;
+ _sigGen = sigGen;
+ _eiGen = eiGen;
+ }
+
+ public override void WriteByte(
+ byte b)
+ {
+ _out.WriteByte(b);
+ }
+
+ public override void Write(
+ byte[] bytes,
+ int off,
+ int len)
+ {
+ _out.Write(bytes, off, len);
+ }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ DoClose();
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ DoClose();
+ base.Close();
+ }
+#endif
+
+ private void DoClose()
+ {
+ Platform.Dispose(_out);
+
+ // TODO Parent context(s) should really be be closed explicitly
+
+ _eiGen.Close();
+
+ outer._digests.Clear(); // clear the current preserved digest state
+
+ if (outer._certs.Count > 0)
+ {
+ Asn1Set certs = CmsUtilities.CreateBerSetFromList(outer._certs);
+
+ WriteToGenerator(_sigGen, new BerTaggedObject(false, 0, certs));
+ }
+
+ if (outer._crls.Count > 0)
+ {
+ Asn1Set crls = CmsUtilities.CreateBerSetFromList(outer._crls);
+
+ WriteToGenerator(_sigGen, new BerTaggedObject(false, 1, crls));
+ }
+
+ //
+ // Calculate the digest hashes
+ //
+ foreach (DictionaryEntry de in outer._messageDigests)
+ {
+ outer._messageHashes.Add(de.Key, DigestUtilities.DoFinal((IDigest)de.Value));
+ }
+
+ // TODO If the digest OIDs for precalculated signers weren't mixed in with
+ // the others, we could fill in outer._digests here, instead of SignerInfoGenerator.Generate
+
+ //
+ // collect all the SignerInfo objects
+ //
+ Asn1EncodableVector signerInfos = new Asn1EncodableVector();
+
+ //
+ // add the generated SignerInfo objects
+ //
+ {
+ foreach (DigestAndSignerInfoGeneratorHolder holder in outer._signerInfs)
+ {
+ AlgorithmIdentifier digestAlgorithm = holder.DigestAlgorithm;
+
+ byte[] calculatedDigest = (byte[])outer._messageHashes[
+ Helper.GetDigestAlgName(holder.digestOID)];
+ outer._digests[holder.digestOID] = calculatedDigest.Clone();
+
+ signerInfos.Add(holder.signerInf.Generate(_contentOID, digestAlgorithm, calculatedDigest));
+ }
+ }
+
+ //
+ // add the precalculated SignerInfo objects.
+ //
+ {
+ foreach (SignerInformation signer in outer._signers)
+ {
+ // TODO Verify the content type and calculated digest match the precalculated SignerInfo
+// if (!signer.ContentType.Equals(_contentOID))
+// {
+// // TODO The precalculated content type did not match - error?
+// }
+//
+// byte[] calculatedDigest = (byte[])outer._digests[signer.DigestAlgOid];
+// if (calculatedDigest == null)
+// {
+// // TODO We can't confirm this digest because we didn't calculate it - error?
+// }
+// else
+// {
+// if (!Arrays.AreEqual(signer.GetContentDigest(), calculatedDigest))
+// {
+// // TODO The precalculated digest did not match - error?
+// }
+// }
+
+ signerInfos.Add(signer.ToSignerInfo());
+ }
+ }
+
+ WriteToGenerator(_sigGen, new DerSet(signerInfos));
+
+ _sigGen.Close();
+ _sGen.Close();
+ }
+
+ private static void WriteToGenerator(
+ Asn1Generator ag,
+ Asn1Encodable ae)
+ {
+ byte[] encoded = ae.GetEncoded();
+ ag.GetRawOutputStream().Write(encoded, 0, encoded.Length);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSSignedGenerator.cs b/bc-sharp-crypto/src/cms/CMSSignedGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0fb1f314d1c2b3f43dcdaf589493b79a378bf1f5
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSSignedGenerator.cs
@@ -0,0 +1,267 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms
+{
+ public class DefaultDigestAlgorithmIdentifierFinder
+ {
+ private static readonly IDictionary digestOids = Platform.CreateHashtable();
+ private static readonly IDictionary digestNameToOids = Platform.CreateHashtable();
+
+ static DefaultDigestAlgorithmIdentifierFinder()
+ {
+ //
+ // digests
+ //
+ digestOids.Add(OiwObjectIdentifiers.MD4WithRsaEncryption, PkcsObjectIdentifiers.MD4);
+ digestOids.Add(OiwObjectIdentifiers.MD4WithRsa, PkcsObjectIdentifiers.MD4);
+ digestOids.Add(OiwObjectIdentifiers.Sha1WithRsa, OiwObjectIdentifiers.IdSha1);
+
+ digestOids.Add(PkcsObjectIdentifiers.Sha224WithRsaEncryption, NistObjectIdentifiers.IdSha224);
+ digestOids.Add(PkcsObjectIdentifiers.Sha256WithRsaEncryption, NistObjectIdentifiers.IdSha256);
+ digestOids.Add(PkcsObjectIdentifiers.Sha384WithRsaEncryption, NistObjectIdentifiers.IdSha384);
+ digestOids.Add(PkcsObjectIdentifiers.Sha512WithRsaEncryption, NistObjectIdentifiers.IdSha512);
+ digestOids.Add(PkcsObjectIdentifiers.MD2WithRsaEncryption, PkcsObjectIdentifiers.MD2);
+ digestOids.Add(PkcsObjectIdentifiers.MD4WithRsaEncryption, PkcsObjectIdentifiers.MD4);
+ digestOids.Add(PkcsObjectIdentifiers.MD5WithRsaEncryption, PkcsObjectIdentifiers.MD5);
+ digestOids.Add(PkcsObjectIdentifiers.Sha1WithRsaEncryption, OiwObjectIdentifiers.IdSha1);
+
+ digestOids.Add(X9ObjectIdentifiers.ECDsaWithSha1, OiwObjectIdentifiers.IdSha1);
+ digestOids.Add(X9ObjectIdentifiers.ECDsaWithSha224, NistObjectIdentifiers.IdSha224);
+ digestOids.Add(X9ObjectIdentifiers.ECDsaWithSha256, NistObjectIdentifiers.IdSha256);
+ digestOids.Add(X9ObjectIdentifiers.ECDsaWithSha384, NistObjectIdentifiers.IdSha384);
+ digestOids.Add(X9ObjectIdentifiers.ECDsaWithSha512, NistObjectIdentifiers.IdSha512);
+ digestOids.Add(X9ObjectIdentifiers.IdDsaWithSha1, OiwObjectIdentifiers.IdSha1);
+
+ digestOids.Add(NistObjectIdentifiers.DsaWithSha224, NistObjectIdentifiers.IdSha224);
+ digestOids.Add(NistObjectIdentifiers.DsaWithSha256, NistObjectIdentifiers.IdSha256);
+ digestOids.Add(NistObjectIdentifiers.DsaWithSha384, NistObjectIdentifiers.IdSha384);
+ digestOids.Add(NistObjectIdentifiers.DsaWithSha512, NistObjectIdentifiers.IdSha512);
+
+ digestOids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128, TeleTrusTObjectIdentifiers.RipeMD128);
+ digestOids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160, TeleTrusTObjectIdentifiers.RipeMD160);
+ digestOids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256, TeleTrusTObjectIdentifiers.RipeMD256);
+
+ digestOids.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94, CryptoProObjectIdentifiers.GostR3411);
+ digestOids.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001, CryptoProObjectIdentifiers.GostR3411);
+
+ digestNameToOids.Add("SHA-1", OiwObjectIdentifiers.IdSha1);
+ digestNameToOids.Add("SHA-224", NistObjectIdentifiers.IdSha224);
+ digestNameToOids.Add("SHA-256", NistObjectIdentifiers.IdSha256);
+ digestNameToOids.Add("SHA-384", NistObjectIdentifiers.IdSha384);
+ digestNameToOids.Add("SHA-512", NistObjectIdentifiers.IdSha512);
+
+ digestNameToOids.Add("SHA1", OiwObjectIdentifiers.IdSha1);
+ digestNameToOids.Add("SHA224", NistObjectIdentifiers.IdSha224);
+ digestNameToOids.Add("SHA256", NistObjectIdentifiers.IdSha256);
+ digestNameToOids.Add("SHA384", NistObjectIdentifiers.IdSha384);
+ digestNameToOids.Add("SHA512", NistObjectIdentifiers.IdSha512);
+
+ digestNameToOids.Add("SHA3-224", NistObjectIdentifiers.IdSha3_224);
+ digestNameToOids.Add("SHA3-256", NistObjectIdentifiers.IdSha3_256);
+ digestNameToOids.Add("SHA3-384", NistObjectIdentifiers.IdSha3_384);
+ digestNameToOids.Add("SHA3-512", NistObjectIdentifiers.IdSha3_512);
+
+ digestNameToOids.Add("SHAKE-128", NistObjectIdentifiers.IdShake128);
+ digestNameToOids.Add("SHAKE-256", NistObjectIdentifiers.IdShake256);
+
+ digestNameToOids.Add("GOST3411", CryptoProObjectIdentifiers.GostR3411);
+
+ digestNameToOids.Add("MD2", PkcsObjectIdentifiers.MD2);
+ digestNameToOids.Add("MD4", PkcsObjectIdentifiers.MD4);
+ digestNameToOids.Add("MD5", PkcsObjectIdentifiers.MD5);
+
+ digestNameToOids.Add("RIPEMD128", TeleTrusTObjectIdentifiers.RipeMD128);
+ digestNameToOids.Add("RIPEMD160", TeleTrusTObjectIdentifiers.RipeMD160);
+ digestNameToOids.Add("RIPEMD256", TeleTrusTObjectIdentifiers.RipeMD256);
+ }
+
+ public AlgorithmIdentifier find(AlgorithmIdentifier sigAlgId)
+ {
+ AlgorithmIdentifier digAlgId;
+
+ if (sigAlgId.Algorithm.Equals(PkcsObjectIdentifiers.IdRsassaPss))
+ {
+ digAlgId = RsassaPssParameters.GetInstance(sigAlgId.Parameters).HashAlgorithm;
+ }
+ else
+ {
+ digAlgId = new AlgorithmIdentifier((DerObjectIdentifier)digestOids[sigAlgId.Algorithm], DerNull.Instance);
+ }
+
+ return digAlgId;
+ }
+
+ public AlgorithmIdentifier find(String digAlgName)
+ {
+ return new AlgorithmIdentifier((DerObjectIdentifier)digestNameToOids[digAlgName], DerNull.Instance);
+ }
+ }
+
+ public class CmsSignedGenerator
+ {
+ /**
+ * Default type for the signed data.
+ */
+ public static readonly string Data = CmsObjectIdentifiers.Data.Id;
+
+ public static readonly string DigestSha1 = OiwObjectIdentifiers.IdSha1.Id;
+ public static readonly string DigestSha224 = NistObjectIdentifiers.IdSha224.Id;
+ public static readonly string DigestSha256 = NistObjectIdentifiers.IdSha256.Id;
+ public static readonly string DigestSha384 = NistObjectIdentifiers.IdSha384.Id;
+ public static readonly string DigestSha512 = NistObjectIdentifiers.IdSha512.Id;
+ public static readonly string DigestMD5 = PkcsObjectIdentifiers.MD5.Id;
+ public static readonly string DigestGost3411 = CryptoProObjectIdentifiers.GostR3411.Id;
+ public static readonly string DigestRipeMD128 = TeleTrusTObjectIdentifiers.RipeMD128.Id;
+ public static readonly string DigestRipeMD160 = TeleTrusTObjectIdentifiers.RipeMD160.Id;
+ public static readonly string DigestRipeMD256 = TeleTrusTObjectIdentifiers.RipeMD256.Id;
+
+ public static readonly string EncryptionRsa = PkcsObjectIdentifiers.RsaEncryption.Id;
+ public static readonly string EncryptionDsa = X9ObjectIdentifiers.IdDsaWithSha1.Id;
+ public static readonly string EncryptionECDsa = X9ObjectIdentifiers.ECDsaWithSha1.Id;
+ public static readonly string EncryptionRsaPss = PkcsObjectIdentifiers.IdRsassaPss.Id;
+ public static readonly string EncryptionGost3410 = CryptoProObjectIdentifiers.GostR3410x94.Id;
+ public static readonly string EncryptionECGost3410 = CryptoProObjectIdentifiers.GostR3410x2001.Id;
+
+ internal IList _certs = Platform.CreateArrayList();
+ internal IList _crls = Platform.CreateArrayList();
+ internal IList _signers = Platform.CreateArrayList();
+ internal IDictionary _digests = Platform.CreateHashtable();
+
+ protected readonly SecureRandom rand;
+
+ protected CmsSignedGenerator()
+ : this(new SecureRandom())
+ {
+ }
+
+ /// Constructor allowing specific source of randomness
+ /// Instance of SecureRandom to use.
+ protected CmsSignedGenerator(
+ SecureRandom rand)
+ {
+ this.rand = rand;
+ }
+
+ internal protected virtual IDictionary GetBaseParameters(
+ DerObjectIdentifier contentType,
+ AlgorithmIdentifier digAlgId,
+ byte[] hash)
+ {
+ IDictionary param = Platform.CreateHashtable();
+
+ if (contentType != null)
+ {
+ param[CmsAttributeTableParameter.ContentType] = contentType;
+ }
+
+ param[CmsAttributeTableParameter.DigestAlgorithmIdentifier] = digAlgId;
+ param[CmsAttributeTableParameter.Digest] = hash.Clone();
+
+ return param;
+ }
+
+ internal protected virtual Asn1Set GetAttributeSet(
+ Asn1.Cms.AttributeTable attr)
+ {
+ return attr == null
+ ? null
+ : new DerSet(attr.ToAsn1EncodableVector());
+ }
+
+ public void AddCertificates(
+ IX509Store certStore)
+ {
+ CollectionUtilities.AddRange(_certs, CmsUtilities.GetCertificatesFromStore(certStore));
+ }
+
+ public void AddCrls(
+ IX509Store crlStore)
+ {
+ CollectionUtilities.AddRange(_crls, CmsUtilities.GetCrlsFromStore(crlStore));
+ }
+
+ /**
+ * Add the attribute certificates contained in the passed in store to the
+ * generator.
+ *
+ * @param store a store of Version 2 attribute certificates
+ * @throws CmsException if an error occurse processing the store.
+ */
+ public void AddAttributeCertificates(
+ IX509Store store)
+ {
+ try
+ {
+ foreach (IX509AttributeCertificate attrCert in store.GetMatches(null))
+ {
+ _certs.Add(new DerTaggedObject(false, 2,
+ AttributeCertificate.GetInstance(Asn1Object.FromByteArray(attrCert.GetEncoded()))));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CmsException("error processing attribute certs", e);
+ }
+ }
+
+ /**
+ * Add a store of precalculated signers to the generator.
+ *
+ * @param signerStore store of signers
+ */
+ public void AddSigners(
+ SignerInformationStore signerStore)
+ {
+ foreach (SignerInformation o in signerStore.GetSigners())
+ {
+ _signers.Add(o);
+ AddSignerCallback(o);
+ }
+ }
+
+ /**
+ * Return a map of oids and byte arrays representing the digests calculated on the content during
+ * the last generate.
+ *
+ * @return a map of oids (as String objects) and byte[] representing digests.
+ */
+ public IDictionary GetGeneratedDigests()
+ {
+ return Platform.CreateHashtable(_digests);
+ }
+
+ internal virtual void AddSignerCallback(
+ SignerInformation si)
+ {
+ }
+
+ internal static SignerIdentifier GetSignerIdentifier(X509Certificate cert)
+ {
+ return new SignerIdentifier(CmsUtilities.GetIssuerAndSerialNumber(cert));
+ }
+
+ internal static SignerIdentifier GetSignerIdentifier(byte[] subjectKeyIdentifier)
+ {
+ return new SignerIdentifier(new DerOctetString(subjectKeyIdentifier));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSSignedHelper.cs b/bc-sharp-crypto/src/cms/CMSSignedHelper.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5b6c93b6af40aae9f7cf90327f99768aede5d029
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSSignedHelper.cs
@@ -0,0 +1,426 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Eac;
+using Org.BouncyCastle.Asn1.Iana;
+using Org.BouncyCastle.Asn1.Misc;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Cms
+{
+ internal class CmsSignedHelper
+ {
+ internal static readonly CmsSignedHelper Instance = new CmsSignedHelper();
+
+ private static readonly string EncryptionECDsaWithSha1 = X9ObjectIdentifiers.ECDsaWithSha1.Id;
+ private static readonly string EncryptionECDsaWithSha224 = X9ObjectIdentifiers.ECDsaWithSha224.Id;
+ private static readonly string EncryptionECDsaWithSha256 = X9ObjectIdentifiers.ECDsaWithSha256.Id;
+ private static readonly string EncryptionECDsaWithSha384 = X9ObjectIdentifiers.ECDsaWithSha384.Id;
+ private static readonly string EncryptionECDsaWithSha512 = X9ObjectIdentifiers.ECDsaWithSha512.Id;
+
+ private static readonly IDictionary encryptionAlgs = Platform.CreateHashtable();
+ private static readonly IDictionary digestAlgs = Platform.CreateHashtable();
+ private static readonly IDictionary digestAliases = Platform.CreateHashtable();
+
+ private static readonly ISet noParams = new HashSet();
+ private static readonly IDictionary ecAlgorithms = Platform.CreateHashtable();
+
+ private static void AddEntries(DerObjectIdentifier oid, string digest, string encryption)
+ {
+ string alias = oid.Id;
+ digestAlgs.Add(alias, digest);
+ encryptionAlgs.Add(alias, encryption);
+ }
+
+ static CmsSignedHelper()
+ {
+ AddEntries(NistObjectIdentifiers.DsaWithSha224, "SHA224", "DSA");
+ AddEntries(NistObjectIdentifiers.DsaWithSha256, "SHA256", "DSA");
+ AddEntries(NistObjectIdentifiers.DsaWithSha384, "SHA384", "DSA");
+ AddEntries(NistObjectIdentifiers.DsaWithSha512, "SHA512", "DSA");
+ AddEntries(OiwObjectIdentifiers.DsaWithSha1, "SHA1", "DSA");
+ AddEntries(OiwObjectIdentifiers.MD4WithRsa, "MD4", "RSA");
+ AddEntries(OiwObjectIdentifiers.MD4WithRsaEncryption, "MD4", "RSA");
+ AddEntries(OiwObjectIdentifiers.MD5WithRsa, "MD5", "RSA");
+ AddEntries(OiwObjectIdentifiers.Sha1WithRsa, "SHA1", "RSA");
+ AddEntries(PkcsObjectIdentifiers.MD2WithRsaEncryption, "MD2", "RSA");
+ AddEntries(PkcsObjectIdentifiers.MD4WithRsaEncryption, "MD4", "RSA");
+ AddEntries(PkcsObjectIdentifiers.MD5WithRsaEncryption, "MD5", "RSA");
+ AddEntries(PkcsObjectIdentifiers.Sha1WithRsaEncryption, "SHA1", "RSA");
+ AddEntries(PkcsObjectIdentifiers.Sha224WithRsaEncryption, "SHA224", "RSA");
+ AddEntries(PkcsObjectIdentifiers.Sha256WithRsaEncryption, "SHA256", "RSA");
+ AddEntries(PkcsObjectIdentifiers.Sha384WithRsaEncryption, "SHA384", "RSA");
+ AddEntries(PkcsObjectIdentifiers.Sha512WithRsaEncryption, "SHA512", "RSA");
+ AddEntries(X9ObjectIdentifiers.ECDsaWithSha1, "SHA1", "ECDSA");
+ AddEntries(X9ObjectIdentifiers.ECDsaWithSha224, "SHA224", "ECDSA");
+ AddEntries(X9ObjectIdentifiers.ECDsaWithSha256, "SHA256", "ECDSA");
+ AddEntries(X9ObjectIdentifiers.ECDsaWithSha384, "SHA384", "ECDSA");
+ AddEntries(X9ObjectIdentifiers.ECDsaWithSha512, "SHA512", "ECDSA");
+ AddEntries(X9ObjectIdentifiers.IdDsaWithSha1, "SHA1", "DSA");
+ AddEntries(EacObjectIdentifiers.id_TA_ECDSA_SHA_1, "SHA1", "ECDSA");
+ AddEntries(EacObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224", "ECDSA");
+ AddEntries(EacObjectIdentifiers.id_TA_ECDSA_SHA_256, "SHA256", "ECDSA");
+ AddEntries(EacObjectIdentifiers.id_TA_ECDSA_SHA_384, "SHA384", "ECDSA");
+ AddEntries(EacObjectIdentifiers.id_TA_ECDSA_SHA_512, "SHA512", "ECDSA");
+ AddEntries(EacObjectIdentifiers.id_TA_RSA_v1_5_SHA_1, "SHA1", "RSA");
+ AddEntries(EacObjectIdentifiers.id_TA_RSA_v1_5_SHA_256, "SHA256", "RSA");
+ AddEntries(EacObjectIdentifiers.id_TA_RSA_PSS_SHA_1, "SHA1", "RSAandMGF1");
+ AddEntries(EacObjectIdentifiers.id_TA_RSA_PSS_SHA_256, "SHA256", "RSAandMGF1");
+
+ encryptionAlgs.Add(X9ObjectIdentifiers.IdDsa.Id, "DSA");
+ encryptionAlgs.Add(PkcsObjectIdentifiers.RsaEncryption.Id, "RSA");
+ encryptionAlgs.Add(TeleTrusTObjectIdentifiers.TeleTrusTRsaSignatureAlgorithm, "RSA");
+ encryptionAlgs.Add(X509ObjectIdentifiers.IdEARsa.Id, "RSA");
+ encryptionAlgs.Add(CmsSignedGenerator.EncryptionRsaPss, "RSAandMGF1");
+ encryptionAlgs.Add(CryptoProObjectIdentifiers.GostR3410x94.Id, "GOST3410");
+ encryptionAlgs.Add(CryptoProObjectIdentifiers.GostR3410x2001.Id, "ECGOST3410");
+ encryptionAlgs.Add("1.3.6.1.4.1.5849.1.6.2", "ECGOST3410");
+ encryptionAlgs.Add("1.3.6.1.4.1.5849.1.1.5", "GOST3410");
+
+ digestAlgs.Add(PkcsObjectIdentifiers.MD2.Id, "MD2");
+ digestAlgs.Add(PkcsObjectIdentifiers.MD4.Id, "MD4");
+ digestAlgs.Add(PkcsObjectIdentifiers.MD5.Id, "MD5");
+ digestAlgs.Add(OiwObjectIdentifiers.IdSha1.Id, "SHA1");
+ digestAlgs.Add(NistObjectIdentifiers.IdSha224.Id, "SHA224");
+ digestAlgs.Add(NistObjectIdentifiers.IdSha256.Id, "SHA256");
+ digestAlgs.Add(NistObjectIdentifiers.IdSha384.Id, "SHA384");
+ digestAlgs.Add(NistObjectIdentifiers.IdSha512.Id, "SHA512");
+ digestAlgs.Add(TeleTrusTObjectIdentifiers.RipeMD128.Id, "RIPEMD128");
+ digestAlgs.Add(TeleTrusTObjectIdentifiers.RipeMD160.Id, "RIPEMD160");
+ digestAlgs.Add(TeleTrusTObjectIdentifiers.RipeMD256.Id, "RIPEMD256");
+ digestAlgs.Add(CryptoProObjectIdentifiers.GostR3411.Id, "GOST3411");
+ digestAlgs.Add("1.3.6.1.4.1.5849.1.2.1", "GOST3411");
+
+ digestAliases.Add("SHA1", new string[] { "SHA-1" });
+ digestAliases.Add("SHA224", new string[] { "SHA-224" });
+ digestAliases.Add("SHA256", new string[] { "SHA-256" });
+ digestAliases.Add("SHA384", new string[] { "SHA-384" });
+ digestAliases.Add("SHA512", new string[] { "SHA-512" });
+
+ noParams.Add(CmsSignedGenerator.EncryptionDsa);
+ // noParams.Add(EncryptionECDsa);
+ noParams.Add(EncryptionECDsaWithSha1);
+ noParams.Add(EncryptionECDsaWithSha224);
+ noParams.Add(EncryptionECDsaWithSha256);
+ noParams.Add(EncryptionECDsaWithSha384);
+ noParams.Add(EncryptionECDsaWithSha512);
+
+ ecAlgorithms.Add(CmsSignedGenerator.DigestSha1, EncryptionECDsaWithSha1);
+ ecAlgorithms.Add(CmsSignedGenerator.DigestSha224, EncryptionECDsaWithSha224);
+ ecAlgorithms.Add(CmsSignedGenerator.DigestSha256, EncryptionECDsaWithSha256);
+ ecAlgorithms.Add(CmsSignedGenerator.DigestSha384, EncryptionECDsaWithSha384);
+ ecAlgorithms.Add(CmsSignedGenerator.DigestSha512, EncryptionECDsaWithSha512);
+ }
+
+ /**
+ * Return the digest algorithm using one of the standard JCA string
+ * representations rather than the algorithm identifier (if possible).
+ */
+ internal string GetDigestAlgName(
+ string digestAlgOid)
+ {
+ string algName = (string)digestAlgs[digestAlgOid];
+
+ if (algName != null)
+ {
+ return algName;
+ }
+
+ return digestAlgOid;
+ }
+
+ internal AlgorithmIdentifier GetEncAlgorithmIdentifier(
+ DerObjectIdentifier encOid,
+ Asn1Encodable sigX509Parameters)
+ {
+ if (noParams.Contains(encOid.Id))
+ {
+ return new AlgorithmIdentifier(encOid);
+ }
+
+ return new AlgorithmIdentifier(encOid, sigX509Parameters);
+ }
+
+ internal string[] GetDigestAliases(
+ string algName)
+ {
+ string[] aliases = (string[]) digestAliases[algName];
+
+ return aliases == null ? new String[0] : (string[]) aliases.Clone();
+ }
+
+ /**
+ * Return the digest encryption algorithm using one of the standard
+ * JCA string representations rather than the algorithm identifier (if
+ * possible).
+ */
+ internal string GetEncryptionAlgName(
+ string encryptionAlgOid)
+ {
+ string algName = (string) encryptionAlgs[encryptionAlgOid];
+
+ if (algName != null)
+ {
+ return algName;
+ }
+
+ return encryptionAlgOid;
+ }
+
+ internal IDigest GetDigestInstance(
+ string algorithm)
+ {
+ try
+ {
+ return DigestUtilities.GetDigest(algorithm);
+ }
+ catch (SecurityUtilityException e)
+ {
+ // This is probably superfluous on C#, since no provider infrastructure,
+ // assuming DigestUtilities already knows all the aliases
+ foreach (string alias in GetDigestAliases(algorithm))
+ {
+ try { return DigestUtilities.GetDigest(alias); }
+ catch (SecurityUtilityException) {}
+ }
+ throw e;
+ }
+ }
+
+ internal ISigner GetSignatureInstance(
+ string algorithm)
+ {
+ return SignerUtilities.GetSigner(algorithm);
+ }
+
+ internal IX509Store CreateAttributeStore(
+ string type,
+ Asn1Set certSet)
+ {
+ IList certs = Platform.CreateArrayList();
+
+ if (certSet != null)
+ {
+ foreach (Asn1Encodable ae in certSet)
+ {
+ try
+ {
+ Asn1Object obj = ae.ToAsn1Object();
+
+ if (obj is Asn1TaggedObject)
+ {
+ Asn1TaggedObject tagged = (Asn1TaggedObject)obj;
+
+ if (tagged.TagNo == 2)
+ {
+ certs.Add(
+ new X509V2AttributeCertificate(
+ Asn1Sequence.GetInstance(tagged, false).GetEncoded()));
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new CmsException("can't re-encode attribute certificate!", ex);
+ }
+ }
+ }
+
+ try
+ {
+ return X509StoreFactory.Create(
+ "AttributeCertificate/" + type,
+ new X509CollectionStoreParameters(certs));
+ }
+ catch (ArgumentException e)
+ {
+ throw new CmsException("can't setup the X509Store", e);
+ }
+ }
+
+ internal IX509Store CreateCertificateStore(
+ string type,
+ Asn1Set certSet)
+ {
+ IList certs = Platform.CreateArrayList();
+
+ if (certSet != null)
+ {
+ AddCertsFromSet(certs, certSet);
+ }
+
+ try
+ {
+ return X509StoreFactory.Create(
+ "Certificate/" + type,
+ new X509CollectionStoreParameters(certs));
+ }
+ catch (ArgumentException e)
+ {
+ throw new CmsException("can't setup the X509Store", e);
+ }
+ }
+
+ internal IX509Store CreateCrlStore(
+ string type,
+ Asn1Set crlSet)
+ {
+ IList crls = Platform.CreateArrayList();
+
+ if (crlSet != null)
+ {
+ AddCrlsFromSet(crls, crlSet);
+ }
+
+ try
+ {
+ return X509StoreFactory.Create(
+ "CRL/" + type,
+ new X509CollectionStoreParameters(crls));
+ }
+ catch (ArgumentException e)
+ {
+ throw new CmsException("can't setup the X509Store", e);
+ }
+ }
+
+ private void AddCertsFromSet(
+ IList certs,
+ Asn1Set certSet)
+ {
+ X509CertificateParser cf = new X509CertificateParser();
+
+ foreach (Asn1Encodable ae in certSet)
+ {
+ try
+ {
+ Asn1Object obj = ae.ToAsn1Object();
+
+ if (obj is Asn1Sequence)
+ {
+ // TODO Build certificate directly from sequence?
+ certs.Add(cf.ReadCertificate(obj.GetEncoded()));
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new CmsException("can't re-encode certificate!", ex);
+ }
+ }
+ }
+
+ private void AddCrlsFromSet(
+ IList crls,
+ Asn1Set crlSet)
+ {
+ X509CrlParser cf = new X509CrlParser();
+
+ foreach (Asn1Encodable ae in crlSet)
+ {
+ try
+ {
+ // TODO Build CRL directly from ae.ToAsn1Object()?
+ crls.Add(cf.ReadCrl(ae.GetEncoded()));
+ }
+ catch (Exception ex)
+ {
+ throw new CmsException("can't re-encode CRL!", ex);
+ }
+ }
+ }
+
+ internal AlgorithmIdentifier FixAlgID(
+ AlgorithmIdentifier algId)
+ {
+ if (algId.Parameters == null)
+ return new AlgorithmIdentifier(algId.Algorithm, DerNull.Instance);
+
+ return algId;
+ }
+
+ internal string GetEncOid(
+ AsymmetricKeyParameter key,
+ string digestOID)
+ {
+ string encOID = null;
+
+ if (key is RsaKeyParameters)
+ {
+ if (!((RsaKeyParameters)key).IsPrivate)
+ throw new ArgumentException("Expected RSA private key");
+
+ encOID = CmsSignedGenerator.EncryptionRsa;
+ }
+ else if (key is DsaPrivateKeyParameters)
+ {
+ if (digestOID.Equals(CmsSignedGenerator.DigestSha1))
+ {
+ encOID = CmsSignedGenerator.EncryptionDsa;
+ }
+ else if (digestOID.Equals(CmsSignedGenerator.DigestSha224))
+ {
+ encOID = NistObjectIdentifiers.DsaWithSha224.Id;
+ }
+ else if (digestOID.Equals(CmsSignedGenerator.DigestSha256))
+ {
+ encOID = NistObjectIdentifiers.DsaWithSha256.Id;
+ }
+ else if (digestOID.Equals(CmsSignedGenerator.DigestSha384))
+ {
+ encOID = NistObjectIdentifiers.DsaWithSha384.Id;
+ }
+ else if (digestOID.Equals(CmsSignedGenerator.DigestSha512))
+ {
+ encOID = NistObjectIdentifiers.DsaWithSha512.Id;
+ }
+ else
+ {
+ throw new ArgumentException("can't mix DSA with anything but SHA1/SHA2");
+ }
+ }
+ else if (key is ECPrivateKeyParameters)
+ {
+ ECPrivateKeyParameters ecPrivKey = (ECPrivateKeyParameters)key;
+ string algName = ecPrivKey.AlgorithmName;
+
+ if (algName == "ECGOST3410")
+ {
+ encOID = CmsSignedGenerator.EncryptionECGost3410;
+ }
+ else
+ {
+ // TODO Should we insist on algName being one of "EC" or "ECDSA", as Java does?
+ encOID = (string)ecAlgorithms[digestOID];
+
+ if (encOID == null)
+ throw new ArgumentException("can't mix ECDSA with anything but SHA family digests");
+ }
+ }
+ else if (key is Gost3410PrivateKeyParameters)
+ {
+ encOID = CmsSignedGenerator.EncryptionGost3410;
+ }
+ else
+ {
+ throw new ArgumentException("Unknown algorithm in CmsSignedGenerator.GetEncOid");
+ }
+
+ return encOID;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSStreamException.cs b/bc-sharp-crypto/src/cms/CMSStreamException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..68a8be017f5fe345f0536854132158c5cb08432a
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSStreamException.cs
@@ -0,0 +1,29 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class CmsStreamException
+ : IOException
+ {
+ public CmsStreamException()
+ {
+ }
+
+ public CmsStreamException(
+ string name)
+ : base(name)
+ {
+ }
+
+ public CmsStreamException(
+ string name,
+ Exception e)
+ : base(name, e)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSTypedStream.cs b/bc-sharp-crypto/src/cms/CMSTypedStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..681583765c2582c880e8e4cd6c3bd4647ca57744
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSTypedStream.cs
@@ -0,0 +1,72 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+ public class CmsTypedStream
+ {
+ private const int BufferSize = 32 * 1024;
+
+ private readonly string _oid;
+ private readonly Stream _in;
+
+ public CmsTypedStream(
+ Stream inStream)
+ : this(PkcsObjectIdentifiers.Data.Id, inStream, BufferSize)
+ {
+ }
+
+ public CmsTypedStream(
+ string oid,
+ Stream inStream)
+ : this(oid, inStream, BufferSize)
+ {
+ }
+
+ public CmsTypedStream(
+ string oid,
+ Stream inStream,
+ int bufSize)
+ {
+ _oid = oid;
+#if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE
+ _in = new FullReaderStream(inStream);
+#else
+ _in = new FullReaderStream(new BufferedStream(inStream, bufSize));
+#endif
+ }
+
+ public string ContentType
+ {
+ get { return _oid; }
+ }
+
+ public Stream ContentStream
+ {
+ get { return _in; }
+ }
+
+ public void Drain()
+ {
+ Streams.Drain(_in);
+ Platform.Dispose(_in);
+ }
+
+ private class FullReaderStream : FilterStream
+ {
+ internal FullReaderStream(Stream input)
+ : base(input)
+ {
+ }
+
+ public override int Read(byte[] buf, int off, int len)
+ {
+ return Streams.ReadFully(base.s, buf, off, len);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CMSUtils.cs b/bc-sharp-crypto/src/cms/CMSUtils.cs
new file mode 100644
index 0000000000000000000000000000000000000000..95d710607bd76ae8e6c90b55a97234415fb05e0c
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CMSUtils.cs
@@ -0,0 +1,186 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms
+{
+ internal class CmsUtilities
+ {
+ // TODO Is there a .NET equivalent to this?
+// private static readonly Runtime RUNTIME = Runtime.getRuntime();
+
+ internal static int MaximumMemory
+ {
+ get
+ {
+ // TODO Is there a .NET equivalent to this?
+ long maxMem = int.MaxValue;//RUNTIME.maxMemory();
+
+ if (maxMem > int.MaxValue)
+ {
+ return int.MaxValue;
+ }
+
+ return (int)maxMem;
+ }
+ }
+
+ internal static ContentInfo ReadContentInfo(
+ byte[] input)
+ {
+ // enforce limit checking as from a byte array
+ return ReadContentInfo(new Asn1InputStream(input));
+ }
+
+ internal static ContentInfo ReadContentInfo(
+ Stream input)
+ {
+ // enforce some limit checking
+ return ReadContentInfo(new Asn1InputStream(input, MaximumMemory));
+ }
+
+ private static ContentInfo ReadContentInfo(
+ Asn1InputStream aIn)
+ {
+ try
+ {
+ return ContentInfo.GetInstance(aIn.ReadObject());
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("IOException reading content.", e);
+ }
+ catch (InvalidCastException e)
+ {
+ throw new CmsException("Malformed content.", e);
+ }
+ catch (ArgumentException e)
+ {
+ throw new CmsException("Malformed content.", e);
+ }
+ }
+
+ public static byte[] StreamToByteArray(
+ Stream inStream)
+ {
+ return Streams.ReadAll(inStream);
+ }
+
+ public static byte[] StreamToByteArray(
+ Stream inStream,
+ int limit)
+ {
+ return Streams.ReadAllLimited(inStream, limit);
+ }
+
+ public static IList GetCertificatesFromStore(
+ IX509Store certStore)
+ {
+ try
+ {
+ IList certs = Platform.CreateArrayList();
+
+ if (certStore != null)
+ {
+ foreach (X509Certificate c in certStore.GetMatches(null))
+ {
+ certs.Add(
+ X509CertificateStructure.GetInstance(
+ Asn1Object.FromByteArray(c.GetEncoded())));
+ }
+ }
+
+ return certs;
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new CmsException("error encoding certs", e);
+ }
+ catch (Exception e)
+ {
+ throw new CmsException("error processing certs", e);
+ }
+ }
+
+ public static IList GetCrlsFromStore(
+ IX509Store crlStore)
+ {
+ try
+ {
+ IList crls = Platform.CreateArrayList();
+
+ if (crlStore != null)
+ {
+ foreach (X509Crl c in crlStore.GetMatches(null))
+ {
+ crls.Add(
+ CertificateList.GetInstance(
+ Asn1Object.FromByteArray(c.GetEncoded())));
+ }
+ }
+
+ return crls;
+ }
+ catch (CrlException e)
+ {
+ throw new CmsException("error encoding crls", e);
+ }
+ catch (Exception e)
+ {
+ throw new CmsException("error processing crls", e);
+ }
+ }
+
+ public static Asn1Set CreateBerSetFromList(
+ IList berObjects)
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ foreach (Asn1Encodable ae in berObjects)
+ {
+ v.Add(ae);
+ }
+
+ return new BerSet(v);
+ }
+
+ public static Asn1Set CreateDerSetFromList(
+ IList derObjects)
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ foreach (Asn1Encodable ae in derObjects)
+ {
+ v.Add(ae);
+ }
+
+ return new DerSet(v);
+ }
+
+ internal static Stream CreateBerOctetOutputStream(Stream s, int tagNo, bool isExplicit, int bufferSize)
+ {
+ BerOctetStringGenerator octGen = new BerOctetStringGenerator(s, tagNo, isExplicit);
+ return octGen.GetOctetOutputStream(bufferSize);
+ }
+
+ internal static TbsCertificateStructure GetTbsCertificateStructure(X509Certificate cert)
+ {
+ return TbsCertificateStructure.GetInstance(Asn1Object.FromByteArray(cert.GetTbsCertificate()));
+ }
+
+ internal static IssuerAndSerialNumber GetIssuerAndSerialNumber(X509Certificate cert)
+ {
+ TbsCertificateStructure tbsCert = GetTbsCertificateStructure(cert);
+ return new IssuerAndSerialNumber(tbsCert.Issuer, tbsCert.SerialNumber.Value);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/CounterSignatureDigestCalculator.cs b/bc-sharp-crypto/src/cms/CounterSignatureDigestCalculator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6f8bf65a2d35c529cbc98e59cc0133feb4c42e83
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/CounterSignatureDigestCalculator.cs
@@ -0,0 +1,28 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Cms
+{
+ internal class CounterSignatureDigestCalculator
+ : IDigestCalculator
+ {
+ private readonly string alg;
+ private readonly byte[] data;
+
+ internal CounterSignatureDigestCalculator(
+ string alg,
+ byte[] data)
+ {
+ this.alg = alg;
+ this.data = data;
+ }
+
+ public byte[] GetDigest()
+ {
+ IDigest digest = CmsSignedHelper.Instance.GetDigestInstance(alg);
+ return DigestUtilities.DoFinal(digest, data);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/DefaultAuthenticatedAttributeTableGenerator.cs b/bc-sharp-crypto/src/cms/DefaultAuthenticatedAttributeTableGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d49b1d9d29331a98f532f13d3c9968517a739360
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/DefaultAuthenticatedAttributeTableGenerator.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * Default authenticated attributes generator.
+ */
+ public class DefaultAuthenticatedAttributeTableGenerator
+ : CmsAttributeTableGenerator
+ {
+ private readonly IDictionary table;
+
+ /**
+ * Initialise to use all defaults
+ */
+ public DefaultAuthenticatedAttributeTableGenerator()
+ {
+ table = Platform.CreateHashtable();
+ }
+
+ /**
+ * Initialise with some extra attributes or overrides.
+ *
+ * @param attributeTable initial attribute table to use.
+ */
+ public DefaultAuthenticatedAttributeTableGenerator(
+ AttributeTable attributeTable)
+ {
+ if (attributeTable != null)
+ {
+ table = attributeTable.ToDictionary();
+ }
+ else
+ {
+ table = Platform.CreateHashtable();
+ }
+ }
+
+ /**
+ * Create a standard attribute table from the passed in parameters - this will
+ * normally include contentType and messageDigest. If the constructor
+ * using an AttributeTable was used, entries in it for contentType and
+ * messageDigest will override the generated ones.
+ *
+ * @param parameters source parameters for table generation.
+ *
+ * @return a filled in IDictionary of attributes.
+ */
+ protected virtual IDictionary CreateStandardAttributeTable(
+ IDictionary parameters)
+ {
+ IDictionary std = Platform.CreateHashtable(table);
+
+ if (!std.Contains(CmsAttributes.ContentType))
+ {
+ DerObjectIdentifier contentType = (DerObjectIdentifier)
+ parameters[CmsAttributeTableParameter.ContentType];
+ Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(CmsAttributes.ContentType,
+ new DerSet(contentType));
+ std[attr.AttrType] = attr;
+ }
+
+ if (!std.Contains(CmsAttributes.MessageDigest))
+ {
+ byte[] messageDigest = (byte[])parameters[CmsAttributeTableParameter.Digest];
+ Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(CmsAttributes.MessageDigest,
+ new DerSet(new DerOctetString(messageDigest)));
+ std[attr.AttrType] = attr;
+ }
+
+ return std;
+ }
+
+ /**
+ * @param parameters source parameters
+ * @return the populated attribute table
+ */
+ public virtual AttributeTable GetAttributes(
+ IDictionary parameters)
+ {
+ IDictionary table = CreateStandardAttributeTable(parameters);
+ return new AttributeTable(table);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/DefaultSignedAttributeTableGenerator.cs b/bc-sharp-crypto/src/cms/DefaultSignedAttributeTableGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..925a98a3c087ed417ecb9f14e6ad5bd200010a7e
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/DefaultSignedAttributeTableGenerator.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * Default signed attributes generator.
+ */
+ public class DefaultSignedAttributeTableGenerator
+ : CmsAttributeTableGenerator
+ {
+ private readonly IDictionary table;
+
+ /**
+ * Initialise to use all defaults
+ */
+ public DefaultSignedAttributeTableGenerator()
+ {
+ table = Platform.CreateHashtable();
+ }
+
+ /**
+ * Initialise with some extra attributes or overrides.
+ *
+ * @param attributeTable initial attribute table to use.
+ */
+ public DefaultSignedAttributeTableGenerator(
+ AttributeTable attributeTable)
+ {
+ if (attributeTable != null)
+ {
+ table = attributeTable.ToDictionary();
+ }
+ else
+ {
+ table = Platform.CreateHashtable();
+ }
+ }
+
+#if SILVERLIGHT || PORTABLE
+ /**
+ * Create a standard attribute table from the passed in parameters - this will
+ * normally include contentType, signingTime, and messageDigest. If the constructor
+ * using an AttributeTable was used, entries in it for contentType, signingTime, and
+ * messageDigest will override the generated ones.
+ *
+ * @param parameters source parameters for table generation.
+ *
+ * @return a filled in Hashtable of attributes.
+ */
+ protected virtual IDictionary createStandardAttributeTable(
+ IDictionary parameters)
+ {
+ IDictionary std = Platform.CreateHashtable(table);
+ DoCreateStandardAttributeTable(parameters, std);
+ return std;
+ }
+#else
+ /**
+ * Create a standard attribute table from the passed in parameters - this will
+ * normally include contentType, signingTime, and messageDigest. If the constructor
+ * using an AttributeTable was used, entries in it for contentType, signingTime, and
+ * messageDigest will override the generated ones.
+ *
+ * @param parameters source parameters for table generation.
+ *
+ * @return a filled in Hashtable of attributes.
+ */
+ protected virtual Hashtable createStandardAttributeTable(
+ IDictionary parameters)
+ {
+ Hashtable std = new Hashtable(table);
+ DoCreateStandardAttributeTable(parameters, std);
+ return std;
+ }
+#endif
+
+ private void DoCreateStandardAttributeTable(IDictionary parameters, IDictionary std)
+ {
+ // contentType will be absent if we're trying to generate a counter signature.
+ if (parameters.Contains(CmsAttributeTableParameter.ContentType))
+ {
+ if (!std.Contains(CmsAttributes.ContentType))
+ {
+ DerObjectIdentifier contentType = (DerObjectIdentifier)
+ parameters[CmsAttributeTableParameter.ContentType];
+ Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(CmsAttributes.ContentType,
+ new DerSet(contentType));
+ std[attr.AttrType] = attr;
+ }
+ }
+
+ if (!std.Contains(CmsAttributes.SigningTime))
+ {
+ Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(CmsAttributes.SigningTime,
+ new DerSet(new Time(DateTime.UtcNow)));
+ std[attr.AttrType] = attr;
+ }
+
+ if (!std.Contains(CmsAttributes.MessageDigest))
+ {
+ byte[] messageDigest = (byte[])parameters[CmsAttributeTableParameter.Digest];
+ Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(CmsAttributes.MessageDigest,
+ new DerSet(new DerOctetString(messageDigest)));
+ std[attr.AttrType] = attr;
+ }
+ }
+
+ /**
+ * @param parameters source parameters
+ * @return the populated attribute table
+ */
+ public virtual AttributeTable GetAttributes(
+ IDictionary parameters)
+ {
+ IDictionary table = createStandardAttributeTable(parameters);
+ return new AttributeTable(table);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/DigOutputStream.cs b/bc-sharp-crypto/src/cms/DigOutputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..103b45cac02c5f8046e3bdadd61aaf66a7598a7f
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/DigOutputStream.cs
@@ -0,0 +1,28 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+ internal class DigOutputStream
+ : BaseOutputStream
+ {
+ private readonly IDigest dig;
+
+ internal DigOutputStream(IDigest dig)
+ {
+ this.dig = dig;
+ }
+
+ public override void WriteByte(byte b)
+ {
+ dig.Update(b);
+ }
+
+ public override void Write(byte[] b, int off, int len)
+ {
+ dig.BlockUpdate(b, off, len);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/IDigestCalculator.cs b/bc-sharp-crypto/src/cms/IDigestCalculator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3661e4023bb526a356e2cbc1300f0363a4249c52
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/IDigestCalculator.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.Cms
+{
+ internal interface IDigestCalculator
+ {
+ byte[] GetDigest();
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/KEKRecipientInfoGenerator.cs b/bc-sharp-crypto/src/cms/KEKRecipientInfoGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6f34fec43d2ac6a60adf12b0627095fee8ad34af
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/KEKRecipientInfoGenerator.cs
@@ -0,0 +1,138 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Kisa;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Ntt;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Cms
+{
+ internal class KekRecipientInfoGenerator : RecipientInfoGenerator
+ {
+ private static readonly CmsEnvelopedHelper Helper = CmsEnvelopedHelper.Instance;
+
+ private KeyParameter keyEncryptionKey;
+ // TODO Can get this from keyEncryptionKey?
+ private string keyEncryptionKeyOID;
+ private KekIdentifier kekIdentifier;
+
+ // Derived
+ private AlgorithmIdentifier keyEncryptionAlgorithm;
+
+ internal KekRecipientInfoGenerator()
+ {
+ }
+
+ internal KekIdentifier KekIdentifier
+ {
+ set { this.kekIdentifier = value; }
+ }
+
+ internal KeyParameter KeyEncryptionKey
+ {
+ set
+ {
+ this.keyEncryptionKey = value;
+ this.keyEncryptionAlgorithm = DetermineKeyEncAlg(keyEncryptionKeyOID, keyEncryptionKey);
+ }
+ }
+
+ internal string KeyEncryptionKeyOID
+ {
+ set { this.keyEncryptionKeyOID = value; }
+ }
+
+ public RecipientInfo Generate(KeyParameter contentEncryptionKey, SecureRandom random)
+ {
+ byte[] keyBytes = contentEncryptionKey.GetKey();
+
+ IWrapper keyWrapper = Helper.CreateWrapper(keyEncryptionAlgorithm.Algorithm.Id);
+ keyWrapper.Init(true, new ParametersWithRandom(keyEncryptionKey, random));
+ Asn1OctetString encryptedKey = new DerOctetString(
+ keyWrapper.Wrap(keyBytes, 0, keyBytes.Length));
+
+ return new RecipientInfo(new KekRecipientInfo(kekIdentifier, keyEncryptionAlgorithm, encryptedKey));
+ }
+
+ private static AlgorithmIdentifier DetermineKeyEncAlg(
+ string algorithm, KeyParameter key)
+ {
+ if (Platform.StartsWith(algorithm, "DES"))
+ {
+ return new AlgorithmIdentifier(
+ PkcsObjectIdentifiers.IdAlgCms3DesWrap,
+ DerNull.Instance);
+ }
+ else if (Platform.StartsWith(algorithm, "RC2"))
+ {
+ return new AlgorithmIdentifier(
+ PkcsObjectIdentifiers.IdAlgCmsRC2Wrap,
+ new DerInteger(58));
+ }
+ else if (Platform.StartsWith(algorithm, "AES"))
+ {
+ int length = key.GetKey().Length * 8;
+ DerObjectIdentifier wrapOid;
+
+ if (length == 128)
+ {
+ wrapOid = NistObjectIdentifiers.IdAes128Wrap;
+ }
+ else if (length == 192)
+ {
+ wrapOid = NistObjectIdentifiers.IdAes192Wrap;
+ }
+ else if (length == 256)
+ {
+ wrapOid = NistObjectIdentifiers.IdAes256Wrap;
+ }
+ else
+ {
+ throw new ArgumentException("illegal keysize in AES");
+ }
+
+ return new AlgorithmIdentifier(wrapOid); // parameters absent
+ }
+ else if (Platform.StartsWith(algorithm, "SEED"))
+ {
+ // parameters absent
+ return new AlgorithmIdentifier(KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap);
+ }
+ else if (Platform.StartsWith(algorithm, "CAMELLIA"))
+ {
+ int length = key.GetKey().Length * 8;
+ DerObjectIdentifier wrapOid;
+
+ if (length == 128)
+ {
+ wrapOid = NttObjectIdentifiers.IdCamellia128Wrap;
+ }
+ else if (length == 192)
+ {
+ wrapOid = NttObjectIdentifiers.IdCamellia192Wrap;
+ }
+ else if (length == 256)
+ {
+ wrapOid = NttObjectIdentifiers.IdCamellia256Wrap;
+ }
+ else
+ {
+ throw new ArgumentException("illegal keysize in Camellia");
+ }
+
+ return new AlgorithmIdentifier(wrapOid); // parameters must be absent
+ }
+ else
+ {
+ throw new ArgumentException("unknown algorithm");
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/KEKRecipientInformation.cs b/bc-sharp-crypto/src/cms/KEKRecipientInformation.cs
new file mode 100644
index 0000000000000000000000000000000000000000..871dc76d4deb3e31535f44be492b7f03e11e7704
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/KEKRecipientInformation.cs
@@ -0,0 +1,62 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * the RecipientInfo class for a recipient who has been sent a message
+ * encrypted using a secret key known to the other side.
+ */
+ public class KekRecipientInformation
+ : RecipientInformation
+ {
+ private KekRecipientInfo info;
+
+ internal KekRecipientInformation(
+ KekRecipientInfo info,
+ CmsSecureReadable secureReadable)
+ : base(info.KeyEncryptionAlgorithm, secureReadable)
+ {
+ this.info = info;
+ this.rid = new RecipientID();
+
+ KekIdentifier kekId = info.KekID;
+
+ rid.KeyIdentifier = kekId.KeyIdentifier.GetOctets();
+ }
+
+ /**
+ * decrypt the content and return an input stream.
+ */
+ public override CmsTypedStream GetContentStream(
+ ICipherParameters key)
+ {
+ try
+ {
+ byte[] encryptedKey = info.EncryptedKey.GetOctets();
+ IWrapper keyWrapper = WrapperUtilities.GetWrapper(keyEncAlg.Algorithm.Id);
+
+ keyWrapper.Init(false, key);
+
+ KeyParameter sKey = ParameterUtilities.CreateKeyParameter(
+ GetContentAlgorithmName(), keyWrapper.Unwrap(encryptedKey, 0, encryptedKey.Length));
+
+ return GetContentFromSessionKey(sKey);
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw new CmsException("couldn't create cipher.", e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CmsException("key invalid in message.", e);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/KeyAgreeRecipientInfoGenerator.cs b/bc-sharp-crypto/src/cms/KeyAgreeRecipientInfoGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6bd2cea912276cb4c2565cd8886c98828b005970
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/KeyAgreeRecipientInfoGenerator.cs
@@ -0,0 +1,171 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Cms.Ecc;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+ internal class KeyAgreeRecipientInfoGenerator : RecipientInfoGenerator
+ {
+ private static readonly CmsEnvelopedHelper Helper = CmsEnvelopedHelper.Instance;
+
+ private DerObjectIdentifier keyAgreementOID;
+ private DerObjectIdentifier keyEncryptionOID;
+ private IList recipientCerts;
+ private AsymmetricCipherKeyPair senderKeyPair;
+
+ internal KeyAgreeRecipientInfoGenerator()
+ {
+ }
+
+ internal DerObjectIdentifier KeyAgreementOID
+ {
+ set { this.keyAgreementOID = value; }
+ }
+
+ internal DerObjectIdentifier KeyEncryptionOID
+ {
+ set { this.keyEncryptionOID = value; }
+ }
+
+ internal ICollection RecipientCerts
+ {
+ set { this.recipientCerts = Platform.CreateArrayList(value); }
+ }
+
+ internal AsymmetricCipherKeyPair SenderKeyPair
+ {
+ set { this.senderKeyPair = value; }
+ }
+
+ public RecipientInfo Generate(KeyParameter contentEncryptionKey, SecureRandom random)
+ {
+ byte[] keyBytes = contentEncryptionKey.GetKey();
+
+ AsymmetricKeyParameter senderPublicKey = senderKeyPair.Public;
+ ICipherParameters senderPrivateParams = senderKeyPair.Private;
+
+
+ OriginatorIdentifierOrKey originator;
+ try
+ {
+ originator = new OriginatorIdentifierOrKey(
+ CreateOriginatorPublicKey(senderPublicKey));
+ }
+ catch (IOException e)
+ {
+ throw new InvalidKeyException("cannot extract originator public key: " + e);
+ }
+
+
+ Asn1OctetString ukm = null;
+ if (keyAgreementOID.Id.Equals(CmsEnvelopedGenerator.ECMqvSha1Kdf))
+ {
+ try
+ {
+ IAsymmetricCipherKeyPairGenerator ephemKPG =
+ GeneratorUtilities.GetKeyPairGenerator(keyAgreementOID);
+ ephemKPG.Init(
+ ((ECPublicKeyParameters)senderPublicKey).CreateKeyGenerationParameters(random));
+
+ AsymmetricCipherKeyPair ephemKP = ephemKPG.GenerateKeyPair();
+
+ ukm = new DerOctetString(
+ new MQVuserKeyingMaterial(
+ CreateOriginatorPublicKey(ephemKP.Public), null));
+
+ senderPrivateParams = new MqvPrivateParameters(
+ (ECPrivateKeyParameters)senderPrivateParams,
+ (ECPrivateKeyParameters)ephemKP.Private,
+ (ECPublicKeyParameters)ephemKP.Public);
+ }
+ catch (IOException e)
+ {
+ throw new InvalidKeyException("cannot extract MQV ephemeral public key: " + e);
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw new InvalidKeyException("cannot determine MQV ephemeral key pair parameters from public key: " + e);
+ }
+ }
+
+
+ DerSequence paramSeq = new DerSequence(
+ keyEncryptionOID,
+ DerNull.Instance);
+ AlgorithmIdentifier keyEncAlg = new AlgorithmIdentifier(keyAgreementOID, paramSeq);
+
+
+ Asn1EncodableVector recipientEncryptedKeys = new Asn1EncodableVector();
+ foreach (X509Certificate recipientCert in recipientCerts)
+ {
+ TbsCertificateStructure tbsCert;
+ try
+ {
+ tbsCert = TbsCertificateStructure.GetInstance(
+ Asn1Object.FromByteArray(recipientCert.GetTbsCertificate()));
+ }
+ catch (Exception)
+ {
+ throw new ArgumentException("can't extract TBS structure from certificate");
+ }
+
+ // TODO Should there be a SubjectKeyIdentifier-based alternative?
+ IssuerAndSerialNumber issuerSerial = new IssuerAndSerialNumber(
+ tbsCert.Issuer, tbsCert.SerialNumber.Value);
+ KeyAgreeRecipientIdentifier karid = new KeyAgreeRecipientIdentifier(issuerSerial);
+
+ ICipherParameters recipientPublicParams = recipientCert.GetPublicKey();
+ if (keyAgreementOID.Id.Equals(CmsEnvelopedGenerator.ECMqvSha1Kdf))
+ {
+ recipientPublicParams = new MqvPublicParameters(
+ (ECPublicKeyParameters)recipientPublicParams,
+ (ECPublicKeyParameters)recipientPublicParams);
+ }
+
+ // Use key agreement to choose a wrap key for this recipient
+ IBasicAgreement keyAgreement = AgreementUtilities.GetBasicAgreementWithKdf(
+ keyAgreementOID, keyEncryptionOID.Id);
+ keyAgreement.Init(new ParametersWithRandom(senderPrivateParams, random));
+ BigInteger agreedValue = keyAgreement.CalculateAgreement(recipientPublicParams);
+
+ int keyEncryptionKeySize = GeneratorUtilities.GetDefaultKeySize(keyEncryptionOID) / 8;
+ byte[] keyEncryptionKeyBytes = X9IntegerConverter.IntegerToBytes(agreedValue, keyEncryptionKeySize);
+ KeyParameter keyEncryptionKey = ParameterUtilities.CreateKeyParameter(
+ keyEncryptionOID, keyEncryptionKeyBytes);
+
+ // Wrap the content encryption key with the agreement key
+ IWrapper keyWrapper = Helper.CreateWrapper(keyEncryptionOID.Id);
+ keyWrapper.Init(true, new ParametersWithRandom(keyEncryptionKey, random));
+ byte[] encryptedKeyBytes = keyWrapper.Wrap(keyBytes, 0, keyBytes.Length);
+
+ Asn1OctetString encryptedKey = new DerOctetString(encryptedKeyBytes);
+
+ recipientEncryptedKeys.Add(new RecipientEncryptedKey(karid, encryptedKey));
+ }
+
+ return new RecipientInfo(new KeyAgreeRecipientInfo(originator, ukm, keyEncAlg,
+ new DerSequence(recipientEncryptedKeys)));
+ }
+
+ private static OriginatorPublicKey CreateOriginatorPublicKey(
+ AsymmetricKeyParameter publicKey)
+ {
+ SubjectPublicKeyInfo spki = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);
+ return new OriginatorPublicKey(
+ new AlgorithmIdentifier(spki.AlgorithmID.Algorithm, DerNull.Instance),
+ spki.PublicKeyData.GetBytes());
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/KeyAgreeRecipientInformation.cs b/bc-sharp-crypto/src/cms/KeyAgreeRecipientInformation.cs
new file mode 100644
index 0000000000000000000000000000000000000000..73e57a76ac159667434b0663246aca72c6e562e8
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/KeyAgreeRecipientInformation.cs
@@ -0,0 +1,226 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Cms.Ecc;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * the RecipientInfo class for a recipient who has been sent a message
+ * encrypted using key agreement.
+ */
+ public class KeyAgreeRecipientInformation
+ : RecipientInformation
+ {
+ private KeyAgreeRecipientInfo info;
+ private Asn1OctetString encryptedKey;
+
+ internal static void ReadRecipientInfo(IList infos, KeyAgreeRecipientInfo info,
+ CmsSecureReadable secureReadable)
+ {
+ try
+ {
+ foreach (Asn1Encodable rek in info.RecipientEncryptedKeys)
+ {
+ RecipientEncryptedKey id = RecipientEncryptedKey.GetInstance(rek.ToAsn1Object());
+
+ RecipientID rid = new RecipientID();
+
+ Asn1.Cms.KeyAgreeRecipientIdentifier karid = id.Identifier;
+
+ Asn1.Cms.IssuerAndSerialNumber iAndSN = karid.IssuerAndSerialNumber;
+ if (iAndSN != null)
+ {
+ rid.Issuer = iAndSN.Name;
+ rid.SerialNumber = iAndSN.SerialNumber.Value;
+ }
+ else
+ {
+ Asn1.Cms.RecipientKeyIdentifier rKeyID = karid.RKeyID;
+
+ // Note: 'date' and 'other' fields of RecipientKeyIdentifier appear to be only informational
+
+ rid.SubjectKeyIdentifier = rKeyID.SubjectKeyIdentifier.GetOctets();
+ }
+
+ infos.Add(new KeyAgreeRecipientInformation(info, rid, id.EncryptedKey,
+ secureReadable));
+ }
+ }
+ catch (IOException e)
+ {
+ throw new ArgumentException("invalid rid in KeyAgreeRecipientInformation", e);
+ }
+ }
+
+ internal KeyAgreeRecipientInformation(
+ KeyAgreeRecipientInfo info,
+ RecipientID rid,
+ Asn1OctetString encryptedKey,
+ CmsSecureReadable secureReadable)
+ : base(info.KeyEncryptionAlgorithm, secureReadable)
+ {
+ this.info = info;
+ this.rid = rid;
+ this.encryptedKey = encryptedKey;
+ }
+
+ private AsymmetricKeyParameter GetSenderPublicKey(
+ AsymmetricKeyParameter receiverPrivateKey,
+ OriginatorIdentifierOrKey originator)
+ {
+ OriginatorPublicKey opk = originator.OriginatorPublicKey;
+ if (opk != null)
+ {
+ return GetPublicKeyFromOriginatorPublicKey(receiverPrivateKey, opk);
+ }
+
+ OriginatorID origID = new OriginatorID();
+
+ Asn1.Cms.IssuerAndSerialNumber iAndSN = originator.IssuerAndSerialNumber;
+ if (iAndSN != null)
+ {
+ origID.Issuer = iAndSN.Name;
+ origID.SerialNumber = iAndSN.SerialNumber.Value;
+ }
+ else
+ {
+ SubjectKeyIdentifier ski = originator.SubjectKeyIdentifier;
+
+ origID.SubjectKeyIdentifier = ski.GetKeyIdentifier();
+ }
+
+ return GetPublicKeyFromOriginatorID(origID);
+ }
+
+ private AsymmetricKeyParameter GetPublicKeyFromOriginatorPublicKey(
+ AsymmetricKeyParameter receiverPrivateKey,
+ OriginatorPublicKey originatorPublicKey)
+ {
+ PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(receiverPrivateKey);
+ SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(
+ privInfo.PrivateKeyAlgorithm,
+ originatorPublicKey.PublicKey.GetBytes());
+ return PublicKeyFactory.CreateKey(pubInfo);
+ }
+
+ private AsymmetricKeyParameter GetPublicKeyFromOriginatorID(
+ OriginatorID origID)
+ {
+ // TODO Support all alternatives for OriginatorIdentifierOrKey
+ // see RFC 3852 6.2.2
+ throw new CmsException("No support for 'originator' as IssuerAndSerialNumber or SubjectKeyIdentifier");
+ }
+
+ private KeyParameter CalculateAgreedWrapKey(
+ string wrapAlg,
+ AsymmetricKeyParameter senderPublicKey,
+ AsymmetricKeyParameter receiverPrivateKey)
+ {
+ DerObjectIdentifier agreeAlgID = keyEncAlg.Algorithm;
+
+ ICipherParameters senderPublicParams = senderPublicKey;
+ ICipherParameters receiverPrivateParams = receiverPrivateKey;
+
+ if (agreeAlgID.Id.Equals(CmsEnvelopedGenerator.ECMqvSha1Kdf))
+ {
+ byte[] ukmEncoding = info.UserKeyingMaterial.GetOctets();
+ MQVuserKeyingMaterial ukm = MQVuserKeyingMaterial.GetInstance(
+ Asn1Object.FromByteArray(ukmEncoding));
+
+ AsymmetricKeyParameter ephemeralKey = GetPublicKeyFromOriginatorPublicKey(
+ receiverPrivateKey, ukm.EphemeralPublicKey);
+
+ senderPublicParams = new MqvPublicParameters(
+ (ECPublicKeyParameters)senderPublicParams,
+ (ECPublicKeyParameters)ephemeralKey);
+ receiverPrivateParams = new MqvPrivateParameters(
+ (ECPrivateKeyParameters)receiverPrivateParams,
+ (ECPrivateKeyParameters)receiverPrivateParams);
+ }
+
+ IBasicAgreement agreement = AgreementUtilities.GetBasicAgreementWithKdf(
+ agreeAlgID, wrapAlg);
+ agreement.Init(receiverPrivateParams);
+ BigInteger agreedValue = agreement.CalculateAgreement(senderPublicParams);
+
+ int wrapKeySize = GeneratorUtilities.GetDefaultKeySize(wrapAlg) / 8;
+ byte[] wrapKeyBytes = X9IntegerConverter.IntegerToBytes(agreedValue, wrapKeySize);
+ return ParameterUtilities.CreateKeyParameter(wrapAlg, wrapKeyBytes);
+ }
+
+ private KeyParameter UnwrapSessionKey(
+ string wrapAlg,
+ KeyParameter agreedKey)
+ {
+ byte[] encKeyOctets = encryptedKey.GetOctets();
+
+ IWrapper keyCipher = WrapperUtilities.GetWrapper(wrapAlg);
+ keyCipher.Init(false, agreedKey);
+ byte[] sKeyBytes = keyCipher.Unwrap(encKeyOctets, 0, encKeyOctets.Length);
+ return ParameterUtilities.CreateKeyParameter(GetContentAlgorithmName(), sKeyBytes);
+ }
+
+ internal KeyParameter GetSessionKey(
+ AsymmetricKeyParameter receiverPrivateKey)
+ {
+ try
+ {
+ string wrapAlg = DerObjectIdentifier.GetInstance(
+ Asn1Sequence.GetInstance(keyEncAlg.Parameters)[0]).Id;
+
+ AsymmetricKeyParameter senderPublicKey = GetSenderPublicKey(
+ receiverPrivateKey, info.Originator);
+
+ KeyParameter agreedWrapKey = CalculateAgreedWrapKey(wrapAlg,
+ senderPublicKey, receiverPrivateKey);
+
+ return UnwrapSessionKey(wrapAlg, agreedWrapKey);
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw new CmsException("couldn't create cipher.", e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CmsException("key invalid in message.", e);
+ }
+ catch (Exception e)
+ {
+ throw new CmsException("originator key invalid.", e);
+ }
+ }
+
+ /**
+ * decrypt the content and return an input stream.
+ */
+ public override CmsTypedStream GetContentStream(
+ ICipherParameters key)
+ {
+ if (!(key is AsymmetricKeyParameter))
+ throw new ArgumentException("KeyAgreement requires asymmetric key", "key");
+
+ AsymmetricKeyParameter receiverPrivateKey = (AsymmetricKeyParameter) key;
+
+ if (!receiverPrivateKey.IsPrivate)
+ throw new ArgumentException("Expected private key", "key");
+
+ KeyParameter sKey = GetSessionKey(receiverPrivateKey);
+
+ return GetContentFromSessionKey(sKey);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/KeyTransRecipientInfoGenerator.cs b/bc-sharp-crypto/src/cms/KeyTransRecipientInfoGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a1d8fbfa856c80aaccdf0d25a088fada3c7cf9b6
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/KeyTransRecipientInfoGenerator.cs
@@ -0,0 +1,87 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+ internal class KeyTransRecipientInfoGenerator : RecipientInfoGenerator
+ {
+ private static readonly CmsEnvelopedHelper Helper = CmsEnvelopedHelper.Instance;
+
+ private TbsCertificateStructure recipientTbsCert;
+ private AsymmetricKeyParameter recipientPublicKey;
+ private Asn1OctetString subjectKeyIdentifier;
+
+ // Derived fields
+ private SubjectPublicKeyInfo info;
+
+ internal KeyTransRecipientInfoGenerator()
+ {
+ }
+
+ internal X509Certificate RecipientCert
+ {
+ set
+ {
+ this.recipientTbsCert = CmsUtilities.GetTbsCertificateStructure(value);
+ this.recipientPublicKey = value.GetPublicKey();
+ this.info = recipientTbsCert.SubjectPublicKeyInfo;
+ }
+ }
+
+ internal AsymmetricKeyParameter RecipientPublicKey
+ {
+ set
+ {
+ this.recipientPublicKey = value;
+
+ try
+ {
+ info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(
+ recipientPublicKey);
+ }
+ catch (IOException)
+ {
+ throw new ArgumentException("can't extract key algorithm from this key");
+ }
+ }
+ }
+
+ internal Asn1OctetString SubjectKeyIdentifier
+ {
+ set { this.subjectKeyIdentifier = value; }
+ }
+
+ public RecipientInfo Generate(KeyParameter contentEncryptionKey, SecureRandom random)
+ {
+ byte[] keyBytes = contentEncryptionKey.GetKey();
+ AlgorithmIdentifier keyEncryptionAlgorithm = info.AlgorithmID;
+
+ IWrapper keyWrapper = Helper.CreateWrapper(keyEncryptionAlgorithm.Algorithm.Id);
+ keyWrapper.Init(true, new ParametersWithRandom(recipientPublicKey, random));
+ byte[] encryptedKeyBytes = keyWrapper.Wrap(keyBytes, 0, keyBytes.Length);
+
+ RecipientIdentifier recipId;
+ if (recipientTbsCert != null)
+ {
+ IssuerAndSerialNumber issuerAndSerial = new IssuerAndSerialNumber(
+ recipientTbsCert.Issuer, recipientTbsCert.SerialNumber.Value);
+ recipId = new RecipientIdentifier(issuerAndSerial);
+ }
+ else
+ {
+ recipId = new RecipientIdentifier(subjectKeyIdentifier);
+ }
+
+ return new RecipientInfo(new KeyTransRecipientInfo(recipId, keyEncryptionAlgorithm,
+ new DerOctetString(encryptedKeyBytes)));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/KeyTransRecipientInformation.cs b/bc-sharp-crypto/src/cms/KeyTransRecipientInformation.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3b1ea7b5e8ae2026f8d3f8efb6a1006c1381ecf6
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/KeyTransRecipientInformation.cs
@@ -0,0 +1,113 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Asn1Pkcs = Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * the KeyTransRecipientInformation class for a recipient who has been sent a secret
+ * key encrypted using their public key that needs to be used to
+ * extract the message.
+ */
+ public class KeyTransRecipientInformation
+ : RecipientInformation
+ {
+ private KeyTransRecipientInfo info;
+
+ internal KeyTransRecipientInformation(
+ KeyTransRecipientInfo info,
+ CmsSecureReadable secureReadable)
+ : base(info.KeyEncryptionAlgorithm, secureReadable)
+ {
+ this.info = info;
+ this.rid = new RecipientID();
+
+ RecipientIdentifier r = info.RecipientIdentifier;
+
+ try
+ {
+ if (r.IsTagged)
+ {
+ Asn1OctetString octs = Asn1OctetString.GetInstance(r.ID);
+
+ rid.SubjectKeyIdentifier = octs.GetOctets();
+ }
+ else
+ {
+ IssuerAndSerialNumber iAnds = IssuerAndSerialNumber.GetInstance(r.ID);
+
+ rid.Issuer = iAnds.Name;
+ rid.SerialNumber = iAnds.SerialNumber.Value;
+ }
+ }
+ catch (IOException)
+ {
+ throw new ArgumentException("invalid rid in KeyTransRecipientInformation");
+ }
+ }
+
+ private string GetExchangeEncryptionAlgorithmName(
+ DerObjectIdentifier oid)
+ {
+ if (Asn1Pkcs.PkcsObjectIdentifiers.RsaEncryption.Equals(oid))
+ {
+ return "RSA//PKCS1Padding";
+ }
+
+ return oid.Id;
+ }
+
+ internal KeyParameter UnwrapKey(ICipherParameters key)
+ {
+ byte[] encryptedKey = info.EncryptedKey.GetOctets();
+ string keyExchangeAlgorithm = GetExchangeEncryptionAlgorithmName(keyEncAlg.Algorithm);
+
+ try
+ {
+ IWrapper keyWrapper = WrapperUtilities.GetWrapper(keyExchangeAlgorithm);
+ keyWrapper.Init(false, key);
+
+ // FIXME Support for MAC algorithm parameters similar to cipher parameters
+ return ParameterUtilities.CreateKeyParameter(
+ GetContentAlgorithmName(), keyWrapper.Unwrap(encryptedKey, 0, encryptedKey.Length));
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw new CmsException("couldn't create cipher.", e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CmsException("key invalid in message.", e);
+ }
+// catch (IllegalBlockSizeException e)
+ catch (DataLengthException e)
+ {
+ throw new CmsException("illegal blocksize in message.", e);
+ }
+// catch (BadPaddingException e)
+ catch (InvalidCipherTextException e)
+ {
+ throw new CmsException("bad padding in message.", e);
+ }
+ }
+
+ /**
+ * decrypt the content and return it as a byte array.
+ */
+ public override CmsTypedStream GetContentStream(
+ ICipherParameters key)
+ {
+ KeyParameter sKey = UnwrapKey(key);
+
+ return GetContentFromSessionKey(sKey);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/MacOutputStream.cs b/bc-sharp-crypto/src/cms/MacOutputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8891dbc2cb1d26a6683e92548785f8216405f408
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/MacOutputStream.cs
@@ -0,0 +1,28 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+ internal class MacOutputStream
+ : BaseOutputStream
+ {
+ private readonly IMac mac;
+
+ internal MacOutputStream(IMac mac)
+ {
+ this.mac = mac;
+ }
+
+ public override void Write(byte[] b, int off, int len)
+ {
+ mac.BlockUpdate(b, off, len);
+ }
+
+ public override void WriteByte(byte b)
+ {
+ mac.Update(b);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/OriginatorId.cs b/bc-sharp-crypto/src/cms/OriginatorId.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5a3b7374d63374fd64cfc211014944afbf40e051
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/OriginatorId.cs
@@ -0,0 +1,51 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * a basic index for an originator.
+ */
+ public class OriginatorID
+ : X509CertStoreSelector
+ {
+ public override int GetHashCode()
+ {
+ int code = Arrays.GetHashCode(this.SubjectKeyIdentifier);
+
+ BigInteger serialNumber = this.SerialNumber;
+ if (serialNumber != null)
+ {
+ code ^= serialNumber.GetHashCode();
+ }
+
+ X509Name issuer = this.Issuer;
+ if (issuer != null)
+ {
+ code ^= issuer.GetHashCode();
+ }
+
+ return code;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return false;
+
+ OriginatorID id = obj as OriginatorID;
+
+ if (id == null)
+ return false;
+
+ return Arrays.AreEqual(SubjectKeyIdentifier, id.SubjectKeyIdentifier)
+ && Platform.Equals(SerialNumber, id.SerialNumber)
+ && IssuersMatch(Issuer, id.Issuer);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/OriginatorInfoGenerator.cs b/bc-sharp-crypto/src/cms/OriginatorInfoGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6bf1087990862b7e6c1eba6dd47289aa98da970d
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/OriginatorInfoGenerator.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms
+{
+ public class OriginatorInfoGenerator
+ {
+ private readonly IList origCerts;
+ private readonly IList origCrls;
+
+ public OriginatorInfoGenerator(X509Certificate origCert)
+ {
+ this.origCerts = Platform.CreateArrayList(1);
+ this.origCrls = null;
+ origCerts.Add(origCert.CertificateStructure);
+ }
+
+ public OriginatorInfoGenerator(IX509Store origCerts)
+ : this(origCerts, null)
+ {
+ }
+
+ public OriginatorInfoGenerator(IX509Store origCerts, IX509Store origCrls)
+ {
+ this.origCerts = CmsUtilities.GetCertificatesFromStore(origCerts);
+ this.origCrls = origCrls == null ? null : CmsUtilities.GetCrlsFromStore(origCrls);
+ }
+
+ public virtual OriginatorInfo Generate()
+ {
+ Asn1Set certSet = CmsUtilities.CreateDerSetFromList(origCerts);
+ Asn1Set crlSet = origCrls == null ? null : CmsUtilities.CreateDerSetFromList(origCrls);
+ return new OriginatorInfo(certSet, crlSet);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/OriginatorInformation.cs b/bc-sharp-crypto/src/cms/OriginatorInformation.cs
new file mode 100644
index 0000000000000000000000000000000000000000..618add6e071461ed159ea75d7c2d85ef0a6c3ee5
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/OriginatorInformation.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms
+{
+ public class OriginatorInformation
+ {
+ private readonly OriginatorInfo originatorInfo;
+
+ internal OriginatorInformation(OriginatorInfo originatorInfo)
+ {
+ this.originatorInfo = originatorInfo;
+ }
+
+ /**
+ * Return the certificates stored in the underlying OriginatorInfo object.
+ *
+ * @return a Store of X509CertificateHolder objects.
+ */
+ public virtual IX509Store GetCertificates()
+ {
+ Asn1Set certSet = originatorInfo.Certificates;
+
+ if (certSet != null)
+ {
+ IList certList = Platform.CreateArrayList(certSet.Count);
+
+ foreach (Asn1Encodable enc in certSet)
+ {
+ Asn1Object obj = enc.ToAsn1Object();
+ if (obj is Asn1Sequence)
+ {
+ certList.Add(new X509Certificate(X509CertificateStructure.GetInstance(obj)));
+ }
+ }
+
+ return X509StoreFactory.Create(
+ "Certificate/Collection",
+ new X509CollectionStoreParameters(certList));
+ }
+
+ return X509StoreFactory.Create(
+ "Certificate/Collection",
+ new X509CollectionStoreParameters(Platform.CreateArrayList()));
+ }
+
+ /**
+ * Return the CRLs stored in the underlying OriginatorInfo object.
+ *
+ * @return a Store of X509CRLHolder objects.
+ */
+ public virtual IX509Store GetCrls()
+ {
+ Asn1Set crlSet = originatorInfo.Certificates;
+
+ if (crlSet != null)
+ {
+ IList crlList = Platform.CreateArrayList(crlSet.Count);
+
+ foreach (Asn1Encodable enc in crlSet)
+ {
+ Asn1Object obj = enc.ToAsn1Object();
+ if (obj is Asn1Sequence)
+ {
+ crlList.Add(new X509Crl(CertificateList.GetInstance(obj)));
+ }
+ }
+
+ return X509StoreFactory.Create(
+ "CRL/Collection",
+ new X509CollectionStoreParameters(crlList));
+ }
+
+ return X509StoreFactory.Create(
+ "CRL/Collection",
+ new X509CollectionStoreParameters(Platform.CreateArrayList()));
+ }
+
+ /**
+ * Return the underlying ASN.1 object defining this SignerInformation object.
+ *
+ * @return a OriginatorInfo.
+ */
+ public virtual OriginatorInfo ToAsn1Structure()
+ {
+ return originatorInfo;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/PKCS5Scheme2PBEKey.cs b/bc-sharp-crypto/src/cms/PKCS5Scheme2PBEKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..08b8518a15c86b6bfcf220f9d9fe3ace81f48b70
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/PKCS5Scheme2PBEKey.cs
@@ -0,0 +1,64 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Cms
+{
+ ///
+ /// PKCS5 scheme-2 - password converted to bytes assuming ASCII.
+ ///
+ public class Pkcs5Scheme2PbeKey
+ : CmsPbeKey
+ {
+ [Obsolete("Use version taking 'char[]' instead")]
+ public Pkcs5Scheme2PbeKey(
+ string password,
+ byte[] salt,
+ int iterationCount)
+ : this(password.ToCharArray(), salt, iterationCount)
+ {
+ }
+
+ [Obsolete("Use version taking 'char[]' instead")]
+ public Pkcs5Scheme2PbeKey(
+ string password,
+ AlgorithmIdentifier keyDerivationAlgorithm)
+ : this(password.ToCharArray(), keyDerivationAlgorithm)
+ {
+ }
+
+ public Pkcs5Scheme2PbeKey(
+ char[] password,
+ byte[] salt,
+ int iterationCount)
+ : base(password, salt, iterationCount)
+ {
+ }
+
+ public Pkcs5Scheme2PbeKey(
+ char[] password,
+ AlgorithmIdentifier keyDerivationAlgorithm)
+ : base(password, keyDerivationAlgorithm)
+ {
+ }
+
+ internal override KeyParameter GetEncoded(
+ string algorithmOid)
+ {
+ Pkcs5S2ParametersGenerator gen = new Pkcs5S2ParametersGenerator();
+
+ gen.Init(
+ PbeParametersGenerator.Pkcs5PasswordToBytes(password),
+ salt,
+ iterationCount);
+
+ return (KeyParameter) gen.GenerateDerivedParameters(
+ algorithmOid,
+ CmsEnvelopedHelper.Instance.GetKeySize(algorithmOid));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/PKCS5Scheme2UTF8PBEKey.cs b/bc-sharp-crypto/src/cms/PKCS5Scheme2UTF8PBEKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7aecc297876c2795074c301e8009d1ef4fa54413
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/PKCS5Scheme2UTF8PBEKey.cs
@@ -0,0 +1,64 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * PKCS5 scheme-2 - password converted to bytes using UTF-8.
+ */
+ public class Pkcs5Scheme2Utf8PbeKey
+ : CmsPbeKey
+ {
+ [Obsolete("Use version taking 'char[]' instead")]
+ public Pkcs5Scheme2Utf8PbeKey(
+ string password,
+ byte[] salt,
+ int iterationCount)
+ : this(password.ToCharArray(), salt, iterationCount)
+ {
+ }
+
+ [Obsolete("Use version taking 'char[]' instead")]
+ public Pkcs5Scheme2Utf8PbeKey(
+ string password,
+ AlgorithmIdentifier keyDerivationAlgorithm)
+ : this(password.ToCharArray(), keyDerivationAlgorithm)
+ {
+ }
+
+ public Pkcs5Scheme2Utf8PbeKey(
+ char[] password,
+ byte[] salt,
+ int iterationCount)
+ : base(password, salt, iterationCount)
+ {
+ }
+
+ public Pkcs5Scheme2Utf8PbeKey(
+ char[] password,
+ AlgorithmIdentifier keyDerivationAlgorithm)
+ : base(password, keyDerivationAlgorithm)
+ {
+ }
+
+ internal override KeyParameter GetEncoded(
+ string algorithmOid)
+ {
+ Pkcs5S2ParametersGenerator gen = new Pkcs5S2ParametersGenerator();
+
+ gen.Init(
+ PbeParametersGenerator.Pkcs5PasswordToUtf8Bytes(password),
+ salt,
+ iterationCount);
+
+ return (KeyParameter) gen.GenerateDerivedParameters(
+ algorithmOid,
+ CmsEnvelopedHelper.Instance.GetKeySize(algorithmOid));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/PasswordRecipientInfoGenerator.cs b/bc-sharp-crypto/src/cms/PasswordRecipientInfoGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9916edfc4b75db8139330c148dedb54108e7711d
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/PasswordRecipientInfoGenerator.cs
@@ -0,0 +1,70 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Cms
+{
+ internal class PasswordRecipientInfoGenerator : RecipientInfoGenerator
+ {
+ private static readonly CmsEnvelopedHelper Helper = CmsEnvelopedHelper.Instance;
+
+ private AlgorithmIdentifier keyDerivationAlgorithm;
+ private KeyParameter keyEncryptionKey;
+ // TODO Can get this from keyEncryptionKey?
+ private string keyEncryptionKeyOID;
+
+ internal PasswordRecipientInfoGenerator()
+ {
+ }
+
+ internal AlgorithmIdentifier KeyDerivationAlgorithm
+ {
+ set { this.keyDerivationAlgorithm = value; }
+ }
+
+ internal KeyParameter KeyEncryptionKey
+ {
+ set { this.keyEncryptionKey = value; }
+ }
+
+ internal string KeyEncryptionKeyOID
+ {
+ set { this.keyEncryptionKeyOID = value; }
+ }
+
+ public RecipientInfo Generate(KeyParameter contentEncryptionKey, SecureRandom random)
+ {
+ byte[] keyBytes = contentEncryptionKey.GetKey();
+
+ string rfc3211WrapperName = Helper.GetRfc3211WrapperName(keyEncryptionKeyOID);
+ IWrapper keyWrapper = Helper.CreateWrapper(rfc3211WrapperName);
+
+ // Note: In Java build, the IV is automatically generated in JCE layer
+ int ivLength = Platform.StartsWith(rfc3211WrapperName, "DESEDE") ? 8 : 16;
+ byte[] iv = new byte[ivLength];
+ random.NextBytes(iv);
+
+ ICipherParameters parameters = new ParametersWithIV(keyEncryptionKey, iv);
+ keyWrapper.Init(true, new ParametersWithRandom(parameters, random));
+ Asn1OctetString encryptedKey = new DerOctetString(
+ keyWrapper.Wrap(keyBytes, 0, keyBytes.Length));
+
+ DerSequence seq = new DerSequence(
+ new DerObjectIdentifier(keyEncryptionKeyOID),
+ new DerOctetString(iv));
+
+ AlgorithmIdentifier keyEncryptionAlgorithm = new AlgorithmIdentifier(
+ PkcsObjectIdentifiers.IdAlgPwriKek, seq);
+
+ return new RecipientInfo(new PasswordRecipientInfo(
+ keyDerivationAlgorithm, keyEncryptionAlgorithm, encryptedKey));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/PasswordRecipientInformation.cs b/bc-sharp-crypto/src/cms/PasswordRecipientInformation.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f629caba6a9643b0e3412c6eeaf5efe63ce2d19f
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/PasswordRecipientInformation.cs
@@ -0,0 +1,79 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * the RecipientInfo class for a recipient who has been sent a message
+ * encrypted using a password.
+ */
+ public class PasswordRecipientInformation
+ : RecipientInformation
+ {
+ private readonly PasswordRecipientInfo info;
+
+ internal PasswordRecipientInformation(
+ PasswordRecipientInfo info,
+ CmsSecureReadable secureReadable)
+ : base(info.KeyEncryptionAlgorithm, secureReadable)
+ {
+ this.info = info;
+ this.rid = new RecipientID();
+ }
+
+ /**
+ * return the object identifier for the key derivation algorithm, or null
+ * if there is none present.
+ *
+ * @return OID for key derivation algorithm, if present.
+ */
+ public virtual AlgorithmIdentifier KeyDerivationAlgorithm
+ {
+ get { return info.KeyDerivationAlgorithm; }
+ }
+
+ /**
+ * decrypt the content and return an input stream.
+ */
+ public override CmsTypedStream GetContentStream(
+ ICipherParameters key)
+ {
+ try
+ {
+ AlgorithmIdentifier kekAlg = AlgorithmIdentifier.GetInstance(info.KeyEncryptionAlgorithm);
+ Asn1Sequence kekAlgParams = (Asn1Sequence)kekAlg.Parameters;
+ byte[] encryptedKey = info.EncryptedKey.GetOctets();
+ string kekAlgName = DerObjectIdentifier.GetInstance(kekAlgParams[0]).Id;
+ string cName = CmsEnvelopedHelper.Instance.GetRfc3211WrapperName(kekAlgName);
+ IWrapper keyWrapper = WrapperUtilities.GetWrapper(cName);
+
+ byte[] iv = Asn1OctetString.GetInstance(kekAlgParams[1]).GetOctets();
+
+ ICipherParameters parameters = ((CmsPbeKey)key).GetEncoded(kekAlgName);
+ parameters = new ParametersWithIV(parameters, iv);
+
+ keyWrapper.Init(false, parameters);
+
+ KeyParameter sKey = ParameterUtilities.CreateKeyParameter(
+ GetContentAlgorithmName(), keyWrapper.Unwrap(encryptedKey, 0, encryptedKey.Length));
+
+ return GetContentFromSessionKey(sKey);
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw new CmsException("couldn't create cipher.", e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CmsException("key invalid in message.", e);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/RecipientId.cs b/bc-sharp-crypto/src/cms/RecipientId.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9b6eb093b7cee529a8b734955592bf9d31cb5e37
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/RecipientId.cs
@@ -0,0 +1,58 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms
+{
+ public class RecipientID
+ : X509CertStoreSelector
+ {
+ private byte[] keyIdentifier;
+
+ public byte[] KeyIdentifier
+ {
+ get { return Arrays.Clone(keyIdentifier); }
+ set { keyIdentifier = Arrays.Clone(value); }
+ }
+
+ public override int GetHashCode()
+ {
+ int code = Arrays.GetHashCode(keyIdentifier)
+ ^ Arrays.GetHashCode(this.SubjectKeyIdentifier);
+
+ BigInteger serialNumber = this.SerialNumber;
+ if (serialNumber != null)
+ {
+ code ^= serialNumber.GetHashCode();
+ }
+
+ X509Name issuer = this.Issuer;
+ if (issuer != null)
+ {
+ code ^= issuer.GetHashCode();
+ }
+
+ return code;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ RecipientID id = obj as RecipientID;
+
+ if (id == null)
+ return false;
+
+ return Arrays.AreEqual(keyIdentifier, id.keyIdentifier)
+ && Arrays.AreEqual(SubjectKeyIdentifier, id.SubjectKeyIdentifier)
+ && Platform.Equals(SerialNumber, id.SerialNumber)
+ && IssuersMatch(Issuer, id.Issuer);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/RecipientInfoGenerator.cs b/bc-sharp-crypto/src/cms/RecipientInfoGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c41db61223254ce8f6daef8252d95b4002a7328f
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/RecipientInfoGenerator.cs
@@ -0,0 +1,26 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Cms
+{
+ interface RecipientInfoGenerator
+ {
+ ///
+ /// Generate a RecipientInfo object for the given key.
+ ///
+ ///
+ /// A
+ ///
+ ///
+ /// A
+ ///
+ ///
+ /// A
+ ///
+ ///
+ RecipientInfo Generate(KeyParameter contentEncryptionKey, SecureRandom random);
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/RecipientInformation.cs b/bc-sharp-crypto/src/cms/RecipientInformation.cs
new file mode 100644
index 0000000000000000000000000000000000000000..272b841f23344c205bd068fa8fc0c110e1729c20
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/RecipientInformation.cs
@@ -0,0 +1,126 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Cms
+{
+ public abstract class RecipientInformation
+ {
+ internal RecipientID rid = new RecipientID();
+ internal AlgorithmIdentifier keyEncAlg;
+ internal CmsSecureReadable secureReadable;
+
+ private byte[] resultMac;
+
+ internal RecipientInformation(
+ AlgorithmIdentifier keyEncAlg,
+ CmsSecureReadable secureReadable)
+ {
+ this.keyEncAlg = keyEncAlg;
+ this.secureReadable = secureReadable;
+ }
+
+ internal string GetContentAlgorithmName()
+ {
+ AlgorithmIdentifier algorithm = secureReadable.Algorithm;
+// return CmsEnvelopedHelper.Instance.GetSymmetricCipherName(algorithm.Algorithm.Id);
+ return algorithm.Algorithm.Id;
+ }
+
+ public RecipientID RecipientID
+ {
+ get { return rid; }
+ }
+
+ public AlgorithmIdentifier KeyEncryptionAlgorithmID
+ {
+ get { return keyEncAlg; }
+ }
+
+ /**
+ * return the object identifier for the key encryption algorithm.
+ *
+ * @return OID for key encryption algorithm.
+ */
+ public string KeyEncryptionAlgOid
+ {
+ get { return keyEncAlg.Algorithm.Id; }
+ }
+
+ /**
+ * return the ASN.1 encoded key encryption algorithm parameters, or null if
+ * there aren't any.
+ *
+ * @return ASN.1 encoding of key encryption algorithm parameters.
+ */
+ public Asn1Object KeyEncryptionAlgParams
+ {
+ get
+ {
+ Asn1Encodable ae = keyEncAlg.Parameters;
+
+ return ae == null ? null : ae.ToAsn1Object();
+ }
+ }
+
+ internal CmsTypedStream GetContentFromSessionKey(
+ KeyParameter sKey)
+ {
+ CmsReadable readable = secureReadable.GetReadable(sKey);
+
+ try
+ {
+ return new CmsTypedStream(readable.GetInputStream());
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("error getting .", e);
+ }
+ }
+
+ public byte[] GetContent(
+ ICipherParameters key)
+ {
+ try
+ {
+ return CmsUtilities.StreamToByteArray(GetContentStream(key).ContentStream);
+ }
+ catch (IOException e)
+ {
+ throw new Exception("unable to parse internal stream: " + e);
+ }
+ }
+
+ /**
+ * Return the MAC calculated for the content stream. Note: this call is only meaningful once all
+ * the content has been read.
+ *
+ * @return byte array containing the mac.
+ */
+ public byte[] GetMac()
+ {
+ if (resultMac == null)
+ {
+ object cryptoObject = secureReadable.CryptoObject;
+ if (cryptoObject is IMac)
+ {
+ resultMac = MacUtilities.DoFinal((IMac)cryptoObject);
+ }
+ }
+
+ return Arrays.Clone(resultMac);
+ }
+
+ public abstract CmsTypedStream GetContentStream(ICipherParameters key);
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/RecipientInformationStore.cs b/bc-sharp-crypto/src/cms/RecipientInformationStore.cs
new file mode 100644
index 0000000000000000000000000000000000000000..33b472f9d9b2032dab86a371f995bd2b44db8ff3
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/RecipientInformationStore.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Cms
+{
+ public class RecipientInformationStore
+ {
+ private readonly IList all; //ArrayList[RecipientInformation]
+ private readonly IDictionary table = Platform.CreateHashtable(); // Hashtable[RecipientID, ArrayList[RecipientInformation]]
+
+ public RecipientInformationStore(
+ ICollection recipientInfos)
+ {
+ foreach (RecipientInformation recipientInformation in recipientInfos)
+ {
+ RecipientID rid = recipientInformation.RecipientID;
+ IList list = (IList)table[rid];
+
+ if (list == null)
+ {
+ table[rid] = list = Platform.CreateArrayList(1);
+ }
+
+ list.Add(recipientInformation);
+ }
+
+ this.all = Platform.CreateArrayList(recipientInfos);
+ }
+
+ public RecipientInformation this[RecipientID selector]
+ {
+ get { return GetFirstRecipient(selector); }
+ }
+
+ /**
+ * Return the first RecipientInformation object that matches the
+ * passed in selector. Null if there are no matches.
+ *
+ * @param selector to identify a recipient
+ * @return a single RecipientInformation object. Null if none matches.
+ */
+ public RecipientInformation GetFirstRecipient(
+ RecipientID selector)
+ {
+ IList list = (IList) table[selector];
+
+ return list == null ? null : (RecipientInformation) list[0];
+ }
+
+ /**
+ * Return the number of recipients in the collection.
+ *
+ * @return number of recipients identified.
+ */
+ public int Count
+ {
+ get { return all.Count; }
+ }
+
+ /**
+ * Return all recipients in the collection
+ *
+ * @return a collection of recipients.
+ */
+ public ICollection GetRecipients()
+ {
+ return Platform.CreateArrayList(all);
+ }
+
+ /**
+ * Return possible empty collection with recipients matching the passed in RecipientID
+ *
+ * @param selector a recipient id to select against.
+ * @return a collection of RecipientInformation objects.
+ */
+ public ICollection GetRecipients(
+ RecipientID selector)
+ {
+ IList list = (IList)table[selector];
+
+ return list == null ? Platform.CreateArrayList() : Platform.CreateArrayList(list);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/SigOutputStream.cs b/bc-sharp-crypto/src/cms/SigOutputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a807fa7fc510407deca344e44fc1ce98cd72e609
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/SigOutputStream.cs
@@ -0,0 +1,43 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Cms
+{
+ internal class SigOutputStream
+ : BaseOutputStream
+ {
+ private readonly ISigner sig;
+
+ internal SigOutputStream(ISigner sig)
+ {
+ this.sig = sig;
+ }
+
+ public override void WriteByte(byte b)
+ {
+ try
+ {
+ sig.Update(b);
+ }
+ catch (SignatureException e)
+ {
+ throw new CmsStreamException("signature problem: " + e);
+ }
+ }
+
+ public override void Write(byte[] b, int off, int len)
+ {
+ try
+ {
+ sig.BlockUpdate(b, off, len);
+ }
+ catch (SignatureException e)
+ {
+ throw new CmsStreamException("signature problem: " + e);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/cms/SignerId.cs b/bc-sharp-crypto/src/cms/SignerId.cs
new file mode 100644
index 0000000000000000000000000000000000000000..baac9369b4c1fc3580f138fca27c3a441054f2a2
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/SignerId.cs
@@ -0,0 +1,51 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * a basic index for a signer.
+ */
+ public class SignerID
+ : X509CertStoreSelector
+ {
+ public override int GetHashCode()
+ {
+ int code = Arrays.GetHashCode(this.SubjectKeyIdentifier);
+
+ BigInteger serialNumber = this.SerialNumber;
+ if (serialNumber != null)
+ {
+ code ^= serialNumber.GetHashCode();
+ }
+
+ X509Name issuer = this.Issuer;
+ if (issuer != null)
+ {
+ code ^= issuer.GetHashCode();
+ }
+
+ return code;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return false;
+
+ SignerID id = obj as SignerID;
+
+ if (id == null)
+ return false;
+
+ return Arrays.AreEqual(SubjectKeyIdentifier, id.SubjectKeyIdentifier)
+ && Platform.Equals(SerialNumber, id.SerialNumber)
+ && IssuersMatch(Issuer, id.Issuer);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/SignerInfoGenerator.cs b/bc-sharp-crypto/src/cms/SignerInfoGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7b9318cc9db445b4daee73e62514b3db1ba49325
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/SignerInfoGenerator.cs
@@ -0,0 +1,166 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+ internal interface ISignerInfoGenerator
+ {
+ SignerInfo Generate(DerObjectIdentifier contentType, AlgorithmIdentifier digestAlgorithm,
+ byte[] calculatedDigest);
+ }
+
+ public class SignerInfoGenerator
+ {
+ internal X509Certificate certificate;
+ internal ISignatureFactory contentSigner;
+ internal SignerIdentifier sigId;
+ internal CmsAttributeTableGenerator signedGen;
+ internal CmsAttributeTableGenerator unsignedGen;
+ private bool isDirectSignature;
+
+ internal SignerInfoGenerator(SignerIdentifier sigId, ISignatureFactory signerFactory): this(sigId, signerFactory, false)
+ {
+
+ }
+
+ internal SignerInfoGenerator(SignerIdentifier sigId, ISignatureFactory signerFactory, bool isDirectSignature)
+ {
+ this.sigId = sigId;
+ this.contentSigner = signerFactory;
+ this.isDirectSignature = isDirectSignature;
+ if (this.isDirectSignature)
+ {
+ this.signedGen = null;
+ this.unsignedGen = null;
+ }
+ else
+ {
+ this.signedGen = new DefaultSignedAttributeTableGenerator();
+ this.unsignedGen = null;
+ }
+ }
+
+ internal SignerInfoGenerator(SignerIdentifier sigId, ISignatureFactory contentSigner, CmsAttributeTableGenerator signedGen, CmsAttributeTableGenerator unsignedGen)
+ {
+ this.sigId = sigId;
+ this.contentSigner = contentSigner;
+ this.signedGen = signedGen;
+ this.unsignedGen = unsignedGen;
+ this.isDirectSignature = false;
+ }
+
+ internal void setAssociatedCertificate(X509Certificate certificate)
+ {
+ this.certificate = certificate;
+ }
+ }
+
+ public class SignerInfoGeneratorBuilder
+ {
+ private bool directSignature;
+ private CmsAttributeTableGenerator signedGen;
+ private CmsAttributeTableGenerator unsignedGen;
+
+ public SignerInfoGeneratorBuilder()
+ {
+ }
+
+ /**
+ * If the passed in flag is true, the signer signature will be based on the data, not
+ * a collection of signed attributes, and no signed attributes will be included.
+ *
+ * @return the builder object
+ */
+ public SignerInfoGeneratorBuilder SetDirectSignature(bool hasNoSignedAttributes)
+ {
+ this.directSignature = hasNoSignedAttributes;
+
+ return this;
+ }
+
+ /**
+ * Provide a custom signed attribute generator.
+ *
+ * @param signedGen a generator of signed attributes.
+ * @return the builder object
+ */
+ public SignerInfoGeneratorBuilder WithSignedAttributeGenerator(CmsAttributeTableGenerator signedGen)
+ {
+ this.signedGen = signedGen;
+
+ return this;
+ }
+
+ /**
+ * Provide a generator of unsigned attributes.
+ *
+ * @param unsignedGen a generator for signed attributes.
+ * @return the builder object
+ */
+ public SignerInfoGeneratorBuilder WithUnsignedAttributeGenerator(CmsAttributeTableGenerator unsignedGen)
+ {
+ this.unsignedGen = unsignedGen;
+
+ return this;
+ }
+
+ /**
+ * Build a generator with the passed in certHolder issuer and serial number as the signerIdentifier.
+ *
+ * @param contentSigner operator for generating the final signature in the SignerInfo with.
+ * @param certHolder carrier for the X.509 certificate related to the contentSigner.
+ * @return a SignerInfoGenerator
+ * @throws OperatorCreationException if the generator cannot be built.
+ */
+ public SignerInfoGenerator Build(ISignatureFactory contentSigner, X509Certificate certificate)
+ {
+ SignerIdentifier sigId = new SignerIdentifier(new IssuerAndSerialNumber(certificate.IssuerDN, new DerInteger(certificate.SerialNumber)));
+
+ SignerInfoGenerator sigInfoGen = CreateGenerator(contentSigner, sigId);
+
+ sigInfoGen.setAssociatedCertificate(certificate);
+
+ return sigInfoGen;
+ }
+
+ /**
+ * Build a generator with the passed in subjectKeyIdentifier as the signerIdentifier. If used you should
+ * try to follow the calculation described in RFC 5280 section 4.2.1.2.
+ *
+ * @param signerFactory operator factory for generating the final signature in the SignerInfo with.
+ * @param subjectKeyIdentifier key identifier to identify the public key for verifying the signature.
+ * @return a SignerInfoGenerator
+ */
+ public SignerInfoGenerator Build(ISignatureFactory signerFactory, byte[] subjectKeyIdentifier)
+ {
+ SignerIdentifier sigId = new SignerIdentifier(new DerOctetString(subjectKeyIdentifier));
+
+ return CreateGenerator(signerFactory, sigId);
+ }
+
+ private SignerInfoGenerator CreateGenerator(ISignatureFactory contentSigner, SignerIdentifier sigId)
+ {
+ if (directSignature)
+ {
+ return new SignerInfoGenerator(sigId, contentSigner, true);
+ }
+
+ if (signedGen != null || unsignedGen != null)
+ {
+ if (signedGen == null)
+ {
+ signedGen = new DefaultSignedAttributeTableGenerator();
+ }
+
+ return new SignerInfoGenerator(sigId, contentSigner, signedGen, unsignedGen);
+ }
+
+ return new SignerInfoGenerator(sigId, contentSigner);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/SignerInformation.cs b/bc-sharp-crypto/src/cms/SignerInformation.cs
new file mode 100644
index 0000000000000000000000000000000000000000..dad128263cb60349c822f92d0e0af377a91b924c
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/SignerInformation.cs
@@ -0,0 +1,761 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * an expanded SignerInfo block from a CMS Signed message
+ */
+ public class SignerInformation
+ {
+ private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance;
+
+ private SignerID sid;
+ private SignerInfo info;
+ private AlgorithmIdentifier digestAlgorithm;
+ private AlgorithmIdentifier encryptionAlgorithm;
+ private readonly Asn1Set signedAttributeSet;
+ private readonly Asn1Set unsignedAttributeSet;
+ private CmsProcessable content;
+ private byte[] signature;
+ private DerObjectIdentifier contentType;
+ private IDigestCalculator digestCalculator;
+ private byte[] resultDigest;
+
+ // Derived
+ private Asn1.Cms.AttributeTable signedAttributeTable;
+ private Asn1.Cms.AttributeTable unsignedAttributeTable;
+ private readonly bool isCounterSignature;
+
+ internal SignerInformation(
+ SignerInfo info,
+ DerObjectIdentifier contentType,
+ CmsProcessable content,
+ IDigestCalculator digestCalculator)
+ {
+ this.info = info;
+ this.sid = new SignerID();
+ this.contentType = contentType;
+ this.isCounterSignature = contentType == null;
+
+ try
+ {
+ SignerIdentifier s = info.SignerID;
+
+ if (s.IsTagged)
+ {
+ Asn1OctetString octs = Asn1OctetString.GetInstance(s.ID);
+
+ sid.SubjectKeyIdentifier = octs.GetEncoded();
+ }
+ else
+ {
+ Asn1.Cms.IssuerAndSerialNumber iAnds =
+ Asn1.Cms.IssuerAndSerialNumber.GetInstance(s.ID);
+
+ sid.Issuer = iAnds.Name;
+ sid.SerialNumber = iAnds.SerialNumber.Value;
+ }
+ }
+ catch (IOException)
+ {
+ throw new ArgumentException("invalid sid in SignerInfo");
+ }
+
+ this.digestAlgorithm = info.DigestAlgorithm;
+ this.signedAttributeSet = info.AuthenticatedAttributes;
+ this.unsignedAttributeSet = info.UnauthenticatedAttributes;
+ this.encryptionAlgorithm = info.DigestEncryptionAlgorithm;
+ this.signature = info.EncryptedDigest.GetOctets();
+
+ this.content = content;
+ this.digestCalculator = digestCalculator;
+ }
+
+ public bool IsCounterSignature
+ {
+ get { return isCounterSignature; }
+ }
+
+ public DerObjectIdentifier ContentType
+ {
+ get { return contentType; }
+ }
+
+ public SignerID SignerID
+ {
+ get { return sid; }
+ }
+
+ /**
+ * return the version number for this objects underlying SignerInfo structure.
+ */
+ public int Version
+ {
+ get { return info.Version.Value.IntValue; }
+ }
+
+ public AlgorithmIdentifier DigestAlgorithmID
+ {
+ get { return digestAlgorithm; }
+ }
+
+ /**
+ * return the object identifier for the signature.
+ */
+ public string DigestAlgOid
+ {
+ get { return digestAlgorithm.Algorithm.Id; }
+ }
+
+ /**
+ * return the signature parameters, or null if there aren't any.
+ */
+ public Asn1Object DigestAlgParams
+ {
+ get
+ {
+ Asn1Encodable ae = digestAlgorithm.Parameters;
+
+ return ae == null ? null : ae.ToAsn1Object();
+ }
+ }
+
+ /**
+ * return the content digest that was calculated during verification.
+ */
+ public byte[] GetContentDigest()
+ {
+ if (resultDigest == null)
+ {
+ throw new InvalidOperationException("method can only be called after verify.");
+ }
+
+ return (byte[])resultDigest.Clone();
+ }
+
+ public AlgorithmIdentifier EncryptionAlgorithmID
+ {
+ get { return encryptionAlgorithm; }
+ }
+
+ /**
+ * return the object identifier for the signature.
+ */
+ public string EncryptionAlgOid
+ {
+ get { return encryptionAlgorithm.Algorithm.Id; }
+ }
+
+ /**
+ * return the signature/encryption algorithm parameters, or null if
+ * there aren't any.
+ */
+ public Asn1Object EncryptionAlgParams
+ {
+ get
+ {
+ Asn1Encodable ae = encryptionAlgorithm.Parameters;
+
+ return ae == null ? null : ae.ToAsn1Object();
+ }
+ }
+
+ /**
+ * return a table of the signed attributes - indexed by
+ * the OID of the attribute.
+ */
+ public Asn1.Cms.AttributeTable SignedAttributes
+ {
+ get
+ {
+ if (signedAttributeSet != null && signedAttributeTable == null)
+ {
+ signedAttributeTable = new Asn1.Cms.AttributeTable(signedAttributeSet);
+ }
+ return signedAttributeTable;
+ }
+ }
+
+ /**
+ * return a table of the unsigned attributes indexed by
+ * the OID of the attribute.
+ */
+ public Asn1.Cms.AttributeTable UnsignedAttributes
+ {
+ get
+ {
+ if (unsignedAttributeSet != null && unsignedAttributeTable == null)
+ {
+ unsignedAttributeTable = new Asn1.Cms.AttributeTable(unsignedAttributeSet);
+ }
+ return unsignedAttributeTable;
+ }
+ }
+
+ /**
+ * return the encoded signature
+ */
+ public byte[] GetSignature()
+ {
+ return (byte[]) signature.Clone();
+ }
+
+ /**
+ * Return a SignerInformationStore containing the counter signatures attached to this
+ * signer. If no counter signatures are present an empty store is returned.
+ */
+ public SignerInformationStore GetCounterSignatures()
+ {
+ // TODO There are several checks implied by the RFC3852 comments that are missing
+
+ /*
+ The countersignature attribute MUST be an unsigned attribute; it MUST
+ NOT be a signed attribute, an authenticated attribute, an
+ unauthenticated attribute, or an unprotected attribute.
+ */
+ Asn1.Cms.AttributeTable unsignedAttributeTable = UnsignedAttributes;
+ if (unsignedAttributeTable == null)
+ {
+ return new SignerInformationStore(Platform.CreateArrayList(0));
+ }
+
+ IList counterSignatures = Platform.CreateArrayList();
+
+ /*
+ The UnsignedAttributes syntax is defined as a SET OF Attributes. The
+ UnsignedAttributes in a signerInfo may include multiple instances of
+ the countersignature attribute.
+ */
+ Asn1EncodableVector allCSAttrs = unsignedAttributeTable.GetAll(CmsAttributes.CounterSignature);
+
+ foreach (Asn1.Cms.Attribute counterSignatureAttribute in allCSAttrs)
+ {
+ /*
+ A countersignature attribute can have multiple attribute values. The
+ syntax is defined as a SET OF AttributeValue, and there MUST be one
+ or more instances of AttributeValue present.
+ */
+ Asn1Set values = counterSignatureAttribute.AttrValues;
+ if (values.Count < 1)
+ {
+ // TODO Throw an appropriate exception?
+ }
+
+ foreach (Asn1Encodable asn1Obj in values)
+ {
+ /*
+ Countersignature values have the same meaning as SignerInfo values
+ for ordinary signatures, except that:
+
+ 1. The signedAttributes field MUST NOT contain a content-type
+ attribute; there is no content type for countersignatures.
+
+ 2. The signedAttributes field MUST contain a message-digest
+ attribute if it contains any other attributes.
+
+ 3. The input to the message-digesting process is the contents
+ octets of the DER encoding of the signatureValue field of the
+ SignerInfo value with which the attribute is associated.
+ */
+ SignerInfo si = SignerInfo.GetInstance(asn1Obj.ToAsn1Object());
+
+ string digestName = CmsSignedHelper.Instance.GetDigestAlgName(si.DigestAlgorithm.Algorithm.Id);
+
+ counterSignatures.Add(new SignerInformation(si, null, null, new CounterSignatureDigestCalculator(digestName, GetSignature())));
+ }
+ }
+
+ return new SignerInformationStore(counterSignatures);
+ }
+
+ /**
+ * return the DER encoding of the signed attributes.
+ * @throws IOException if an encoding error occurs.
+ */
+ public byte[] GetEncodedSignedAttributes()
+ {
+ return signedAttributeSet == null
+ ? null
+ : signedAttributeSet.GetEncoded(Asn1Encodable.Der);
+ }
+
+ private bool DoVerify(
+ AsymmetricKeyParameter key)
+ {
+ string digestName = Helper.GetDigestAlgName(this.DigestAlgOid);
+ IDigest digest = Helper.GetDigestInstance(digestName);
+
+ DerObjectIdentifier sigAlgOid = this.encryptionAlgorithm.Algorithm;
+ Asn1Encodable sigParams = this.encryptionAlgorithm.Parameters;
+ ISigner sig;
+
+ if (sigAlgOid.Equals(Asn1.Pkcs.PkcsObjectIdentifiers.IdRsassaPss))
+ {
+ // RFC 4056 2.2
+ // When the id-RSASSA-PSS algorithm identifier is used for a signature,
+ // the AlgorithmIdentifier parameters field MUST contain RSASSA-PSS-params.
+ if (sigParams == null)
+ throw new CmsException("RSASSA-PSS signature must specify algorithm parameters");
+
+ try
+ {
+ // TODO Provide abstract configuration mechanism
+ // (via alternate SignerUtilities.GetSigner method taking ASN.1 params)
+
+ Asn1.Pkcs.RsassaPssParameters pss = Asn1.Pkcs.RsassaPssParameters.GetInstance(
+ sigParams.ToAsn1Object());
+
+ if (!pss.HashAlgorithm.Algorithm.Equals(this.digestAlgorithm.Algorithm))
+ throw new CmsException("RSASSA-PSS signature parameters specified incorrect hash algorithm");
+ if (!pss.MaskGenAlgorithm.Algorithm.Equals(Asn1.Pkcs.PkcsObjectIdentifiers.IdMgf1))
+ throw new CmsException("RSASSA-PSS signature parameters specified unknown MGF");
+
+ IDigest pssDigest = DigestUtilities.GetDigest(pss.HashAlgorithm.Algorithm);
+ int saltLength = pss.SaltLength.Value.IntValue;
+ byte trailerField = (byte) pss.TrailerField.Value.IntValue;
+
+ // RFC 4055 3.1
+ // The value MUST be 1, which represents the trailer field with hexadecimal value 0xBC
+ if (trailerField != 1)
+ throw new CmsException("RSASSA-PSS signature parameters must have trailerField of 1");
+
+ sig = new PssSigner(new RsaBlindedEngine(), pssDigest, saltLength);
+ }
+ catch (Exception e)
+ {
+ throw new CmsException("failed to set RSASSA-PSS signature parameters", e);
+ }
+ }
+ else
+ {
+ // TODO Probably too strong a check at the moment
+// if (sigParams != null)
+// throw new CmsException("unrecognised signature parameters provided");
+
+ string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(this.EncryptionAlgOid);
+
+ sig = Helper.GetSignatureInstance(signatureName);
+
+ //sig = Helper.GetSignatureInstance(this.EncryptionAlgOid);
+ //sig = SignerUtilities.GetSigner(sigAlgOid);
+ }
+
+ try
+ {
+ if (digestCalculator != null)
+ {
+ resultDigest = digestCalculator.GetDigest();
+ }
+ else
+ {
+ if (content != null)
+ {
+ content.Write(new DigOutputStream(digest));
+ }
+ else if (signedAttributeSet == null)
+ {
+ // TODO Get rid of this exception and just treat content==null as empty not missing?
+ throw new CmsException("data not encapsulated in signature - use detached constructor.");
+ }
+
+ resultDigest = DigestUtilities.DoFinal(digest);
+ }
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("can't process mime object to create signature.", e);
+ }
+
+ // RFC 3852 11.1 Check the content-type attribute is correct
+ {
+ Asn1Object validContentType = GetSingleValuedSignedAttribute(
+ CmsAttributes.ContentType, "content-type");
+ if (validContentType == null)
+ {
+ if (!isCounterSignature && signedAttributeSet != null)
+ throw new CmsException("The content-type attribute type MUST be present whenever signed attributes are present in signed-data");
+ }
+ else
+ {
+ if (isCounterSignature)
+ throw new CmsException("[For counter signatures,] the signedAttributes field MUST NOT contain a content-type attribute");
+
+ if (!(validContentType is DerObjectIdentifier))
+ throw new CmsException("content-type attribute value not of ASN.1 type 'OBJECT IDENTIFIER'");
+
+ DerObjectIdentifier signedContentType = (DerObjectIdentifier)validContentType;
+
+ if (!signedContentType.Equals(contentType))
+ throw new CmsException("content-type attribute value does not match eContentType");
+ }
+ }
+
+ // RFC 3852 11.2 Check the message-digest attribute is correct
+ {
+ Asn1Object validMessageDigest = GetSingleValuedSignedAttribute(
+ CmsAttributes.MessageDigest, "message-digest");
+ if (validMessageDigest == null)
+ {
+ if (signedAttributeSet != null)
+ throw new CmsException("the message-digest signed attribute type MUST be present when there are any signed attributes present");
+ }
+ else
+ {
+ if (!(validMessageDigest is Asn1OctetString))
+ {
+ throw new CmsException("message-digest attribute value not of ASN.1 type 'OCTET STRING'");
+ }
+
+ Asn1OctetString signedMessageDigest = (Asn1OctetString)validMessageDigest;
+
+ if (!Arrays.AreEqual(resultDigest, signedMessageDigest.GetOctets()))
+ throw new CmsException("message-digest attribute value does not match calculated value");
+ }
+ }
+
+ // RFC 3852 11.4 Validate countersignature attribute(s)
+ {
+ Asn1.Cms.AttributeTable signedAttrTable = this.SignedAttributes;
+ if (signedAttrTable != null
+ && signedAttrTable.GetAll(CmsAttributes.CounterSignature).Count > 0)
+ {
+ throw new CmsException("A countersignature attribute MUST NOT be a signed attribute");
+ }
+
+ Asn1.Cms.AttributeTable unsignedAttrTable = this.UnsignedAttributes;
+ if (unsignedAttrTable != null)
+ {
+ foreach (Asn1.Cms.Attribute csAttr in unsignedAttrTable.GetAll(CmsAttributes.CounterSignature))
+ {
+ if (csAttr.AttrValues.Count < 1)
+ throw new CmsException("A countersignature attribute MUST contain at least one AttributeValue");
+
+ // Note: We don't recursively validate the countersignature value
+ }
+ }
+ }
+
+ try
+ {
+ sig.Init(false, key);
+
+ if (signedAttributeSet == null)
+ {
+ if (digestCalculator != null)
+ {
+ // need to decrypt signature and check message bytes
+ return VerifyDigest(resultDigest, key, this.GetSignature());
+ }
+ else if (content != null)
+ {
+ // TODO Use raw signature of the hash value instead
+ content.Write(new SigOutputStream(sig));
+ }
+ }
+ else
+ {
+ byte[] tmp = this.GetEncodedSignedAttributes();
+ sig.BlockUpdate(tmp, 0, tmp.Length);
+ }
+
+ return sig.VerifySignature(this.GetSignature());
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new CmsException("key not appropriate to signature in message.", e);
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("can't process mime object to create signature.", e);
+ }
+ catch (SignatureException e)
+ {
+ throw new CmsException("invalid signature format in message: " + e.Message, e);
+ }
+ }
+
+ private bool IsNull(
+ Asn1Encodable o)
+ {
+ return (o is Asn1Null) || (o == null);
+ }
+
+ private DigestInfo DerDecode(
+ byte[] encoding)
+ {
+ if (encoding[0] != (int)(Asn1Tags.Constructed | Asn1Tags.Sequence))
+ {
+ throw new IOException("not a digest info object");
+ }
+
+ DigestInfo digInfo = DigestInfo.GetInstance(Asn1Object.FromByteArray(encoding));
+
+ // length check to avoid Bleichenbacher vulnerability
+
+ if (digInfo.GetEncoded().Length != encoding.Length)
+ {
+ throw new CmsException("malformed RSA signature");
+ }
+
+ return digInfo;
+ }
+
+ private bool VerifyDigest(
+ byte[] digest,
+ AsymmetricKeyParameter key,
+ byte[] signature)
+ {
+ string algorithm = Helper.GetEncryptionAlgName(this.EncryptionAlgOid);
+
+ try
+ {
+ if (algorithm.Equals("RSA"))
+ {
+ IBufferedCipher c = CmsEnvelopedHelper.Instance.CreateAsymmetricCipher("RSA/ECB/PKCS1Padding");
+
+ c.Init(false, key);
+
+ byte[] decrypt = c.DoFinal(signature);
+
+ DigestInfo digInfo = DerDecode(decrypt);
+
+ if (!digInfo.AlgorithmID.Algorithm.Equals(digestAlgorithm.Algorithm))
+ {
+ return false;
+ }
+
+ if (!IsNull(digInfo.AlgorithmID.Parameters))
+ {
+ return false;
+ }
+
+ byte[] sigHash = digInfo.GetDigest();
+
+ return Arrays.ConstantTimeAreEqual(digest, sigHash);
+ }
+ else if (algorithm.Equals("DSA"))
+ {
+ ISigner sig = SignerUtilities.GetSigner("NONEwithDSA");
+
+ sig.Init(false, key);
+
+ sig.BlockUpdate(digest, 0, digest.Length);
+
+ return sig.VerifySignature(signature);
+ }
+ else
+ {
+ throw new CmsException("algorithm: " + algorithm + " not supported in base signatures.");
+ }
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw e;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CmsException("Exception processing signature: " + e, e);
+ }
+ catch (IOException e)
+ {
+ throw new CmsException("Exception decoding signature: " + e, e);
+ }
+ }
+
+ /**
+ * verify that the given public key successfully handles and confirms the
+ * signature associated with this signer.
+ */
+ public bool Verify(
+ AsymmetricKeyParameter pubKey)
+ {
+ if (pubKey.IsPrivate)
+ throw new ArgumentException("Expected public key", "pubKey");
+
+ // Optional, but still need to validate if present
+ GetSigningTime();
+
+ return DoVerify(pubKey);
+ }
+
+ /**
+ * verify that the given certificate successfully handles and confirms
+ * the signature associated with this signer and, if a signingTime
+ * attribute is available, that the certificate was valid at the time the
+ * signature was generated.
+ */
+ public bool Verify(
+ X509Certificate cert)
+ {
+ Asn1.Cms.Time signingTime = GetSigningTime();
+ if (signingTime != null)
+ {
+ cert.CheckValidity(signingTime.Date);
+ }
+
+ return DoVerify(cert.GetPublicKey());
+ }
+
+ /**
+ * Return the base ASN.1 CMS structure that this object contains.
+ *
+ * @return an object containing a CMS SignerInfo structure.
+ */
+ public SignerInfo ToSignerInfo()
+ {
+ return info;
+ }
+
+ private Asn1Object GetSingleValuedSignedAttribute(
+ DerObjectIdentifier attrOID, string printableName)
+ {
+
+ Asn1.Cms.AttributeTable unsignedAttrTable = this.UnsignedAttributes;
+ if (unsignedAttrTable != null
+ && unsignedAttrTable.GetAll(attrOID).Count > 0)
+ {
+ throw new CmsException("The " + printableName
+ + " attribute MUST NOT be an unsigned attribute");
+ }
+
+ Asn1.Cms.AttributeTable signedAttrTable = this.SignedAttributes;
+ if (signedAttrTable == null)
+ {
+ return null;
+ }
+
+ Asn1EncodableVector v = signedAttrTable.GetAll(attrOID);
+ switch (v.Count)
+ {
+ case 0:
+ return null;
+ case 1:
+ Asn1.Cms.Attribute t = (Asn1.Cms.Attribute) v[0];
+ Asn1Set attrValues = t.AttrValues;
+
+ if (attrValues.Count != 1)
+ throw new CmsException("A " + printableName
+ + " attribute MUST have a single attribute value");
+
+ return attrValues[0].ToAsn1Object();
+ default:
+ throw new CmsException("The SignedAttributes in a signerInfo MUST NOT include multiple instances of the "
+ + printableName + " attribute");
+ }
+ }
+
+ private Asn1.Cms.Time GetSigningTime()
+ {
+ Asn1Object validSigningTime = GetSingleValuedSignedAttribute(
+ CmsAttributes.SigningTime, "signing-time");
+
+ if (validSigningTime == null)
+ return null;
+
+ try
+ {
+ return Asn1.Cms.Time.GetInstance(validSigningTime);
+ }
+ catch (ArgumentException)
+ {
+ throw new CmsException("signing-time attribute value not a valid 'Time' structure");
+ }
+ }
+
+ /**
+ * Return a signer information object with the passed in unsigned
+ * attributes replacing the ones that are current associated with
+ * the object passed in.
+ *
+ * @param signerInformation the signerInfo to be used as the basis.
+ * @param unsignedAttributes the unsigned attributes to add.
+ * @return a copy of the original SignerInformationObject with the changed attributes.
+ */
+ public static SignerInformation ReplaceUnsignedAttributes(
+ SignerInformation signerInformation,
+ Asn1.Cms.AttributeTable unsignedAttributes)
+ {
+ SignerInfo sInfo = signerInformation.info;
+ Asn1Set unsignedAttr = null;
+
+ if (unsignedAttributes != null)
+ {
+ unsignedAttr = new DerSet(unsignedAttributes.ToAsn1EncodableVector());
+ }
+
+ return new SignerInformation(
+ new SignerInfo(
+ sInfo.SignerID,
+ sInfo.DigestAlgorithm,
+ sInfo.AuthenticatedAttributes,
+ sInfo.DigestEncryptionAlgorithm,
+ sInfo.EncryptedDigest,
+ unsignedAttr),
+ signerInformation.contentType,
+ signerInformation.content,
+ null);
+ }
+
+ /**
+ * Return a signer information object with passed in SignerInformationStore representing counter
+ * signatures attached as an unsigned attribute.
+ *
+ * @param signerInformation the signerInfo to be used as the basis.
+ * @param counterSigners signer info objects carrying counter signature.
+ * @return a copy of the original SignerInformationObject with the changed attributes.
+ */
+ public static SignerInformation AddCounterSigners(
+ SignerInformation signerInformation,
+ SignerInformationStore counterSigners)
+ {
+ // TODO Perform checks from RFC 3852 11.4
+
+ SignerInfo sInfo = signerInformation.info;
+ Asn1.Cms.AttributeTable unsignedAttr = signerInformation.UnsignedAttributes;
+ Asn1EncodableVector v;
+
+ if (unsignedAttr != null)
+ {
+ v = unsignedAttr.ToAsn1EncodableVector();
+ }
+ else
+ {
+ v = new Asn1EncodableVector();
+ }
+
+ Asn1EncodableVector sigs = new Asn1EncodableVector();
+
+ foreach (SignerInformation sigInf in counterSigners.GetSigners())
+ {
+ sigs.Add(sigInf.ToSignerInfo());
+ }
+
+ v.Add(new Asn1.Cms.Attribute(CmsAttributes.CounterSignature, new DerSet(sigs)));
+
+ return new SignerInformation(
+ new SignerInfo(
+ sInfo.SignerID,
+ sInfo.DigestAlgorithm,
+ sInfo.AuthenticatedAttributes,
+ sInfo.DigestEncryptionAlgorithm,
+ sInfo.EncryptedDigest,
+ new DerSet(v)),
+ signerInformation.contentType,
+ signerInformation.content,
+ null);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/SignerInformationStore.cs b/bc-sharp-crypto/src/cms/SignerInformationStore.cs
new file mode 100644
index 0000000000000000000000000000000000000000..27940865dc8d61f9c6cd03c9e6feb9940d818749
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/SignerInformationStore.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Cms
+{
+ public class SignerInformationStore
+ {
+ private readonly IList all; //ArrayList[SignerInformation]
+ private readonly IDictionary table = Platform.CreateHashtable(); // Hashtable[SignerID, ArrayList[SignerInformation]]
+
+ /**
+ * Create a store containing a single SignerInformation object.
+ *
+ * @param signerInfo the signer information to contain.
+ */
+ public SignerInformationStore(
+ SignerInformation signerInfo)
+ {
+ this.all = Platform.CreateArrayList(1);
+ this.all.Add(signerInfo);
+
+ SignerID sid = signerInfo.SignerID;
+
+ table[sid] = all;
+ }
+
+ /**
+ * Create a store containing a collection of SignerInformation objects.
+ *
+ * @param signerInfos a collection signer information objects to contain.
+ */
+ public SignerInformationStore(
+ ICollection signerInfos)
+ {
+ foreach (SignerInformation signer in signerInfos)
+ {
+ SignerID sid = signer.SignerID;
+ IList list = (IList)table[sid];
+
+ if (list == null)
+ {
+ table[sid] = list = Platform.CreateArrayList(1);
+ }
+
+ list.Add(signer);
+ }
+
+ this.all = Platform.CreateArrayList(signerInfos);
+ }
+
+ /**
+ * Return the first SignerInformation object that matches the
+ * passed in selector. Null if there are no matches.
+ *
+ * @param selector to identify a signer
+ * @return a single SignerInformation object. Null if none matches.
+ */
+ public SignerInformation GetFirstSigner(
+ SignerID selector)
+ {
+ IList list = (IList) table[selector];
+
+ return list == null ? null : (SignerInformation) list[0];
+ }
+
+ /// The number of signers in the collection.
+ public int Count
+ {
+ get { return all.Count; }
+ }
+
+ /// An ICollection of all signers in the collection
+ public ICollection GetSigners()
+ {
+ return Platform.CreateArrayList(all);
+ }
+
+ /**
+ * Return possible empty collection with signers matching the passed in SignerID
+ *
+ * @param selector a signer id to select against.
+ * @return a collection of SignerInformation objects.
+ */
+ public ICollection GetSigners(
+ SignerID selector)
+ {
+ IList list = (IList) table[selector];
+
+ return list == null ? Platform.CreateArrayList() : Platform.CreateArrayList(list);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/cms/SimpleAttributeTableGenerator.cs b/bc-sharp-crypto/src/cms/SimpleAttributeTableGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b3df21c29195e9c7afa9059964c99cf9af7f0771
--- /dev/null
+++ b/bc-sharp-crypto/src/cms/SimpleAttributeTableGenerator.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.Cms;
+
+namespace Org.BouncyCastle.Cms
+{
+ /**
+ * Basic generator that just returns a preconstructed attribute table
+ */
+ public class SimpleAttributeTableGenerator
+ : CmsAttributeTableGenerator
+ {
+ private readonly AttributeTable attributes;
+
+ public SimpleAttributeTableGenerator(
+ AttributeTable attributes)
+ {
+ this.attributes = attributes;
+ }
+
+ public virtual AttributeTable GetAttributes(
+ IDictionary parameters)
+ {
+ return attributes;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/AsymmetricCipherKeyPair.cs b/bc-sharp-crypto/src/crypto/AsymmetricCipherKeyPair.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b00a3dc021e2e9f32f254273f2246c3b1c435e87
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/AsymmetricCipherKeyPair.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * a holding class for public/private parameter pairs.
+ */
+ public class AsymmetricCipherKeyPair
+ {
+ private readonly AsymmetricKeyParameter publicParameter;
+ private readonly AsymmetricKeyParameter privateParameter;
+
+ /**
+ * basic constructor.
+ *
+ * @param publicParam a public key parameters object.
+ * @param privateParam the corresponding private key parameters.
+ */
+ public AsymmetricCipherKeyPair(
+ AsymmetricKeyParameter publicParameter,
+ AsymmetricKeyParameter privateParameter)
+ {
+ if (publicParameter.IsPrivate)
+ throw new ArgumentException("Expected a public key", "publicParameter");
+ if (!privateParameter.IsPrivate)
+ throw new ArgumentException("Expected a private key", "privateParameter");
+
+ this.publicParameter = publicParameter;
+ this.privateParameter = privateParameter;
+ }
+
+ /**
+ * return the public key parameters.
+ *
+ * @return the public key parameters.
+ */
+ public AsymmetricKeyParameter Public
+ {
+ get { return publicParameter; }
+ }
+
+ /**
+ * return the private key parameters.
+ *
+ * @return the private key parameters.
+ */
+ public AsymmetricKeyParameter Private
+ {
+ get { return privateParameter; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/AsymmetricKeyParameter.cs b/bc-sharp-crypto/src/crypto/AsymmetricKeyParameter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7502ee305ac4313199d3aa94376d67c2b556fd9d
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/AsymmetricKeyParameter.cs
@@ -0,0 +1,47 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto
+{
+ public abstract class AsymmetricKeyParameter
+ : ICipherParameters
+ {
+ private readonly bool privateKey;
+
+ protected AsymmetricKeyParameter(
+ bool privateKey)
+ {
+ this.privateKey = privateKey;
+ }
+
+ public bool IsPrivate
+ {
+ get { return privateKey; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ AsymmetricKeyParameter other = obj as AsymmetricKeyParameter;
+
+ if (other == null)
+ {
+ return false;
+ }
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ AsymmetricKeyParameter other)
+ {
+ return privateKey == other.privateKey;
+ }
+
+ public override int GetHashCode()
+ {
+ return privateKey.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/BufferedAeadBlockCipher.cs b/bc-sharp-crypto/src/crypto/BufferedAeadBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7ba41090fe6a2ab8f15776dcc7f9f02f4d5cc037
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/BufferedAeadBlockCipher.cs
@@ -0,0 +1,247 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * The AEAD block ciphers already handle buffering internally, so this class
+ * just takes care of implementing IBufferedCipher methods.
+ */
+ public class BufferedAeadBlockCipher
+ : BufferedCipherBase
+ {
+ private readonly IAeadBlockCipher cipher;
+
+ public BufferedAeadBlockCipher(
+ IAeadBlockCipher cipher)
+ {
+ if (cipher == null)
+ throw new ArgumentNullException("cipher");
+
+ this.cipher = cipher;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return cipher.AlgorithmName; }
+ }
+
+ /**
+ * initialise the cipher.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param param the key and other data required by the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public override void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ parameters = ((ParametersWithRandom) parameters).Parameters;
+ }
+
+ cipher.Init(forEncryption, parameters);
+ }
+
+ /**
+ * return the blocksize for the underlying cipher.
+ *
+ * @return the blocksize for the underlying cipher.
+ */
+ public override int GetBlockSize()
+ {
+ return cipher.GetBlockSize();
+ }
+
+ /**
+ * return the size of the output buffer required for an update
+ * an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update
+ * with len bytes of input.
+ */
+ public override int GetUpdateOutputSize(
+ int length)
+ {
+ return cipher.GetUpdateOutputSize(length);
+ }
+
+ /**
+ * return the size of the output buffer required for an update plus a
+ * doFinal with an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update and doFinal
+ * with len bytes of input.
+ */
+ public override int GetOutputSize(
+ int length)
+ {
+ return cipher.GetOutputSize(length);
+ }
+
+ /**
+ * process a single byte, producing an output block if necessary.
+ *
+ * @param in the input byte.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ */
+ public override int ProcessByte(
+ byte input,
+ byte[] output,
+ int outOff)
+ {
+ return cipher.ProcessByte(input, output, outOff);
+ }
+
+ public override byte[] ProcessByte(
+ byte input)
+ {
+ int outLength = GetUpdateOutputSize(1);
+
+ byte[] outBytes = outLength > 0 ? new byte[outLength] : null;
+
+ int pos = ProcessByte(input, outBytes, 0);
+
+ if (outLength > 0 && pos < outLength)
+ {
+ byte[] tmp = new byte[pos];
+ Array.Copy(outBytes, 0, tmp, 0, pos);
+ outBytes = tmp;
+ }
+
+ return outBytes;
+ }
+
+ public override byte[] ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (input == null)
+ throw new ArgumentNullException("input");
+ if (length < 1)
+ return null;
+
+ int outLength = GetUpdateOutputSize(length);
+
+ byte[] outBytes = outLength > 0 ? new byte[outLength] : null;
+
+ int pos = ProcessBytes(input, inOff, length, outBytes, 0);
+
+ if (outLength > 0 && pos < outLength)
+ {
+ byte[] tmp = new byte[pos];
+ Array.Copy(outBytes, 0, tmp, 0, pos);
+ outBytes = tmp;
+ }
+
+ return outBytes;
+ }
+
+ /**
+ * process an array of bytes, producing output if necessary.
+ *
+ * @param in the input byte array.
+ * @param inOff the offset at which the input data starts.
+ * @param len the number of bytes to be copied out of the input array.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ */
+ public override int ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] output,
+ int outOff)
+ {
+ return cipher.ProcessBytes(input, inOff, length, output, outOff);
+ }
+
+ public override byte[] DoFinal()
+ {
+ byte[] outBytes = new byte[GetOutputSize(0)];
+
+ int pos = DoFinal(outBytes, 0);
+
+ if (pos < outBytes.Length)
+ {
+ byte[] tmp = new byte[pos];
+ Array.Copy(outBytes, 0, tmp, 0, pos);
+ outBytes = tmp;
+ }
+
+ return outBytes;
+ }
+
+ public override byte[] DoFinal(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ if (input == null)
+ throw new ArgumentNullException("input");
+
+ byte[] outBytes = new byte[GetOutputSize(inLen)];
+
+ int pos = (inLen > 0)
+ ? ProcessBytes(input, inOff, inLen, outBytes, 0)
+ : 0;
+
+ pos += DoFinal(outBytes, pos);
+
+ if (pos < outBytes.Length)
+ {
+ byte[] tmp = new byte[pos];
+ Array.Copy(outBytes, 0, tmp, 0, pos);
+ outBytes = tmp;
+ }
+
+ return outBytes;
+ }
+
+ /**
+ * Process the last block in the buffer.
+ *
+ * @param out the array the block currently being held is copied into.
+ * @param outOff the offset at which the copying starts.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there is insufficient space in out for
+ * the output, or the input is not block size aligned and should be.
+ * @exception InvalidOperationException if the underlying cipher is not
+ * initialised.
+ * @exception InvalidCipherTextException if padding is expected and not found.
+ * @exception DataLengthException if the input is not block size
+ * aligned.
+ */
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ return cipher.DoFinal(output, outOff);
+ }
+
+ /**
+ * Reset the buffer and cipher. After resetting the object is in the same
+ * state as it was after the last init (if there was one).
+ */
+ public override void Reset()
+ {
+ cipher.Reset();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/BufferedAsymmetricBlockCipher.cs b/bc-sharp-crypto/src/crypto/BufferedAsymmetricBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..09ec59f6917950c9a0bed2716cd3500267762618
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/BufferedAsymmetricBlockCipher.cs
@@ -0,0 +1,152 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Engines;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * a buffer wrapper for an asymmetric block cipher, allowing input
+ * to be accumulated in a piecemeal fashion until final processing.
+ */
+ public class BufferedAsymmetricBlockCipher
+ : BufferedCipherBase
+ {
+ private readonly IAsymmetricBlockCipher cipher;
+
+ private byte[] buffer;
+ private int bufOff;
+
+ /**
+ * base constructor.
+ *
+ * @param cipher the cipher this buffering object wraps.
+ */
+ public BufferedAsymmetricBlockCipher(
+ IAsymmetricBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ }
+
+ /**
+ * return the amount of data sitting in the buffer.
+ *
+ * @return the amount of data sitting in the buffer.
+ */
+ internal int GetBufferPosition()
+ {
+ return bufOff;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return cipher.AlgorithmName; }
+ }
+
+ public override int GetBlockSize()
+ {
+ return cipher.GetInputBlockSize();
+ }
+
+ public override int GetOutputSize(
+ int length)
+ {
+ return cipher.GetOutputBlockSize();
+ }
+
+ public override int GetUpdateOutputSize(
+ int length)
+ {
+ return 0;
+ }
+
+ /**
+ * initialise the buffer and the underlying cipher.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param param the key and other data required by the cipher.
+ */
+ public override void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ Reset();
+
+ cipher.Init(forEncryption, parameters);
+
+ //
+ // we allow for an extra byte where people are using their own padding
+ // mechanisms on a raw cipher.
+ //
+ this.buffer = new byte[cipher.GetInputBlockSize() + (forEncryption ? 1 : 0)];
+ this.bufOff = 0;
+ }
+
+ public override byte[] ProcessByte(
+ byte input)
+ {
+ if (bufOff >= buffer.Length)
+ throw new DataLengthException("attempt to process message to long for cipher");
+
+ buffer[bufOff++] = input;
+ return null;
+ }
+
+ public override byte[] ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (length < 1)
+ return null;
+
+ if (input == null)
+ throw new ArgumentNullException("input");
+ if (bufOff + length > buffer.Length)
+ throw new DataLengthException("attempt to process message to long for cipher");
+
+ Array.Copy(input, inOff, buffer, bufOff, length);
+ bufOff += length;
+ return null;
+ }
+
+ /**
+ * process the contents of the buffer using the underlying
+ * cipher.
+ *
+ * @return the result of the encryption/decryption process on the
+ * buffer.
+ * @exception InvalidCipherTextException if we are given a garbage block.
+ */
+ public override byte[] DoFinal()
+ {
+ byte[] outBytes = bufOff > 0
+ ? cipher.ProcessBlock(buffer, 0, bufOff)
+ : EmptyBuffer;
+
+ Reset();
+
+ return outBytes;
+ }
+
+ public override byte[] DoFinal(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ ProcessBytes(input, inOff, length);
+ return DoFinal();
+ }
+
+ /// Reset the buffer
+ public override void Reset()
+ {
+ if (buffer != null)
+ {
+ Array.Clear(buffer, 0, buffer.Length);
+ bufOff = 0;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/BufferedBlockCipher.cs b/bc-sharp-crypto/src/crypto/BufferedBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c87d2daf92c9fe06bbae7d86877a35f1ce724c28
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/BufferedBlockCipher.cs
@@ -0,0 +1,367 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * A wrapper class that allows block ciphers to be used to process data in
+ * a piecemeal fashion. The BufferedBlockCipher outputs a block only when the
+ * buffer is full and more data is being added, or on a doFinal.
+ *
+ * Note: in the case where the underlying cipher is either a CFB cipher or an
+ * OFB one the last block may not be a multiple of the block size.
+ *
+ */
+ public class BufferedBlockCipher
+ : BufferedCipherBase
+ {
+ internal byte[] buf;
+ internal int bufOff;
+ internal bool forEncryption;
+ internal IBlockCipher cipher;
+
+ /**
+ * constructor for subclasses
+ */
+ protected BufferedBlockCipher()
+ {
+ }
+
+ /**
+ * Create a buffered block cipher without padding.
+ *
+ * @param cipher the underlying block cipher this buffering object wraps.
+ * false otherwise.
+ */
+ public BufferedBlockCipher(
+ IBlockCipher cipher)
+ {
+ if (cipher == null)
+ throw new ArgumentNullException("cipher");
+
+ this.cipher = cipher;
+ buf = new byte[cipher.GetBlockSize()];
+ bufOff = 0;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return cipher.AlgorithmName; }
+ }
+
+ /**
+ * initialise the cipher.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param param the key and other data required by the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ // Note: This doubles as the Init in the event that this cipher is being used as an IWrapper
+ public override void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+
+ ParametersWithRandom pwr = parameters as ParametersWithRandom;
+ if (pwr != null)
+ parameters = pwr.Parameters;
+
+ Reset();
+
+ cipher.Init(forEncryption, parameters);
+ }
+
+ /**
+ * return the blocksize for the underlying cipher.
+ *
+ * @return the blocksize for the underlying cipher.
+ */
+ public override int GetBlockSize()
+ {
+ return cipher.GetBlockSize();
+ }
+
+ /**
+ * return the size of the output buffer required for an update
+ * an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update
+ * with len bytes of input.
+ */
+ public override int GetUpdateOutputSize(
+ int length)
+ {
+ int total = length + bufOff;
+ int leftOver = total % buf.Length;
+ return total - leftOver;
+ }
+
+ /**
+ * return the size of the output buffer required for an update plus a
+ * doFinal with an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update and doFinal
+ * with len bytes of input.
+ */
+ public override int GetOutputSize(
+ int length)
+ {
+ // Note: Can assume IsPartialBlockOkay is true for purposes of this calculation
+ return length + bufOff;
+ }
+
+ /**
+ * process a single byte, producing an output block if necessary.
+ *
+ * @param in the input byte.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ */
+ public override int ProcessByte(
+ byte input,
+ byte[] output,
+ int outOff)
+ {
+ buf[bufOff++] = input;
+
+ if (bufOff == buf.Length)
+ {
+ if ((outOff + buf.Length) > output.Length)
+ throw new DataLengthException("output buffer too short");
+
+ bufOff = 0;
+ return cipher.ProcessBlock(buf, 0, output, outOff);
+ }
+
+ return 0;
+ }
+
+ public override byte[] ProcessByte(
+ byte input)
+ {
+ int outLength = GetUpdateOutputSize(1);
+
+ byte[] outBytes = outLength > 0 ? new byte[outLength] : null;
+
+ int pos = ProcessByte(input, outBytes, 0);
+
+ if (outLength > 0 && pos < outLength)
+ {
+ byte[] tmp = new byte[pos];
+ Array.Copy(outBytes, 0, tmp, 0, pos);
+ outBytes = tmp;
+ }
+
+ return outBytes;
+ }
+
+ public override byte[] ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (input == null)
+ throw new ArgumentNullException("input");
+ if (length < 1)
+ return null;
+
+ int outLength = GetUpdateOutputSize(length);
+
+ byte[] outBytes = outLength > 0 ? new byte[outLength] : null;
+
+ int pos = ProcessBytes(input, inOff, length, outBytes, 0);
+
+ if (outLength > 0 && pos < outLength)
+ {
+ byte[] tmp = new byte[pos];
+ Array.Copy(outBytes, 0, tmp, 0, pos);
+ outBytes = tmp;
+ }
+
+ return outBytes;
+ }
+
+ /**
+ * process an array of bytes, producing output if necessary.
+ *
+ * @param in the input byte array.
+ * @param inOff the offset at which the input data starts.
+ * @param len the number of bytes to be copied out of the input array.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ */
+ public override int ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] output,
+ int outOff)
+ {
+ if (length < 1)
+ {
+ if (length < 0)
+ throw new ArgumentException("Can't have a negative input length!");
+
+ return 0;
+ }
+
+ int blockSize = GetBlockSize();
+ int outLength = GetUpdateOutputSize(length);
+
+ if (outLength > 0)
+ {
+ Check.OutputLength(output, outOff, outLength, "output buffer too short");
+ }
+
+ int resultLen = 0;
+ int gapLen = buf.Length - bufOff;
+ if (length > gapLen)
+ {
+ Array.Copy(input, inOff, buf, bufOff, gapLen);
+ resultLen += cipher.ProcessBlock(buf, 0, output, outOff);
+ bufOff = 0;
+ length -= gapLen;
+ inOff += gapLen;
+ while (length > buf.Length)
+ {
+ resultLen += cipher.ProcessBlock(input, inOff, output, outOff + resultLen);
+ length -= blockSize;
+ inOff += blockSize;
+ }
+ }
+ Array.Copy(input, inOff, buf, bufOff, length);
+ bufOff += length;
+ if (bufOff == buf.Length)
+ {
+ resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen);
+ bufOff = 0;
+ }
+ return resultLen;
+ }
+
+ public override byte[] DoFinal()
+ {
+ byte[] outBytes = EmptyBuffer;
+
+ int length = GetOutputSize(0);
+ if (length > 0)
+ {
+ outBytes = new byte[length];
+
+ int pos = DoFinal(outBytes, 0);
+ if (pos < outBytes.Length)
+ {
+ byte[] tmp = new byte[pos];
+ Array.Copy(outBytes, 0, tmp, 0, pos);
+ outBytes = tmp;
+ }
+ }
+ else
+ {
+ Reset();
+ }
+
+ return outBytes;
+ }
+
+ public override byte[] DoFinal(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ if (input == null)
+ throw new ArgumentNullException("input");
+
+ int length = GetOutputSize(inLen);
+
+ byte[] outBytes = EmptyBuffer;
+
+ if (length > 0)
+ {
+ outBytes = new byte[length];
+
+ int pos = (inLen > 0)
+ ? ProcessBytes(input, inOff, inLen, outBytes, 0)
+ : 0;
+
+ pos += DoFinal(outBytes, pos);
+
+ if (pos < outBytes.Length)
+ {
+ byte[] tmp = new byte[pos];
+ Array.Copy(outBytes, 0, tmp, 0, pos);
+ outBytes = tmp;
+ }
+ }
+ else
+ {
+ Reset();
+ }
+
+ return outBytes;
+ }
+
+ /**
+ * Process the last block in the buffer.
+ *
+ * @param out the array the block currently being held is copied into.
+ * @param outOff the offset at which the copying starts.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there is insufficient space in out for
+ * the output, or the input is not block size aligned and should be.
+ * @exception InvalidOperationException if the underlying cipher is not
+ * initialised.
+ * @exception InvalidCipherTextException if padding is expected and not found.
+ * @exception DataLengthException if the input is not block size
+ * aligned.
+ */
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ try
+ {
+ if (bufOff != 0)
+ {
+ Check.DataLength(!cipher.IsPartialBlockOkay, "data not block size aligned");
+ Check.OutputLength(output, outOff, bufOff, "output buffer too short for DoFinal()");
+
+ // NB: Can't copy directly, or we may write too much output
+ cipher.ProcessBlock(buf, 0, buf, 0);
+ Array.Copy(buf, 0, output, outOff, bufOff);
+ }
+
+ return bufOff;
+ }
+ finally
+ {
+ Reset();
+ }
+ }
+
+ /**
+ * Reset the buffer and cipher. After resetting the object is in the same
+ * state as it was after the last init (if there was one).
+ */
+ public override void Reset()
+ {
+ Array.Clear(buf, 0, buf.Length);
+ bufOff = 0;
+
+ cipher.Reset();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/BufferedCipherBase.cs b/bc-sharp-crypto/src/crypto/BufferedCipherBase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9d8610211d7b323eac1f345ab9d090afcc51c11c
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/BufferedCipherBase.cs
@@ -0,0 +1,113 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ public abstract class BufferedCipherBase
+ : IBufferedCipher
+ {
+ protected static readonly byte[] EmptyBuffer = new byte[0];
+
+ public abstract string AlgorithmName { get; }
+
+ public abstract void Init(bool forEncryption, ICipherParameters parameters);
+
+ public abstract int GetBlockSize();
+
+ public abstract int GetOutputSize(int inputLen);
+ public abstract int GetUpdateOutputSize(int inputLen);
+
+ public abstract byte[] ProcessByte(byte input);
+
+ public virtual int ProcessByte(
+ byte input,
+ byte[] output,
+ int outOff)
+ {
+ byte[] outBytes = ProcessByte(input);
+ if (outBytes == null)
+ return 0;
+ if (outOff + outBytes.Length > output.Length)
+ throw new DataLengthException("output buffer too short");
+ outBytes.CopyTo(output, outOff);
+ return outBytes.Length;
+ }
+
+ public virtual byte[] ProcessBytes(
+ byte[] input)
+ {
+ return ProcessBytes(input, 0, input.Length);
+ }
+
+ public abstract byte[] ProcessBytes(byte[] input, int inOff, int length);
+
+ public virtual int ProcessBytes(
+ byte[] input,
+ byte[] output,
+ int outOff)
+ {
+ return ProcessBytes(input, 0, input.Length, output, outOff);
+ }
+
+ public virtual int ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] output,
+ int outOff)
+ {
+ byte[] outBytes = ProcessBytes(input, inOff, length);
+ if (outBytes == null)
+ return 0;
+ if (outOff + outBytes.Length > output.Length)
+ throw new DataLengthException("output buffer too short");
+ outBytes.CopyTo(output, outOff);
+ return outBytes.Length;
+ }
+
+ public abstract byte[] DoFinal();
+
+ public virtual byte[] DoFinal(
+ byte[] input)
+ {
+ return DoFinal(input, 0, input.Length);
+ }
+
+ public abstract byte[] DoFinal(
+ byte[] input,
+ int inOff,
+ int length);
+
+ public virtual int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ byte[] outBytes = DoFinal();
+ if (outOff + outBytes.Length > output.Length)
+ throw new DataLengthException("output buffer too short");
+ outBytes.CopyTo(output, outOff);
+ return outBytes.Length;
+ }
+
+ public virtual int DoFinal(
+ byte[] input,
+ byte[] output,
+ int outOff)
+ {
+ return DoFinal(input, 0, input.Length, output, outOff);
+ }
+
+ public virtual int DoFinal(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] output,
+ int outOff)
+ {
+ int len = ProcessBytes(input, inOff, length, output, outOff);
+ len += DoFinal(output, outOff + len);
+ return len;
+ }
+
+ public abstract void Reset();
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/BufferedIesCipher.cs b/bc-sharp-crypto/src/crypto/BufferedIesCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6dab4ae3322b54d314753fd4b66e610c8d28d4f6
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/BufferedIesCipher.cs
@@ -0,0 +1,113 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto
+{
+ public class BufferedIesCipher
+ : BufferedCipherBase
+ {
+ private readonly IesEngine engine;
+ private bool forEncryption;
+ private MemoryStream buffer = new MemoryStream();
+
+ public BufferedIesCipher(
+ IesEngine engine)
+ {
+ if (engine == null)
+ throw new ArgumentNullException("engine");
+
+ this.engine = engine;
+ }
+
+ public override string AlgorithmName
+ {
+ // TODO Create IESEngine.AlgorithmName
+ get { return "IES"; }
+ }
+
+ public override void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+
+ // TODO
+ throw Platform.CreateNotImplementedException("IES");
+ }
+
+ public override int GetBlockSize()
+ {
+ return 0;
+ }
+
+ public override int GetOutputSize(
+ int inputLen)
+ {
+ if (engine == null)
+ throw new InvalidOperationException("cipher not initialised");
+
+ int baseLen = inputLen + (int) buffer.Length;
+ return forEncryption
+ ? baseLen + 20
+ : baseLen - 20;
+ }
+
+ public override int GetUpdateOutputSize(
+ int inputLen)
+ {
+ return 0;
+ }
+
+ public override byte[] ProcessByte(
+ byte input)
+ {
+ buffer.WriteByte(input);
+ return null;
+ }
+
+ public override byte[] ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (input == null)
+ throw new ArgumentNullException("input");
+ if (inOff < 0)
+ throw new ArgumentException("inOff");
+ if (length < 0)
+ throw new ArgumentException("length");
+ if (inOff + length > input.Length)
+ throw new ArgumentException("invalid offset/length specified for input array");
+
+ buffer.Write(input, inOff, length);
+ return null;
+ }
+
+ public override byte[] DoFinal()
+ {
+ byte[] buf = buffer.ToArray();
+
+ Reset();
+
+ return engine.ProcessBlock(buf, 0, buf.Length);
+ }
+
+ public override byte[] DoFinal(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ ProcessBytes(input, inOff, length);
+ return DoFinal();
+ }
+
+ public override void Reset()
+ {
+ buffer.SetLength(0);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/BufferedStreamCipher.cs b/bc-sharp-crypto/src/crypto/BufferedStreamCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2d4987bba67b4ff0377a25239f7957796cb4679f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/BufferedStreamCipher.cs
@@ -0,0 +1,131 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto
+{
+ public class BufferedStreamCipher
+ : BufferedCipherBase
+ {
+ private readonly IStreamCipher cipher;
+
+ public BufferedStreamCipher(
+ IStreamCipher cipher)
+ {
+ if (cipher == null)
+ throw new ArgumentNullException("cipher");
+
+ this.cipher = cipher;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return cipher.AlgorithmName; }
+ }
+
+ public override void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ parameters = ((ParametersWithRandom) parameters).Parameters;
+ }
+
+ cipher.Init(forEncryption, parameters);
+ }
+
+ public override int GetBlockSize()
+ {
+ return 0;
+ }
+
+ public override int GetOutputSize(
+ int inputLen)
+ {
+ return inputLen;
+ }
+
+ public override int GetUpdateOutputSize(
+ int inputLen)
+ {
+ return inputLen;
+ }
+
+ public override byte[] ProcessByte(
+ byte input)
+ {
+ return new byte[]{ cipher.ReturnByte(input) };
+ }
+
+ public override int ProcessByte(
+ byte input,
+ byte[] output,
+ int outOff)
+ {
+ if (outOff >= output.Length)
+ throw new DataLengthException("output buffer too short");
+
+ output[outOff] = cipher.ReturnByte(input);
+ return 1;
+ }
+
+ public override byte[] ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (length < 1)
+ return null;
+
+ byte[] output = new byte[length];
+ cipher.ProcessBytes(input, inOff, length, output, 0);
+ return output;
+ }
+
+ public override int ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] output,
+ int outOff)
+ {
+ if (length < 1)
+ return 0;
+
+ if (length > 0)
+ {
+ cipher.ProcessBytes(input, inOff, length, output, outOff);
+ }
+
+ return length;
+ }
+
+ public override byte[] DoFinal()
+ {
+ Reset();
+
+ return EmptyBuffer;
+ }
+
+ public override byte[] DoFinal(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (length < 1)
+ return EmptyBuffer;
+
+ byte[] output = ProcessBytes(input, inOff, length);
+
+ Reset();
+
+ return output;
+ }
+
+ public override void Reset()
+ {
+ cipher.Reset();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/Check.cs b/bc-sharp-crypto/src/crypto/Check.cs
new file mode 100644
index 0000000000000000000000000000000000000000..96a05c64be7e315ae25c02f55b1f0e763b8cc4d4
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/Check.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ internal class Check
+ {
+ internal static void DataLength(bool condition, string msg)
+ {
+ if (condition)
+ throw new DataLengthException(msg);
+ }
+
+ internal static void DataLength(byte[] buf, int off, int len, string msg)
+ {
+ if (off + len > buf.Length)
+ throw new DataLengthException(msg);
+ }
+
+ internal static void OutputLength(byte[] buf, int off, int len, string msg)
+ {
+ if (off + len > buf.Length)
+ throw new OutputLengthException(msg);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/CipherKeyGenerator.cs b/bc-sharp-crypto/src/crypto/CipherKeyGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d8d9b29b52792c622b9727b5efbc9e5f88637ba6
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/CipherKeyGenerator.cs
@@ -0,0 +1,83 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * The base class for symmetric, or secret, cipher key generators.
+ */
+ public class CipherKeyGenerator
+ {
+ protected internal SecureRandom random;
+ protected internal int strength;
+ private bool uninitialised = true;
+ private int defaultStrength;
+
+ public CipherKeyGenerator()
+ {
+ }
+
+ internal CipherKeyGenerator(
+ int defaultStrength)
+ {
+ if (defaultStrength < 1)
+ throw new ArgumentException("strength must be a positive value", "defaultStrength");
+
+ this.defaultStrength = defaultStrength;
+ }
+
+ public int DefaultStrength
+ {
+ get { return defaultStrength; }
+ }
+
+ /**
+ * initialise the key generator.
+ *
+ * @param param the parameters to be used for key generation
+ */
+ public void Init(
+ KeyGenerationParameters parameters)
+ {
+ if (parameters == null)
+ throw new ArgumentNullException("parameters");
+
+ this.uninitialised = false;
+
+ engineInit(parameters);
+ }
+
+ protected virtual void engineInit(
+ KeyGenerationParameters parameters)
+ {
+ this.random = parameters.Random;
+ this.strength = (parameters.Strength + 7) / 8;
+ }
+
+ /**
+ * Generate a secret key.
+ *
+ * @return a byte array containing the key value.
+ */
+ public byte[] GenerateKey()
+ {
+ if (uninitialised)
+ {
+ if (defaultStrength < 1)
+ throw new InvalidOperationException("Generator has not been initialised");
+
+ uninitialised = false;
+
+ engineInit(new KeyGenerationParameters(new SecureRandom(), defaultStrength));
+ }
+
+ return engineGenerateKey();
+ }
+
+ protected virtual byte[] engineGenerateKey()
+ {
+ return SecureRandom.GetNextBytes(random, strength);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/CryptoException.cs b/bc-sharp-crypto/src/crypto/CryptoException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..73d450be13446835f91ff31d2d57ba0b93679da5
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/CryptoException.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class CryptoException
+ : Exception
+ {
+ public CryptoException()
+ {
+ }
+
+ public CryptoException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public CryptoException(
+ string message,
+ Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/DataLengthException.cs b/bc-sharp-crypto/src/crypto/DataLengthException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..447ff2a170bc5d3a843e93ad0a90a2f53011aab9
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/DataLengthException.cs
@@ -0,0 +1,42 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * this exception is thrown if a buffer that is meant to have output
+ * copied into it turns out to be too short, or if we've been given
+ * insufficient input. In general this exception will Get thrown rather
+ * than an ArrayOutOfBounds exception.
+ */
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class DataLengthException
+ : CryptoException
+ {
+ /**
+ * base constructor.
+ */
+ public DataLengthException()
+ {
+ }
+
+ /**
+ * create a DataLengthException with the given message.
+ *
+ * @param message the message to be carried with the exception.
+ */
+ public DataLengthException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public DataLengthException(
+ string message,
+ Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/IAsymmetricBlockCipher.cs b/bc-sharp-crypto/src/crypto/IAsymmetricBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..455cfaa6928c07228b2880729a0e3f3ea9c7905a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IAsymmetricBlockCipher.cs
@@ -0,0 +1,30 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /// Base interface for a public/private key block cipher.
+ public interface IAsymmetricBlockCipher
+ {
+ /// The name of the algorithm this cipher implements.
+ string AlgorithmName { get; }
+
+ /// Initialise the cipher.
+ /// Initialise for encryption if true, for decryption if false.
+ /// The key or other data required by the cipher.
+ void Init(bool forEncryption, ICipherParameters parameters);
+
+ /// The maximum size, in bytes, an input block may be.
+ int GetInputBlockSize();
+
+ /// The maximum size, in bytes, an output block will be.
+ int GetOutputBlockSize();
+
+ /// Process a block.
+ /// The input buffer.
+ /// The offset into inBuf that the input block begins.
+ /// The length of the input block.
+ /// Input decrypts improperly.
+ /// Input is too large for the cipher.
+ byte[] ProcessBlock(byte[] inBuf, int inOff, int inLen);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/IAsymmetricCipherKeyPairGenerator.cs b/bc-sharp-crypto/src/crypto/IAsymmetricCipherKeyPairGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9ec5dfada89cb2b53fc76db9aac92325150b9809
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IAsymmetricCipherKeyPairGenerator.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * interface that a public/private key pair generator should conform to.
+ */
+ public interface IAsymmetricCipherKeyPairGenerator
+ {
+ /**
+ * intialise the key pair generator.
+ *
+ * @param the parameters the key pair is to be initialised with.
+ */
+ void Init(KeyGenerationParameters parameters);
+
+ /**
+ * return an AsymmetricCipherKeyPair containing the Generated keys.
+ *
+ * @return an AsymmetricCipherKeyPair containing the Generated keys.
+ */
+ AsymmetricCipherKeyPair GenerateKeyPair();
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/IBasicAgreement.cs b/bc-sharp-crypto/src/crypto/IBasicAgreement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7dfc618d6fe02558434537259a7165dace4a0911
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IBasicAgreement.cs
@@ -0,0 +1,29 @@
+using System;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * The basic interface that basic Diffie-Hellman implementations
+ * conforms to.
+ */
+ public interface IBasicAgreement
+ {
+ /**
+ * initialise the agreement engine.
+ */
+ void Init(ICipherParameters parameters);
+
+ /**
+ * return the field size for the agreement algorithm in bytes.
+ */
+ int GetFieldSize();
+
+ /**
+ * given a public key from a given party calculate the next
+ * message in the agreement sequence.
+ */
+ BigInteger CalculateAgreement(ICipherParameters pubKey);
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/IBlockCipher.cs b/bc-sharp-crypto/src/crypto/IBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a3ad6d6e5f8f238a608d22657b7b06ac3be3ed74
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IBlockCipher.cs
@@ -0,0 +1,36 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /// Base interface for a symmetric key block cipher.
+ public interface IBlockCipher
+ {
+ /// The name of the algorithm this cipher implements.
+ string AlgorithmName { get; }
+
+ /// Initialise the cipher.
+ /// Initialise for encryption if true, for decryption if false.
+ /// The key or other data required by the cipher.
+ void Init(bool forEncryption, ICipherParameters parameters);
+
+ /// The block size for this cipher, in bytes.
+ int GetBlockSize();
+
+ /// Indicates whether this cipher can handle partial blocks.
+ bool IsPartialBlockOkay { get; }
+
+ /// Process a block.
+ /// The input buffer.
+ /// The offset into inBuf that the input block begins.
+ /// The output buffer.
+ /// The offset into outBuf to write the output block.
+ /// If input block is wrong size, or outBuf too small.
+ /// The number of bytes processed and produced.
+ int ProcessBlock(byte[] inBuf, int inOff, byte[] outBuf, int outOff);
+
+ ///
+ /// Reset the cipher to the same state as it was after the last init (if there was one).
+ ///
+ void Reset();
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/IBlockResult.cs b/bc-sharp-crypto/src/crypto/IBlockResult.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0f054fedc10b34a95b6a7316cf333b5c099f05f8
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IBlockResult.cs
@@ -0,0 +1,24 @@
+
+namespace Org.BouncyCastle.Crypto
+{
+ ///
+ /// Operators that reduce their input to a single block return an object
+ /// of this type.
+ ///
+ public interface IBlockResult
+ {
+ ///
+ /// Return the final result of the operation.
+ ///
+ /// A block of bytes, representing the result of an operation.
+ byte[] Collect();
+
+ ///
+ /// Store the final result of the operation by copying it into the destination array.
+ ///
+ /// The number of bytes copied into destination.
+ /// The byte array to copy the result into.
+ /// The offset into destination to start copying the result at.
+ int Collect(byte[] destination, int offset);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/IBufferedCipher.cs b/bc-sharp-crypto/src/crypto/IBufferedCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..69dec9596cda2dc9fedb9617b9af6c4e513ffbc3
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IBufferedCipher.cs
@@ -0,0 +1,44 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /// Block cipher engines are expected to conform to this interface.
+ public interface IBufferedCipher
+ {
+ /// The name of the algorithm this cipher implements.
+ string AlgorithmName { get; }
+
+ /// Initialise the cipher.
+ /// If true the cipher is initialised for encryption,
+ /// if false for decryption.
+ /// The key and other data required by the cipher.
+ void Init(bool forEncryption, ICipherParameters parameters);
+
+ int GetBlockSize();
+
+ int GetOutputSize(int inputLen);
+
+ int GetUpdateOutputSize(int inputLen);
+
+ byte[] ProcessByte(byte input);
+ int ProcessByte(byte input, byte[] output, int outOff);
+
+ byte[] ProcessBytes(byte[] input);
+ byte[] ProcessBytes(byte[] input, int inOff, int length);
+ int ProcessBytes(byte[] input, byte[] output, int outOff);
+ int ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff);
+
+ byte[] DoFinal();
+ byte[] DoFinal(byte[] input);
+ byte[] DoFinal(byte[] input, int inOff, int length);
+ int DoFinal(byte[] output, int outOff);
+ int DoFinal(byte[] input, byte[] output, int outOff);
+ int DoFinal(byte[] input, int inOff, int length, byte[] output, int outOff);
+
+ ///
+ /// Reset the cipher. After resetting the cipher is in the same state
+ /// as it was after the last init (if there was one).
+ ///
+ void Reset();
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/ICipherParameters.cs b/bc-sharp-crypto/src/crypto/ICipherParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fff0941c7e7d80de77576d9ffe8c1dc3f6e3ade1
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/ICipherParameters.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * all parameter classes implement this.
+ */
+ public interface ICipherParameters
+ {
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/IDSA.cs b/bc-sharp-crypto/src/crypto/IDSA.cs
new file mode 100644
index 0000000000000000000000000000000000000000..46056d8ca16e9a6e3f4b8e53a6b03e8ecbf64a10
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IDSA.cs
@@ -0,0 +1,40 @@
+using System;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * interface for classes implementing the Digital Signature Algorithm
+ */
+ public interface IDsa
+ {
+ string AlgorithmName { get; }
+
+ /**
+ * initialise the signer for signature generation or signature
+ * verification.
+ *
+ * @param forSigning true if we are generating a signature, false
+ * otherwise.
+ * @param param key parameters for signature generation.
+ */
+ void Init(bool forSigning, ICipherParameters parameters);
+
+ /**
+ * sign the passed in message (usually the output of a hash function).
+ *
+ * @param message the message to be signed.
+ * @return two big integers representing the r and s values respectively.
+ */
+ BigInteger[] GenerateSignature(byte[] message);
+
+ /**
+ * verify the message message against the signature values r and s.
+ *
+ * @param message the message that was supposed to have been signed.
+ * @param r the r signature value.
+ * @param s the s signature value.
+ */
+ bool VerifySignature(byte[] message, BigInteger r, BigInteger s);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/IDerivationFunction.cs b/bc-sharp-crypto/src/crypto/IDerivationFunction.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7f289f790f5ad9f94bb5458952fcb7543acf496d
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IDerivationFunction.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * base interface for general purpose byte derivation functions.
+ */
+ public interface IDerivationFunction
+ {
+ void Init(IDerivationParameters parameters);
+
+ /**
+ * return the message digest used as the basis for the function
+ */
+ IDigest Digest
+ {
+ get;
+ }
+
+ int GenerateBytes(byte[] output, int outOff, int length);
+ //throws DataLengthException, ArgumentException;
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/IDerivationParameters.cs b/bc-sharp-crypto/src/crypto/IDerivationParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f1c848568d6d522694016bd2ec04f4a3389c916c
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IDerivationParameters.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * Parameters for key/byte stream derivation classes
+ */
+ public interface IDerivationParameters
+ {
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/IDigest.cs b/bc-sharp-crypto/src/crypto/IDigest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6769dcc4206577f712c0b5080c11e147f18f0584
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IDigest.cs
@@ -0,0 +1,61 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * interface that a message digest conforms to.
+ */
+ public interface IDigest
+ {
+ /**
+ * return the algorithm name
+ *
+ * @return the algorithm name
+ */
+ string AlgorithmName { get; }
+
+ /**
+ * return the size, in bytes, of the digest produced by this message digest.
+ *
+ * @return the size, in bytes, of the digest produced by this message digest.
+ */
+ int GetDigestSize();
+
+ /**
+ * return the size, in bytes, of the internal buffer used by this digest.
+ *
+ * @return the size, in bytes, of the internal buffer used by this digest.
+ */
+ int GetByteLength();
+
+ /**
+ * update the message digest with a single byte.
+ *
+ * @param inByte the input byte to be entered.
+ */
+ void Update(byte input);
+
+ /**
+ * update the message digest with a block of bytes.
+ *
+ * @param input the byte array containing the data.
+ * @param inOff the offset into the byte array where the data starts.
+ * @param len the length of the data.
+ */
+ void BlockUpdate(byte[] input, int inOff, int length);
+
+ /**
+ * Close the digest, producing the final digest value. The doFinal
+ * call leaves the digest reset.
+ *
+ * @param output the array the digest is to be copied into.
+ * @param outOff the offset into the out array the digest is to start at.
+ */
+ int DoFinal(byte[] output, int outOff);
+
+ /**
+ * reset the digest back to it's initial state.
+ */
+ void Reset();
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/IEntropySource.cs b/bc-sharp-crypto/src/crypto/IEntropySource.cs
new file mode 100644
index 0000000000000000000000000000000000000000..62e3bc76cf897f9fca8ea8939ca5d1d2f93e4e3c
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IEntropySource.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ ///
+ /// Base interface describing an entropy source for a DRBG.
+ ///
+ public interface IEntropySource
+ {
+ ///
+ /// Return whether or not this entropy source is regarded as prediction resistant.
+ ///
+ /// true if this instance is prediction resistant; otherwise, false .
+ bool IsPredictionResistant { get; }
+
+ ///
+ /// Return a byte array of entropy.
+ ///
+ /// The entropy bytes.
+ byte[] GetEntropy();
+
+ ///
+ /// Return the number of bits of entropy this source can produce.
+ ///
+ /// The size, in bits, of the return value of getEntropy.
+ int EntropySize { get; }
+ }
+}
+
diff --git a/bc-sharp-crypto/src/crypto/IEntropySourceProvider.cs b/bc-sharp-crypto/src/crypto/IEntropySourceProvider.cs
new file mode 100644
index 0000000000000000000000000000000000000000..756414171dbfdebb26505626eabe1fe141276331
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IEntropySourceProvider.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ ///
+ /// Base interface describing a provider of entropy sources.
+ ///
+ public interface IEntropySourceProvider
+ {
+ ///
+ /// Return an entropy source providing a block of entropy.
+ ///
+ /// The size of the block of entropy required.
+ /// An entropy source providing bitsRequired blocks of entropy.
+ IEntropySource Get(int bitsRequired);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/IMac.cs b/bc-sharp-crypto/src/crypto/IMac.cs
new file mode 100644
index 0000000000000000000000000000000000000000..03a86e8b67301dbe7d6620fd8d5bd1395a03e581
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IMac.cs
@@ -0,0 +1,69 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * The base interface for implementations of message authentication codes (MACs).
+ */
+ public interface IMac
+ {
+ /**
+ * Initialise the MAC.
+ *
+ * @param param the key and other data required by the MAC.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ void Init(ICipherParameters parameters);
+
+ /**
+ * Return the name of the algorithm the MAC implements.
+ *
+ * @return the name of the algorithm the MAC implements.
+ */
+ string AlgorithmName { get; }
+
+ /**
+ * Return the block size for this MAC (in bytes).
+ *
+ * @return the block size for this MAC in bytes.
+ */
+ int GetMacSize();
+
+ /**
+ * add a single byte to the mac for processing.
+ *
+ * @param in the byte to be processed.
+ * @exception InvalidOperationException if the MAC is not initialised.
+ */
+ void Update(byte input);
+
+ /**
+ * @param in the array containing the input.
+ * @param inOff the index in the array the data begins at.
+ * @param len the length of the input starting at inOff.
+ * @exception InvalidOperationException if the MAC is not initialised.
+ * @exception DataLengthException if there isn't enough data in in.
+ */
+ void BlockUpdate(byte[] input, int inOff, int len);
+
+ /**
+ * Compute the final stage of the MAC writing the output to the out
+ * parameter.
+ *
+ * doFinal leaves the MAC in the same state it was after the last init.
+ *
+ * @param out the array the MAC is to be output to.
+ * @param outOff the offset into the out buffer the output is to start at.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception InvalidOperationException if the MAC is not initialised.
+ */
+ int DoFinal(byte[] output, int outOff);
+
+ /**
+ * Reset the MAC. At the end of resetting the MAC should be in the
+ * in the same state it was after the last init (if there was one).
+ */
+ void Reset();
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/ISignatureFactory.cs b/bc-sharp-crypto/src/crypto/ISignatureFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cbca7d1a7af339033680554f5490ab33c2b2a90c
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/ISignatureFactory.cs
@@ -0,0 +1,23 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ ///
+ /// Base interface for operators that serve as stream-based signature calculators.
+ ///
+ public interface ISignatureFactory
+ {
+ /// The algorithm details object for this calculator.
+ Object AlgorithmDetails { get ; }
+
+ ///
+ /// Create a stream calculator for this signature calculator. The stream
+ /// calculator is used for the actual operation of entering the data to be signed
+ /// and producing the signature block.
+ ///
+ /// A calculator producing an IBlockResult with a signature in it.
+ IStreamCalculator CreateCalculator();
+ }
+}
+
+
diff --git a/bc-sharp-crypto/src/crypto/ISigner.cs b/bc-sharp-crypto/src/crypto/ISigner.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e03bbf4d3841fa5a73fea840257789cba61c4cda
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/ISigner.cs
@@ -0,0 +1,50 @@
+
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Crypto
+{
+ public interface ISigner
+ {
+ /**
+ * Return the name of the algorithm the signer implements.
+ *
+ * @return the name of the algorithm the signer implements.
+ */
+ string AlgorithmName { get; }
+
+ /**
+ * Initialise the signer for signing or verification.
+ *
+ * @param forSigning true if for signing, false otherwise
+ * @param param necessary parameters.
+ */
+ void Init(bool forSigning, ICipherParameters parameters);
+
+ /**
+ * update the internal digest with the byte b
+ */
+ void Update(byte input);
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ void BlockUpdate(byte[] input, int inOff, int length);
+
+ /**
+ * Generate a signature for the message we've been loaded with using
+ * the key we were initialised with.
+ */
+ byte[] GenerateSignature();
+ /**
+ * return true if the internal state represents the signature described
+ * in the passed in array.
+ */
+ bool VerifySignature(byte[] signature);
+
+ /**
+ * reset the internal state
+ */
+ void Reset();
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/ISignerWithRecovery.cs b/bc-sharp-crypto/src/crypto/ISignerWithRecovery.cs
new file mode 100644
index 0000000000000000000000000000000000000000..024f5cef5ad4ea910c6d3b2428b9ade97eb20dd4
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/ISignerWithRecovery.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * Signer with message recovery.
+ */
+ public interface ISignerWithRecovery
+ : ISigner
+ {
+ /**
+ * Returns true if the signer has recovered the full message as
+ * part of signature verification.
+ *
+ * @return true if full message recovered.
+ */
+ bool HasFullMessage();
+
+ /**
+ * Returns a reference to what message was recovered (if any).
+ *
+ * @return full/partial message, null if nothing.
+ */
+ byte[] GetRecoveredMessage();
+
+ /**
+ * Perform an update with the recovered message before adding any other data. This must
+ * be the first update method called, and calling it will result in the signer assuming
+ * that further calls to update will include message content past what is recoverable.
+ *
+ * @param signature the signature that we are in the process of verifying.
+ * @throws IllegalStateException
+ */
+ void UpdateWithRecoveredMessage(byte[] signature);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/IStreamCalculator.cs b/bc-sharp-crypto/src/crypto/IStreamCalculator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..19a54284576e6a37b76b67eec55f5f3fe99d6f8f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IStreamCalculator.cs
@@ -0,0 +1,23 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto
+{
+ ///
+ /// Base interface for cryptographic operations such as Hashes, MACs, and Signatures which reduce a stream of data
+ /// to a single value.
+ ///
+ public interface IStreamCalculator
+ {
+ /// Return a "sink" stream which only exists to update the implementing object.
+ /// A stream to write to in order to update the implementing object.
+ Stream Stream { get; }
+
+ ///
+ /// Return the result of processing the stream. This value is only available once the stream
+ /// has been closed.
+ ///
+ /// The result of processing the stream.
+ Object GetResult();
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/IStreamCipher.cs b/bc-sharp-crypto/src/crypto/IStreamCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8e575a7e529146ceba0019895dd4e071ace512e6
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IStreamCipher.cs
@@ -0,0 +1,45 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /// The interface stream ciphers conform to.
+ public interface IStreamCipher
+ {
+ /// The name of the algorithm this cipher implements.
+ string AlgorithmName { get; }
+
+ /// Initialise the cipher.
+ /// If true the cipher is initialised for encryption,
+ /// if false for decryption.
+ /// The key and other data required by the cipher.
+ ///
+ /// If the parameters argument is inappropriate.
+ ///
+ void Init(bool forEncryption, ICipherParameters parameters);
+
+ /// encrypt/decrypt a single byte returning the result.
+ /// the byte to be processed.
+ /// the result of processing the input byte.
+ byte ReturnByte(byte input);
+
+ ///
+ /// Process a block of bytes from input putting the result into output .
+ ///
+ /// The input byte array.
+ ///
+ /// The offset into input where the data to be processed starts.
+ ///
+ /// The number of bytes to be processed.
+ /// The output buffer the processed bytes go into.
+ ///
+ /// The offset into output the processed data starts at.
+ ///
+ /// If the output buffer is too small.
+ void ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff);
+
+ ///
+ /// Reset the cipher to the same state as it was after the last init (if there was one).
+ ///
+ void Reset();
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/IVerifier.cs b/bc-sharp-crypto/src/crypto/IVerifier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..560cabf8e066c83eb311c83c9cab58bbde20d140
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IVerifier.cs
@@ -0,0 +1,25 @@
+namespace Org.BouncyCastle.Crypto
+{
+ ///
+ /// Operators that reduce their input to the validation of a signature produce this type.
+ ///
+ public interface IVerifier
+ {
+ ///
+ /// Return true if the passed in data matches what is expected by the verification result.
+ ///
+ /// The bytes representing the signature.
+ /// true if the signature verifies, false otherwise.
+ bool IsVerified(byte[] data);
+
+ ///
+ /// Return true if the length bytes from off in the source array match the signature
+ /// expected by the verification result.
+ ///
+ /// Byte array containing the signature.
+ /// The offset into the source array where the signature starts.
+ /// The number of bytes in source making up the signature.
+ /// true if the signature verifies, false otherwise.
+ bool IsVerified(byte[] source, int off, int length);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/IVerifierFactory.cs b/bc-sharp-crypto/src/crypto/IVerifierFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9502b14a78454c14996577ae6e5544519e635b09
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IVerifierFactory.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ ///
+ /// Base interface for operators that serve as stream-based signature verifiers.
+ ///
+ public interface IVerifierFactory
+ {
+ /// The algorithm details object for this verifier.
+ Object AlgorithmDetails { get ; }
+
+ ///
+ /// Create a stream calculator for this verifier. The stream
+ /// calculator is used for the actual operation of entering the data to be verified
+ /// and producing a result which can be used to verify the original signature.
+ ///
+ /// A calculator producing an IVerifier which can verify the signature.
+ IStreamCalculator CreateCalculator();
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/IVerifierFactoryProvider.cs b/bc-sharp-crypto/src/crypto/IVerifierFactoryProvider.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9cfcbb2c1a893c05b2dcd18450c0644701c05923
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IVerifierFactoryProvider.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ ///
+ /// Base interface for a provider to support the dynamic creation of signature verifiers.
+ ///
+ public interface IVerifierFactoryProvider
+ {
+ ///
+ /// Return a signature verfier for signature algorithm described in the passed in algorithm details object.
+ ///
+ /// The details of the signature algorithm verification is required for.
+ /// A new signature verifier.
+ IVerifierFactory CreateVerifierFactory (Object algorithmDetails);
+ }
+}
+
diff --git a/bc-sharp-crypto/src/crypto/IWrapper.cs b/bc-sharp-crypto/src/crypto/IWrapper.cs
new file mode 100644
index 0000000000000000000000000000000000000000..58202b302ccf9f6ba5193942f4e7a0439431ef9b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IWrapper.cs
@@ -0,0 +1,18 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto
+{
+ public interface IWrapper
+ {
+ /// The name of the algorithm this cipher implements.
+ string AlgorithmName { get; }
+
+ void Init(bool forWrapping, ICipherParameters parameters);
+
+ byte[] Wrap(byte[] input, int inOff, int length);
+
+ byte[] Unwrap(byte[] input, int inOff, int length);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/IXof.cs b/bc-sharp-crypto/src/crypto/IXof.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f76304d482616a9155f89d9499425cf3f3f0739a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/IXof.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ ///
+ /// With FIPS PUB 202 a new kind of message digest was announced which supported extendable output, or variable digest sizes.
+ /// This interface provides the extra method required to support variable output on a digest implementation.
+ ///
+ public interface IXof
+ : IDigest
+ {
+ ///
+ /// Output the results of the final calculation for this digest to outLen number of bytes.
+ ///
+ /// output array to write the output bytes to.
+ /// offset to start writing the bytes at.
+ /// the number of output bytes requested.
+ /// the number of bytes written
+ int DoFinal(byte[] output, int outOff, int outLen);
+
+ ///
+ /// Start outputting the results of the final calculation for this digest. Unlike DoFinal, this method
+ /// will continue producing output until the Xof is explicitly reset, or signals otherwise.
+ ///
+ /// output array to write the output bytes to.
+ /// offset to start writing the bytes at.
+ /// the number of output bytes requested.
+ /// the number of bytes written
+ int DoOutput(byte[] output, int outOff, int outLen);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/InvalidCipherTextException.cs b/bc-sharp-crypto/src/crypto/InvalidCipherTextException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0fe540d960e914407c462f28ae2ebca91ac0d5cd
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/InvalidCipherTextException.cs
@@ -0,0 +1,40 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * this exception is thrown whenever we find something we don't expect in a
+ * message.
+ */
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class InvalidCipherTextException
+ : CryptoException
+ {
+ /**
+ * base constructor.
+ */
+ public InvalidCipherTextException()
+ {
+ }
+
+ /**
+ * create a InvalidCipherTextException with the given message.
+ *
+ * @param message the message to be carried with the exception.
+ */
+ public InvalidCipherTextException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public InvalidCipherTextException(
+ string message,
+ Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/KeyGenerationParameters.cs b/bc-sharp-crypto/src/crypto/KeyGenerationParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0cb6b07c785c3061064ec4d7e606e8c5a8a71faf
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/KeyGenerationParameters.cs
@@ -0,0 +1,55 @@
+using System;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * The base class for parameters to key generators.
+ */
+ public class KeyGenerationParameters
+ {
+ private SecureRandom random;
+ private int strength;
+
+ /**
+ * initialise the generator with a source of randomness
+ * and a strength (in bits).
+ *
+ * @param random the random byte source.
+ * @param strength the size, in bits, of the keys we want to produce.
+ */
+ public KeyGenerationParameters(
+ SecureRandom random,
+ int strength)
+ {
+ if (random == null)
+ throw new ArgumentNullException("random");
+ if (strength < 1)
+ throw new ArgumentException("strength must be a positive value", "strength");
+
+ this.random = random;
+ this.strength = strength;
+ }
+
+ /**
+ * return the random source associated with this
+ * generator.
+ *
+ * @return the generators random source.
+ */
+ public SecureRandom Random
+ {
+ get { return random; }
+ }
+
+ /**
+ * return the bit strength for keys produced by this generator,
+ *
+ * @return the strength of the keys this generator produces (in bits).
+ */
+ public int Strength
+ {
+ get { return strength; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/MaxBytesExceededException.cs b/bc-sharp-crypto/src/crypto/MaxBytesExceededException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8992c45da5fdc658f7a7ead46c492b24f25730cd
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/MaxBytesExceededException.cs
@@ -0,0 +1,32 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ ///
+ /// This exception is thrown whenever a cipher requires a change of key, iv
+ /// or similar after x amount of bytes enciphered
+ ///
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class MaxBytesExceededException
+ : CryptoException
+ {
+ public MaxBytesExceededException()
+ {
+ }
+
+ public MaxBytesExceededException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public MaxBytesExceededException(
+ string message,
+ Exception e)
+ : base(message, e)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/OutputLengthException.cs b/bc-sharp-crypto/src/crypto/OutputLengthException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..437589f472976f4cf05a29721904a2362ebc8f0c
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/OutputLengthException.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class OutputLengthException
+ : DataLengthException
+ {
+ public OutputLengthException()
+ {
+ }
+
+ public OutputLengthException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public OutputLengthException(
+ string message,
+ Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/PbeParametersGenerator.cs b/bc-sharp-crypto/src/crypto/PbeParametersGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..97d23df902432208870b4fae787b3e71487702e6
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/PbeParametersGenerator.cs
@@ -0,0 +1,202 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * super class for all Password Based Encyrption (Pbe) parameter generator classes.
+ */
+ public abstract class PbeParametersGenerator
+ {
+ protected byte[] mPassword;
+ protected byte[] mSalt;
+ protected int mIterationCount;
+
+ /**
+ * base constructor.
+ */
+ protected PbeParametersGenerator()
+ {
+ }
+
+ /**
+ * initialise the Pbe generator.
+ *
+ * @param password the password converted into bytes (see below).
+ * @param salt the salt to be mixed with the password.
+ * @param iterationCount the number of iterations the "mixing" function
+ * is to be applied for.
+ */
+ public virtual void Init(
+ byte[] password,
+ byte[] salt,
+ int iterationCount)
+ {
+ if (password == null)
+ throw new ArgumentNullException("password");
+ if (salt == null)
+ throw new ArgumentNullException("salt");
+
+ this.mPassword = Arrays.Clone(password);
+ this.mSalt = Arrays.Clone(salt);
+ this.mIterationCount = iterationCount;
+ }
+
+ public virtual byte[] Password
+ {
+ get { return Arrays.Clone(mPassword); }
+ }
+
+ /**
+ * return the password byte array.
+ *
+ * @return the password byte array.
+ */
+ [Obsolete("Use 'Password' property")]
+ public byte[] GetPassword()
+ {
+ return Password;
+ }
+
+ public virtual byte[] Salt
+ {
+ get { return Arrays.Clone(mSalt); }
+ }
+
+ /**
+ * return the salt byte array.
+ *
+ * @return the salt byte array.
+ */
+ [Obsolete("Use 'Salt' property")]
+ public byte[] GetSalt()
+ {
+ return Salt;
+ }
+
+ /**
+ * return the iteration count.
+ *
+ * @return the iteration count.
+ */
+ public virtual int IterationCount
+ {
+ get { return mIterationCount; }
+ }
+
+ /**
+ * Generate derived parameters for a key of length keySize.
+ *
+ * @param keySize the length, in bits, of the key required.
+ * @return a parameters object representing a key.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public abstract ICipherParameters GenerateDerivedParameters(int keySize);
+ public abstract ICipherParameters GenerateDerivedParameters(string algorithm, int keySize);
+
+ /**
+ * Generate derived parameters for a key of length keySize, and
+ * an initialisation vector (IV) of length ivSize.
+ *
+ * @param keySize the length, in bits, of the key required.
+ * @param ivSize the length, in bits, of the iv required.
+ * @return a parameters object representing a key and an IV.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public abstract ICipherParameters GenerateDerivedParameters(int keySize, int ivSize);
+ public abstract ICipherParameters GenerateDerivedParameters(string algorithm, int keySize, int ivSize);
+
+ /**
+ * Generate derived parameters for a key of length keySize, specifically
+ * for use with a MAC.
+ *
+ * @param keySize the length, in bits, of the key required.
+ * @return a parameters object representing a key.
+ */
+ public abstract ICipherParameters GenerateDerivedMacParameters(int keySize);
+
+ /**
+ * converts a password to a byte array according to the scheme in
+ * Pkcs5 (ascii, no padding)
+ *
+ * @param password a character array representing the password.
+ * @return a byte array representing the password.
+ */
+ public static byte[] Pkcs5PasswordToBytes(
+ char[] password)
+ {
+ if (password == null)
+ return new byte[0];
+
+ return Strings.ToByteArray(password);
+ }
+
+ [Obsolete("Use version taking 'char[]' instead")]
+ public static byte[] Pkcs5PasswordToBytes(
+ string password)
+ {
+ if (password == null)
+ return new byte[0];
+
+ return Strings.ToByteArray(password);
+ }
+
+ /**
+ * converts a password to a byte array according to the scheme in
+ * PKCS5 (UTF-8, no padding)
+ *
+ * @param password a character array representing the password.
+ * @return a byte array representing the password.
+ */
+ public static byte[] Pkcs5PasswordToUtf8Bytes(
+ char[] password)
+ {
+ if (password == null)
+ return new byte[0];
+
+ return Encoding.UTF8.GetBytes(password);
+ }
+
+ [Obsolete("Use version taking 'char[]' instead")]
+ public static byte[] Pkcs5PasswordToUtf8Bytes(
+ string password)
+ {
+ if (password == null)
+ return new byte[0];
+
+ return Encoding.UTF8.GetBytes(password);
+ }
+
+ /**
+ * converts a password to a byte array according to the scheme in
+ * Pkcs12 (unicode, big endian, 2 zero pad bytes at the end).
+ *
+ * @param password a character array representing the password.
+ * @return a byte array representing the password.
+ */
+ public static byte[] Pkcs12PasswordToBytes(
+ char[] password)
+ {
+ return Pkcs12PasswordToBytes(password, false);
+ }
+
+ public static byte[] Pkcs12PasswordToBytes(
+ char[] password,
+ bool wrongPkcs12Zero)
+ {
+ if (password == null || password.Length < 1)
+ {
+ return new byte[wrongPkcs12Zero ? 2 : 0];
+ }
+
+ // +1 for extra 2 pad bytes.
+ byte[] bytes = new byte[(password.Length + 1) * 2];
+
+ Encoding.BigEndianUnicode.GetBytes(password, 0, password.Length, bytes, 0);
+
+ return bytes;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/StreamBlockCipher.cs b/bc-sharp-crypto/src/crypto/StreamBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ef2a8b68aa27bf5e39a35ab48d16d21c2348ae41
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/StreamBlockCipher.cs
@@ -0,0 +1,109 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto
+{
+ /**
+ * a wrapper for block ciphers with a single byte block size, so that they
+ * can be treated like stream ciphers.
+ */
+ public class StreamBlockCipher
+ : IStreamCipher
+ {
+ private readonly IBlockCipher cipher;
+ private readonly byte[] oneByte = new byte[1];
+
+ /**
+ * basic constructor.
+ *
+ * @param cipher the block cipher to be wrapped.
+ * @exception ArgumentException if the cipher has a block size other than
+ * one.
+ */
+ public StreamBlockCipher(
+ IBlockCipher cipher)
+ {
+ if (cipher == null)
+ throw new ArgumentNullException("cipher");
+ if (cipher.GetBlockSize() != 1)
+ throw new ArgumentException("block cipher block size != 1.", "cipher");
+
+ this.cipher = cipher;
+ }
+
+ /**
+ * initialise the underlying cipher.
+ *
+ * @param forEncryption true if we are setting up for encryption, false otherwise.
+ * @param param the necessary parameters for the underlying cipher to be initialised.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ cipher.Init(forEncryption, parameters);
+ }
+
+ /**
+ * return the name of the algorithm we are wrapping.
+ *
+ * @return the name of the algorithm we are wrapping.
+ */
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName; }
+ }
+
+ /**
+ * encrypt/decrypt a single byte returning the result.
+ *
+ * @param in the byte to be processed.
+ * @return the result of processing the input byte.
+ */
+ public byte ReturnByte(
+ byte input)
+ {
+ oneByte[0] = input;
+
+ cipher.ProcessBlock(oneByte, 0, oneByte, 0);
+
+ return oneByte[0];
+ }
+
+ /**
+ * process a block of bytes from in putting the result into out.
+ *
+ * @param in the input byte array.
+ * @param inOff the offset into the in array where the data to be processed starts.
+ * @param len the number of bytes to be processed.
+ * @param out the output buffer the processed bytes go into.
+ * @param outOff the offset into the output byte array the processed data stars at.
+ * @exception DataLengthException if the output buffer is too small.
+ */
+ public void ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] output,
+ int outOff)
+ {
+ if (outOff + length > output.Length)
+ throw new DataLengthException("output buffer too small in ProcessBytes()");
+
+ for (int i = 0; i != length; i++)
+ {
+ cipher.ProcessBlock(input, inOff + i, output, outOff + i);
+ }
+ }
+
+ /**
+ * reset the underlying cipher. This leaves it in the same state
+ * it was at after the last init (if there was one).
+ */
+ public void Reset()
+ {
+ cipher.Reset();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/DHAgreement.cs b/bc-sharp-crypto/src/crypto/agreement/DHAgreement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e988c0d539bb9559f1dd4f38d55d9ac4dcc6a072
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/DHAgreement.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+ /**
+ * a Diffie-Hellman key exchange engine.
+ *
+ * note: This uses MTI/A0 key agreement in order to make the key agreement
+ * secure against passive attacks. If you're doing Diffie-Hellman and both
+ * parties have long term public keys you should look at using this. For
+ * further information have a look at RFC 2631.
+ *
+ * It's possible to extend this to more than two parties as well, for the moment
+ * that is left as an exercise for the reader.
+ */
+ public class DHAgreement
+ {
+ private DHPrivateKeyParameters key;
+ private DHParameters dhParams;
+ private BigInteger privateValue;
+ private SecureRandom random;
+
+ public void Init(
+ ICipherParameters parameters)
+ {
+ AsymmetricKeyParameter kParam;
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+
+ this.random = rParam.Random;
+ kParam = (AsymmetricKeyParameter)rParam.Parameters;
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ kParam = (AsymmetricKeyParameter)parameters;
+ }
+
+ if (!(kParam is DHPrivateKeyParameters))
+ {
+ throw new ArgumentException("DHEngine expects DHPrivateKeyParameters");
+ }
+
+ this.key = (DHPrivateKeyParameters)kParam;
+ this.dhParams = key.Parameters;
+ }
+
+ /**
+ * calculate our initial message.
+ */
+ public BigInteger CalculateMessage()
+ {
+ DHKeyPairGenerator dhGen = new DHKeyPairGenerator();
+ dhGen.Init(new DHKeyGenerationParameters(random, dhParams));
+ AsymmetricCipherKeyPair dhPair = dhGen.GenerateKeyPair();
+
+ this.privateValue = ((DHPrivateKeyParameters)dhPair.Private).X;
+
+ return ((DHPublicKeyParameters)dhPair.Public).Y;
+ }
+
+ /**
+ * given a message from a given party and the corresponding public key
+ * calculate the next message in the agreement sequence. In this case
+ * this will represent the shared secret.
+ */
+ public BigInteger CalculateAgreement(
+ DHPublicKeyParameters pub,
+ BigInteger message)
+ {
+ if (pub == null)
+ throw new ArgumentNullException("pub");
+ if (message == null)
+ throw new ArgumentNullException("message");
+
+ if (!pub.Parameters.Equals(dhParams))
+ throw new ArgumentException("Diffie-Hellman public key has wrong parameters.");
+
+ BigInteger p = dhParams.P;
+
+ BigInteger peerY = pub.Y;
+ if (peerY == null || peerY.CompareTo(BigInteger.One) <= 0 || peerY.CompareTo(p.Subtract(BigInteger.One)) >= 0)
+ throw new ArgumentException("Diffie-Hellman public key is weak");
+
+ BigInteger result = peerY.ModPow(privateValue, p);
+ if (result.Equals(BigInteger.One))
+ throw new InvalidOperationException("Shared key can't be 1");
+
+ return message.ModPow(key.X, p).Multiply(result).Mod(p);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/DHBasicAgreement.cs b/bc-sharp-crypto/src/crypto/agreement/DHBasicAgreement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6c3fe65955b656f0cc6c158af7e28acaceb702ef
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/DHBasicAgreement.cs
@@ -0,0 +1,72 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+ /**
+ * a Diffie-Hellman key agreement class.
+ *
+ * note: This is only the basic algorithm, it doesn't take advantage of
+ * long term public keys if they are available. See the DHAgreement class
+ * for a "better" implementation.
+ */
+ public class DHBasicAgreement
+ : IBasicAgreement
+ {
+ private DHPrivateKeyParameters key;
+ private DHParameters dhParams;
+
+ public virtual void Init(
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ parameters = ((ParametersWithRandom) parameters).Parameters;
+ }
+
+ if (!(parameters is DHPrivateKeyParameters))
+ {
+ throw new ArgumentException("DHEngine expects DHPrivateKeyParameters");
+ }
+
+ this.key = (DHPrivateKeyParameters) parameters;
+ this.dhParams = key.Parameters;
+ }
+
+ public virtual int GetFieldSize()
+ {
+ return (key.Parameters.P.BitLength + 7) / 8;
+ }
+
+ /**
+ * given a short term public key from a given party calculate the next
+ * message in the agreement sequence.
+ */
+ public virtual BigInteger CalculateAgreement(
+ ICipherParameters pubKey)
+ {
+ if (this.key == null)
+ throw new InvalidOperationException("Agreement algorithm not initialised");
+
+ DHPublicKeyParameters pub = (DHPublicKeyParameters)pubKey;
+
+ if (!pub.Parameters.Equals(dhParams))
+ throw new ArgumentException("Diffie-Hellman public key has wrong parameters.");
+
+ BigInteger p = dhParams.P;
+
+ BigInteger peerY = pub.Y;
+ if (peerY == null || peerY.CompareTo(BigInteger.One) <= 0 || peerY.CompareTo(p.Subtract(BigInteger.One)) >= 0)
+ throw new ArgumentException("Diffie-Hellman public key is weak");
+
+ BigInteger result = peerY.ModPow(key.X, p);
+ if (result.Equals(BigInteger.One))
+ throw new InvalidOperationException("Shared key can't be 1");
+
+ return result;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/DHStandardGroups.cs b/bc-sharp-crypto/src/crypto/agreement/DHStandardGroups.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0143c63256568358fc4c116e684252f67e8a4f33
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/DHStandardGroups.cs
@@ -0,0 +1,307 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+ /// Standard Diffie-Hellman groups from various IETF specifications.
+ public class DHStandardGroups
+ {
+ private static BigInteger FromHex(string hex)
+ {
+ return new BigInteger(1, Hex.Decode(hex));
+ }
+
+ private static DHParameters FromPG(string hexP, string hexG)
+ {
+ return new DHParameters(FromHex(hexP), FromHex(hexG));
+ }
+
+ private static DHParameters FromPGQ(string hexP, string hexG, string hexQ)
+ {
+ return new DHParameters(FromHex(hexP), FromHex(hexG), FromHex(hexQ));
+ }
+
+ private static DHParameters Rfc7919Parameters(string hexP, int l)
+ {
+ // NOTE: All the groups in RFC 7919 use safe primes, i.e. q = (p-1)/2, and generator g = 2
+ BigInteger p = FromHex(hexP);
+ return new DHParameters(p, BigInteger.Two, p.ShiftRight(1), l);
+ }
+
+ /*
+ * RFC 2409
+ */
+ private static readonly string rfc2409_768_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ + "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF";
+ private static readonly string rfc2409_768_g = "02";
+ public static readonly DHParameters rfc2409_768 = FromPG(rfc2409_768_p, rfc2409_768_g);
+
+ private static readonly string rfc2409_1024_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
+ + "FFFFFFFFFFFFFFFF";
+ private static readonly string rfc2409_1024_g = "02";
+ public static readonly DHParameters rfc2409_1024 = FromPG(rfc2409_1024_p, rfc2409_1024_g);
+
+ /*
+ * RFC 3526
+ */
+ private static readonly string rfc3526_1536_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF";
+ private static readonly string rfc3526_1536_g = "02";
+ public static readonly DHParameters rfc3526_1536 = FromPG(rfc3526_1536_p, rfc3526_1536_g);
+
+ private static readonly string rfc3526_2048_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AACAA68FFFFFFFFFFFFFFFF";
+ private static readonly string rfc3526_2048_g = "02";
+ public static readonly DHParameters rfc3526_2048 = FromPG(rfc3526_2048_p, rfc3526_2048_g);
+
+ private static readonly string rfc3526_3072_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+ + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+ + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+ + "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF";
+ private static readonly string rfc3526_3072_g = "02";
+ public static readonly DHParameters rfc3526_3072 = FromPG(rfc3526_3072_p, rfc3526_3072_g);
+
+ private static readonly string rfc3526_4096_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+ + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+ + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+ + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
+ + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
+ + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
+ + "FFFFFFFFFFFFFFFF";
+ private static readonly string rfc3526_4096_g = "02";
+ public static readonly DHParameters rfc3526_4096 = FromPG(rfc3526_4096_p, rfc3526_4096_g);
+
+ private static readonly string rfc3526_6144_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
+ + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
+ + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
+ + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
+ + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
+ + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
+ + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
+ + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
+ + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
+ + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
+ + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+ + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC"
+ + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26"
+ + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB"
+ + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
+ + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127"
+ + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
+ + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406"
+ + "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918"
+ + "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151"
+ + "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03"
+ + "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F"
+ + "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
+ + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B"
+ + "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632"
+ + "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E"
+ + "6DCC4024FFFFFFFFFFFFFFFF";
+ private static readonly string rfc3526_6144_g = "02";
+ public static readonly DHParameters rfc3526_6144 = FromPG(rfc3526_6144_p, rfc3526_6144_g);
+
+ private static readonly string rfc3526_8192_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+ + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+ + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+ + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
+ + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
+ + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
+ + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" + "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
+ + "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" + "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
+ + "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" + "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
+ + "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
+ + "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" + "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
+ + "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" + "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300"
+ + "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" + "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
+ + "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" + "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A"
+ + "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" + "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1"
+ + "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" + "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47"
+ + "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" + "60C980DD98EDD3DFFFFFFFFFFFFFFFFF";
+ private static readonly string rfc3526_8192_g = "02";
+ public static readonly DHParameters rfc3526_8192 = FromPG(rfc3526_8192_p, rfc3526_8192_g);
+
+ /*
+ * RFC 4306
+ */
+ public static readonly DHParameters rfc4306_768 = rfc2409_768;
+ public static readonly DHParameters rfc4306_1024 = rfc2409_1024;
+
+ /*
+ * RFC 5114
+ */
+ private static readonly string rfc5114_1024_160_p = "B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C6"
+ + "9A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C0" + "13ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD70"
+ + "98488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0" + "A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708"
+ + "DF1FB2BC2E4A4371";
+ private static readonly string rfc5114_1024_160_g = "A4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507F"
+ + "D6406CFF14266D31266FEA1E5C41564B777E690F5504F213" + "160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1"
+ + "909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28A" + "D662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24"
+ + "855E6EEB22B3B2E5";
+ private static readonly string rfc5114_1024_160_q = "F518AA8781A8DF278ABA4E7D64B7CB9D49462353";
+
+ ///
+ /// Existence of a "hidden SNFS" backdoor cannot be ruled out. see https://eprint.iacr.org/2016/961.pdf .
+ ///
+ [Obsolete("Existence of a 'hidden SNFS' backdoor cannot be ruled out.")]
+ public static readonly DHParameters rfc5114_1024_160 = FromPGQ(rfc5114_1024_160_p, rfc5114_1024_160_g,
+ rfc5114_1024_160_q);
+
+ private static readonly string rfc5114_2048_224_p = "AD107E1E9123A9D0D660FAA79559C51FA20D64E5683B9FD1"
+ + "B54B1597B61D0A75E6FA141DF95A56DBAF9A3C407BA1DF15" + "EB3D688A309C180E1DE6B85A1274A0A66D3F8152AD6AC212"
+ + "9037C9EDEFDA4DF8D91E8FEF55B7394B7AD5B7D0B6C12207" + "C9F98D11ED34DBF6C6BA0B2C8BBC27BE6A00E0A0B9C49708"
+ + "B3BF8A317091883681286130BC8985DB1602E714415D9330" + "278273C7DE31EFDC7310F7121FD5A07415987D9ADC0A486D"
+ + "CDF93ACC44328387315D75E198C641A480CD86A1B9E587E8" + "BE60E69CC928B2B9C52172E413042E9B23F10B0E16E79763"
+ + "C9B53DCF4BA80A29E3FB73C16B8E75B97EF363E2FFA31F71" + "CF9DE5384E71B81C0AC4DFFE0C10E64F";
+ private static readonly string rfc5114_2048_224_g = "AC4032EF4F2D9AE39DF30B5C8FFDAC506CDEBE7B89998CAF"
+ + "74866A08CFE4FFE3A6824A4E10B9A6F0DD921F01A70C4AFA" + "AB739D7700C29F52C57DB17C620A8652BE5E9001A8D66AD7"
+ + "C17669101999024AF4D027275AC1348BB8A762D0521BC98A" + "E247150422EA1ED409939D54DA7460CDB5F6C6B250717CBE"
+ + "F180EB34118E98D119529A45D6F834566E3025E316A330EF" + "BB77A86F0C1AB15B051AE3D428C8F8ACB70A8137150B8EEB"
+ + "10E183EDD19963DDD9E263E4770589EF6AA21E7F5F2FF381" + "B539CCE3409D13CD566AFBB48D6C019181E1BCFE94B30269"
+ + "EDFE72FE9B6AA4BD7B5A0F1C71CFFF4C19C418E1F6EC0179" + "81BC087F2A7065B384B890D3191F2BFA";
+ private static readonly string rfc5114_2048_224_q = "801C0D34C58D93FE997177101F80535A4738CEBCBF389A99B36371EB";
+
+ ///
+ /// Existence of a "hidden SNFS" backdoor cannot be ruled out. see https://eprint.iacr.org/2016/961.pdf .
+ ///
+ [Obsolete("Existence of a 'hidden SNFS' backdoor cannot be ruled out.")]
+ public static readonly DHParameters rfc5114_2048_224 = FromPGQ(rfc5114_2048_224_p, rfc5114_2048_224_g,
+ rfc5114_2048_224_q);
+
+ private static readonly string rfc5114_2048_256_p = "87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F2"
+ + "5D2CEED4435E3B00E00DF8F1D61957D4FAF7DF4561B2AA30" + "16C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD"
+ + "5A8A9D306BCF67ED91F9E6725B4758C022E0B1EF4275BF7B" + "6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C"
+ + "4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0E" + "F13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D9"
+ + "67E144E5140564251CCACB83E6B486F6B3CA3F7971506026" + "C0B857F689962856DED4010ABD0BE621C3A3960A54E710C3"
+ + "75F26375D7014103A4B54330C198AF126116D2276E11715F" + "693877FAD7EF09CADB094AE91E1A1597";
+ private static readonly string rfc5114_2048_256_g = "3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF2054"
+ + "07F4793A1A0BA12510DBC15077BE463FFF4FED4AAC0BB555" + "BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18"
+ + "A55AE31341000A650196F931C77A57F2DDF463E5E9EC144B" + "777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC83"
+ + "1D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55" + "A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14"
+ + "C8484B1E052588B9B7D2BBD2DF016199ECD06E1557CD0915" + "B3353BBB64E0EC377FD028370DF92B52C7891428CDC67EB6"
+ + "184B523D1DB246C32F63078490F00EF8D647D148D4795451" + "5E2327CFEF98C582664B4C0F6CC41659";
+ private static readonly string rfc5114_2048_256_q = "8CF83642A709A097B447997640129DA299B1A47D1EB3750B"
+ + "A308B0FE64F5FBD3";
+
+ ///
+ /// Existence of a "hidden SNFS" backdoor cannot be ruled out. see https://eprint.iacr.org/2016/961.pdf .
+ ///
+ [Obsolete("Existence of a 'hidden SNFS' backdoor cannot be ruled out.")]
+ public static readonly DHParameters rfc5114_2048_256 = FromPGQ(rfc5114_2048_256_p, rfc5114_2048_256_g,
+ rfc5114_2048_256_q);
+
+ /*
+ * RFC 5996
+ */
+ public static readonly DHParameters rfc5996_768 = rfc4306_768;
+ public static readonly DHParameters rfc5996_1024 = rfc4306_1024;
+
+ /*
+ * RFC 7919
+ */
+ private static readonly string rfc7919_ffdhe2048_p = "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1"
+ + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561"
+ + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735"
+ + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19"
+ + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73"
+ + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + "886B423861285C97FFFFFFFFFFFFFFFF";
+ public static readonly DHParameters rfc7919_ffdhe2048 = Rfc7919Parameters(rfc7919_ffdhe2048_p, 225);
+
+ private static readonly string rfc7919_ffdhe3072_p = "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1"
+ + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561"
+ + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735"
+ + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19"
+ + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73"
+ + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238"
+ + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3"
+ + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF"
+ + "3C1B20EE3FD59D7C25E41D2B66C62E37FFFFFFFFFFFFFFFF";
+ public static readonly DHParameters rfc7919_ffdhe3072 = Rfc7919Parameters(rfc7919_ffdhe3072_p, 275);
+
+ private static readonly string rfc7919_ffdhe4096_p = "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1"
+ + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561"
+ + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735"
+ + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19"
+ + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73"
+ + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238"
+ + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3"
+ + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF"
+ + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004"
+ + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + "A907600A918130C46DC778F971AD0038092999A333CB8B7A"
+ + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E655F6A"
+ + "FFFFFFFFFFFFFFFF";
+ public static readonly DHParameters rfc7919_ffdhe4096 = Rfc7919Parameters(rfc7919_ffdhe4096_p, 325);
+
+ private static readonly string rfc7919_ffdhe6144_p = "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1"
+ + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561"
+ + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735"
+ + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19"
+ + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73"
+ + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238"
+ + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3"
+ + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF"
+ + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004"
+ + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + "A907600A918130C46DC778F971AD0038092999A333CB8B7A"
+ + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902"
+ + "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6" + "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A"
+ + "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477" + "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3"
+ + "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4" + "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6"
+ + "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C" + "D72B03746AE77F5E62292C311562A846505DC82DB854338A"
+ + "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04" + "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1"
+ + "A41D570D7938DAD4A40E329CD0E40E65FFFFFFFFFFFFFFFF";
+ public static readonly DHParameters rfc7919_ffdhe6144 = Rfc7919Parameters(rfc7919_ffdhe6144_p, 375);
+
+ private static readonly string rfc7919_ffdhe8192_p = "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1"
+ + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561"
+ + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735"
+ + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19"
+ + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73"
+ + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238"
+ + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3"
+ + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF"
+ + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004"
+ + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + "A907600A918130C46DC778F971AD0038092999A333CB8B7A"
+ + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902"
+ + "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6" + "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A"
+ + "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477" + "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3"
+ + "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4" + "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6"
+ + "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C" + "D72B03746AE77F5E62292C311562A846505DC82DB854338A"
+ + "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04" + "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1"
+ + "A41D570D7938DAD4A40E329CCFF46AAA36AD004CF600C838" + "1E425A31D951AE64FDB23FCEC9509D43687FEB69EDD1CC5E"
+ + "0B8CC3BDF64B10EF86B63142A3AB8829555B2F747C932665" + "CB2C0F1CC01BD70229388839D2AF05E454504AC78B758282"
+ + "2846C0BA35C35F5C59160CC046FD8251541FC68C9C86B022" + "BB7099876A460E7451A8A93109703FEE1C217E6C3826E52C"
+ + "51AA691E0E423CFC99E9E31650C1217B624816CDAD9A95F9" + "D5B8019488D9C0A0A1FE3075A577E23183F81D4A3F2FA457"
+ + "1EFC8CE0BA8A4FE8B6855DFE72B0A66EDED2FBABFBE58A30" + "FAFABE1C5D71A87E2F741EF8C1FE86FEA6BBFDE530677F0D"
+ + "97D11D49F7A8443D0822E506A9F4614E011E2A94838FF88C" + "D68C8BB7C5C6424CFFFFFFFFFFFFFFFF";
+ public static readonly DHParameters rfc7919_ffdhe8192 = Rfc7919Parameters(rfc7919_ffdhe8192_p, 400);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/ECDHBasicAgreement.cs b/bc-sharp-crypto/src/crypto/agreement/ECDHBasicAgreement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ca7b3fa3fbf2bd2df73070280eb00981e66e60e8
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/ECDHBasicAgreement.cs
@@ -0,0 +1,60 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+ /**
+ * P1363 7.2.1 ECSVDP-DH
+ *
+ * ECSVDP-DH is Elliptic Curve Secret Value Derivation Primitive,
+ * Diffie-Hellman version. It is based on the work of [DH76], [Mil86],
+ * and [Kob87]. This primitive derives a shared secret value from one
+ * party's private key and another party's public key, where both have
+ * the same set of EC domain parameters. If two parties correctly
+ * execute this primitive, they will produce the same output. This
+ * primitive can be invoked by a scheme to derive a shared secret key;
+ * specifically, it may be used with the schemes ECKAS-DH1 and
+ * DL/ECKAS-DH2. It assumes that the input keys are valid (see also
+ * Section 7.2.2).
+ */
+ public class ECDHBasicAgreement
+ : IBasicAgreement
+ {
+ protected internal ECPrivateKeyParameters privKey;
+
+ public virtual void Init(
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ parameters = ((ParametersWithRandom)parameters).Parameters;
+ }
+
+ this.privKey = (ECPrivateKeyParameters)parameters;
+ }
+
+ public virtual int GetFieldSize()
+ {
+ return (privKey.Parameters.Curve.FieldSize + 7) / 8;
+ }
+
+ public virtual BigInteger CalculateAgreement(
+ ICipherParameters pubKey)
+ {
+ ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey;
+ if (!pub.Parameters.Equals(privKey.Parameters))
+ throw new InvalidOperationException("ECDH public key has wrong domain parameters");
+
+ ECPoint P = pub.Q.Multiply(privKey.D).Normalize();
+
+ if (P.IsInfinity)
+ throw new InvalidOperationException("Infinity is not a valid agreement value for ECDH");
+
+ return P.AffineXCoord.ToBigInteger();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/ECDHCBasicAgreement.cs b/bc-sharp-crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1c9ae45f9c09d6639a5d8725d4cbf3ebdf2fd562
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
@@ -0,0 +1,68 @@
+using System;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+ /**
+ * P1363 7.2.2 ECSVDP-DHC
+ *
+ * ECSVDP-DHC is Elliptic Curve Secret Value Derivation Primitive,
+ * Diffie-Hellman version with cofactor multiplication. It is based on
+ * the work of [DH76], [Mil86], [Kob87], [LMQ98] and [Kal98a]. This
+ * primitive derives a shared secret value from one party's private key
+ * and another party's public key, where both have the same set of EC
+ * domain parameters. If two parties correctly execute this primitive,
+ * they will produce the same output. This primitive can be invoked by a
+ * scheme to derive a shared secret key; specifically, it may be used
+ * with the schemes ECKAS-DH1 and DL/ECKAS-DH2. It does not assume the
+ * validity of the input public key (see also Section 7.2.1).
+ *
+ * Note: As stated P1363 compatibility mode with ECDH can be preset, and
+ * in this case the implementation doesn't have a ECDH compatibility mode
+ * (if you want that just use ECDHBasicAgreement and note they both implement
+ * BasicAgreement!).
+ */
+ public class ECDHCBasicAgreement
+ : IBasicAgreement
+ {
+ private ECPrivateKeyParameters privKey;
+
+ public virtual void Init(
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ parameters = ((ParametersWithRandom) parameters).Parameters;
+ }
+
+ this.privKey = (ECPrivateKeyParameters)parameters;
+ }
+
+ public virtual int GetFieldSize()
+ {
+ return (privKey.Parameters.Curve.FieldSize + 7) / 8;
+ }
+
+ public virtual BigInteger CalculateAgreement(
+ ICipherParameters pubKey)
+ {
+ ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey;
+ ECDomainParameters parameters = pub.Parameters;
+ if (!parameters.Equals(privKey.Parameters))
+ throw new InvalidOperationException("ECDHC public key has wrong domain parameters");
+
+ BigInteger hd = parameters.H.Multiply(privKey.D).Mod(parameters.N);
+
+ ECPoint P = pub.Q.Multiply(hd).Normalize();
+
+ if (P.IsInfinity)
+ throw new InvalidOperationException("Infinity is not a valid agreement value for ECDHC");
+
+ return P.AffineXCoord.ToBigInteger();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs b/bc-sharp-crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1de80d1e5a14e30af6b1760d63eb2707afe27c03
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto.Agreement.Kdf;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+ public class ECDHWithKdfBasicAgreement
+ : ECDHBasicAgreement
+ {
+ private readonly string algorithm;
+ private readonly IDerivationFunction kdf;
+
+ public ECDHWithKdfBasicAgreement(
+ string algorithm,
+ IDerivationFunction kdf)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+ if (kdf == null)
+ throw new ArgumentNullException("kdf");
+
+ this.algorithm = algorithm;
+ this.kdf = kdf;
+ }
+
+ public override BigInteger CalculateAgreement(
+ ICipherParameters pubKey)
+ {
+ // Note that the ec.KeyAgreement class in JCE only uses kdf in one
+ // of the engineGenerateSecret methods.
+
+ BigInteger result = base.CalculateAgreement(pubKey);
+
+ int keySize = GeneratorUtilities.GetDefaultKeySize(algorithm);
+
+ DHKdfParameters dhKdfParams = new DHKdfParameters(
+ new DerObjectIdentifier(algorithm),
+ keySize,
+ BigIntToBytes(result));
+
+ kdf.Init(dhKdfParams);
+
+ byte[] keyBytes = new byte[keySize / 8];
+ kdf.GenerateBytes(keyBytes, 0, keyBytes.Length);
+
+ return new BigInteger(1, keyBytes);
+ }
+
+ private byte[] BigIntToBytes(BigInteger r)
+ {
+ int byteLength = X9IntegerConverter.GetByteLength(privKey.Parameters.Curve);
+ return X9IntegerConverter.IntegerToBytes(r, byteLength);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/ECMqvBasicAgreement.cs b/bc-sharp-crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8d5cebb132b62f687aaa76b4f436b4727c253bb5
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
@@ -0,0 +1,93 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+ public class ECMqvBasicAgreement
+ : IBasicAgreement
+ {
+ protected internal MqvPrivateParameters privParams;
+
+ public virtual void Init(
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ parameters = ((ParametersWithRandom)parameters).Parameters;
+ }
+
+ this.privParams = (MqvPrivateParameters)parameters;
+ }
+
+ public virtual int GetFieldSize()
+ {
+ return (privParams.StaticPrivateKey.Parameters.Curve.FieldSize + 7) / 8;
+ }
+
+ public virtual BigInteger CalculateAgreement(
+ ICipherParameters pubKey)
+ {
+ MqvPublicParameters pubParams = (MqvPublicParameters)pubKey;
+
+ ECPrivateKeyParameters staticPrivateKey = privParams.StaticPrivateKey;
+ ECDomainParameters parameters = staticPrivateKey.Parameters;
+
+ if (!parameters.Equals(pubParams.StaticPublicKey.Parameters))
+ throw new InvalidOperationException("ECMQV public key components have wrong domain parameters");
+
+ ECPoint agreement = CalculateMqvAgreement(parameters, staticPrivateKey,
+ privParams.EphemeralPrivateKey, privParams.EphemeralPublicKey,
+ pubParams.StaticPublicKey, pubParams.EphemeralPublicKey).Normalize();
+
+ if (agreement.IsInfinity)
+ throw new InvalidOperationException("Infinity is not a valid agreement value for MQV");
+
+ return agreement.AffineXCoord.ToBigInteger();
+ }
+
+ // The ECMQV Primitive as described in SEC-1, 3.4
+ private static ECPoint CalculateMqvAgreement(
+ ECDomainParameters parameters,
+ ECPrivateKeyParameters d1U,
+ ECPrivateKeyParameters d2U,
+ ECPublicKeyParameters Q2U,
+ ECPublicKeyParameters Q1V,
+ ECPublicKeyParameters Q2V)
+ {
+ BigInteger n = parameters.N;
+ int e = (n.BitLength + 1) / 2;
+ BigInteger powE = BigInteger.One.ShiftLeft(e);
+
+ ECCurve curve = parameters.Curve;
+
+ ECPoint[] points = new ECPoint[]{
+ // The Q2U public key is optional - but will be calculated for us if it wasn't present
+ ECAlgorithms.ImportPoint(curve, Q2U.Q),
+ ECAlgorithms.ImportPoint(curve, Q1V.Q),
+ ECAlgorithms.ImportPoint(curve, Q2V.Q)
+ };
+
+ curve.NormalizeAll(points);
+
+ ECPoint q2u = points[0], q1v = points[1], q2v = points[2];
+
+ BigInteger x = q2u.AffineXCoord.ToBigInteger();
+ BigInteger xBar = x.Mod(powE);
+ BigInteger Q2UBar = xBar.SetBit(e);
+ BigInteger s = d1U.D.Multiply(Q2UBar).Add(d2U.D).Mod(n);
+
+ BigInteger xPrime = q2v.AffineXCoord.ToBigInteger();
+ BigInteger xPrimeBar = xPrime.Mod(powE);
+ BigInteger Q2VBar = xPrimeBar.SetBit(e);
+
+ BigInteger hs = parameters.H.Multiply(s).Mod(n);
+
+ return ECAlgorithms.SumOfTwoMultiplies(
+ q1v, Q2VBar.Multiply(hs).Mod(n), q2v, hs);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs b/bc-sharp-crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7d79fc4680592e83e39002b60925b87a7fdb0aa5
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto.Agreement.Kdf;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+ public class ECMqvWithKdfBasicAgreement
+ : ECMqvBasicAgreement
+ {
+ private readonly string algorithm;
+ private readonly IDerivationFunction kdf;
+
+ public ECMqvWithKdfBasicAgreement(
+ string algorithm,
+ IDerivationFunction kdf)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+ if (kdf == null)
+ throw new ArgumentNullException("kdf");
+
+ this.algorithm = algorithm;
+ this.kdf = kdf;
+ }
+
+ public override BigInteger CalculateAgreement(
+ ICipherParameters pubKey)
+ {
+ // Note that the ec.KeyAgreement class in JCE only uses kdf in one
+ // of the engineGenerateSecret methods.
+
+ BigInteger result = base.CalculateAgreement(pubKey);
+
+ int keySize = GeneratorUtilities.GetDefaultKeySize(algorithm);
+
+ DHKdfParameters dhKdfParams = new DHKdfParameters(
+ new DerObjectIdentifier(algorithm),
+ keySize,
+ BigIntToBytes(result));
+
+ kdf.Init(dhKdfParams);
+
+ byte[] keyBytes = new byte[keySize / 8];
+ kdf.GenerateBytes(keyBytes, 0, keyBytes.Length);
+
+ return new BigInteger(1, keyBytes);
+ }
+
+ private byte[] BigIntToBytes(BigInteger r)
+ {
+ int byteLength = X9IntegerConverter.GetByteLength(privParams.StaticPrivateKey.Parameters.Curve);
+ return X9IntegerConverter.IntegerToBytes(r, byteLength);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/jpake/JPakeParticipant.cs b/bc-sharp-crypto/src/crypto/agreement/jpake/JPakeParticipant.cs
new file mode 100644
index 0000000000000000000000000000000000000000..794284866811cf761ff18719fa642f6dcd98171e
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/jpake/JPakeParticipant.cs
@@ -0,0 +1,456 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Agreement.JPake
+{
+ ///
+ /// A participant in a Password Authenticated Key Exchange by Juggling (J-PAKE) exchange.
+ ///
+ /// The J-PAKE exchange is defined by Feng Hao and Peter Ryan in the paper
+ ///
+ /// "Password Authenticated Key Exchange by Juggling, 2008."
+ ///
+ /// The J-PAKE protocol is symmetric.
+ /// There is no notion of a client or server , but rather just two participants .
+ /// An instance of JPakeParticipant represents one participant, and
+ /// is the primary interface for executing the exchange.
+ ///
+ /// To execute an exchange, construct a JPakeParticipant on each end,
+ /// and call the following 7 methods
+ /// (once and only once, in the given order, for each participant, sending messages between them as described):
+ ///
+ /// CreateRound1PayloadToSend() - and send the payload to the other participant
+ /// ValidateRound1PayloadReceived(JPakeRound1Payload) - use the payload received from the other participant
+ /// CreateRound2PayloadToSend() - and send the payload to the other participant
+ /// ValidateRound2PayloadReceived(JPakeRound2Payload) - use the payload received from the other participant
+ /// CalculateKeyingMaterial()
+ /// CreateRound3PayloadToSend(BigInteger) - and send the payload to the other participant
+ /// ValidateRound3PayloadReceived(JPakeRound3Payload, BigInteger) - use the payload received from the other participant
+ ///
+ /// Each side should derive a session key from the keying material returned by CalculateKeyingMaterial().
+ /// The caller is responsible for deriving the session key using a secure key derivation function (KDF).
+ ///
+ /// Round 3 is an optional key confirmation process.
+ /// If you do not execute round 3, then there is no assurance that both participants are using the same key.
+ /// (i.e. if the participants used different passwords, then their session keys will differ.)
+ ///
+ /// If the round 3 validation succeeds, then the keys are guaranteed to be the same on both sides.
+ ///
+ /// The symmetric design can easily support the asymmetric cases when one party initiates the communication.
+ /// e.g. Sometimes the round1 payload and round2 payload may be sent in one pass.
+ /// Also, in some cases, the key confirmation payload can be sent together with the round2 payload.
+ /// These are the trivial techniques to optimize the communication.
+ ///
+ /// The key confirmation process is implemented as specified in
+ /// NIST SP 800-56A Revision 1 ,
+ /// Section 8.2 Unilateral Key Confirmation for Key Agreement Schemes.
+ ///
+ /// This class is stateful and NOT threadsafe.
+ /// Each instance should only be used for ONE complete J-PAKE exchange
+ /// (i.e. a new JPakeParticipant should be constructed for each new J-PAKE exchange).
+ ///
+ public class JPakeParticipant
+ {
+ // Possible internal states. Used for state checking.
+ public static readonly int STATE_INITIALIZED = 0;
+ public static readonly int STATE_ROUND_1_CREATED = 10;
+ public static readonly int STATE_ROUND_1_VALIDATED = 20;
+ public static readonly int STATE_ROUND_2_CREATED = 30;
+ public static readonly int STATE_ROUND_2_VALIDATED = 40;
+ public static readonly int STATE_KEY_CALCULATED = 50;
+ public static readonly int STATE_ROUND_3_CREATED = 60;
+ public static readonly int STATE_ROUND_3_VALIDATED = 70;
+
+ // Unique identifier of this participant.
+ // The two participants in the exchange must NOT share the same id.
+ private string participantId;
+
+ // Shared secret. This only contains the secret between construction
+ // and the call to CalculateKeyingMaterial().
+ //
+ // i.e. When CalculateKeyingMaterial() is called, this buffer overwritten with 0's,
+ // and the field is set to null.
+ private char[] password;
+
+ // Digest to use during calculations.
+ private IDigest digest;
+
+ // Source of secure random data.
+ private readonly SecureRandom random;
+
+ private readonly BigInteger p;
+ private readonly BigInteger q;
+ private readonly BigInteger g;
+
+ // The participantId of the other participant in this exchange.
+ private string partnerParticipantId;
+
+ // Alice's x1 or Bob's x3.
+ private BigInteger x1;
+ // Alice's x2 or Bob's x4.
+ private BigInteger x2;
+ // Alice's g^x1 or Bob's g^x3.
+ private BigInteger gx1;
+ // Alice's g^x2 or Bob's g^x4.
+ private BigInteger gx2;
+ // Alice's g^x3 or Bob's g^x1.
+ private BigInteger gx3;
+ // Alice's g^x4 or Bob's g^x2.
+ private BigInteger gx4;
+ // Alice's B or Bob's A.
+ private BigInteger b;
+
+ // The current state.
+ // See the STATE_* constants for possible values.
+ private int state;
+
+ ///
+ /// Convenience constructor for a new JPakeParticipant that uses
+ /// the JPakePrimeOrderGroups#NIST_3072 prime order group,
+ /// a SHA-256 digest, and a default SecureRandom implementation.
+ ///
+ /// After construction, the State state will be STATE_INITIALIZED.
+ ///
+ /// Throws NullReferenceException if any argument is null. Throws
+ /// ArgumentException if password is empty.
+ ///
+ /// Unique identifier of this participant.
+ /// The two participants in the exchange must NOT share the same id.
+ /// Shared secret.
+ /// A defensive copy of this array is made (and cleared once CalculateKeyingMaterial() is called).
+ /// Caller should clear the input password as soon as possible.
+ public JPakeParticipant(string participantId, char[] password)
+ : this(participantId, password, JPakePrimeOrderGroups.NIST_3072) { }
+
+ ///
+ /// Convenience constructor for a new JPakeParticipant that uses
+ /// a SHA-256 digest, and a default SecureRandom implementation.
+ ///
+ /// After construction, the State state will be STATE_INITIALIZED.
+ ///
+ /// Throws NullReferenceException if any argument is null. Throws
+ /// ArgumentException if password is empty.
+ ///
+ /// Unique identifier of this participant.
+ /// The two participants in the exchange must NOT share the same id.
+ /// Shared secret.
+ /// A defensive copy of this array is made (and cleared once CalculateKeyingMaterial() is called).
+ /// Caller should clear the input password as soon as possible.
+ /// Prime order group. See JPakePrimeOrderGroups for standard groups.
+ public JPakeParticipant(string participantId, char[] password, JPakePrimeOrderGroup group)
+ : this(participantId, password, group, new Sha256Digest(), new SecureRandom()) { }
+
+
+ ///
+ /// Constructor for a new JPakeParticipant.
+ ///
+ /// After construction, the State state will be STATE_INITIALIZED.
+ ///
+ /// Throws NullReferenceException if any argument is null. Throws
+ /// ArgumentException if password is empty.
+ ///
+ /// Unique identifier of this participant.
+ /// The two participants in the exchange must NOT share the same id.
+ /// Shared secret.
+ /// A defensive copy of this array is made (and cleared once CalculateKeyingMaterial() is called).
+ /// Caller should clear the input password as soon as possible.
+ /// Prime order group. See JPakePrimeOrderGroups for standard groups.
+ /// Digest to use during zero knowledge proofs and key confirmation
+ /// (SHA-256 or stronger preferred).
+ /// Source of secure random data for x1 and x2, and for the zero knowledge proofs.
+ public JPakeParticipant(string participantId, char[] password, JPakePrimeOrderGroup group, IDigest digest, SecureRandom random)
+ {
+ JPakeUtilities.ValidateNotNull(participantId, "participantId");
+ JPakeUtilities.ValidateNotNull(password, "password");
+ JPakeUtilities.ValidateNotNull(group, "p");
+ JPakeUtilities.ValidateNotNull(digest, "digest");
+ JPakeUtilities.ValidateNotNull(random, "random");
+
+ if (password.Length == 0)
+ {
+ throw new ArgumentException("Password must not be empty.");
+ }
+
+ this.participantId = participantId;
+
+ // Create a defensive copy so as to fully encapsulate the password.
+ //
+ // This array will contain the password for the lifetime of this
+ // participant BEFORE CalculateKeyingMaterial() is called.
+ //
+ // i.e. When CalculateKeyingMaterial() is called, the array will be cleared
+ // in order to remove the password from memory.
+ //
+ // The caller is responsible for clearing the original password array
+ // given as input to this constructor.
+ this.password = new char[password.Length];
+ Array.Copy(password, this.password, password.Length);
+
+ this.p = group.P;
+ this.q = group.Q;
+ this.g = group.G;
+
+ this.digest = digest;
+ this.random = random;
+
+ this.state = STATE_INITIALIZED;
+ }
+
+ ///
+ /// Gets the current state of this participant.
+ /// See the STATE_* constants for possible values.
+ ///
+ public virtual int State
+ {
+ get { return state; }
+ }
+
+
+ ///
+ /// Creates and returns the payload to send to the other participant during round 1.
+ ///
+ /// After execution, the State state} will be STATE_ROUND_1_CREATED}.
+ ///
+ public virtual JPakeRound1Payload CreateRound1PayloadToSend()
+ {
+ if (this.state >= STATE_ROUND_1_CREATED)
+ throw new InvalidOperationException("Round 1 payload already created for " + this.participantId);
+
+ this.x1 = JPakeUtilities.GenerateX1(q, random);
+ this.x2 = JPakeUtilities.GenerateX2(q, random);
+
+ this.gx1 = JPakeUtilities.CalculateGx(p, g, x1);
+ this.gx2 = JPakeUtilities.CalculateGx(p, g, x2);
+ BigInteger[] knowledgeProofForX1 = JPakeUtilities.CalculateZeroKnowledgeProof(p, q, g, gx1, x1, participantId, digest, random);
+ BigInteger[] knowledgeProofForX2 = JPakeUtilities.CalculateZeroKnowledgeProof(p, q, g, gx2, x2, participantId, digest, random);
+
+ this.state = STATE_ROUND_1_CREATED;
+
+ return new JPakeRound1Payload(participantId, gx1, gx2, knowledgeProofForX1, knowledgeProofForX2);
+ }
+
+ ///
+ /// Validates the payload received from the other participant during round 1.
+ ///
+ /// Must be called prior to CreateRound2PayloadToSend().
+ ///
+ /// After execution, the State state will be STATE_ROUND_1_VALIDATED.
+ ///
+ /// Throws CryptoException if validation fails. Throws InvalidOperationException
+ /// if called multiple times.
+ ///
+ public virtual void ValidateRound1PayloadReceived(JPakeRound1Payload round1PayloadReceived)
+ {
+ if (this.state >= STATE_ROUND_1_VALIDATED)
+ throw new InvalidOperationException("Validation already attempted for round 1 payload for " + this.participantId);
+
+ this.partnerParticipantId = round1PayloadReceived.ParticipantId;
+ this.gx3 = round1PayloadReceived.Gx1;
+ this.gx4 = round1PayloadReceived.Gx2;
+
+ BigInteger[] knowledgeProofForX3 = round1PayloadReceived.KnowledgeProofForX1;
+ BigInteger[] knowledgeProofForX4 = round1PayloadReceived.KnowledgeProofForX2;
+
+ JPakeUtilities.ValidateParticipantIdsDiffer(participantId, round1PayloadReceived.ParticipantId);
+ JPakeUtilities.ValidateGx4(gx4);
+ JPakeUtilities.ValidateZeroKnowledgeProof(p, q, g, gx3, knowledgeProofForX3, round1PayloadReceived.ParticipantId, digest);
+ JPakeUtilities.ValidateZeroKnowledgeProof(p, q, g, gx4, knowledgeProofForX4, round1PayloadReceived.ParticipantId, digest);
+ this.state = STATE_ROUND_1_VALIDATED;
+ }
+
+ ///
+ /// Creates and returns the payload to send to the other participant during round 2.
+ ///
+ /// ValidateRound1PayloadReceived(JPakeRound1Payload) must be called prior to this method.
+ ///
+ /// After execution, the State state will be STATE_ROUND_2_CREATED.
+ ///
+ /// Throws InvalidOperationException if called prior to ValidateRound1PayloadReceived(JPakeRound1Payload), or multiple times
+ ///
+ public virtual JPakeRound2Payload CreateRound2PayloadToSend()
+ {
+ if (this.state >= STATE_ROUND_2_CREATED)
+ throw new InvalidOperationException("Round 2 payload already created for " + this.participantId);
+ if (this.state < STATE_ROUND_1_VALIDATED)
+ throw new InvalidOperationException("Round 1 payload must be validated prior to creating round 2 payload for " + this.participantId);
+
+ BigInteger gA = JPakeUtilities.CalculateGA(p, gx1, gx3, gx4);
+ BigInteger s = JPakeUtilities.CalculateS(password);
+ BigInteger x2s = JPakeUtilities.CalculateX2s(q, x2, s);
+ BigInteger A = JPakeUtilities.CalculateA(p, q, gA, x2s);
+ BigInteger[] knowledgeProofForX2s = JPakeUtilities.CalculateZeroKnowledgeProof(p, q, gA, A, x2s, participantId, digest, random);
+
+ this.state = STATE_ROUND_2_CREATED;
+
+ return new JPakeRound2Payload(participantId, A, knowledgeProofForX2s);
+ }
+
+ ///
+ /// Validates the payload received from the other participant during round 2.
+ /// Note that this DOES NOT detect a non-common password.
+ /// The only indication of a non-common password is through derivation
+ /// of different keys (which can be detected explicitly by executing round 3 and round 4)
+ ///
+ /// Must be called prior to CalculateKeyingMaterial().
+ ///
+ /// After execution, the State state will be STATE_ROUND_2_VALIDATED.
+ ///
+ /// Throws CryptoException if validation fails. Throws
+ /// InvalidOperationException if called prior to ValidateRound1PayloadReceived(JPakeRound1Payload), or multiple times
+ ///
+ public virtual void ValidateRound2PayloadReceived(JPakeRound2Payload round2PayloadReceived)
+ {
+ if (this.state >= STATE_ROUND_2_VALIDATED)
+ throw new InvalidOperationException("Validation already attempted for round 2 payload for " + this.participantId);
+ if (this.state < STATE_ROUND_1_VALIDATED)
+ throw new InvalidOperationException("Round 1 payload must be validated prior to validation round 2 payload for " + this.participantId);
+
+ BigInteger gB = JPakeUtilities.CalculateGA(p, gx3, gx1, gx2);
+ this.b = round2PayloadReceived.A;
+ BigInteger[] knowledgeProofForX4s = round2PayloadReceived.KnowledgeProofForX2s;
+
+ JPakeUtilities.ValidateParticipantIdsDiffer(participantId, round2PayloadReceived.ParticipantId);
+ JPakeUtilities.ValidateParticipantIdsEqual(this.partnerParticipantId, round2PayloadReceived.ParticipantId);
+ JPakeUtilities.ValidateGa(gB);
+ JPakeUtilities.ValidateZeroKnowledgeProof(p, q, gB, b, knowledgeProofForX4s, round2PayloadReceived.ParticipantId, digest);
+
+ this.state = STATE_ROUND_2_VALIDATED;
+ }
+
+ ///
+ /// Calculates and returns the key material.
+ /// A session key must be derived from this key material using a secure key derivation function (KDF).
+ /// The KDF used to derive the key is handled externally (i.e. not by JPakeParticipant).
+ ///
+ /// The keying material will be identical for each participant if and only if
+ /// each participant's password is the same. i.e. If the participants do not
+ /// share the same password, then each participant will derive a different key.
+ /// Therefore, if you immediately start using a key derived from
+ /// the keying material, then you must handle detection of incorrect keys.
+ /// If you want to handle this detection explicitly, you can optionally perform
+ /// rounds 3 and 4. See JPakeParticipant for details on how to execute
+ /// rounds 3 and 4.
+ ///
+ /// The keying material will be in the range [0, p-1] .
+ ///
+ /// ValidateRound2PayloadReceived(JPakeRound2Payload) must be called prior to this method.
+ ///
+ /// As a side effect, the internal password array is cleared, since it is no longer needed.
+ ///
+ /// After execution, the State state will be STATE_KEY_CALCULATED.
+ ///
+ /// Throws InvalidOperationException if called prior to ValidateRound2PayloadReceived(JPakeRound2Payload),
+ /// or if called multiple times.
+ ///
+ public virtual BigInteger CalculateKeyingMaterial()
+ {
+ if (this.state >= STATE_KEY_CALCULATED)
+ throw new InvalidOperationException("Key already calculated for " + participantId);
+ if (this.state < STATE_ROUND_2_VALIDATED)
+ throw new InvalidOperationException("Round 2 payload must be validated prior to creating key for " + participantId);
+
+ BigInteger s = JPakeUtilities.CalculateS(password);
+
+ // Clear the password array from memory, since we don't need it anymore.
+ // Also set the field to null as a flag to indicate that the key has already been calculated.
+ Array.Clear(password, 0, password.Length);
+ this.password = null;
+
+ BigInteger keyingMaterial = JPakeUtilities.CalculateKeyingMaterial(p, q, gx4, x2, s, b);
+
+ // Clear the ephemeral private key fields as well.
+ // Note that we're relying on the garbage collector to do its job to clean these up.
+ // The old objects will hang around in memory until the garbage collector destroys them.
+ //
+ // If the ephemeral private keys x1 and x2 are leaked,
+ // the attacker might be able to brute-force the password.
+ this.x1 = null;
+ this.x2 = null;
+ this.b = null;
+
+ // Do not clear gx* yet, since those are needed by round 3.
+
+ this.state = STATE_KEY_CALCULATED;
+
+ return keyingMaterial;
+ }
+
+ ///
+ /// Creates and returns the payload to send to the other participant during round 3.
+ ///
+ /// See JPakeParticipant for more details on round 3.
+ ///
+ /// After execution, the State state} will be STATE_ROUND_3_CREATED.
+ /// Throws InvalidOperationException if called prior to CalculateKeyingMaterial, or multiple
+ /// times.
+ ///
+ /// The keying material as returned from CalculateKeyingMaterial().
+ public virtual JPakeRound3Payload CreateRound3PayloadToSend(BigInteger keyingMaterial)
+ {
+ if (this.state >= STATE_ROUND_3_CREATED)
+ throw new InvalidOperationException("Round 3 payload already created for " + this.participantId);
+ if (this.state < STATE_KEY_CALCULATED)
+ throw new InvalidOperationException("Keying material must be calculated prior to creating round 3 payload for " + this.participantId);
+
+ BigInteger macTag = JPakeUtilities.CalculateMacTag(
+ this.participantId,
+ this.partnerParticipantId,
+ this.gx1,
+ this.gx2,
+ this.gx3,
+ this.gx4,
+ keyingMaterial,
+ this.digest);
+
+ this.state = STATE_ROUND_3_CREATED;
+
+ return new JPakeRound3Payload(participantId, macTag);
+ }
+
+ ///
+ /// Validates the payload received from the other participant during round 3.
+ ///
+ /// See JPakeParticipant for more details on round 3.
+ ///
+ /// After execution, the State state will be STATE_ROUND_3_VALIDATED.
+ ///
+ /// Throws CryptoException if validation fails. Throws InvalidOperationException if called prior to
+ /// CalculateKeyingMaterial or multiple times
+ ///
+ /// The round 3 payload received from the other participant.
+ /// The keying material as returned from CalculateKeyingMaterial().
+ public virtual void ValidateRound3PayloadReceived(JPakeRound3Payload round3PayloadReceived, BigInteger keyingMaterial)
+ {
+ if (this.state >= STATE_ROUND_3_VALIDATED)
+ throw new InvalidOperationException("Validation already attempted for round 3 payload for " + this.participantId);
+ if (this.state < STATE_KEY_CALCULATED)
+ throw new InvalidOperationException("Keying material must be calculated prior to validating round 3 payload for " + this.participantId);
+
+ JPakeUtilities.ValidateParticipantIdsDiffer(participantId, round3PayloadReceived.ParticipantId);
+ JPakeUtilities.ValidateParticipantIdsEqual(this.partnerParticipantId, round3PayloadReceived.ParticipantId);
+
+ JPakeUtilities.ValidateMacTag(
+ this.participantId,
+ this.partnerParticipantId,
+ this.gx1,
+ this.gx2,
+ this.gx3,
+ this.gx4,
+ keyingMaterial,
+ this.digest,
+ round3PayloadReceived.MacTag);
+
+ // Clear the rest of the fields.
+ this.gx1 = null;
+ this.gx2 = null;
+ this.gx3 = null;
+ this.gx4 = null;
+
+ this.state = STATE_ROUND_3_VALIDATED;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/jpake/JPakePrimeOrderGroup.cs b/bc-sharp-crypto/src/crypto/agreement/jpake/JPakePrimeOrderGroup.cs
new file mode 100644
index 0000000000000000000000000000000000000000..08ffe1a55e5aaa0d298498888e094ad5b33168da
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/jpake/JPakePrimeOrderGroup.cs
@@ -0,0 +1,103 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Agreement.JPake
+{
+ ///
+ /// A pre-computed prime order group for use during a J-PAKE exchange.
+ ///
+ /// Typically a Schnorr group is used. In general, J-PAKE can use any prime order group
+ /// that is suitable for public key cryptography, including elliptic curve cryptography.
+ ///
+ /// See JPakePrimeOrderGroups for convenient standard groups.
+ ///
+ /// NIST publishes
+ /// many groups that can be used for the desired level of security.
+ ///
+ public class JPakePrimeOrderGroup
+ {
+ private readonly BigInteger p;
+ private readonly BigInteger q;
+ private readonly BigInteger g;
+
+ ///
+ /// Constructs a new JPakePrimeOrderGroup.
+ ///
+ /// In general, you should use one of the pre-approved groups from
+ /// JPakePrimeOrderGroups, rather than manually constructing one.
+ ///
+ /// The following basic checks are performed:
+ ///
+ /// p-1 must be evenly divisible by q
+ /// g must be in [2, p-1]
+ /// g^q mod p must equal 1
+ /// p must be prime (within reasonably certainty)
+ /// q must be prime (within reasonably certainty)
+ ///
+ /// The prime checks are performed using BigInteger#isProbablePrime(int),
+ /// and are therefore subject to the same probability guarantees.
+ ///
+ /// These checks prevent trivial mistakes.
+ /// However, due to the small uncertainties if p and q are not prime,
+ /// advanced attacks are not prevented.
+ /// Use it at your own risk.
+ ///
+ /// Throws NullReferenceException if any argument is null. Throws
+ /// InvalidOperationException is any of the above validations fail.
+ ///
+ public JPakePrimeOrderGroup(BigInteger p, BigInteger q, BigInteger g)
+ : this(p, q, g, false)
+ {
+ // Don't skip the checks on user-specified groups.
+ }
+
+ ///
+ /// Constructor used by the pre-approved groups in JPakePrimeOrderGroups.
+ /// These pre-approved groups can avoid the expensive checks.
+ /// User-specified groups should not use this constructor.
+ ///
+ public JPakePrimeOrderGroup(BigInteger p, BigInteger q, BigInteger g, bool skipChecks)
+ {
+ JPakeUtilities.ValidateNotNull(p, "p");
+ JPakeUtilities.ValidateNotNull(q, "q");
+ JPakeUtilities.ValidateNotNull(g, "g");
+
+ if (!skipChecks)
+ {
+ if (!p.Subtract(JPakeUtilities.One).Mod(q).Equals(JPakeUtilities.Zero))
+ throw new ArgumentException("p-1 must be evenly divisible by q");
+ if (g.CompareTo(BigInteger.Two) == -1 || g.CompareTo(p.Subtract(JPakeUtilities.One)) == 1)
+ throw new ArgumentException("g must be in [2, p-1]");
+ if (!g.ModPow(q, p).Equals(JPakeUtilities.One))
+ throw new ArgumentException("g^q mod p must equal 1");
+
+ // Note these checks do not guarantee that p and q are prime.
+ // We just have reasonable certainty that they are prime.
+ if (!p.IsProbablePrime(20))
+ throw new ArgumentException("p must be prime");
+ if (!q.IsProbablePrime(20))
+ throw new ArgumentException("q must be prime");
+ }
+
+ this.p = p;
+ this.q = q;
+ this.g = g;
+ }
+
+ public virtual BigInteger P
+ {
+ get { return p; }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public virtual BigInteger G
+ {
+ get { return g; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/jpake/JPakePrimeOrderGroups.cs b/bc-sharp-crypto/src/crypto/agreement/jpake/JPakePrimeOrderGroups.cs
new file mode 100644
index 0000000000000000000000000000000000000000..192cd2b5119e46505f52f57a6062e09c0477e419
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/jpake/JPakePrimeOrderGroups.cs
@@ -0,0 +1,108 @@
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Agreement.JPake
+{
+ ///
+ /// Standard pre-computed prime order groups for use by J-PAKE.
+ /// (J-PAKE can use pre-computed prime order groups, same as DSA and Diffie-Hellman.)
+ ///
+ /// This class contains some convenient constants for use as input for
+ /// constructing {@link JPAKEParticipant}s.
+ ///
+ /// The prime order groups below are taken from Sun's JDK JavaDoc (docs/guide/security/CryptoSpec.html#AppB),
+ /// and from the prime order groups
+ /// published by NIST .
+ ///
+ public class JPakePrimeOrderGroups
+ {
+ ///
+ /// From Sun's JDK JavaDoc (docs/guide/security/CryptoSpec.html#AppB)
+ /// 1024-bit p, 160-bit q and 1024-bit g for 80-bit security.
+ ///
+ public static readonly JPakePrimeOrderGroup SUN_JCE_1024 = new JPakePrimeOrderGroup(
+ // p
+ new BigInteger(
+ "fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669" +
+ "455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b7" +
+ "6b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb" +
+ "83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7", 16),
+ // q
+ new BigInteger("9760508f15230bccb292b982a2eb840bf0581cf5", 16),
+ // g
+ new BigInteger(
+ "f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d078267" +
+ "5159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e1" +
+ "3c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243b" +
+ "cca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a", 16),
+ true
+ );
+
+ ///
+ /// From NIST.
+ /// 2048-bit p, 224-bit q and 2048-bit g for 112-bit security.
+ ///
+ public static readonly JPakePrimeOrderGroup NIST_2048 = new JPakePrimeOrderGroup(
+ // p
+ new BigInteger(
+ "C196BA05AC29E1F9C3C72D56DFFC6154A033F1477AC88EC37F09BE6C5BB95F51" +
+ "C296DD20D1A28A067CCC4D4316A4BD1DCA55ED1066D438C35AEBAABF57E7DAE4" +
+ "28782A95ECA1C143DB701FD48533A3C18F0FE23557EA7AE619ECACC7E0B51652" +
+ "A8776D02A425567DED36EABD90CA33A1E8D988F0BBB92D02D1D20290113BB562" +
+ "CE1FC856EEB7CDD92D33EEA6F410859B179E7E789A8F75F645FAE2E136D252BF" +
+ "FAFF89528945C1ABE705A38DBC2D364AADE99BE0D0AAD82E5320121496DC65B3" +
+ "930E38047294FF877831A16D5228418DE8AB275D7D75651CEFED65F78AFC3EA7" +
+ "FE4D79B35F62A0402A1117599ADAC7B269A59F353CF450E6982D3B1702D9CA83", 16),
+ // q
+ new BigInteger("90EAF4D1AF0708B1B612FF35E0A2997EB9E9D263C9CE659528945C0D", 16),
+ // g
+ new BigInteger(
+ "A59A749A11242C58C894E9E5A91804E8FA0AC64B56288F8D47D51B1EDC4D6544" +
+ "4FECA0111D78F35FC9FDD4CB1F1B79A3BA9CBEE83A3F811012503C8117F98E50" +
+ "48B089E387AF6949BF8784EBD9EF45876F2E6A5A495BE64B6E770409494B7FEE" +
+ "1DBB1E4B2BC2A53D4F893D418B7159592E4FFFDF6969E91D770DAEBD0B5CB14C" +
+ "00AD68EC7DC1E5745EA55C706C4A1C5C88964E34D09DEB753AD418C1AD0F4FDF" +
+ "D049A955E5D78491C0B7A2F1575A008CCD727AB376DB6E695515B05BD412F5B8" +
+ "C2F4C77EE10DA48ABD53F5DD498927EE7B692BBBCDA2FB23A516C5B4533D7398" +
+ "0B2A3B60E384ED200AE21B40D273651AD6060C13D97FD69AA13C5611A51B9085", 16),
+ true
+ );
+
+ ///
+ /// From NIST.
+ /// 3072-bit p, 256-bit q and 3072-bit g for 128-bit security.
+ ///
+ public static readonly JPakePrimeOrderGroup NIST_3072 = new JPakePrimeOrderGroup(
+ // p
+ new BigInteger(
+ "90066455B5CFC38F9CAA4A48B4281F292C260FEEF01FD61037E56258A7795A1C" +
+ "7AD46076982CE6BB956936C6AB4DCFE05E6784586940CA544B9B2140E1EB523F" +
+ "009D20A7E7880E4E5BFA690F1B9004A27811CD9904AF70420EEFD6EA11EF7DA1" +
+ "29F58835FF56B89FAA637BC9AC2EFAAB903402229F491D8D3485261CD068699B" +
+ "6BA58A1DDBBEF6DB51E8FE34E8A78E542D7BA351C21EA8D8F1D29F5D5D159394" +
+ "87E27F4416B0CA632C59EFD1B1EB66511A5A0FBF615B766C5862D0BD8A3FE7A0" +
+ "E0DA0FB2FE1FCB19E8F9996A8EA0FCCDE538175238FC8B0EE6F29AF7F642773E" +
+ "BE8CD5402415A01451A840476B2FCEB0E388D30D4B376C37FE401C2A2C2F941D" +
+ "AD179C540C1C8CE030D460C4D983BE9AB0B20F69144C1AE13F9383EA1C08504F" +
+ "B0BF321503EFE43488310DD8DC77EC5B8349B8BFE97C2C560EA878DE87C11E3D" +
+ "597F1FEA742D73EEC7F37BE43949EF1A0D15C3F3E3FC0A8335617055AC91328E" +
+ "C22B50FC15B941D3D1624CD88BC25F3E941FDDC6200689581BFEC416B4B2CB73", 16),
+ // q
+ new BigInteger("CFA0478A54717B08CE64805B76E5B14249A77A4838469DF7F7DC987EFCCFB11D", 16),
+ // g
+ new BigInteger(
+ "5E5CBA992E0A680D885EB903AEA78E4A45A469103D448EDE3B7ACCC54D521E37" +
+ "F84A4BDD5B06B0970CC2D2BBB715F7B82846F9A0C393914C792E6A923E2117AB" +
+ "805276A975AADB5261D91673EA9AAFFEECBFA6183DFCB5D3B7332AA19275AFA1" +
+ "F8EC0B60FB6F66CC23AE4870791D5982AAD1AA9485FD8F4A60126FEB2CF05DB8" +
+ "A7F0F09B3397F3937F2E90B9E5B9C9B6EFEF642BC48351C46FB171B9BFA9EF17" +
+ "A961CE96C7E7A7CC3D3D03DFAD1078BA21DA425198F07D2481622BCE45969D9C" +
+ "4D6063D72AB7A0F08B2F49A7CC6AF335E08C4720E31476B67299E231F8BD90B3" +
+ "9AC3AE3BE0C6B6CACEF8289A2E2873D58E51E029CAFBD55E6841489AB66B5B4B" +
+ "9BA6E2F784660896AFF387D92844CCB8B69475496DE19DA2E58259B090489AC8" +
+ "E62363CDF82CFD8EF2A427ABCD65750B506F56DDE3B988567A88126B914D7828" +
+ "E2B63A6D7ED0747EC59E0E0A23CE7D8A74C1D2C2A7AFB6A29799620F00E11C33" +
+ "787F7DED3B30E1A22D09F1FBDA1ABBBFBF25CAE05A13F812E34563F99410E73B", 16),
+ true
+ );
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/jpake/JPakeRound1Payload.cs b/bc-sharp-crypto/src/crypto/agreement/jpake/JPakeRound1Payload.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9e4ab7a5f6295af06cba4487049bd2285ce84c43
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/jpake/JPakeRound1Payload.cs
@@ -0,0 +1,101 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Agreement.JPake
+{
+ ///
+ /// The payload sent/received during the first round of a J-PAKE exchange.
+ ///
+ /// Each JPAKEParticipant creates and sends an instance of this payload to
+ /// the other. The payload to send should be created via
+ /// JPAKEParticipant.CreateRound1PayloadToSend().
+ ///
+ /// Each participant must also validate the payload received from the other.
+ /// The received payload should be validated via
+ /// JPAKEParticipant.ValidateRound1PayloadReceived(JPakeRound1Payload).
+ ///
+ public class JPakeRound1Payload
+ {
+ ///
+ /// The id of the JPAKEParticipant who created/sent this payload.
+ ///
+ private readonly string participantId;
+
+ ///
+ /// The value of g^x1
+ ///
+ private readonly BigInteger gx1;
+
+ ///
+ /// The value of g^x2
+ ///
+ private readonly BigInteger gx2;
+
+ ///
+ /// The zero knowledge proof for x1.
+ ///
+ /// This is a two element array, containing {g^v, r} for x1.
+ ///
+ private readonly BigInteger[] knowledgeProofForX1;
+
+ ///
+ /// The zero knowledge proof for x2.
+ ///
+ /// This is a two element array, containing {g^v, r} for x2.
+ ///
+ private readonly BigInteger[] knowledgeProofForX2;
+
+ public JPakeRound1Payload(string participantId, BigInteger gx1, BigInteger gx2, BigInteger[] knowledgeProofForX1, BigInteger[] knowledgeProofForX2)
+ {
+ JPakeUtilities.ValidateNotNull(participantId, "participantId");
+ JPakeUtilities.ValidateNotNull(gx1, "gx1");
+ JPakeUtilities.ValidateNotNull(gx2, "gx2");
+ JPakeUtilities.ValidateNotNull(knowledgeProofForX1, "knowledgeProofForX1");
+ JPakeUtilities.ValidateNotNull(knowledgeProofForX2, "knowledgeProofForX2");
+
+ this.participantId = participantId;
+ this.gx1 = gx1;
+ this.gx2 = gx2;
+ this.knowledgeProofForX1 = new BigInteger[knowledgeProofForX1.Length];
+ Array.Copy(knowledgeProofForX1, this.knowledgeProofForX1, knowledgeProofForX1.Length);
+ this.knowledgeProofForX2 = new BigInteger[knowledgeProofForX2.Length];
+ Array.Copy(knowledgeProofForX2, this.knowledgeProofForX2, knowledgeProofForX2.Length);
+ }
+
+ public virtual string ParticipantId
+ {
+ get { return participantId; }
+ }
+
+ public virtual BigInteger Gx1
+ {
+ get { return gx1; }
+ }
+
+ public virtual BigInteger Gx2
+ {
+ get { return gx2; }
+ }
+
+ public virtual BigInteger[] KnowledgeProofForX1
+ {
+ get
+ {
+ BigInteger[] kp = new BigInteger[knowledgeProofForX1.Length];
+ Array.Copy(knowledgeProofForX1, kp, knowledgeProofForX1.Length);
+ return kp;
+ }
+ }
+
+ public virtual BigInteger[] KnowledgeProofForX2
+ {
+ get
+ {
+ BigInteger[] kp = new BigInteger[knowledgeProofForX2.Length];
+ Array.Copy(knowledgeProofForX2, kp, knowledgeProofForX2.Length);
+ return kp;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/jpake/JPakeRound2Payload.cs b/bc-sharp-crypto/src/crypto/agreement/jpake/JPakeRound2Payload.cs
new file mode 100644
index 0000000000000000000000000000000000000000..47962cb3ff201d05dff656c6e5cc0cd5d81e1373
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/jpake/JPakeRound2Payload.cs
@@ -0,0 +1,72 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Agreement.JPake
+{
+ ///
+ /// The payload sent/received during the second round of a J-PAKE exchange.
+ ///
+ /// Each JPAKEParticipant creates and sends an instance
+ /// of this payload to the other JPAKEParticipant.
+ /// The payload to send should be created via
+ /// JPAKEParticipant#createRound2PayloadToSend()
+ ///
+ /// Each JPAKEParticipant must also validate the payload
+ /// received from the other JPAKEParticipant.
+ /// The received payload should be validated via
+ /// JPAKEParticipant#validateRound2PayloadReceived(JPakeRound2Payload)
+ ///
+ public class JPakeRound2Payload
+ {
+ ///
+ /// The id of the JPAKEParticipant who created/sent this payload.
+ ///
+ private readonly string participantId;
+
+ ///
+ /// The value of A, as computed during round 2.
+ ///
+ private readonly BigInteger a;
+
+ ///
+ /// The zero knowledge proof for x2 * s.
+ ///
+ /// This is a two element array, containing {g^v, r} for x2 * s.
+ ///
+ private readonly BigInteger[] knowledgeProofForX2s;
+
+ public JPakeRound2Payload(string participantId, BigInteger a, BigInteger[] knowledgeProofForX2s)
+ {
+ JPakeUtilities.ValidateNotNull(participantId, "participantId");
+ JPakeUtilities.ValidateNotNull(a, "a");
+ JPakeUtilities.ValidateNotNull(knowledgeProofForX2s, "knowledgeProofForX2s");
+
+ this.participantId = participantId;
+ this.a = a;
+ this.knowledgeProofForX2s = new BigInteger[knowledgeProofForX2s.Length];
+ knowledgeProofForX2s.CopyTo(this.knowledgeProofForX2s, 0);
+ }
+
+ public virtual string ParticipantId
+ {
+ get { return participantId; }
+ }
+
+ public virtual BigInteger A
+ {
+ get { return a; }
+ }
+
+ public virtual BigInteger[] KnowledgeProofForX2s
+ {
+ get
+ {
+ BigInteger[] kp = new BigInteger[knowledgeProofForX2s.Length];
+ Array.Copy(knowledgeProofForX2s, kp, knowledgeProofForX2s.Length);
+ return kp;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/jpake/JPakeRound3Payload.cs b/bc-sharp-crypto/src/crypto/agreement/jpake/JPakeRound3Payload.cs
new file mode 100644
index 0000000000000000000000000000000000000000..767702f23699acdaba1bbe99eece56d1b9805d48
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/jpake/JPakeRound3Payload.cs
@@ -0,0 +1,51 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Agreement.JPake
+{
+ ///
+ /// The payload sent/received during the optional third round of a J-PAKE exchange,
+ /// which is for explicit key confirmation.
+ ///
+ /// Each JPAKEParticipant creates and sends an instance
+ /// of this payload to the other JPAKEParticipant.
+ /// The payload to send should be created via
+ /// JPAKEParticipant#createRound3PayloadToSend(BigInteger)
+ ///
+ /// Eeach JPAKEParticipant must also validate the payload
+ /// received from the other JPAKEParticipant.
+ /// The received payload should be validated via
+ /// JPAKEParticipant#validateRound3PayloadReceived(JPakeRound3Payload, BigInteger)
+ ///
+ public class JPakeRound3Payload
+ {
+ ///
+ /// The id of the {@link JPAKEParticipant} who created/sent this payload.
+ ///
+ private readonly string participantId;
+
+ ///
+ /// The value of MacTag, as computed by round 3.
+ ///
+ /// See JPAKEUtil#calculateMacTag(string, string, BigInteger, BigInteger, BigInteger, BigInteger, BigInteger, org.bouncycastle.crypto.Digest)
+ ///
+ private readonly BigInteger macTag;
+
+ public JPakeRound3Payload(string participantId, BigInteger magTag)
+ {
+ this.participantId = participantId;
+ this.macTag = magTag;
+ }
+
+ public virtual string ParticipantId
+ {
+ get { return participantId; }
+ }
+
+ public virtual BigInteger MacTag
+ {
+ get { return macTag; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/jpake/JPakeUtilities.cs b/bc-sharp-crypto/src/crypto/agreement/jpake/JPakeUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b23518a8c76f69391d4580929cd747405da345f2
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/jpake/JPakeUtilities.cs
@@ -0,0 +1,390 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Agreement.JPake
+{
+ ///
+ /// Primitives needed for a J-PAKE exchange.
+ ///
+ /// The recommended way to perform a J-PAKE exchange is by using
+ /// two JPAKEParticipants. Internally, those participants
+ /// call these primitive operations in JPakeUtilities.
+ ///
+ /// The primitives, however, can be used without a JPAKEParticipant if needed.
+ ///
+ public abstract class JPakeUtilities
+ {
+ public static readonly BigInteger Zero = BigInteger.Zero;
+ public static readonly BigInteger One = BigInteger.One;
+
+ ///
+ /// Return a value that can be used as x1 or x3 during round 1.
+ /// The returned value is a random value in the range [0, q-1].
+ ///
+ public static BigInteger GenerateX1(BigInteger q, SecureRandom random)
+ {
+ BigInteger min = Zero;
+ BigInteger max = q.Subtract(One);
+ return BigIntegers.CreateRandomInRange(min, max, random);
+ }
+
+ ///
+ /// Return a value that can be used as x2 or x4 during round 1.
+ /// The returned value is a random value in the range [1, q-1].
+ ///
+ public static BigInteger GenerateX2(BigInteger q, SecureRandom random)
+ {
+ BigInteger min = One;
+ BigInteger max = q.Subtract(One);
+ return BigIntegers.CreateRandomInRange(min, max, random);
+ }
+
+ ///
+ /// Converts the given password to a BigInteger
+ /// for use in arithmetic calculations.
+ ///
+ public static BigInteger CalculateS(char[] password)
+ {
+ return new BigInteger(Encoding.UTF8.GetBytes(password));
+ }
+
+ ///
+ /// Calculate g^x mod p as done in round 1.
+ ///
+ public static BigInteger CalculateGx(BigInteger p, BigInteger g, BigInteger x)
+ {
+ return g.ModPow(x, p);
+ }
+
+ ///
+ /// Calculate ga as done in round 2.
+ ///
+ public static BigInteger CalculateGA(BigInteger p, BigInteger gx1, BigInteger gx3, BigInteger gx4)
+ {
+ // ga = g^(x1+x3+x4) = g^x1 * g^x3 * g^x4
+ return gx1.Multiply(gx3).Multiply(gx4).Mod(p);
+ }
+
+ ///
+ /// Calculate x2 * s as done in round 2.
+ ///
+ public static BigInteger CalculateX2s(BigInteger q, BigInteger x2, BigInteger s)
+ {
+ return x2.Multiply(s).Mod(q);
+ }
+
+ ///
+ /// Calculate A as done in round 2.
+ ///
+ public static BigInteger CalculateA(BigInteger p, BigInteger q, BigInteger gA, BigInteger x2s)
+ {
+ // A = ga^(x*s)
+ return gA.ModPow(x2s, p);
+ }
+
+ ///
+ /// Calculate a zero knowledge proof of x using Schnorr's signature.
+ /// The returned array has two elements {g^v, r = v-x*h} for x.
+ ///
+ public static BigInteger[] CalculateZeroKnowledgeProof(BigInteger p, BigInteger q, BigInteger g,
+ BigInteger gx, BigInteger x, string participantId, IDigest digest, SecureRandom random)
+ {
+ /* Generate a random v, and compute g^v */
+ BigInteger vMin = Zero;
+ BigInteger vMax = q.Subtract(One);
+ BigInteger v = BigIntegers.CreateRandomInRange(vMin, vMax, random);
+
+ BigInteger gv = g.ModPow(v, p);
+ BigInteger h = CalculateHashForZeroKnowledgeProof(g, gv, gx, participantId, digest); // h
+
+ return new BigInteger[]
+ {
+ gv,
+ v.Subtract(x.Multiply(h)).Mod(q) // r = v-x*h
+ };
+ }
+
+ private static BigInteger CalculateHashForZeroKnowledgeProof(BigInteger g, BigInteger gr, BigInteger gx,
+ string participantId, IDigest digest)
+ {
+ digest.Reset();
+
+ UpdateDigestIncludingSize(digest, g);
+
+ UpdateDigestIncludingSize(digest, gr);
+
+ UpdateDigestIncludingSize(digest, gx);
+
+ UpdateDigestIncludingSize(digest, participantId);
+
+ byte[] output = DigestUtilities.DoFinal(digest);
+
+ return new BigInteger(output);
+ }
+
+ ///
+ /// Validates that g^x4 is not 1.
+ /// throws CryptoException if g^x4 is 1
+ ///
+ public static void ValidateGx4(BigInteger gx4)
+ {
+ if (gx4.Equals(One))
+ throw new CryptoException("g^x validation failed. g^x should not be 1.");
+ }
+
+ ///
+ /// Validates that ga is not 1.
+ ///
+ /// As described by Feng Hao...
+ /// Alice could simply check ga != 1 to ensure it is a generator.
+ /// In fact, as we will explain in Section 3, (x1 + x3 + x4 ) is random over Zq even in the face of active attacks.
+ /// Hence, the probability for ga = 1 is extremely small - on the order of 2^160 for 160-bit q.
+ ///
+ /// throws CryptoException if ga is 1
+ ///
+ public static void ValidateGa(BigInteger ga)
+ {
+ if (ga.Equals(One))
+ throw new CryptoException("ga is equal to 1. It should not be. The chances of this happening are on the order of 2^160 for a 160-bit q. Try again.");
+ }
+
+ ///
+ /// Validates the zero knowledge proof (generated by
+ /// calculateZeroKnowledgeProof(BigInteger, BigInteger, BigInteger, BigInteger, BigInteger, string, Digest, SecureRandom)
+ /// is correct.
+ ///
+ /// throws CryptoException if the zero knowledge proof is not correct
+ ///
+ public static void ValidateZeroKnowledgeProof(BigInteger p, BigInteger q, BigInteger g,
+ BigInteger gx, BigInteger[] zeroKnowledgeProof, string participantId, IDigest digest)
+ {
+ /* sig={g^v,r} */
+ BigInteger gv = zeroKnowledgeProof[0];
+ BigInteger r = zeroKnowledgeProof[1];
+
+ BigInteger h = CalculateHashForZeroKnowledgeProof(g, gv, gx, participantId, digest);
+ if (!(gx.CompareTo(Zero) == 1 && // g^x > 0
+ gx.CompareTo(p) == -1 && // g^x < p
+ gx.ModPow(q, p).CompareTo(One) == 0 && // g^x^q mod q = 1
+ /*
+ * Below, I took a straightforward way to compute g^r * g^x^h,
+ * which needs 2 exp. Using a simultaneous computation technique
+ * would only need 1 exp.
+ */
+ g.ModPow(r, p).Multiply(gx.ModPow(h, p)).Mod(p).CompareTo(gv) == 0)) // g^v=g^r * g^x^h
+ {
+ throw new CryptoException("Zero-knowledge proof validation failed");
+ }
+ }
+
+ ///
+ /// Calculates the keying material, which can be done after round 2 has completed.
+ /// A session key must be derived from this key material using a secure key derivation function (KDF).
+ /// The KDF used to derive the key is handled externally (i.e. not by JPAKEParticipant).
+ ///
+ /// KeyingMaterial = (B/g^{x2*x4*s})^x2
+ ///
+ public static BigInteger CalculateKeyingMaterial(BigInteger p, BigInteger q,
+ BigInteger gx4, BigInteger x2, BigInteger s, BigInteger B)
+ {
+ return gx4.ModPow(x2.Multiply(s).Negate().Mod(q), p).Multiply(B).ModPow(x2, p);
+ }
+
+ ///
+ /// Validates that the given participant ids are not equal.
+ /// (For the J-PAKE exchange, each participant must use a unique id.)
+ ///
+ /// Throws CryptoException if the participantId strings are equal.
+ ///
+ public static void ValidateParticipantIdsDiffer(string participantId1, string participantId2)
+ {
+ if (participantId1.Equals(participantId2))
+ {
+ throw new CryptoException(
+ "Both participants are using the same participantId ("
+ + participantId1
+ + "). This is not allowed. "
+ + "Each participant must use a unique participantId.");
+ }
+ }
+
+ ///
+ /// Validates that the given participant ids are equal.
+ /// This is used to ensure that the payloads received from
+ /// each round all come from the same participant.
+ ///
+ public static void ValidateParticipantIdsEqual(string expectedParticipantId, string actualParticipantId)
+ {
+ if (!expectedParticipantId.Equals(actualParticipantId))
+ {
+ throw new CryptoException(
+ "Received payload from incorrect partner ("
+ + actualParticipantId
+ + "). Expected to receive payload from "
+ + expectedParticipantId
+ + ".");
+ }
+ }
+
+ ///
+ /// Validates that the given object is not null.
+ /// throws NullReferenceException if the object is null.
+ ///
+ /// object in question
+ /// name of the object (to be used in exception message)
+ public static void ValidateNotNull(object obj, string description)
+ {
+ if (obj == null)
+ throw new ArgumentNullException(description);
+ }
+
+ ///
+ /// Calculates the MacTag (to be used for key confirmation), as defined by
+ /// NIST SP 800-56A Revision 1 ,
+ /// Section 8.2 Unilateral Key Confirmation for Key Agreement Schemes.
+ ///
+ /// MacTag = HMAC(MacKey, MacLen, MacData)
+ /// MacKey = H(K || "JPAKE_KC")
+ /// MacData = "KC_1_U" || participantId || partnerParticipantId || gx1 || gx2 || gx3 || gx4
+ ///
+ /// Note that both participants use "KC_1_U" because the sender of the round 3 message
+ /// is always the initiator for key confirmation.
+ ///
+ /// HMAC = {@link HMac} used with the given {@link Digest}
+ /// H = The given {@link Digest}
+ /// MacLen = length of MacTag
+ ///
+ public static BigInteger CalculateMacTag(string participantId, string partnerParticipantId,
+ BigInteger gx1, BigInteger gx2, BigInteger gx3, BigInteger gx4, BigInteger keyingMaterial, IDigest digest)
+ {
+ byte[] macKey = CalculateMacKey(keyingMaterial, digest);
+
+ HMac mac = new HMac(digest);
+ mac.Init(new KeyParameter(macKey));
+ Arrays.Fill(macKey, (byte)0);
+
+ /*
+ * MacData = "KC_1_U" || participantId_Alice || participantId_Bob || gx1 || gx2 || gx3 || gx4.
+ */
+ UpdateMac(mac, "KC_1_U");
+ UpdateMac(mac, participantId);
+ UpdateMac(mac, partnerParticipantId);
+ UpdateMac(mac, gx1);
+ UpdateMac(mac, gx2);
+ UpdateMac(mac, gx3);
+ UpdateMac(mac, gx4);
+
+ byte[] macOutput = MacUtilities.DoFinal(mac);
+
+ return new BigInteger(macOutput);
+ }
+
+ ///
+ /// Calculates the MacKey (i.e. the key to use when calculating the MagTag for key confirmation).
+ ///
+ /// MacKey = H(K || "JPAKE_KC")
+ ///
+ private static byte[] CalculateMacKey(BigInteger keyingMaterial, IDigest digest)
+ {
+ digest.Reset();
+
+ UpdateDigest(digest, keyingMaterial);
+ /*
+ * This constant is used to ensure that the macKey is NOT the same as the derived key.
+ */
+ UpdateDigest(digest, "JPAKE_KC");
+
+ return DigestUtilities.DoFinal(digest);
+ }
+
+ ///
+ /// Validates the MacTag received from the partner participant.
+ ///
+ /// throws CryptoException if the participantId strings are equal.
+ ///
+ public static void ValidateMacTag(string participantId, string partnerParticipantId,
+ BigInteger gx1, BigInteger gx2, BigInteger gx3, BigInteger gx4,
+ BigInteger keyingMaterial, IDigest digest, BigInteger partnerMacTag)
+ {
+ /*
+ * Calculate the expected MacTag using the parameters as the partner
+ * would have used when the partner called calculateMacTag.
+ *
+ * i.e. basically all the parameters are reversed.
+ * participantId <-> partnerParticipantId
+ * x1 <-> x3
+ * x2 <-> x4
+ */
+ BigInteger expectedMacTag = CalculateMacTag(partnerParticipantId, participantId, gx3, gx4, gx1, gx2, keyingMaterial, digest);
+
+ if (!expectedMacTag.Equals(partnerMacTag))
+ {
+ throw new CryptoException(
+ "Partner MacTag validation failed. "
+ + "Therefore, the password, MAC, or digest algorithm of each participant does not match.");
+ }
+ }
+
+ private static void UpdateDigest(IDigest digest, BigInteger bigInteger)
+ {
+ UpdateDigest(digest, BigIntegers.AsUnsignedByteArray(bigInteger));
+ }
+
+ private static void UpdateDigest(IDigest digest, string str)
+ {
+ UpdateDigest(digest, Encoding.UTF8.GetBytes(str));
+ }
+
+ private static void UpdateDigest(IDigest digest, byte[] bytes)
+ {
+ digest.BlockUpdate(bytes, 0, bytes.Length);
+ Arrays.Fill(bytes, (byte)0);
+ }
+
+ private static void UpdateDigestIncludingSize(IDigest digest, BigInteger bigInteger)
+ {
+ UpdateDigestIncludingSize(digest, BigIntegers.AsUnsignedByteArray(bigInteger));
+ }
+
+ private static void UpdateDigestIncludingSize(IDigest digest, string str)
+ {
+ UpdateDigestIncludingSize(digest, Encoding.UTF8.GetBytes(str));
+ }
+
+ private static void UpdateDigestIncludingSize(IDigest digest, byte[] bytes)
+ {
+ digest.BlockUpdate(IntToByteArray(bytes.Length), 0, 4);
+ digest.BlockUpdate(bytes, 0, bytes.Length);
+ Arrays.Fill(bytes, (byte)0);
+ }
+
+ private static void UpdateMac(IMac mac, BigInteger bigInteger)
+ {
+ UpdateMac(mac, BigIntegers.AsUnsignedByteArray(bigInteger));
+ }
+
+ private static void UpdateMac(IMac mac, string str)
+ {
+ UpdateMac(mac, Encoding.UTF8.GetBytes(str));
+ }
+
+ private static void UpdateMac(IMac mac, byte[] bytes)
+ {
+ mac.BlockUpdate(bytes, 0, bytes.Length);
+ Arrays.Fill(bytes, (byte)0);
+ }
+
+ private static byte[] IntToByteArray(int value)
+ {
+ return Pack.UInt32_To_BE((uint)value);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/kdf/DHKdfParameters.cs b/bc-sharp-crypto/src/crypto/agreement/kdf/DHKdfParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f6c9e6079abdb6474a0ac38ce42583b7b2489946
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/kdf/DHKdfParameters.cs
@@ -0,0 +1,57 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Crypto.Agreement.Kdf
+{
+ public class DHKdfParameters
+ : IDerivationParameters
+ {
+ private readonly DerObjectIdentifier algorithm;
+ private readonly int keySize;
+ private readonly byte[] z;
+ private readonly byte[] extraInfo;
+
+ public DHKdfParameters(
+ DerObjectIdentifier algorithm,
+ int keySize,
+ byte[] z)
+ : this(algorithm, keySize, z, null)
+ {
+ }
+
+ public DHKdfParameters(
+ DerObjectIdentifier algorithm,
+ int keySize,
+ byte[] z,
+ byte[] extraInfo)
+ {
+ this.algorithm = algorithm;
+ this.keySize = keySize;
+ this.z = z; // TODO Clone?
+ this.extraInfo = extraInfo;
+ }
+
+ public DerObjectIdentifier Algorithm
+ {
+ get { return algorithm; }
+ }
+
+ public int KeySize
+ {
+ get { return keySize; }
+ }
+
+ public byte[] GetZ()
+ {
+ // TODO Clone?
+ return z;
+ }
+
+ public byte[] GetExtraInfo()
+ {
+ // TODO Clone?
+ return extraInfo;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/kdf/DHKekGenerator.cs b/bc-sharp-crypto/src/crypto/agreement/kdf/DHKekGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..259e21e69f58db4ac55f9edbeea098623868ec28
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/kdf/DHKekGenerator.cs
@@ -0,0 +1,112 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Agreement.Kdf
+{
+ /**
+ * RFC 2631 Diffie-hellman KEK derivation function.
+ */
+ public class DHKekGenerator
+ : IDerivationFunction
+ {
+ private readonly IDigest digest;
+
+ private DerObjectIdentifier algorithm;
+ private int keySize;
+ private byte[] z;
+ private byte[] partyAInfo;
+
+ public DHKekGenerator(IDigest digest)
+ {
+ this.digest = digest;
+ }
+
+ public virtual void Init(IDerivationParameters param)
+ {
+ DHKdfParameters parameters = (DHKdfParameters)param;
+
+ this.algorithm = parameters.Algorithm;
+ this.keySize = parameters.KeySize;
+ this.z = parameters.GetZ(); // TODO Clone?
+ this.partyAInfo = parameters.GetExtraInfo(); // TODO Clone?
+ }
+
+ public virtual IDigest Digest
+ {
+ get { return digest; }
+ }
+
+ public virtual int GenerateBytes(byte[] outBytes, int outOff, int len)
+ {
+ if ((outBytes.Length - len) < outOff)
+ {
+ throw new DataLengthException("output buffer too small");
+ }
+
+ long oBytes = len;
+ int outLen = digest.GetDigestSize();
+
+ //
+ // this is at odds with the standard implementation, the
+ // maximum value should be hBits * (2^32 - 1) where hBits
+ // is the digest output size in bits. We can't have an
+ // array with a long index at the moment...
+ //
+ if (oBytes > ((2L << 32) - 1))
+ {
+ throw new ArgumentException("Output length too large");
+ }
+
+ int cThreshold = (int)((oBytes + outLen - 1) / outLen);
+
+ byte[] dig = new byte[digest.GetDigestSize()];
+
+ uint counter = 1;
+
+ for (int i = 0; i < cThreshold; i++)
+ {
+ digest.BlockUpdate(z, 0, z.Length);
+
+ // KeySpecificInfo
+ DerSequence keyInfo = new DerSequence(
+ algorithm,
+ new DerOctetString(Pack.UInt32_To_BE(counter)));
+
+ // OtherInfo
+ Asn1EncodableVector v1 = new Asn1EncodableVector(keyInfo);
+
+ if (partyAInfo != null)
+ {
+ v1.Add(new DerTaggedObject(true, 0, new DerOctetString(partyAInfo)));
+ }
+
+ v1.Add(new DerTaggedObject(true, 2, new DerOctetString(Pack.UInt32_To_BE((uint)keySize))));
+
+ byte[] other = new DerSequence(v1).GetDerEncoded();
+
+ digest.BlockUpdate(other, 0, other.Length);
+
+ digest.DoFinal(dig, 0);
+
+ if (len > outLen)
+ {
+ Array.Copy(dig, 0, outBytes, outOff, outLen);
+ outOff += outLen;
+ len -= outLen;
+ }
+ else
+ {
+ Array.Copy(dig, 0, outBytes, outOff, len);
+ }
+
+ counter++;
+ }
+
+ digest.Reset();
+
+ return (int)oBytes;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/kdf/ECDHKekGenerator.cs b/bc-sharp-crypto/src/crypto/agreement/kdf/ECDHKekGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..74464574ca1f6562a8e3992b26d4e2d765d20ac2
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/kdf/ECDHKekGenerator.cs
@@ -0,0 +1,55 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Agreement.Kdf
+{
+ /**
+ * X9.63 based key derivation function for ECDH CMS.
+ */
+ public class ECDHKekGenerator
+ : IDerivationFunction
+ {
+ private readonly IDerivationFunction kdf;
+
+ private DerObjectIdentifier algorithm;
+ private int keySize;
+ private byte[] z;
+
+ public ECDHKekGenerator(IDigest digest)
+ {
+ this.kdf = new Kdf2BytesGenerator(digest);
+ }
+
+ public virtual void Init(IDerivationParameters param)
+ {
+ DHKdfParameters parameters = (DHKdfParameters)param;
+
+ this.algorithm = parameters.Algorithm;
+ this.keySize = parameters.KeySize;
+ this.z = parameters.GetZ(); // TODO Clone?
+ }
+
+ public virtual IDigest Digest
+ {
+ get { return kdf.Digest; }
+ }
+
+ public virtual int GenerateBytes(byte[] outBytes, int outOff, int len)
+ {
+ // TODO Create an ASN.1 class for this (RFC3278)
+ // ECC-CMS-SharedInfo
+ DerSequence s = new DerSequence(
+ new AlgorithmIdentifier(algorithm, DerNull.Instance),
+ new DerTaggedObject(true, 2, new DerOctetString(Pack.UInt32_To_BE((uint)keySize))));
+
+ kdf.Init(new KdfParameters(z, s.GetDerEncoded()));
+
+ return kdf.GenerateBytes(outBytes, outOff, len);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/srp/SRP6Client.cs b/bc-sharp-crypto/src/crypto/agreement/srp/SRP6Client.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f075d7ad1c58962c10bd22ea7b3724ca3cf37a45
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/srp/SRP6Client.cs
@@ -0,0 +1,164 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Agreement.Srp
+{
+ /**
+ * Implements the client side SRP-6a protocol. Note that this class is stateful, and therefore NOT threadsafe.
+ * This implementation of SRP is based on the optimized message sequence put forth by Thomas Wu in the paper
+ * "SRP-6: Improvements and Refinements to the Secure Remote Password Protocol, 2002"
+ */
+ public class Srp6Client
+ {
+ protected BigInteger N;
+ protected BigInteger g;
+
+ protected BigInteger privA;
+ protected BigInteger pubA;
+
+ protected BigInteger B;
+
+ protected BigInteger x;
+ protected BigInteger u;
+ protected BigInteger S;
+
+ protected BigInteger M1;
+ protected BigInteger M2;
+ protected BigInteger Key;
+
+ protected IDigest digest;
+ protected SecureRandom random;
+
+ public Srp6Client()
+ {
+ }
+
+ /**
+ * Initialises the client to begin new authentication attempt
+ * @param N The safe prime associated with the client's verifier
+ * @param g The group parameter associated with the client's verifier
+ * @param digest The digest algorithm associated with the client's verifier
+ * @param random For key generation
+ */
+ public virtual void Init(BigInteger N, BigInteger g, IDigest digest, SecureRandom random)
+ {
+ this.N = N;
+ this.g = g;
+ this.digest = digest;
+ this.random = random;
+ }
+
+ public virtual void Init(Srp6GroupParameters group, IDigest digest, SecureRandom random)
+ {
+ Init(group.N, group.G, digest, random);
+ }
+
+ /**
+ * Generates client's credentials given the client's salt, identity and password
+ * @param salt The salt used in the client's verifier.
+ * @param identity The user's identity (eg. username)
+ * @param password The user's password
+ * @return Client's public value to send to server
+ */
+ public virtual BigInteger GenerateClientCredentials(byte[] salt, byte[] identity, byte[] password)
+ {
+ this.x = Srp6Utilities.CalculateX(digest, N, salt, identity, password);
+ this.privA = SelectPrivateValue();
+ this.pubA = g.ModPow(privA, N);
+
+ return pubA;
+ }
+
+ /**
+ * Generates client's verification message given the server's credentials
+ * @param serverB The server's credentials
+ * @return Client's verification message for the server
+ * @throws CryptoException If server's credentials are invalid
+ */
+ public virtual BigInteger CalculateSecret(BigInteger serverB)
+ {
+ this.B = Srp6Utilities.ValidatePublicValue(N, serverB);
+ this.u = Srp6Utilities.CalculateU(digest, N, pubA, B);
+ this.S = CalculateS();
+
+ return S;
+ }
+
+ protected virtual BigInteger SelectPrivateValue()
+ {
+ return Srp6Utilities.GeneratePrivateValue(digest, N, g, random);
+ }
+
+ private BigInteger CalculateS()
+ {
+ BigInteger k = Srp6Utilities.CalculateK(digest, N, g);
+ BigInteger exp = u.Multiply(x).Add(privA);
+ BigInteger tmp = g.ModPow(x, N).Multiply(k).Mod(N);
+ return B.Subtract(tmp).Mod(N).ModPow(exp, N);
+ }
+
+ /**
+ * Computes the client evidence message M1 using the previously received values.
+ * To be called after calculating the secret S.
+ * @return M1: the client side generated evidence message
+ * @throws CryptoException
+ */
+ public virtual BigInteger CalculateClientEvidenceMessage()
+ {
+ // Verify pre-requirements
+ if (this.pubA == null || this.B == null || this.S == null)
+ {
+ throw new CryptoException("Impossible to compute M1: " +
+ "some data are missing from the previous operations (A,B,S)");
+ }
+ // compute the client evidence message 'M1'
+ this.M1 = Srp6Utilities.CalculateM1(digest, N, pubA, B, S);
+ return M1;
+ }
+
+ /** Authenticates the server evidence message M2 received and saves it only if correct.
+ * @param M2: the server side generated evidence message
+ * @return A boolean indicating if the server message M2 was the expected one.
+ * @throws CryptoException
+ */
+ public virtual bool VerifyServerEvidenceMessage(BigInteger serverM2)
+ {
+ // Verify pre-requirements
+ if (this.pubA == null || this.M1 == null || this.S == null)
+ {
+ throw new CryptoException("Impossible to compute and verify M2: " +
+ "some data are missing from the previous operations (A,M1,S)");
+ }
+
+ // Compute the own server evidence message 'M2'
+ BigInteger computedM2 = Srp6Utilities.CalculateM2(digest, N, pubA, M1, S);
+ if (computedM2.Equals(serverM2))
+ {
+ this.M2 = serverM2;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Computes the final session key as a result of the SRP successful mutual authentication
+ * To be called after verifying the server evidence message M2.
+ * @return Key: the mutually authenticated symmetric session key
+ * @throws CryptoException
+ */
+ public virtual BigInteger CalculateSessionKey()
+ {
+ // Verify pre-requirements (here we enforce a previous calculation of M1 and M2)
+ if (this.S == null || this.M1 == null || this.M2 == null)
+ {
+ throw new CryptoException("Impossible to compute Key: " +
+ "some data are missing from the previous operations (S,M1,M2)");
+ }
+ this.Key = Srp6Utilities.CalculateKey(digest, N, S);
+ return Key;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/srp/SRP6Server.cs b/bc-sharp-crypto/src/crypto/agreement/srp/SRP6Server.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fd0c9f1cb9063fbadd9e5f3bb1aa8ffa7cf841a0
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/srp/SRP6Server.cs
@@ -0,0 +1,163 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Agreement.Srp
+{
+ /**
+ * Implements the server side SRP-6a protocol. Note that this class is stateful, and therefore NOT threadsafe.
+ * This implementation of SRP is based on the optimized message sequence put forth by Thomas Wu in the paper
+ * "SRP-6: Improvements and Refinements to the Secure Remote Password Protocol, 2002"
+ */
+ public class Srp6Server
+ {
+ protected BigInteger N;
+ protected BigInteger g;
+ protected BigInteger v;
+
+ protected SecureRandom random;
+ protected IDigest digest;
+
+ protected BigInteger A;
+
+ protected BigInteger privB;
+ protected BigInteger pubB;
+
+ protected BigInteger u;
+ protected BigInteger S;
+ protected BigInteger M1;
+ protected BigInteger M2;
+ protected BigInteger Key;
+
+ public Srp6Server()
+ {
+ }
+
+ /**
+ * Initialises the server to accept a new client authentication attempt
+ * @param N The safe prime associated with the client's verifier
+ * @param g The group parameter associated with the client's verifier
+ * @param v The client's verifier
+ * @param digest The digest algorithm associated with the client's verifier
+ * @param random For key generation
+ */
+ public virtual void Init(BigInteger N, BigInteger g, BigInteger v, IDigest digest, SecureRandom random)
+ {
+ this.N = N;
+ this.g = g;
+ this.v = v;
+
+ this.random = random;
+ this.digest = digest;
+ }
+
+ public virtual void Init(Srp6GroupParameters group, BigInteger v, IDigest digest, SecureRandom random)
+ {
+ Init(group.N, group.G, v, digest, random);
+ }
+
+ /**
+ * Generates the server's credentials that are to be sent to the client.
+ * @return The server's public value to the client
+ */
+ public virtual BigInteger GenerateServerCredentials()
+ {
+ BigInteger k = Srp6Utilities.CalculateK(digest, N, g);
+ this.privB = SelectPrivateValue();
+ this.pubB = k.Multiply(v).Mod(N).Add(g.ModPow(privB, N)).Mod(N);
+
+ return pubB;
+ }
+
+ /**
+ * Processes the client's credentials. If valid the shared secret is generated and returned.
+ * @param clientA The client's credentials
+ * @return A shared secret BigInteger
+ * @throws CryptoException If client's credentials are invalid
+ */
+ public virtual BigInteger CalculateSecret(BigInteger clientA)
+ {
+ this.A = Srp6Utilities.ValidatePublicValue(N, clientA);
+ this.u = Srp6Utilities.CalculateU(digest, N, A, pubB);
+ this.S = CalculateS();
+
+ return S;
+ }
+
+ protected virtual BigInteger SelectPrivateValue()
+ {
+ return Srp6Utilities.GeneratePrivateValue(digest, N, g, random);
+ }
+
+ private BigInteger CalculateS()
+ {
+ return v.ModPow(u, N).Multiply(A).Mod(N).ModPow(privB, N);
+ }
+
+ /**
+ * Authenticates the received client evidence message M1 and saves it only if correct.
+ * To be called after calculating the secret S.
+ * @param M1: the client side generated evidence message
+ * @return A boolean indicating if the client message M1 was the expected one.
+ * @throws CryptoException
+ */
+ public virtual bool VerifyClientEvidenceMessage(BigInteger clientM1)
+ {
+ // Verify pre-requirements
+ if (this.A == null || this.pubB == null || this.S == null)
+ {
+ throw new CryptoException("Impossible to compute and verify M1: " +
+ "some data are missing from the previous operations (A,B,S)");
+ }
+
+ // Compute the own client evidence message 'M1'
+ BigInteger computedM1 = Srp6Utilities.CalculateM1(digest, N, A, pubB, S);
+ if (computedM1.Equals(clientM1))
+ {
+ this.M1 = clientM1;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Computes the server evidence message M2 using the previously verified values.
+ * To be called after successfully verifying the client evidence message M1.
+ * @return M2: the server side generated evidence message
+ * @throws CryptoException
+ */
+ public virtual BigInteger CalculateServerEvidenceMessage()
+ {
+ // Verify pre-requirements
+ if (this.A == null || this.M1 == null || this.S == null)
+ {
+ throw new CryptoException("Impossible to compute M2: " +
+ "some data are missing from the previous operations (A,M1,S)");
+ }
+
+ // Compute the server evidence message 'M2'
+ this.M2 = Srp6Utilities.CalculateM2(digest, N, A, M1, S);
+ return M2;
+ }
+
+ /**
+ * Computes the final session key as a result of the SRP successful mutual authentication
+ * To be called after calculating the server evidence message M2.
+ * @return Key: the mutual authenticated symmetric session key
+ * @throws CryptoException
+ */
+ public virtual BigInteger CalculateSessionKey()
+ {
+ // Verify pre-requirements
+ if (this.S == null || this.M1 == null || this.M2 == null)
+ {
+ throw new CryptoException("Impossible to compute Key: " +
+ "some data are missing from the previous operations (S,M1,M2)");
+ }
+ this.Key = Srp6Utilities.CalculateKey(digest, N, S);
+ return Key;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/srp/SRP6StandardGroups.cs b/bc-sharp-crypto/src/crypto/agreement/srp/SRP6StandardGroups.cs
new file mode 100644
index 0000000000000000000000000000000000000000..36f4aba111565dda4cd575d9efb2fcf51c7e2195
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/srp/SRP6StandardGroups.cs
@@ -0,0 +1,159 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Agreement.Srp
+{
+ public class Srp6StandardGroups
+ {
+ private static BigInteger FromHex(string hex)
+ {
+ return new BigInteger(1, Hex.Decode(hex));
+ }
+
+ private static Srp6GroupParameters FromNG(string hexN, string hexG)
+ {
+ return new Srp6GroupParameters(FromHex(hexN), FromHex(hexG));
+ }
+
+ /*
+ * RFC 5054
+ */
+ private const string rfc5054_1024_N = "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
+ + "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
+ + "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
+ + "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A" + "FD5138FE8376435B9FC61D2FC0EB06E3";
+ private const string rfc5054_1024_g = "02";
+ public static readonly Srp6GroupParameters rfc5054_1024 = FromNG(rfc5054_1024_N, rfc5054_1024_g);
+
+ private const string rfc5054_1536_N = "9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA961"
+ + "4B19CC4D5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F843"
+ + "80B655BB9A22E8DCDF028A7CEC67F0D08134B1C8B97989149B609E0B"
+ + "E3BAB63D47548381DBC5B1FC764E3F4B53DD9DA1158BFD3E2B9C8CF5"
+ + "6EDF019539349627DB2FD53D24B7C48665772E437D6C7F8CE442734A"
+ + "F7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E5A021FFF5E91479E"
+ + "8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB";
+ private const string rfc5054_1536_g = "02";
+ public static readonly Srp6GroupParameters rfc5054_1536 = FromNG(rfc5054_1536_N, rfc5054_1536_g);
+
+ private const string rfc5054_2048_N = "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC319294"
+ + "3DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310D"
+ + "CD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FB"
+ + "D5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF74"
+ + "7359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A"
+ + "436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D"
+ + "5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E73"
+ + "03CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB6"
+ + "94B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F" + "9E4AFF73";
+ private const string rfc5054_2048_g = "02";
+ public static readonly Srp6GroupParameters rfc5054_2048 = FromNG(rfc5054_2048_N, rfc5054_2048_g);
+
+ private const string rfc5054_3072_N = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
+ + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
+ + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
+ + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
+ + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
+ + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
+ + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
+ + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
+ + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
+ + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
+ + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+ + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + "E0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF";
+ private const string rfc5054_3072_g = "05";
+ public static readonly Srp6GroupParameters rfc5054_3072 = FromNG(rfc5054_3072_N, rfc5054_3072_g);
+
+ private const string rfc5054_4096_N = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
+ + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
+ + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
+ + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
+ + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
+ + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
+ + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
+ + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
+ + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
+ + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
+ + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+ + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC"
+ + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26"
+ + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB"
+ + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
+ + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127"
+ + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" + "FFFFFFFFFFFFFFFF";
+ private const string rfc5054_4096_g = "05";
+ public static readonly Srp6GroupParameters rfc5054_4096 = FromNG(rfc5054_4096_N, rfc5054_4096_g);
+
+ private const string rfc5054_6144_N = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
+ + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
+ + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
+ + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
+ + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
+ + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
+ + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
+ + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
+ + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
+ + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
+ + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+ + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC"
+ + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26"
+ + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB"
+ + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
+ + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127"
+ + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
+ + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406"
+ + "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918"
+ + "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151"
+ + "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03"
+ + "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F"
+ + "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
+ + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B"
+ + "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632"
+ + "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" + "6DCC4024FFFFFFFFFFFFFFFF";
+ private const string rfc5054_6144_g = "05";
+ public static readonly Srp6GroupParameters rfc5054_6144 = FromNG(rfc5054_6144_N, rfc5054_6144_g);
+
+ private const string rfc5054_8192_N = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
+ + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
+ + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
+ + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
+ + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
+ + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
+ + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
+ + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
+ + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
+ + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
+ + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+ + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC"
+ + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26"
+ + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB"
+ + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
+ + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127"
+ + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
+ + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406"
+ + "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918"
+ + "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151"
+ + "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03"
+ + "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F"
+ + "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
+ + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B"
+ + "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632"
+ + "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E"
+ + "6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA"
+ + "3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C"
+ + "5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
+ + "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC886"
+ + "2F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6"
+ + "6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC5"
+ + "0846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268"
+ + "359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6"
+ + "FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" + "60C980DD98EDD3DFFFFFFFFFFFFFFFFF";
+ private const string rfc5054_8192_g = "13";
+ public static readonly Srp6GroupParameters rfc5054_8192 = FromNG(rfc5054_8192_N, rfc5054_8192_g);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/srp/SRP6Utilities.cs b/bc-sharp-crypto/src/crypto/agreement/srp/SRP6Utilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ef6d8f24ceed798f8c4bfc292e10d87a4741fbce
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/srp/SRP6Utilities.cs
@@ -0,0 +1,153 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Agreement.Srp
+{
+ public class Srp6Utilities
+ {
+ public static BigInteger CalculateK(IDigest digest, BigInteger N, BigInteger g)
+ {
+ return HashPaddedPair(digest, N, N, g);
+ }
+
+ public static BigInteger CalculateU(IDigest digest, BigInteger N, BigInteger A, BigInteger B)
+ {
+ return HashPaddedPair(digest, N, A, B);
+ }
+
+ public static BigInteger CalculateX(IDigest digest, BigInteger N, byte[] salt, byte[] identity, byte[] password)
+ {
+ byte[] output = new byte[digest.GetDigestSize()];
+
+ digest.BlockUpdate(identity, 0, identity.Length);
+ digest.Update((byte)':');
+ digest.BlockUpdate(password, 0, password.Length);
+ digest.DoFinal(output, 0);
+
+ digest.BlockUpdate(salt, 0, salt.Length);
+ digest.BlockUpdate(output, 0, output.Length);
+ digest.DoFinal(output, 0);
+
+ return new BigInteger(1, output);
+ }
+
+ public static BigInteger GeneratePrivateValue(IDigest digest, BigInteger N, BigInteger g, SecureRandom random)
+ {
+ int minBits = System.Math.Min(256, N.BitLength / 2);
+ BigInteger min = BigInteger.One.ShiftLeft(minBits - 1);
+ BigInteger max = N.Subtract(BigInteger.One);
+
+ return BigIntegers.CreateRandomInRange(min, max, random);
+ }
+
+ public static BigInteger ValidatePublicValue(BigInteger N, BigInteger val)
+ {
+ val = val.Mod(N);
+
+ // Check that val % N != 0
+ if (val.Equals(BigInteger.Zero))
+ throw new CryptoException("Invalid public value: 0");
+
+ return val;
+ }
+
+ /**
+ * Computes the client evidence message (M1) according to the standard routine:
+ * M1 = H( A | B | S )
+ * @param digest The Digest used as the hashing function H
+ * @param N Modulus used to get the pad length
+ * @param A The public client value
+ * @param B The public server value
+ * @param S The secret calculated by both sides
+ * @return M1 The calculated client evidence message
+ */
+ public static BigInteger CalculateM1(IDigest digest, BigInteger N, BigInteger A, BigInteger B, BigInteger S)
+ {
+ BigInteger M1 = HashPaddedTriplet(digest, N, A, B, S);
+ return M1;
+ }
+
+ /**
+ * Computes the server evidence message (M2) according to the standard routine:
+ * M2 = H( A | M1 | S )
+ * @param digest The Digest used as the hashing function H
+ * @param N Modulus used to get the pad length
+ * @param A The public client value
+ * @param M1 The client evidence message
+ * @param S The secret calculated by both sides
+ * @return M2 The calculated server evidence message
+ */
+ public static BigInteger CalculateM2(IDigest digest, BigInteger N, BigInteger A, BigInteger M1, BigInteger S)
+ {
+ BigInteger M2 = HashPaddedTriplet(digest, N, A, M1, S);
+ return M2;
+ }
+
+ /**
+ * Computes the final Key according to the standard routine: Key = H(S)
+ * @param digest The Digest used as the hashing function H
+ * @param N Modulus used to get the pad length
+ * @param S The secret calculated by both sides
+ * @return
+ */
+ public static BigInteger CalculateKey(IDigest digest, BigInteger N, BigInteger S)
+ {
+ int padLength = (N.BitLength + 7) / 8;
+ byte[] _S = GetPadded(S, padLength);
+ digest.BlockUpdate(_S, 0, _S.Length);
+
+ byte[] output = new byte[digest.GetDigestSize()];
+ digest.DoFinal(output, 0);
+ return new BigInteger(1, output);
+ }
+
+ private static BigInteger HashPaddedTriplet(IDigest digest, BigInteger N, BigInteger n1, BigInteger n2, BigInteger n3)
+ {
+ int padLength = (N.BitLength + 7) / 8;
+
+ byte[] n1_bytes = GetPadded(n1, padLength);
+ byte[] n2_bytes = GetPadded(n2, padLength);
+ byte[] n3_bytes = GetPadded(n3, padLength);
+
+ digest.BlockUpdate(n1_bytes, 0, n1_bytes.Length);
+ digest.BlockUpdate(n2_bytes, 0, n2_bytes.Length);
+ digest.BlockUpdate(n3_bytes, 0, n3_bytes.Length);
+
+ byte[] output = new byte[digest.GetDigestSize()];
+ digest.DoFinal(output, 0);
+
+ return new BigInteger(1, output);
+ }
+
+ private static BigInteger HashPaddedPair(IDigest digest, BigInteger N, BigInteger n1, BigInteger n2)
+ {
+ int padLength = (N.BitLength + 7) / 8;
+
+ byte[] n1_bytes = GetPadded(n1, padLength);
+ byte[] n2_bytes = GetPadded(n2, padLength);
+
+ digest.BlockUpdate(n1_bytes, 0, n1_bytes.Length);
+ digest.BlockUpdate(n2_bytes, 0, n2_bytes.Length);
+
+ byte[] output = new byte[digest.GetDigestSize()];
+ digest.DoFinal(output, 0);
+
+ return new BigInteger(1, output);
+ }
+
+ private static byte[] GetPadded(BigInteger n, int length)
+ {
+ byte[] bs = BigIntegers.AsUnsignedByteArray(n);
+ if (bs.Length < length)
+ {
+ byte[] tmp = new byte[length];
+ Array.Copy(bs, 0, tmp, length - bs.Length, bs.Length);
+ bs = tmp;
+ }
+ return bs;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/agreement/srp/SRP6VerifierGenerator.cs b/bc-sharp-crypto/src/crypto/agreement/srp/SRP6VerifierGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..956973598cb735d856c00fa87f282a4559257d76
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/agreement/srp/SRP6VerifierGenerator.cs
@@ -0,0 +1,55 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Agreement.Srp
+{
+ /**
+ * Generates new SRP verifier for user
+ */
+ public class Srp6VerifierGenerator
+ {
+ protected BigInteger N;
+ protected BigInteger g;
+ protected IDigest digest;
+
+ public Srp6VerifierGenerator()
+ {
+ }
+
+ /**
+ * Initialises generator to create new verifiers
+ * @param N The safe prime to use (see DHParametersGenerator)
+ * @param g The group parameter to use (see DHParametersGenerator)
+ * @param digest The digest to use. The same digest type will need to be used later for the actual authentication
+ * attempt. Also note that the final session key size is dependent on the chosen digest.
+ */
+ public virtual void Init(BigInteger N, BigInteger g, IDigest digest)
+ {
+ this.N = N;
+ this.g = g;
+ this.digest = digest;
+ }
+
+ public virtual void Init(Srp6GroupParameters group, IDigest digest)
+ {
+ Init(group.N, group.G, digest);
+ }
+
+ /**
+ * Creates a new SRP verifier
+ * @param salt The salt to use, generally should be large and random
+ * @param identity The user's identifying information (eg. username)
+ * @param password The user's password
+ * @return A new verifier for use in future SRP authentication
+ */
+ public virtual BigInteger GenerateVerifier(byte[] salt, byte[] identity, byte[] password)
+ {
+ BigInteger x = Srp6Utilities.CalculateX(digest, N, salt, identity, password);
+
+ return g.ModPow(x, N);
+ }
+ }
+}
+
diff --git a/bc-sharp-crypto/src/crypto/digests/DSTU7564Digest.cs b/bc-sharp-crypto/src/crypto/digests/DSTU7564Digest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9de41dd6b0ada9a55b4a4ba41c67d3c851e00a3e
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/DSTU7564Digest.cs
@@ -0,0 +1,562 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+//using Org.BouncyCastle.Utilities;
+
+
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * implementation of Ukrainian DSTU 7564 hash function
+ */
+ public class Dstu7564Digest : IDigest, IMemoable
+ {
+ private const int ROWS = 8;
+ private const int REDUCTION_POLYNOMIAL = 0x011d;
+ private const int BITS_IN_BYTE = 8;
+
+
+ private const int NB_512 = 8; //Number of 8-byte words in state for <=256-bit hash code.
+ private const int NB_1024 = 16; //Number of 8-byte words in state for <=512-bit hash code.
+
+ private const int NR_512 = 10; //Number of rounds for 512-bit state.
+ private const int NR_1024 = 14; //Number of rounds for 1024-bit state.
+
+ private const int STATE_BYTE_SIZE_512 = ROWS * NB_512;
+ private const int STATE_BYTE_SIZE_1024 = ROWS * NB_1024;
+
+ private int hashSize;
+ private int blockSize;
+
+
+
+ private int columns;
+ private int rounds;
+
+
+ private byte[] padded_;
+
+ private byte[][] state_;
+
+ private ulong inputLength;
+ private int bufOff;
+ private byte[] buf;
+
+ public Dstu7564Digest(Dstu7564Digest digest)
+ {
+ copyIn(digest);
+ }
+
+ private void copyIn(Dstu7564Digest digest)
+ {
+ this.hashSize = digest.hashSize;
+ this.blockSize = digest.blockSize;
+
+ this.columns = digest.columns;
+ this.rounds = digest.rounds;
+
+ this.padded_ = Arrays.Clone(digest.padded_);
+ this.state_ = new byte[digest.state_.Length][];
+ for (int i = 0; i != this.state_.Length; i++)
+ {
+ this.state_[i] = Arrays.Clone(digest.state_[i]);
+ }
+
+ this.inputLength = digest.inputLength;
+ this.bufOff = digest.bufOff;
+ this.buf = Arrays.Clone(digest.buf);
+ }
+
+ public Dstu7564Digest(int hashSizeBits)
+ {
+ if (hashSizeBits == 256 || hashSizeBits == 384 || hashSizeBits == 512)
+ {
+ this.hashSize = hashSizeBits / 8;
+ }
+ else
+ {
+ throw new ArgumentException("Hash size is not recommended. Use 256 or 384 or 512 size");
+ }
+
+ if (hashSizeBits > 256)
+ {
+ this.blockSize = 1024 / 8;
+ this.columns = NB_1024;
+ this.rounds = NR_1024;
+ this.state_ = new byte[STATE_BYTE_SIZE_1024][];
+
+ }
+ else
+ {
+ this.blockSize = 512 / 8;
+ this.columns = NB_512;
+ this.rounds = NR_512;
+ this.state_ = new byte[STATE_BYTE_SIZE_512][];
+
+ }
+
+ //Console.WriteLine("length: " + state_.Length);
+
+ for (int i = 0; i < state_.Length; i++)
+ {
+ this.state_[i] = new byte[columns];
+ }
+
+ this.state_[0][0] = (byte)state_.Length;
+
+ this.hashSize = hashSizeBits / 8;
+
+ this.padded_ = null;
+ this.buf = new byte[blockSize];
+ }
+
+ public string AlgorithmName
+ {
+ get { return "DSTU7564"; }
+ }
+
+
+ public virtual void BlockUpdate(byte[] input, int inOff, int length)
+ {
+ while (bufOff != 0 && length > 0)
+ {
+ Update(input[inOff++]);
+ length--;
+ }
+
+ if (length > 0)
+ {
+ while (length > blockSize)
+ {
+ ProcessBlock(input, inOff);
+ inOff += blockSize;
+ inputLength += (ulong)blockSize;
+ length -= blockSize;
+ }
+
+ while (length > 0)
+ {
+ Update(input[inOff++]);
+ length--;
+ }
+ }
+ }
+
+ protected byte[] Pad(byte[] input, int inOff, int length)
+ {
+ //Console.WriteLine(length);
+
+ byte[] padded;
+ if (blockSize - length < 13) // terminator byte + 96 bits of length
+ {
+ padded = new byte[2 * blockSize];
+ }
+ else
+ {
+ padded = new byte[blockSize];
+ }
+
+
+ Array.Copy(input, inOff, padded, 0, length);
+ padded[length] = 0x80;
+ Pack.UInt64_To_LE(inputLength * 8, padded, padded.Length - 12);
+
+ return padded;
+ }
+
+ protected void ProcessBlock(byte[] input, int inOff)
+ {
+ byte[][] temp1 = new byte[STATE_BYTE_SIZE_1024][];
+ byte[][] temp2 = new byte[STATE_BYTE_SIZE_1024][];
+
+ for (int i = 0; i < state_.Length; i++)
+ {
+ temp1[i] = new byte[ROWS];
+ temp2[i] = new byte[ROWS];
+ }
+
+ for (int i = 0; i < ROWS; ++i)
+ {
+ for (int j = 0; j < columns; ++j)
+ {
+ //Console.WriteLine("row = {0}, column = {1}", i, j);
+
+ temp1[j][i] = (byte)(state_[j][i] ^ input[j * ROWS + i + inOff]);
+ temp2[j][i] = input[j * ROWS + i + inOff];
+
+ }
+
+ }
+
+ P(temp1);
+
+ Q(temp2);
+
+ for (int i = 0; i < ROWS; ++i)
+ {
+ for (int j = 0; j < columns; ++j)
+ {
+ state_[j][i] ^= (byte)(temp1[j][i] ^ temp2[j][i]);
+
+ }
+
+ }
+ }
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ padded_ = Pad(buf, 0, bufOff);
+
+ int paddedLen = padded_.Length;
+ int paddedOff = 0;
+
+ while (paddedLen != 0)
+ {
+ ProcessBlock(padded_, paddedOff);
+ paddedOff += blockSize;
+ paddedLen -= blockSize;
+ }
+
+
+ //Console.WriteLine(stateLine.Length);
+
+ byte[][] temp = new byte[STATE_BYTE_SIZE_1024][];
+ for (int i = 0; i < state_.Length; i++)
+ {
+ temp[i] = new byte[ROWS];
+ Array.Copy(state_[i], temp[i], ROWS);
+ }
+
+ P(temp);
+
+ for (int i = 0; i < ROWS; ++i)
+ {
+ for (int j = 0; j < columns; ++j)
+ {
+ state_[j][i] ^= temp[j][i];
+ //Console.Write("{0:x} ", state_[j][i]);
+ }
+ //Console.WriteLine();
+ }
+
+ byte[] stateLine = new byte[ROWS * columns];
+ int stateLineIndex = 0;
+ for (int j = 0; j < columns; ++j)
+ {
+ for (int i = 0; i < ROWS; ++i)
+ {
+
+ stateLine[stateLineIndex] = state_[j][i];
+ stateLineIndex++;
+
+ //Console.WriteLine("index = {0}, row = {1}, column = {2}", stateLineIndex, i, j);
+
+ }
+ }
+
+ //Console.WriteLine("final: " + Hex.ToHexString(stateLine));
+ //Console.WriteLine(stateLine.Length);
+
+ Array.Copy(stateLine, stateLine.Length - hashSize, output, outOff, hashSize);
+
+ Reset();
+
+ return hashSize;
+ }
+
+ public void Reset()
+ {
+ for (int bufferIndex = 0; bufferIndex < state_.Length; bufferIndex++)
+ {
+ state_[bufferIndex] = new byte[columns];
+ }
+
+ state_[0][0] = (byte)state_.Length;
+
+ inputLength = 0;
+ bufOff = 0;
+
+ Arrays.Fill(buf, (byte)0);
+
+ if (padded_ != null)
+ {
+ Arrays.Fill(padded_, (byte)0);
+ }
+ }
+
+ public int GetDigestSize()
+ {
+ return hashSize;
+ }
+
+ public int GetByteLength()
+ {
+ return blockSize;
+ }
+
+ public void Update(byte input)
+ {
+ buf[bufOff++] = input;
+ if (bufOff == blockSize)
+ {
+ ProcessBlock(buf, 0);
+ bufOff = 0;
+ }
+ inputLength++;
+ }
+
+ void SubBytes(byte[][] state)
+ {
+ int i, j;
+ for (i = 0; i < ROWS; ++i)
+ {
+ for (j = 0; j < columns; ++j)
+ {
+ state[j][i] = sBoxes[i % 4][state[j][i]];
+ }
+ }
+ }
+
+ void ShiftBytes(byte[][] state)
+ {
+ int i, j;
+ byte[] temp = new byte[NB_1024];
+ int shift = -1;
+ for (i = 0; i < ROWS; ++i)
+ {
+ if ((i == ROWS - 1) && (columns == NB_1024))
+ {
+ shift = 11;
+ }
+ else
+ {
+ ++shift;
+ }
+ for (j = 0; j < columns; ++j)
+ {
+ temp[(j + shift) % columns] = state[j][i];
+ }
+ for (j = 0; j < columns; ++j)
+ {
+ state[j][i] = temp[j];
+ }
+ }
+ }
+
+ byte MultiplyGF(byte x, byte y)
+ {
+ int i;
+ byte r = 0;
+ byte hbit = 0;
+ for (i = 0; i < BITS_IN_BYTE; ++i)
+ {
+ if ((y & 0x1) == 1)
+ {
+ r ^= x;
+ }
+
+ hbit = (byte)(x & 0x80);
+
+ x <<= 1;
+
+ if (hbit == 0x80)
+ {
+ x = (byte)((int)x ^ REDUCTION_POLYNOMIAL);
+ }
+
+ y >>= 1;
+ }
+ return r;
+ }
+
+ private void MixColumns(byte[][] state)
+ {
+ int i, row, col, b;
+ byte product;
+ byte[] result = new byte[ROWS];
+
+ for (col = 0; col < columns; ++col)
+ {
+ Array.Clear(result, 0, ROWS);
+ for (row = ROWS - 1; row >= 0; --row)
+ {
+ product = 0;
+ for (b = ROWS - 1; b >= 0; --b)
+ {
+ product ^= MultiplyGF(state[col][b], mds_matrix[row][b]);
+ }
+ result[row] = product;
+ }
+ for (i = 0; i < ROWS; ++i)
+ {
+ state[col][i] = result[i];
+ }
+ }
+ }
+
+ void AddRoundConstantP(byte[][] state, int round)
+ {
+ int i;
+ for (i = 0; i < columns; ++i)
+ {
+ state[i][0] ^= (byte)((i * 0x10) ^ round);
+ }
+ }
+
+ void AddRoundConstantQ(byte[][] state, int round)
+ {
+ int j;
+ UInt64[] s = new UInt64[columns];
+
+ for (j = 0; j < columns; j++)
+ {
+ s[j] = Pack.LE_To_UInt64(state[j]);
+
+ s[j] = s[j] + (0x00F0F0F0F0F0F0F3UL ^ ((((UInt64)(columns - j - 1) * 0x10UL) ^ (UInt64)round) << (7 * 8)));
+
+ state[j] = Pack.UInt64_To_LE(s[j]);
+ }
+ }
+
+ void P(byte[][] state)
+ {
+ int i;
+ for (i = 0; i < rounds; ++i)
+ {
+ AddRoundConstantP(state, i);
+ SubBytes(state);
+ ShiftBytes(state);
+ MixColumns(state);
+ }
+ }
+
+ void Q(byte[][] state)
+ {
+ int i;
+ for (i = 0; i < rounds; ++i)
+ {
+ AddRoundConstantQ(state, i);
+ SubBytes(state);
+ ShiftBytes(state);
+ MixColumns(state);
+ }
+ }
+
+ public IMemoable Copy()
+ {
+ return new Dstu7564Digest(this);
+ }
+
+ public void Reset(IMemoable other)
+ {
+ Dstu7564Digest d = (Dstu7564Digest)other;
+
+ copyIn(d);
+ }
+
+ private readonly byte[][] mds_matrix = new byte[][]
+ {
+ new byte[] {0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04},
+ new byte[] {0x04, 0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07},
+ new byte[] {0x07, 0x04, 0x01, 0x01, 0x05, 0x01, 0x08, 0x06},
+ new byte[] {0x06, 0x07, 0x04, 0x01, 0x01, 0x05, 0x01, 0x08},
+ new byte[] {0x08, 0x06, 0x07, 0x04, 0x01, 0x01, 0x05, 0x01},
+ new byte[] {0x01, 0x08, 0x06, 0x07, 0x04, 0x01, 0x01, 0x05},
+ new byte[] {0x05, 0x01, 0x08, 0x06, 0x07, 0x04, 0x01, 0x01},
+ new byte[] {0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04, 0x01}
+ };
+
+
+
+
+ private readonly byte[][] sBoxes = new byte[][]
+ {
+ new byte[]
+ {
+ 0xa8, 0x43, 0x5f, 0x06, 0x6b, 0x75, 0x6c, 0x59, 0x71, 0xdf, 0x87, 0x95, 0x17, 0xf0, 0xd8, 0x09,
+ 0x6d, 0xf3, 0x1d, 0xcb, 0xc9, 0x4d, 0x2c, 0xaf, 0x79, 0xe0, 0x97, 0xfd, 0x6f, 0x4b, 0x45, 0x39,
+ 0x3e, 0xdd, 0xa3, 0x4f, 0xb4, 0xb6, 0x9a, 0x0e, 0x1f, 0xbf, 0x15, 0xe1, 0x49, 0xd2, 0x93, 0xc6,
+ 0x92, 0x72, 0x9e, 0x61, 0xd1, 0x63, 0xfa, 0xee, 0xf4, 0x19, 0xd5, 0xad, 0x58, 0xa4, 0xbb, 0xa1,
+ 0xdc, 0xf2, 0x83, 0x37, 0x42, 0xe4, 0x7a, 0x32, 0x9c, 0xcc, 0xab, 0x4a, 0x8f, 0x6e, 0x04, 0x27,
+ 0x2e, 0xe7, 0xe2, 0x5a, 0x96, 0x16, 0x23, 0x2b, 0xc2, 0x65, 0x66, 0x0f, 0xbc, 0xa9, 0x47, 0x41,
+ 0x34, 0x48, 0xfc, 0xb7, 0x6a, 0x88, 0xa5, 0x53, 0x86, 0xf9, 0x5b, 0xdb, 0x38, 0x7b, 0xc3, 0x1e,
+ 0x22, 0x33, 0x24, 0x28, 0x36, 0xc7, 0xb2, 0x3b, 0x8e, 0x77, 0xba, 0xf5, 0x14, 0x9f, 0x08, 0x55,
+ 0x9b, 0x4c, 0xfe, 0x60, 0x5c, 0xda, 0x18, 0x46, 0xcd, 0x7d, 0x21, 0xb0, 0x3f, 0x1b, 0x89, 0xff,
+ 0xeb, 0x84, 0x69, 0x3a, 0x9d, 0xd7, 0xd3, 0x70, 0x67, 0x40, 0xb5, 0xde, 0x5d, 0x30, 0x91, 0xb1,
+ 0x78, 0x11, 0x01, 0xe5, 0x00, 0x68, 0x98, 0xa0, 0xc5, 0x02, 0xa6, 0x74, 0x2d, 0x0b, 0xa2, 0x76,
+ 0xb3, 0xbe, 0xce, 0xbd, 0xae, 0xe9, 0x8a, 0x31, 0x1c, 0xec, 0xf1, 0x99, 0x94, 0xaa, 0xf6, 0x26,
+ 0x2f, 0xef, 0xe8, 0x8c, 0x35, 0x03, 0xd4, 0x7f, 0xfb, 0x05, 0xc1, 0x5e, 0x90, 0x20, 0x3d, 0x82,
+ 0xf7, 0xea, 0x0a, 0x0d, 0x7e, 0xf8, 0x50, 0x1a, 0xc4, 0x07, 0x57, 0xb8, 0x3c, 0x62, 0xe3, 0xc8,
+ 0xac, 0x52, 0x64, 0x10, 0xd0, 0xd9, 0x13, 0x0c, 0x12, 0x29, 0x51, 0xb9, 0xcf, 0xd6, 0x73, 0x8d,
+ 0x81, 0x54, 0xc0, 0xed, 0x4e, 0x44, 0xa7, 0x2a, 0x85, 0x25, 0xe6, 0xca, 0x7c, 0x8b, 0x56, 0x80
+ },
+
+ new byte[]
+ {
+ 0xce, 0xbb, 0xeb, 0x92, 0xea, 0xcb, 0x13, 0xc1, 0xe9, 0x3a, 0xd6, 0xb2, 0xd2, 0x90, 0x17, 0xf8,
+ 0x42, 0x15, 0x56, 0xb4, 0x65, 0x1c, 0x88, 0x43, 0xc5, 0x5c, 0x36, 0xba, 0xf5, 0x57, 0x67, 0x8d,
+ 0x31, 0xf6, 0x64, 0x58, 0x9e, 0xf4, 0x22, 0xaa, 0x75, 0x0f, 0x02, 0xb1, 0xdf, 0x6d, 0x73, 0x4d,
+ 0x7c, 0x26, 0x2e, 0xf7, 0x08, 0x5d, 0x44, 0x3e, 0x9f, 0x14, 0xc8, 0xae, 0x54, 0x10, 0xd8, 0xbc,
+ 0x1a, 0x6b, 0x69, 0xf3, 0xbd, 0x33, 0xab, 0xfa, 0xd1, 0x9b, 0x68, 0x4e, 0x16, 0x95, 0x91, 0xee,
+ 0x4c, 0x63, 0x8e, 0x5b, 0xcc, 0x3c, 0x19, 0xa1, 0x81, 0x49, 0x7b, 0xd9, 0x6f, 0x37, 0x60, 0xca,
+ 0xe7, 0x2b, 0x48, 0xfd, 0x96, 0x45, 0xfc, 0x41, 0x12, 0x0d, 0x79, 0xe5, 0x89, 0x8c, 0xe3, 0x20,
+ 0x30, 0xdc, 0xb7, 0x6c, 0x4a, 0xb5, 0x3f, 0x97, 0xd4, 0x62, 0x2d, 0x06, 0xa4, 0xa5, 0x83, 0x5f,
+ 0x2a, 0xda, 0xc9, 0x00, 0x7e, 0xa2, 0x55, 0xbf, 0x11, 0xd5, 0x9c, 0xcf, 0x0e, 0x0a, 0x3d, 0x51,
+ 0x7d, 0x93, 0x1b, 0xfe, 0xc4, 0x47, 0x09, 0x86, 0x0b, 0x8f, 0x9d, 0x6a, 0x07, 0xb9, 0xb0, 0x98,
+ 0x18, 0x32, 0x71, 0x4b, 0xef, 0x3b, 0x70, 0xa0, 0xe4, 0x40, 0xff, 0xc3, 0xa9, 0xe6, 0x78, 0xf9,
+ 0x8b, 0x46, 0x80, 0x1e, 0x38, 0xe1, 0xb8, 0xa8, 0xe0, 0x0c, 0x23, 0x76, 0x1d, 0x25, 0x24, 0x05,
+ 0xf1, 0x6e, 0x94, 0x28, 0x9a, 0x84, 0xe8, 0xa3, 0x4f, 0x77, 0xd3, 0x85, 0xe2, 0x52, 0xf2, 0x82,
+ 0x50, 0x7a, 0x2f, 0x74, 0x53, 0xb3, 0x61, 0xaf, 0x39, 0x35, 0xde, 0xcd, 0x1f, 0x99, 0xac, 0xad,
+ 0x72, 0x2c, 0xdd, 0xd0, 0x87, 0xbe, 0x5e, 0xa6, 0xec, 0x04, 0xc6, 0x03, 0x34, 0xfb, 0xdb, 0x59,
+ 0xb6, 0xc2, 0x01, 0xf0, 0x5a, 0xed, 0xa7, 0x66, 0x21, 0x7f, 0x8a, 0x27, 0xc7, 0xc0, 0x29, 0xd7
+ },
+
+ new byte[]
+ {
+ 0x93, 0xd9, 0x9a, 0xb5, 0x98, 0x22, 0x45, 0xfc, 0xba, 0x6a, 0xdf, 0x02, 0x9f, 0xdc, 0x51, 0x59,
+ 0x4a, 0x17, 0x2b, 0xc2, 0x94, 0xf4, 0xbb, 0xa3, 0x62, 0xe4, 0x71, 0xd4, 0xcd, 0x70, 0x16, 0xe1,
+ 0x49, 0x3c, 0xc0, 0xd8, 0x5c, 0x9b, 0xad, 0x85, 0x53, 0xa1, 0x7a, 0xc8, 0x2d, 0xe0, 0xd1, 0x72,
+ 0xa6, 0x2c, 0xc4, 0xe3, 0x76, 0x78, 0xb7, 0xb4, 0x09, 0x3b, 0x0e, 0x41, 0x4c, 0xde, 0xb2, 0x90,
+ 0x25, 0xa5, 0xd7, 0x03, 0x11, 0x00, 0xc3, 0x2e, 0x92, 0xef, 0x4e, 0x12, 0x9d, 0x7d, 0xcb, 0x35,
+ 0x10, 0xd5, 0x4f, 0x9e, 0x4d, 0xa9, 0x55, 0xc6, 0xd0, 0x7b, 0x18, 0x97, 0xd3, 0x36, 0xe6, 0x48,
+ 0x56, 0x81, 0x8f, 0x77, 0xcc, 0x9c, 0xb9, 0xe2, 0xac, 0xb8, 0x2f, 0x15, 0xa4, 0x7c, 0xda, 0x38,
+ 0x1e, 0x0b, 0x05, 0xd6, 0x14, 0x6e, 0x6c, 0x7e, 0x66, 0xfd, 0xb1, 0xe5, 0x60, 0xaf, 0x5e, 0x33,
+ 0x87, 0xc9, 0xf0, 0x5d, 0x6d, 0x3f, 0x88, 0x8d, 0xc7, 0xf7, 0x1d, 0xe9, 0xec, 0xed, 0x80, 0x29,
+ 0x27, 0xcf, 0x99, 0xa8, 0x50, 0x0f, 0x37, 0x24, 0x28, 0x30, 0x95, 0xd2, 0x3e, 0x5b, 0x40, 0x83,
+ 0xb3, 0x69, 0x57, 0x1f, 0x07, 0x1c, 0x8a, 0xbc, 0x20, 0xeb, 0xce, 0x8e, 0xab, 0xee, 0x31, 0xa2,
+ 0x73, 0xf9, 0xca, 0x3a, 0x1a, 0xfb, 0x0d, 0xc1, 0xfe, 0xfa, 0xf2, 0x6f, 0xbd, 0x96, 0xdd, 0x43,
+ 0x52, 0xb6, 0x08, 0xf3, 0xae, 0xbe, 0x19, 0x89, 0x32, 0x26, 0xb0, 0xea, 0x4b, 0x64, 0x84, 0x82,
+ 0x6b, 0xf5, 0x79, 0xbf, 0x01, 0x5f, 0x75, 0x63, 0x1b, 0x23, 0x3d, 0x68, 0x2a, 0x65, 0xe8, 0x91,
+ 0xf6, 0xff, 0x13, 0x58, 0xf1, 0x47, 0x0a, 0x7f, 0xc5, 0xa7, 0xe7, 0x61, 0x5a, 0x06, 0x46, 0x44,
+ 0x42, 0x04, 0xa0, 0xdb, 0x39, 0x86, 0x54, 0xaa, 0x8c, 0x34, 0x21, 0x8b, 0xf8, 0x0c, 0x74, 0x67
+ },
+
+ new byte[]
+ {
+ 0x68, 0x8d, 0xca, 0x4d, 0x73, 0x4b, 0x4e, 0x2a, 0xd4, 0x52, 0x26, 0xb3, 0x54, 0x1e, 0x19, 0x1f,
+ 0x22, 0x03, 0x46, 0x3d, 0x2d, 0x4a, 0x53, 0x83, 0x13, 0x8a, 0xb7, 0xd5, 0x25, 0x79, 0xf5, 0xbd,
+ 0x58, 0x2f, 0x0d, 0x02, 0xed, 0x51, 0x9e, 0x11, 0xf2, 0x3e, 0x55, 0x5e, 0xd1, 0x16, 0x3c, 0x66,
+ 0x70, 0x5d, 0xf3, 0x45, 0x40, 0xcc, 0xe8, 0x94, 0x56, 0x08, 0xce, 0x1a, 0x3a, 0xd2, 0xe1, 0xdf,
+ 0xb5, 0x38, 0x6e, 0x0e, 0xe5, 0xf4, 0xf9, 0x86, 0xe9, 0x4f, 0xd6, 0x85, 0x23, 0xcf, 0x32, 0x99,
+ 0x31, 0x14, 0xae, 0xee, 0xc8, 0x48, 0xd3, 0x30, 0xa1, 0x92, 0x41, 0xb1, 0x18, 0xc4, 0x2c, 0x71,
+ 0x72, 0x44, 0x15, 0xfd, 0x37, 0xbe, 0x5f, 0xaa, 0x9b, 0x88, 0xd8, 0xab, 0x89, 0x9c, 0xfa, 0x60,
+ 0xea, 0xbc, 0x62, 0x0c, 0x24, 0xa6, 0xa8, 0xec, 0x67, 0x20, 0xdb, 0x7c, 0x28, 0xdd, 0xac, 0x5b,
+ 0x34, 0x7e, 0x10, 0xf1, 0x7b, 0x8f, 0x63, 0xa0, 0x05, 0x9a, 0x43, 0x77, 0x21, 0xbf, 0x27, 0x09,
+ 0xc3, 0x9f, 0xb6, 0xd7, 0x29, 0xc2, 0xeb, 0xc0, 0xa4, 0x8b, 0x8c, 0x1d, 0xfb, 0xff, 0xc1, 0xb2,
+ 0x97, 0x2e, 0xf8, 0x65, 0xf6, 0x75, 0x07, 0x04, 0x49, 0x33, 0xe4, 0xd9, 0xb9, 0xd0, 0x42, 0xc7,
+ 0x6c, 0x90, 0x00, 0x8e, 0x6f, 0x50, 0x01, 0xc5, 0xda, 0x47, 0x3f, 0xcd, 0x69, 0xa2, 0xe2, 0x7a,
+ 0xa7, 0xc6, 0x93, 0x0f, 0x0a, 0x06, 0xe6, 0x2b, 0x96, 0xa3, 0x1c, 0xaf, 0x6a, 0x12, 0x84, 0x39,
+ 0xe7, 0xb0, 0x82, 0xf7, 0xfe, 0x9d, 0x87, 0x5c, 0x81, 0x35, 0xde, 0xb4, 0xa5, 0xfc, 0x80, 0xef,
+ 0xcb, 0xbb, 0x6b, 0x76, 0xba, 0x5a, 0x7d, 0x78, 0x0b, 0x95, 0xe3, 0xad, 0x74, 0x98, 0x3b, 0x36,
+ 0x64, 0x6d, 0xdc, 0xf0, 0x59, 0xa9, 0x4c, 0x17, 0x7f, 0x91, 0xb8, 0xc9, 0x57, 0x1b, 0xe0, 0x61
+ }
+ };
+
+
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/GOST3411Digest.cs b/bc-sharp-crypto/src/crypto/digests/GOST3411Digest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..218adf68c5540ea98118cb93e4ee0813496dd3be
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/GOST3411Digest.cs
@@ -0,0 +1,356 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * implementation of GOST R 34.11-94
+ */
+ public class Gost3411Digest
+ : IDigest, IMemoable
+ {
+ private const int DIGEST_LENGTH = 32;
+
+ private byte[] H = new byte[32], L = new byte[32],
+ M = new byte[32], Sum = new byte[32];
+ private byte[][] C = MakeC();
+
+ private byte[] xBuf = new byte[32];
+ private int xBufOff;
+ private ulong byteCount;
+
+ private readonly IBlockCipher cipher = new Gost28147Engine();
+ private byte[] sBox;
+
+ private static byte[][] MakeC()
+ {
+ byte[][] c = new byte[4][];
+ for (int i = 0; i < 4; ++i)
+ {
+ c[i] = new byte[32];
+ }
+ return c;
+ }
+
+ /**
+ * Standard constructor
+ */
+ public Gost3411Digest()
+ {
+ sBox = Gost28147Engine.GetSBox("D-A");
+ cipher.Init(true, new ParametersWithSBox(null, sBox));
+
+ Reset();
+ }
+
+ /**
+ * Constructor to allow use of a particular sbox with GOST28147
+ * @see GOST28147Engine#getSBox(String)
+ */
+ public Gost3411Digest(byte[] sBoxParam)
+ {
+ sBox = Arrays.Clone(sBoxParam);
+ cipher.Init(true, new ParametersWithSBox(null, sBox));
+
+ Reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public Gost3411Digest(Gost3411Digest t)
+ {
+ Reset(t);
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Gost3411"; }
+ }
+
+ public int GetDigestSize()
+ {
+ return DIGEST_LENGTH;
+ }
+
+ public void Update(
+ byte input)
+ {
+ xBuf[xBufOff++] = input;
+ if (xBufOff == xBuf.Length)
+ {
+ sumByteArray(xBuf); // calc sum M
+ processBlock(xBuf, 0);
+ xBufOff = 0;
+ }
+ byteCount++;
+ }
+
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ while ((xBufOff != 0) && (length > 0))
+ {
+ Update(input[inOff]);
+ inOff++;
+ length--;
+ }
+
+ while (length > xBuf.Length)
+ {
+ Array.Copy(input, inOff, xBuf, 0, xBuf.Length);
+
+ sumByteArray(xBuf); // calc sum M
+ processBlock(xBuf, 0);
+ inOff += xBuf.Length;
+ length -= xBuf.Length;
+ byteCount += (uint)xBuf.Length;
+ }
+
+ // load in the remainder.
+ while (length > 0)
+ {
+ Update(input[inOff]);
+ inOff++;
+ length--;
+ }
+ }
+
+ // (i + 1 + 4(k - 1)) = 8i + k i = 0-3, k = 1-8
+ private byte[] K = new byte[32];
+
+ private byte[] P(byte[] input)
+ {
+ int fourK = 0;
+ for(int k = 0; k < 8; k++)
+ {
+ K[fourK++] = input[k];
+ K[fourK++] = input[8 + k];
+ K[fourK++] = input[16 + k];
+ K[fourK++] = input[24 + k];
+ }
+
+ return K;
+ }
+
+ //A (x) = (x0 ^ x1) || x3 || x2 || x1
+ byte[] a = new byte[8];
+ private byte[] A(byte[] input)
+ {
+ for(int j=0; j<8; j++)
+ {
+ a[j]=(byte)(input[j] ^ input[j+8]);
+ }
+
+ Array.Copy(input, 8, input, 0, 24);
+ Array.Copy(a, 0, input, 24, 8);
+
+ return input;
+ }
+
+ //Encrypt function, ECB mode
+ private void E(byte[] key, byte[] s, int sOff, byte[] input, int inOff)
+ {
+ cipher.Init(true, new KeyParameter(key));
+
+ cipher.ProcessBlock(input, inOff, s, sOff);
+ }
+
+ // (in:) n16||..||n1 ==> (out:) n1^n2^n3^n4^n13^n16||n16||..||n2
+ internal short[] wS = new short[16], w_S = new short[16];
+
+ private void fw(byte[] input)
+ {
+ cpyBytesToShort(input, wS);
+ w_S[15] = (short)(wS[0] ^ wS[1] ^ wS[2] ^ wS[3] ^ wS[12] ^ wS[15]);
+ Array.Copy(wS, 1, w_S, 0, 15);
+ cpyShortToBytes(w_S, input);
+ }
+
+ // block processing
+ internal byte[] S = new byte[32], U = new byte[32], V = new byte[32], W = new byte[32];
+
+ private void processBlock(byte[] input, int inOff)
+ {
+ Array.Copy(input, inOff, M, 0, 32);
+
+ //key step 1
+
+ // H = h3 || h2 || h1 || h0
+ // S = s3 || s2 || s1 || s0
+ H.CopyTo(U, 0);
+ M.CopyTo(V, 0);
+ for (int j=0; j<32; j++)
+ {
+ W[j] = (byte)(U[j]^V[j]);
+ }
+ // Encrypt gost28147-ECB
+ E(P(W), S, 0, H, 0); // s0 = EK0 [h0]
+
+ //keys step 2,3,4
+ for (int i=1; i<4; i++)
+ {
+ byte[] tmpA = A(U);
+ for (int j=0; j<32; j++)
+ {
+ U[j] = (byte)(tmpA[j] ^ C[i][j]);
+ }
+ V = A(A(V));
+ for (int j=0; j<32; j++)
+ {
+ W[j] = (byte)(U[j]^V[j]);
+ }
+ // Encrypt gost28147-ECB
+ E(P(W), S, i * 8, H, i * 8); // si = EKi [hi]
+ }
+
+ // x(M, H) = y61(H^y(M^y12(S)))
+ for(int n = 0; n < 12; n++)
+ {
+ fw(S);
+ }
+ for(int n = 0; n < 32; n++)
+ {
+ S[n] = (byte)(S[n] ^ M[n]);
+ }
+
+ fw(S);
+
+ for(int n = 0; n < 32; n++)
+ {
+ S[n] = (byte)(H[n] ^ S[n]);
+ }
+ for(int n = 0; n < 61; n++)
+ {
+ fw(S);
+ }
+ Array.Copy(S, 0, H, 0, H.Length);
+ }
+
+ private void finish()
+ {
+ ulong bitCount = byteCount * 8;
+ Pack.UInt64_To_LE(bitCount, L);
+
+ while (xBufOff != 0)
+ {
+ Update((byte)0);
+ }
+
+ processBlock(L, 0);
+ processBlock(Sum, 0);
+ }
+
+ public int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ finish();
+
+ H.CopyTo(output, outOff);
+
+ Reset();
+
+ return DIGEST_LENGTH;
+ }
+
+ /**
+ * reset the chaining variables to the IV values.
+ */
+ private static readonly byte[] C2 = {
+ 0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,
+ (byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,
+ 0x00,(byte)0xFF,(byte)0xFF,0x00,(byte)0xFF,0x00,0x00,(byte)0xFF,
+ (byte)0xFF,0x00,0x00,0x00,(byte)0xFF,(byte)0xFF,0x00,(byte)0xFF
+ };
+
+ public void Reset()
+ {
+ byteCount = 0;
+ xBufOff = 0;
+
+ Array.Clear(H, 0, H.Length);
+ Array.Clear(L, 0, L.Length);
+ Array.Clear(M, 0, M.Length);
+ Array.Clear(C[1], 0, C[1].Length); // real index C = +1 because index array with 0.
+ Array.Clear(C[3], 0, C[3].Length);
+ Array.Clear(Sum, 0, Sum.Length);
+ Array.Clear(xBuf, 0, xBuf.Length);
+
+ C2.CopyTo(C[2], 0);
+ }
+
+ // 256 bitsblock modul -> (Sum + a mod (2^256))
+ private void sumByteArray(
+ byte[] input)
+ {
+ int carry = 0;
+
+ for (int i = 0; i != Sum.Length; i++)
+ {
+ int sum = (Sum[i] & 0xff) + (input[i] & 0xff) + carry;
+
+ Sum[i] = (byte)sum;
+
+ carry = sum >> 8;
+ }
+ }
+
+ private static void cpyBytesToShort(byte[] S, short[] wS)
+ {
+ for(int i = 0; i < S.Length / 2; i++)
+ {
+ wS[i] = (short)(((S[i*2+1]<<8)&0xFF00)|(S[i*2]&0xFF));
+ }
+ }
+
+ private static void cpyShortToBytes(short[] wS, byte[] S)
+ {
+ for(int i=0; i> 8);
+ S[i*2] = (byte)wS[i];
+ }
+ }
+
+ public int GetByteLength()
+ {
+ return 32;
+ }
+
+ public IMemoable Copy()
+ {
+ return new Gost3411Digest(this);
+ }
+
+ public void Reset(IMemoable other)
+ {
+ Gost3411Digest t = (Gost3411Digest)other;
+
+ this.sBox = t.sBox;
+ cipher.Init(true, new ParametersWithSBox(null, sBox));
+
+ Reset();
+
+ Array.Copy(t.H, 0, this.H, 0, t.H.Length);
+ Array.Copy(t.L, 0, this.L, 0, t.L.Length);
+ Array.Copy(t.M, 0, this.M, 0, t.M.Length);
+ Array.Copy(t.Sum, 0, this.Sum, 0, t.Sum.Length);
+ Array.Copy(t.C[1], 0, this.C[1], 0, t.C[1].Length);
+ Array.Copy(t.C[2], 0, this.C[2], 0, t.C[2].Length);
+ Array.Copy(t.C[3], 0, this.C[3], 0, t.C[3].Length);
+ Array.Copy(t.xBuf, 0, this.xBuf, 0, t.xBuf.Length);
+
+ this.xBufOff = t.xBufOff;
+ this.byteCount = t.byteCount;
+ }
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/GOST3411_2012Digest.cs b/bc-sharp-crypto/src/crypto/digests/GOST3411_2012Digest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..43951292404c6442db2c834d94096c48d4d231ba
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/GOST3411_2012Digest.cs
@@ -0,0 +1,1036 @@
+using System;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ public abstract class GOST3411_2012Digest:IDigest,IMemoable
+ {
+ private readonly byte[] IV = new byte[64];
+ private readonly byte[] N = new byte[64];
+ private readonly byte[] Sigma = new byte[64];
+ private readonly byte[] Ki = new byte[64];
+ private readonly byte[] m = new byte[64];
+ private readonly byte[] h = new byte[64];
+
+ // Temporary buffers
+ private readonly byte[] tmp = new byte[64];
+ private readonly byte[] block = new byte[64];
+
+ private int bOff = 64;
+
+ protected GOST3411_2012Digest(byte[] IV)
+ {
+ System.Array.Copy(IV,this.IV,64);
+ System.Array.Copy(IV, h, 64);
+ }
+
+ public abstract string AlgorithmName { get; }
+
+ public abstract IMemoable Copy();
+
+ public virtual int DoFinal(byte[] output, int outOff)
+ {
+ int lenM = 64 - bOff;
+
+ // At this point it is certain that lenM is smaller than 64
+ for (int i = 0; i != 64 - lenM; i++)
+ {
+ m[i] = 0;
+ }
+
+ m[63 - lenM] = 1;
+
+ if (bOff != 64)
+ {
+ System.Array.Copy(block, bOff, m, 64 - lenM, lenM);
+ }
+
+ g_N(h, N, m);
+ addMod512(N, lenM * 8);
+ addMod512(Sigma, m);
+ g_N(h, Zero, N);
+ g_N(h, Zero, Sigma);
+
+ reverse(h, tmp);
+
+ Array.Copy(tmp, 0, output, outOff, 64);
+
+ Reset();
+ return 64;
+ }
+
+ public int GetByteLength()
+ {
+ return 64;
+ }
+
+ public abstract int GetDigestSize();
+
+
+ public void Reset()
+ {
+ bOff = 64;
+ Arrays.Fill(N, (byte)0);
+ Arrays.Fill(Sigma, (byte)0);
+ System.Array.Copy(IV, 0, h, 0, 64);
+ Arrays.Fill(block, (byte)0);
+ }
+
+ public void Reset(IMemoable other)
+ {
+ GOST3411_2012Digest o = (GOST3411_2012Digest)other;
+
+ System.Array.Copy(o.IV, 0, this.IV, 0, 64);
+ System.Array.Copy(o.N, 0, this.N, 0, 64);
+ System.Array.Copy(o.Sigma, 0, this.Sigma, 0, 64);
+ System.Array.Copy(o.Ki, 0, this.Ki, 0, 64);
+ System.Array.Copy(o.m, 0, this.m, 0, 64);
+ System.Array.Copy(o.h, 0, this.h, 0, 64);
+
+ System.Array.Copy(o.block, 0, this.block, 0, 64);
+ this.bOff = o.bOff;
+ }
+
+ public void Update(byte input)
+ {
+ block[--bOff] = input;
+ if (bOff == 0)
+ {
+ g_N(h, N, block);
+ addMod512(N, 512);
+ addMod512(Sigma, block);
+ bOff = 64;
+ }
+ }
+
+
+ public void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ while (bOff != 64 && len > 0)
+ {
+ Update(input[inOff++]);
+ len--;
+ }
+ while (len >= 64)
+ {
+ System.Array.Copy(input, inOff, tmp, 0, 64);
+ reverse(tmp, block);
+ g_N(h, N, block);
+ addMod512(N, 512);
+ addMod512(Sigma, block);
+
+ len -= 64;
+ inOff += 64;
+ }
+ while (len > 0)
+ {
+ Update(input[inOff++]);
+ len--;
+ }
+ }
+
+
+
+
+ private void F(byte[] V)
+ {
+ ulong[] res = new ulong[8];
+ ulong r;
+
+ r = 0;
+ r ^= T[0][(V[56] & 0xFF)];
+ r ^= T[1][(V[48] & 0xFF)];
+ r ^= T[2][(V[40] & 0xFF)];
+ r ^= T[3][(V[32] & 0xFF)];
+ r ^= T[4][(V[24] & 0xFF)];
+ r ^= T[5][(V[16] & 0xFF)];
+ r ^= T[6][(V[8] & 0xFF)];
+ r ^= T[7][(V[0] & 0xFF)];
+ res[0] = r;
+
+ r = 0;
+ r ^= T[0][(V[57] & 0xFF)];
+ r ^= T[1][(V[49] & 0xFF)];
+ r ^= T[2][(V[41] & 0xFF)];
+ r ^= T[3][(V[33] & 0xFF)];
+ r ^= T[4][(V[25] & 0xFF)];
+ r ^= T[5][(V[17] & 0xFF)];
+ r ^= T[6][(V[9] & 0xFF)];
+ r ^= T[7][(V[1] & 0xFF)];
+ res[1] = r;
+
+ r = 0;
+ r ^= T[0][(V[58] & 0xFF)];
+ r ^= T[1][(V[50] & 0xFF)];
+ r ^= T[2][(V[42] & 0xFF)];
+ r ^= T[3][(V[34] & 0xFF)];
+ r ^= T[4][(V[26] & 0xFF)];
+ r ^= T[5][(V[18] & 0xFF)];
+ r ^= T[6][(V[10] & 0xFF)];
+ r ^= T[7][(V[2] & 0xFF)];
+ res[2] = r;
+
+ r = 0;
+ r ^= T[0][(V[59] & 0xFF)];
+ r ^= T[1][(V[51] & 0xFF)];
+ r ^= T[2][(V[43] & 0xFF)];
+ r ^= T[3][(V[35] & 0xFF)];
+ r ^= T[4][(V[27] & 0xFF)];
+ r ^= T[5][(V[19] & 0xFF)];
+ r ^= T[6][(V[11] & 0xFF)];
+ r ^= T[7][(V[3] & 0xFF)];
+ res[3] = r;
+
+ r = 0;
+ r ^= T[0][(V[60] & 0xFF)];
+ r ^= T[1][(V[52] & 0xFF)];
+ r ^= T[2][(V[44] & 0xFF)];
+ r ^= T[3][(V[36] & 0xFF)];
+ r ^= T[4][(V[28] & 0xFF)];
+ r ^= T[5][(V[20] & 0xFF)];
+ r ^= T[6][(V[12] & 0xFF)];
+ r ^= T[7][(V[4] & 0xFF)];
+ res[4] = r;
+
+ r = 0;
+ r ^= T[0][(V[61] & 0xFF)];
+ r ^= T[1][(V[53] & 0xFF)];
+ r ^= T[2][(V[45] & 0xFF)];
+ r ^= T[3][(V[37] & 0xFF)];
+ r ^= T[4][(V[29] & 0xFF)];
+ r ^= T[5][(V[21] & 0xFF)];
+ r ^= T[6][(V[13] & 0xFF)];
+ r ^= T[7][(V[5] & 0xFF)];
+ res[5] = r;
+
+ r = 0;
+ r ^= T[0][(V[62] & 0xFF)];
+ r ^= T[1][(V[54] & 0xFF)];
+ r ^= T[2][(V[46] & 0xFF)];
+ r ^= T[3][(V[38] & 0xFF)];
+ r ^= T[4][(V[30] & 0xFF)];
+ r ^= T[5][(V[22] & 0xFF)];
+ r ^= T[6][(V[14] & 0xFF)];
+ r ^= T[7][(V[6] & 0xFF)];
+ res[6] = r;
+
+ r = 0;
+ r ^= T[0][(V[63] & 0xFF)];
+ r ^= T[1][(V[55] & 0xFF)];
+ r ^= T[2][(V[47] & 0xFF)];
+ r ^= T[3][(V[39] & 0xFF)];
+ r ^= T[4][(V[31] & 0xFF)];
+ r ^= T[5][(V[23] & 0xFF)];
+ r ^= T[6][(V[15] & 0xFF)];
+ r ^= T[7][(V[7] & 0xFF)];
+ res[7] = r;
+
+ r = res[0];
+ V[7] = (byte)(r >> 56);
+ V[6] = (byte)(r >> 48);
+ V[5] = (byte)(r >> 40);
+ V[4] = (byte)(r >> 32);
+ V[3] = (byte)(r >> 24);
+ V[2] = (byte)(r >> 16);
+ V[1] = (byte)(r >> 8);
+ V[0] = (byte)(r);
+
+ r = res[1];
+ V[15] = (byte)(r >> 56);
+ V[14] = (byte)(r >> 48);
+ V[13] = (byte)(r >> 40);
+ V[12] = (byte)(r >> 32);
+ V[11] = (byte)(r >> 24);
+ V[10] = (byte)(r >> 16);
+ V[9] = (byte)(r >> 8);
+ V[8] = (byte)(r);
+
+ r = res[2];
+ V[23] = (byte)(r >> 56);
+ V[22] = (byte)(r >> 48);
+ V[21] = (byte)(r >> 40);
+ V[20] = (byte)(r >> 32);
+ V[19] = (byte)(r >> 24);
+ V[18] = (byte)(r >> 16);
+ V[17] = (byte)(r >> 8);
+ V[16] = (byte)(r);
+
+ r = res[3];
+ V[31] = (byte)(r >> 56);
+ V[30] = (byte)(r >> 48);
+ V[29] = (byte)(r >> 40);
+ V[28] = (byte)(r >> 32);
+ V[27] = (byte)(r >> 24);
+ V[26] = (byte)(r >> 16);
+ V[25] = (byte)(r >> 8);
+ V[24] = (byte)(r);
+
+ r = res[4];
+ V[39] = (byte)(r >> 56);
+ V[38] = (byte)(r >> 48);
+ V[37] = (byte)(r >> 40);
+ V[36] = (byte)(r >> 32);
+ V[35] = (byte)(r >> 24);
+ V[34] = (byte)(r >> 16);
+ V[33] = (byte)(r >> 8);
+ V[32] = (byte)(r);
+
+ r = res[5];
+ V[47] = (byte)(r >> 56);
+ V[46] = (byte)(r >> 48);
+ V[45] = (byte)(r >> 40);
+ V[44] = (byte)(r >> 32);
+ V[43] = (byte)(r >> 24);
+ V[42] = (byte)(r >> 16);
+ V[41] = (byte)(r >> 8);
+ V[40] = (byte)(r);
+
+ r = res[6];
+ V[55] = (byte)(r >> 56);
+ V[54] = (byte)(r >> 48);
+ V[53] = (byte)(r >> 40);
+ V[52] = (byte)(r >> 32);
+ V[51] = (byte)(r >> 24);
+ V[50] = (byte)(r >> 16);
+ V[49] = (byte)(r >> 8);
+ V[48] = (byte)(r);
+
+ r = res[7];
+ V[63] = (byte)(r >> 56);
+ V[62] = (byte)(r >> 48);
+ V[61] = (byte)(r >> 40);
+ V[60] = (byte)(r >> 32);
+ V[59] = (byte)(r >> 24);
+ V[58] = (byte)(r >> 16);
+ V[57] = (byte)(r >> 8);
+ V[56] = (byte)(r);
+ }
+
+ private void xor512(byte[] A, byte[] B)
+ {
+ for (int i = 0; i < 64; ++i)
+ {
+ A[i] ^= B[i];
+ }
+ }
+
+ private void E(byte[] K, byte[] m)
+ {
+ System.Array.Copy(K, 0, Ki, 0, 64);
+ xor512(K, m);
+ F(K);
+ for (int i = 0; i < 11; ++i)
+ {
+ xor512(Ki, C[i]);
+ F(Ki);
+ xor512(K, Ki);
+ F(K);
+ }
+ xor512(Ki, C[11]);
+ F(Ki);
+ xor512(K, Ki);
+ }
+
+ private void g_N(byte[] h, byte[] N, byte[] m)
+ {
+ System.Array.Copy(h, 0, tmp, 0, 64);
+
+ xor512(h, N);
+ F(h);
+
+ E(h, m);
+ xor512(h, tmp);
+ xor512(h, m);
+ }
+
+ private void addMod512(byte[] A, int num)
+ {
+ int c;
+ c = (A[63] & 0xFF) + (num & 0xFF);
+ A[63] = (byte)c;
+
+ c = (A[62] & 0xFF) + ((num >> 8) & 0xFF) + (c >> 8);
+ A[62] = (byte)c;
+
+ for (int i = 61; (i >= 0) && (c > 0); --i)
+ {
+ c = (A[i] & 0xFF) + (c >> 8);
+ A[i] = (byte)c;
+ }
+ }
+
+ private void addMod512(byte[] A, byte[] B)
+ {
+ for (int c = 0, i = 63; i >= 0; --i)
+ {
+ c = (A[i] & 0xFF) + (B[i] & 0xFF) + (c >> 8);
+ A[i] = (byte)c;
+ }
+ }
+
+ private void reverse(byte[] src, byte[] dst)
+ {
+ int len = src.Length;
+ for (int i = 0; i < len; i++)
+ {
+ dst[len - 1 - i] = src[i];
+ }
+ }
+
+ private static readonly byte[][] C = new byte[][]{ new byte[]{
+ (byte)0xb1, (byte)0x08, (byte)0x5b, (byte)0xda, (byte)0x1e, (byte)0xca, (byte)0xda, (byte)0xe9,
+ (byte)0xeb, (byte)0xcb, (byte)0x2f, (byte)0x81, (byte)0xc0, (byte)0x65, (byte)0x7c, (byte)0x1f,
+ (byte)0x2f, (byte)0x6a, (byte)0x76, (byte)0x43, (byte)0x2e, (byte)0x45, (byte)0xd0, (byte)0x16,
+ (byte)0x71, (byte)0x4e, (byte)0xb8, (byte)0x8d, (byte)0x75, (byte)0x85, (byte)0xc4, (byte)0xfc,
+ (byte)0x4b, (byte)0x7c, (byte)0xe0, (byte)0x91, (byte)0x92, (byte)0x67, (byte)0x69, (byte)0x01,
+ (byte)0xa2, (byte)0x42, (byte)0x2a, (byte)0x08, (byte)0xa4, (byte)0x60, (byte)0xd3, (byte)0x15,
+ (byte)0x05, (byte)0x76, (byte)0x74, (byte)0x36, (byte)0xcc, (byte)0x74, (byte)0x4d, (byte)0x23,
+ (byte)0xdd, (byte)0x80, (byte)0x65, (byte)0x59, (byte)0xf2, (byte)0xa6, (byte)0x45, (byte)0x07},
+
+ new byte[]{
+ (byte)0x6f, (byte)0xa3, (byte)0xb5, (byte)0x8a, (byte)0xa9, (byte)0x9d, (byte)0x2f, (byte)0x1a,
+ (byte)0x4f, (byte)0xe3, (byte)0x9d, (byte)0x46, (byte)0x0f, (byte)0x70, (byte)0xb5, (byte)0xd7,
+ (byte)0xf3, (byte)0xfe, (byte)0xea, (byte)0x72, (byte)0x0a, (byte)0x23, (byte)0x2b, (byte)0x98,
+ (byte)0x61, (byte)0xd5, (byte)0x5e, (byte)0x0f, (byte)0x16, (byte)0xb5, (byte)0x01, (byte)0x31,
+ (byte)0x9a, (byte)0xb5, (byte)0x17, (byte)0x6b, (byte)0x12, (byte)0xd6, (byte)0x99, (byte)0x58,
+ (byte)0x5c, (byte)0xb5, (byte)0x61, (byte)0xc2, (byte)0xdb, (byte)0x0a, (byte)0xa7, (byte)0xca,
+ (byte)0x55, (byte)0xdd, (byte)0xa2, (byte)0x1b, (byte)0xd7, (byte)0xcb, (byte)0xcd, (byte)0x56,
+ (byte)0xe6, (byte)0x79, (byte)0x04, (byte)0x70, (byte)0x21, (byte)0xb1, (byte)0x9b, (byte)0xb7},
+ new byte[]{
+ (byte)0xf5, (byte)0x74, (byte)0xdc, (byte)0xac, (byte)0x2b, (byte)0xce, (byte)0x2f, (byte)0xc7,
+ (byte)0x0a, (byte)0x39, (byte)0xfc, (byte)0x28, (byte)0x6a, (byte)0x3d, (byte)0x84, (byte)0x35,
+ (byte)0x06, (byte)0xf1, (byte)0x5e, (byte)0x5f, (byte)0x52, (byte)0x9c, (byte)0x1f, (byte)0x8b,
+ (byte)0xf2, (byte)0xea, (byte)0x75, (byte)0x14, (byte)0xb1, (byte)0x29, (byte)0x7b, (byte)0x7b,
+ (byte)0xd3, (byte)0xe2, (byte)0x0f, (byte)0xe4, (byte)0x90, (byte)0x35, (byte)0x9e, (byte)0xb1,
+ (byte)0xc1, (byte)0xc9, (byte)0x3a, (byte)0x37, (byte)0x60, (byte)0x62, (byte)0xdb, (byte)0x09,
+ (byte)0xc2, (byte)0xb6, (byte)0xf4, (byte)0x43, (byte)0x86, (byte)0x7a, (byte)0xdb, (byte)0x31,
+ (byte)0x99, (byte)0x1e, (byte)0x96, (byte)0xf5, (byte)0x0a, (byte)0xba, (byte)0x0a, (byte)0xb2},
+ new byte[]{
+ (byte)0xef, (byte)0x1f, (byte)0xdf, (byte)0xb3, (byte)0xe8, (byte)0x15, (byte)0x66, (byte)0xd2,
+ (byte)0xf9, (byte)0x48, (byte)0xe1, (byte)0xa0, (byte)0x5d, (byte)0x71, (byte)0xe4, (byte)0xdd,
+ (byte)0x48, (byte)0x8e, (byte)0x85, (byte)0x7e, (byte)0x33, (byte)0x5c, (byte)0x3c, (byte)0x7d,
+ (byte)0x9d, (byte)0x72, (byte)0x1c, (byte)0xad, (byte)0x68, (byte)0x5e, (byte)0x35, (byte)0x3f,
+ (byte)0xa9, (byte)0xd7, (byte)0x2c, (byte)0x82, (byte)0xed, (byte)0x03, (byte)0xd6, (byte)0x75,
+ (byte)0xd8, (byte)0xb7, (byte)0x13, (byte)0x33, (byte)0x93, (byte)0x52, (byte)0x03, (byte)0xbe,
+ (byte)0x34, (byte)0x53, (byte)0xea, (byte)0xa1, (byte)0x93, (byte)0xe8, (byte)0x37, (byte)0xf1,
+ (byte)0x22, (byte)0x0c, (byte)0xbe, (byte)0xbc, (byte)0x84, (byte)0xe3, (byte)0xd1, (byte)0x2e},
+ new byte[] {
+ (byte)0x4b, (byte)0xea, (byte)0x6b, (byte)0xac, (byte)0xad, (byte)0x47, (byte)0x47, (byte)0x99,
+ (byte)0x9a, (byte)0x3f, (byte)0x41, (byte)0x0c, (byte)0x6c, (byte)0xa9, (byte)0x23, (byte)0x63,
+ (byte)0x7f, (byte)0x15, (byte)0x1c, (byte)0x1f, (byte)0x16, (byte)0x86, (byte)0x10, (byte)0x4a,
+ (byte)0x35, (byte)0x9e, (byte)0x35, (byte)0xd7, (byte)0x80, (byte)0x0f, (byte)0xff, (byte)0xbd,
+ (byte)0xbf, (byte)0xcd, (byte)0x17, (byte)0x47, (byte)0x25, (byte)0x3a, (byte)0xf5, (byte)0xa3,
+ (byte)0xdf, (byte)0xff, (byte)0x00, (byte)0xb7, (byte)0x23, (byte)0x27, (byte)0x1a, (byte)0x16,
+ (byte)0x7a, (byte)0x56, (byte)0xa2, (byte)0x7e, (byte)0xa9, (byte)0xea, (byte)0x63, (byte)0xf5,
+ (byte)0x60, (byte)0x17, (byte)0x58, (byte)0xfd, (byte)0x7c, (byte)0x6c, (byte)0xfe, (byte)0x57},
+ new byte[]{
+ (byte)0xae, (byte)0x4f, (byte)0xae, (byte)0xae, (byte)0x1d, (byte)0x3a, (byte)0xd3, (byte)0xd9,
+ (byte)0x6f, (byte)0xa4, (byte)0xc3, (byte)0x3b, (byte)0x7a, (byte)0x30, (byte)0x39, (byte)0xc0,
+ (byte)0x2d, (byte)0x66, (byte)0xc4, (byte)0xf9, (byte)0x51, (byte)0x42, (byte)0xa4, (byte)0x6c,
+ (byte)0x18, (byte)0x7f, (byte)0x9a, (byte)0xb4, (byte)0x9a, (byte)0xf0, (byte)0x8e, (byte)0xc6,
+ (byte)0xcf, (byte)0xfa, (byte)0xa6, (byte)0xb7, (byte)0x1c, (byte)0x9a, (byte)0xb7, (byte)0xb4,
+ (byte)0x0a, (byte)0xf2, (byte)0x1f, (byte)0x66, (byte)0xc2, (byte)0xbe, (byte)0xc6, (byte)0xb6,
+ (byte)0xbf, (byte)0x71, (byte)0xc5, (byte)0x72, (byte)0x36, (byte)0x90, (byte)0x4f, (byte)0x35,
+ (byte)0xfa, (byte)0x68, (byte)0x40, (byte)0x7a, (byte)0x46, (byte)0x64, (byte)0x7d, (byte)0x6e},
+ new byte[] {
+ (byte)0xf4, (byte)0xc7, (byte)0x0e, (byte)0x16, (byte)0xee, (byte)0xaa, (byte)0xc5, (byte)0xec,
+ (byte)0x51, (byte)0xac, (byte)0x86, (byte)0xfe, (byte)0xbf, (byte)0x24, (byte)0x09, (byte)0x54,
+ (byte)0x39, (byte)0x9e, (byte)0xc6, (byte)0xc7, (byte)0xe6, (byte)0xbf, (byte)0x87, (byte)0xc9,
+ (byte)0xd3, (byte)0x47, (byte)0x3e, (byte)0x33, (byte)0x19, (byte)0x7a, (byte)0x93, (byte)0xc9,
+ (byte)0x09, (byte)0x92, (byte)0xab, (byte)0xc5, (byte)0x2d, (byte)0x82, (byte)0x2c, (byte)0x37,
+ (byte)0x06, (byte)0x47, (byte)0x69, (byte)0x83, (byte)0x28, (byte)0x4a, (byte)0x05, (byte)0x04,
+ (byte)0x35, (byte)0x17, (byte)0x45, (byte)0x4c, (byte)0xa2, (byte)0x3c, (byte)0x4a, (byte)0xf3,
+ (byte)0x88, (byte)0x86, (byte)0x56, (byte)0x4d, (byte)0x3a, (byte)0x14, (byte)0xd4, (byte)0x93},
+ new byte[] {
+ (byte)0x9b, (byte)0x1f, (byte)0x5b, (byte)0x42, (byte)0x4d, (byte)0x93, (byte)0xc9, (byte)0xa7,
+ (byte)0x03, (byte)0xe7, (byte)0xaa, (byte)0x02, (byte)0x0c, (byte)0x6e, (byte)0x41, (byte)0x41,
+ (byte)0x4e, (byte)0xb7, (byte)0xf8, (byte)0x71, (byte)0x9c, (byte)0x36, (byte)0xde, (byte)0x1e,
+ (byte)0x89, (byte)0xb4, (byte)0x44, (byte)0x3b, (byte)0x4d, (byte)0xdb, (byte)0xc4, (byte)0x9a,
+ (byte)0xf4, (byte)0x89, (byte)0x2b, (byte)0xcb, (byte)0x92, (byte)0x9b, (byte)0x06, (byte)0x90,
+ (byte)0x69, (byte)0xd1, (byte)0x8d, (byte)0x2b, (byte)0xd1, (byte)0xa5, (byte)0xc4, (byte)0x2f,
+ (byte)0x36, (byte)0xac, (byte)0xc2, (byte)0x35, (byte)0x59, (byte)0x51, (byte)0xa8, (byte)0xd9,
+ (byte)0xa4, (byte)0x7f, (byte)0x0d, (byte)0xd4, (byte)0xbf, (byte)0x02, (byte)0xe7, (byte)0x1e},
+ new byte[]{
+ (byte)0x37, (byte)0x8f, (byte)0x5a, (byte)0x54, (byte)0x16, (byte)0x31, (byte)0x22, (byte)0x9b,
+ (byte)0x94, (byte)0x4c, (byte)0x9a, (byte)0xd8, (byte)0xec, (byte)0x16, (byte)0x5f, (byte)0xde,
+ (byte)0x3a, (byte)0x7d, (byte)0x3a, (byte)0x1b, (byte)0x25, (byte)0x89, (byte)0x42, (byte)0x24,
+ (byte)0x3c, (byte)0xd9, (byte)0x55, (byte)0xb7, (byte)0xe0, (byte)0x0d, (byte)0x09, (byte)0x84,
+ (byte)0x80, (byte)0x0a, (byte)0x44, (byte)0x0b, (byte)0xdb, (byte)0xb2, (byte)0xce, (byte)0xb1,
+ (byte)0x7b, (byte)0x2b, (byte)0x8a, (byte)0x9a, (byte)0xa6, (byte)0x07, (byte)0x9c, (byte)0x54,
+ (byte)0x0e, (byte)0x38, (byte)0xdc, (byte)0x92, (byte)0xcb, (byte)0x1f, (byte)0x2a, (byte)0x60,
+ (byte)0x72, (byte)0x61, (byte)0x44, (byte)0x51, (byte)0x83, (byte)0x23, (byte)0x5a, (byte)0xdb},
+ new byte[] {
+ (byte)0xab, (byte)0xbe, (byte)0xde, (byte)0xa6, (byte)0x80, (byte)0x05, (byte)0x6f, (byte)0x52,
+ (byte)0x38, (byte)0x2a, (byte)0xe5, (byte)0x48, (byte)0xb2, (byte)0xe4, (byte)0xf3, (byte)0xf3,
+ (byte)0x89, (byte)0x41, (byte)0xe7, (byte)0x1c, (byte)0xff, (byte)0x8a, (byte)0x78, (byte)0xdb,
+ (byte)0x1f, (byte)0xff, (byte)0xe1, (byte)0x8a, (byte)0x1b, (byte)0x33, (byte)0x61, (byte)0x03,
+ (byte)0x9f, (byte)0xe7, (byte)0x67, (byte)0x02, (byte)0xaf, (byte)0x69, (byte)0x33, (byte)0x4b,
+ (byte)0x7a, (byte)0x1e, (byte)0x6c, (byte)0x30, (byte)0x3b, (byte)0x76, (byte)0x52, (byte)0xf4,
+ (byte)0x36, (byte)0x98, (byte)0xfa, (byte)0xd1, (byte)0x15, (byte)0x3b, (byte)0xb6, (byte)0xc3,
+ (byte)0x74, (byte)0xb4, (byte)0xc7, (byte)0xfb, (byte)0x98, (byte)0x45, (byte)0x9c, (byte)0xed},
+ new byte[] {
+ (byte)0x7b, (byte)0xcd, (byte)0x9e, (byte)0xd0, (byte)0xef, (byte)0xc8, (byte)0x89, (byte)0xfb,
+ (byte)0x30, (byte)0x02, (byte)0xc6, (byte)0xcd, (byte)0x63, (byte)0x5a, (byte)0xfe, (byte)0x94,
+ (byte)0xd8, (byte)0xfa, (byte)0x6b, (byte)0xbb, (byte)0xeb, (byte)0xab, (byte)0x07, (byte)0x61,
+ (byte)0x20, (byte)0x01, (byte)0x80, (byte)0x21, (byte)0x14, (byte)0x84, (byte)0x66, (byte)0x79,
+ (byte)0x8a, (byte)0x1d, (byte)0x71, (byte)0xef, (byte)0xea, (byte)0x48, (byte)0xb9, (byte)0xca,
+ (byte)0xef, (byte)0xba, (byte)0xcd, (byte)0x1d, (byte)0x7d, (byte)0x47, (byte)0x6e, (byte)0x98,
+ (byte)0xde, (byte)0xa2, (byte)0x59, (byte)0x4a, (byte)0xc0, (byte)0x6f, (byte)0xd8, (byte)0x5d,
+ (byte)0x6b, (byte)0xca, (byte)0xa4, (byte)0xcd, (byte)0x81, (byte)0xf3, (byte)0x2d, (byte)0x1b},
+ new byte[] {
+ (byte)0x37, (byte)0x8e, (byte)0xe7, (byte)0x67, (byte)0xf1, (byte)0x16, (byte)0x31, (byte)0xba,
+ (byte)0xd2, (byte)0x13, (byte)0x80, (byte)0xb0, (byte)0x04, (byte)0x49, (byte)0xb1, (byte)0x7a,
+ (byte)0xcd, (byte)0xa4, (byte)0x3c, (byte)0x32, (byte)0xbc, (byte)0xdf, (byte)0x1d, (byte)0x77,
+ (byte)0xf8, (byte)0x20, (byte)0x12, (byte)0xd4, (byte)0x30, (byte)0x21, (byte)0x9f, (byte)0x9b,
+ (byte)0x5d, (byte)0x80, (byte)0xef, (byte)0x9d, (byte)0x18, (byte)0x91, (byte)0xcc, (byte)0x86,
+ (byte)0xe7, (byte)0x1d, (byte)0xa4, (byte)0xaa, (byte)0x88, (byte)0xe1, (byte)0x28, (byte)0x52,
+ (byte)0xfa, (byte)0xf4, (byte)0x17, (byte)0xd5, (byte)0xd9, (byte)0xb2, (byte)0x1b, (byte)0x99,
+ (byte)0x48, (byte)0xbc, (byte)0x92, (byte)0x4a, (byte)0xf1, (byte)0x1b, (byte)0xd7, (byte)0x20}
+ };
+
+ private static readonly byte[] Zero = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ private readonly static ulong[][] T = {
+ new ulong[] {
+ 0xE6F87E5C5B711FD0L, 0x258377800924FA16L, 0xC849E07E852EA4A8L, 0x5B4686A18F06C16AL,
+ 0x0B32E9A2D77B416EL, 0xABDA37A467815C66L, 0xF61796A81A686676L, 0xF5DC0B706391954BL,
+ 0x4862F38DB7E64BF1L, 0xFF5C629A68BD85C5L, 0xCB827DA6FCD75795L, 0x66D36DAF69B9F089L,
+ 0x356C9F74483D83B0L, 0x7CBCECB1238C99A1L, 0x36A702AC31C4708DL, 0x9EB6A8D02FBCDFD6L,
+ 0x8B19FA51E5B3AE37L, 0x9CCFB5408A127D0BL, 0xBC0C78B508208F5AL, 0xE533E3842288ECEDL,
+ 0xCEC2C7D377C15FD2L, 0xEC7817B6505D0F5EL, 0xB94CC2C08336871DL, 0x8C205DB4CB0B04ADL,
+ 0x763C855B28A0892FL, 0x588D1B79F6FF3257L, 0x3FECF69E4311933EL, 0x0FC0D39F803A18C9L,
+ 0xEE010A26F5F3AD83L, 0x10EFE8F4411979A6L, 0x5DCDA10C7DE93A10L, 0x4A1BEE1D1248E92CL,
+ 0x53BFF2DB21847339L, 0xB4F50CCFA6A23D09L, 0x5FB4BC9CD84798CDL, 0xE88A2D8B071C56F9L,
+ 0x7F7771695A756A9CL, 0xC5F02E71A0BA1EBCL, 0xA663F9AB4215E672L, 0x2EB19E22DE5FBB78L,
+ 0x0DB9CE0F2594BA14L, 0x82520E6397664D84L, 0x2F031E6A0208EA98L, 0x5C7F2144A1BE6BF0L,
+ 0x7A37CB1CD16362DBL, 0x83E08E2B4B311C64L, 0xCF70479BAB960E32L, 0x856BA986B9DEE71EL,
+ 0xB5478C877AF56CE9L, 0xB8FE42885F61D6FDL, 0x1BDD0156966238C8L, 0x622157923EF8A92EL,
+ 0xFC97FF42114476F8L, 0x9D7D350856452CEBL, 0x4C90C9B0E0A71256L, 0x2308502DFBCB016CL,
+ 0x2D7A03FAA7A64845L, 0xF46E8B38BFC6C4ABL, 0xBDBEF8FDD477DEBAL, 0x3AAC4CEBC8079B79L,
+ 0xF09CB105E8879D0CL, 0x27FA6A10AC8A58CBL, 0x8960E7C1401D0CEAL, 0x1A6F811E4A356928L,
+ 0x90C4FB0773D196FFL, 0x43501A2F609D0A9FL, 0xF7A516E0C63F3796L, 0x1CE4A6B3B8DA9252L,
+ 0x1324752C38E08A9BL, 0xA5A864733BEC154FL, 0x2BF124575549B33FL, 0xD766DB15440DC5C7L,
+ 0xA7D179E39E42B792L, 0xDADF151A61997FD3L, 0x86A0345EC0271423L, 0x38D5517B6DA939A4L,
+ 0x6518F077104003B4L, 0x02791D90A5AEA2DDL, 0x88D267899C4A5D0AL, 0x930F66DF0A2865C2L,
+ 0x4EE9D4204509B08BL, 0x325538916685292AL, 0x412907BFC533A842L, 0xB27E2B62544DC673L,
+ 0x6C5304456295E007L, 0x5AF406E95351908AL, 0x1F2F3B6BC123616FL, 0xC37B09DC5255E5C6L,
+ 0x3967D133B1FE6844L, 0x298839C7F0E711E2L, 0x409B87F71964F9A2L, 0xE938ADC3DB4B0719L,
+ 0x0C0B4E47F9C3EBF4L, 0x5534D576D36B8843L, 0x4610A05AEB8B02D8L, 0x20C3CDF58232F251L,
+ 0x6DE1840DBEC2B1E7L, 0xA0E8DE06B0FA1D08L, 0x7B854B540D34333BL, 0x42E29A67BCCA5B7FL,
+ 0xD8A6088AC437DD0EL, 0xC63BB3A9D943ED81L, 0x21714DBD5E65A3B1L, 0x6761EDE7B5EEA169L,
+ 0x2431F7C8D573ABF6L, 0xD51FC685E1A3671AL, 0x5E063CD40410C92DL, 0x283AB98F2CB04002L,
+ 0x8FEBC06CB2F2F790L, 0x17D64F116FA1D33CL, 0xE07359F1A99EE4AAL, 0x784ED68C74CDC006L,
+ 0x6E2A19D5C73B42DAL, 0x8712B4161C7045C3L, 0x371582E4ED93216DL, 0xACE390414939F6FCL,
+ 0x7EC5F12186223B7CL, 0xC0B094042BAC16FBL, 0xF9D745379A527EBFL, 0x737C3F2EA3B68168L,
+ 0x33E7B8D9BAD278CAL, 0xA9A32A34C22FFEBBL, 0xE48163CCFEDFBD0DL, 0x8E5940246EA5A670L,
+ 0x51C6EF4B842AD1E4L, 0x22BAD065279C508CL, 0xD91488C218608CEEL, 0x319EA5491F7CDA17L,
+ 0xD394E128134C9C60L, 0x094BF43272D5E3B3L, 0x9BF612A5A4AAD791L, 0xCCBBDA43D26FFD0FL,
+ 0x34DE1F3C946AD250L, 0x4F5B5468995EE16BL, 0xDF9FAF6FEA8F7794L, 0x2648EA5870DD092BL,
+ 0xBFC7E56D71D97C67L, 0xDDE6B2FF4F21D549L, 0x3C276B463AE86003L, 0x91767B4FAF86C71FL,
+ 0x68A13E7835D4B9A0L, 0xB68C115F030C9FD4L, 0x141DD2C916582001L, 0x983D8F7DDD5324ACL,
+ 0x64AA703FCC175254L, 0xC2C989948E02B426L, 0x3E5E76D69F46C2DEL, 0x50746F03587D8004L,
+ 0x45DB3D829272F1E5L, 0x60584A029B560BF3L, 0xFBAE58A73FFCDC62L, 0xA15A5E4E6CAD4CE8L,
+ 0x4BA96E55CE1FB8CCL, 0x08F9747AAE82B253L, 0xC102144CF7FB471BL, 0x9F042898F3EB8E36L,
+ 0x068B27ADF2EFFB7AL, 0xEDCA97FE8C0A5EBEL, 0x778E0513F4F7D8CFL, 0x302C2501C32B8BF7L,
+ 0x8D92DDFC175C554DL, 0xF865C57F46052F5FL, 0xEAF3301BA2B2F424L, 0xAA68B7ECBBD60D86L,
+ 0x998F0F350104754CL, 0x0000000000000000L, 0xF12E314D34D0CCECL, 0x710522BE061823B5L,
+ 0xAF280D9930C005C1L, 0x97FD5CE25D693C65L, 0x19A41CC633CC9A15L, 0x95844172F8C79EB8L,
+ 0xDC5432B7937684A9L, 0x9436C13A2490CF58L, 0x802B13F332C8EF59L, 0xC442AE397CED4F5CL,
+ 0xFA1CD8EFE3AB8D82L, 0xF2E5AC954D293FD1L, 0x6AD823E8907A1B7DL, 0x4D2249F83CF043B6L,
+ 0x03CB9DD879F9F33DL, 0xDE2D2F2736D82674L, 0x2A43A41F891EE2DFL, 0x6F98999D1B6C133AL,
+ 0xD4AD46CD3DF436FAL, 0xBB35DF50269825C0L, 0x964FDCAA813E6D85L, 0xEB41B0537EE5A5C4L,
+ 0x0540BA758B160847L, 0xA41AE43BE7BB44AFL, 0xE3B8C429D0671797L, 0x819993BBEE9FBEB9L,
+ 0xAE9A8DD1EC975421L, 0xF3572CDD917E6E31L, 0x6393D7DAE2AFF8CEL, 0x47A2201237DC5338L,
+ 0xA32343DEC903EE35L, 0x79FC56C4A89A91E6L, 0x01B28048DC5751E0L, 0x1296F564E4B7DB7BL,
+ 0x75F7188351597A12L, 0xDB6D9552BDCE2E33L, 0x1E9DBB231D74308FL, 0x520D7293FDD322D9L,
+ 0xE20A44610C304677L, 0xFEEEE2D2B4EAD425L, 0xCA30FDEE20800675L, 0x61EACA4A47015A13L,
+ 0xE74AFE1487264E30L, 0x2CC883B27BF119A5L, 0x1664CF59B3F682DCL, 0xA811AA7C1E78AF5BL,
+ 0x1D5626FB648DC3B2L, 0xB73E9117DF5BCE34L, 0xD05F7CF06AB56F5DL, 0xFD257F0ACD132718L,
+ 0x574DC8E676C52A9EL, 0x0739A7E52EB8AA9AL, 0x5486553E0F3CD9A3L, 0x56FF48AEAA927B7EL,
+ 0xBE756525AD8E2D87L, 0x7D0E6CF9FFDBC841L, 0x3B1ECCA31450CA99L, 0x6913BE30E983E840L,
+ 0xAD511009956EA71CL, 0xB1B5B6BA2DB4354EL, 0x4469BDCA4E25A005L, 0x15AF5281CA0F71E1L,
+ 0x744598CB8D0E2BF2L, 0x593F9B312AA863B7L, 0xEFB38A6E29A4FC63L, 0x6B6AA3A04C2D4A9DL,
+ 0x3D95EB0EE6BF31E3L, 0xA291C3961554BFD5L, 0x18169C8EEF9BCBF5L, 0x115D68BC9D4E2846L,
+ 0xBA875F18FACF7420L, 0xD1EDFCB8B6E23EBDL, 0xB00736F2F1E364AEL, 0x84D929CE6589B6FEL,
+ 0x70B7A2F6DA4F7255L, 0x0E7253D75C6D4929L, 0x04F23A3D574159A7L, 0x0A8069EA0B2C108EL,
+ 0x49D073C56BB11A11L, 0x8AAB7A1939E4FFD7L, 0xCD095A0B0E38ACEFL, 0xC9FB60365979F548L,
+ 0x92BDE697D67F3422L, 0xC78933E10514BC61L, 0xE1C1D9B975C9B54AL, 0xD2266160CF1BCD80L,
+ 0x9A4492ED78FD8671L, 0xB3CCAB2A881A9793L, 0x72CEBF667FE1D088L, 0xD6D45B5D985A9427L
+ },
+ new ulong[]{
+ 0xC811A8058C3F55DEL, 0x65F5B43196B50619L, 0xF74F96B1D6706E43L, 0x859D1E8BCB43D336L,
+ 0x5AAB8A85CCFA3D84L, 0xF9C7BF99C295FCFDL, 0xA21FD5A1DE4B630FL, 0xCDB3EF763B8B456DL,
+ 0x803F59F87CF7C385L, 0xB27C73BE5F31913CL, 0x98E3AC6633B04821L, 0xBF61674C26B8F818L,
+ 0x0FFBC995C4C130C8L, 0xAAA0862010761A98L, 0x6057F342210116AAL, 0xF63C760C0654CC35L,
+ 0x2DDB45CC667D9042L, 0xBCF45A964BD40382L, 0x68E8A0C3EF3C6F3DL, 0xA7BD92D269FF73BCL,
+ 0x290AE20201ED2287L, 0xB7DE34CDE885818FL, 0xD901EEA7DD61059BL, 0xD6FA273219A03553L,
+ 0xD56F1AE874CCCEC9L, 0xEA31245C2E83F554L, 0x7034555DA07BE499L, 0xCE26D2AC56E7BEF7L,
+ 0xFD161857A5054E38L, 0x6A0E7DA4527436D1L, 0x5BD86A381CDE9FF2L, 0xCAF7756231770C32L,
+ 0xB09AAED9E279C8D0L, 0x5DEF1091C60674DBL, 0x111046A2515E5045L, 0x23536CE4729802FCL,
+ 0xC50CBCF7F5B63CFAL, 0x73A16887CD171F03L, 0x7D2941AFD9F28DBDL, 0x3F5E3EB45A4F3B9DL,
+ 0x84EEFE361B677140L, 0x3DB8E3D3E7076271L, 0x1A3A28F9F20FD248L, 0x7EBC7C75B49E7627L,
+ 0x74E5F293C7EB565CL, 0x18DCF59E4F478BA4L, 0x0C6EF44FA9ADCB52L, 0xC699812D98DAC760L,
+ 0x788B06DC6E469D0EL, 0xFC65F8EA7521EC4EL, 0x30A5F7219E8E0B55L, 0x2BEC3F65BCA57B6BL,
+ 0xDDD04969BAF1B75EL, 0x99904CDBE394EA57L, 0x14B201D1E6EA40F6L, 0xBBB0C08241284ADDL,
+ 0x50F20463BF8F1DFFL, 0xE8D7F93B93CBACB8L, 0x4D8CB68E477C86E8L, 0xC1DD1B3992268E3FL,
+ 0x7C5AA11209D62FCBL, 0x2F3D98ABDB35C9AEL, 0x671369562BFD5FF5L, 0x15C1E16C36CEE280L,
+ 0x1D7EB2EDF8F39B17L, 0xDA94D37DB00DFE01L, 0x877BC3EC760B8ADAL, 0xCB8495DFE153AE44L,
+ 0x05A24773B7B410B3L, 0x12857B783C32ABDFL, 0x8EB770D06812513BL, 0x536739B9D2E3E665L,
+ 0x584D57E271B26468L, 0xD789C78FC9849725L, 0xA935BBFA7D1AE102L, 0x8B1537A3DFA64188L,
+ 0xD0CD5D9BC378DE7AL, 0x4AC82C9A4D80CFB7L, 0x42777F1B83BDB620L, 0x72D2883A1D33BD75L,
+ 0x5E7A2D4BAB6A8F41L, 0xF4DAAB6BBB1C95D9L, 0x905CFFE7FD8D31B6L, 0x83AA6422119B381FL,
+ 0xC0AEFB8442022C49L, 0xA0F908C663033AE3L, 0xA428AF0804938826L, 0xADE41C341A8A53C7L,
+ 0xAE7121EE77E6A85DL, 0xC47F5C4A25929E8CL, 0xB538E9AA55CDD863L, 0x06377AA9DAD8EB29L,
+ 0xA18AE87BB3279895L, 0x6EDFDA6A35E48414L, 0x6B7D9D19825094A7L, 0xD41CFA55A4E86CBFL,
+ 0xE5CAEDC9EA42C59CL, 0xA36C351C0E6FC179L, 0x5181E4DE6FABBF89L, 0xFFF0C530184D17D4L,
+ 0x9D41EB1584045892L, 0x1C0D525028D73961L, 0xF178EC180CA8856AL, 0x9A0571018EF811CDL,
+ 0x4091A27C3EF5EFCCL, 0x19AF15239F6329D2L, 0x347450EFF91EB990L, 0xE11B4A078DD27759L,
+ 0xB9561DE5FC601331L, 0x912F1F5A2DA993C0L, 0x1654DCB65BA2191AL, 0x3E2DDE098A6B99EBL,
+ 0x8A66D71E0F82E3FEL, 0x8C51ADB7D55A08D7L, 0x4533E50F8941FF7FL, 0x02E6DD67BD4859ECL,
+ 0xE068AABA5DF6D52FL, 0xC24826E3FF4A75A5L, 0x6C39070D88ACDDF8L, 0x6486548C4691A46FL,
+ 0xD1BEBD26135C7C0CL, 0xB30F93038F15334AL, 0x82D9849FC1BF9A69L, 0x9C320BA85420FAE4L,
+ 0xFA528243AFF90767L, 0x9ED4D6CFE968A308L, 0xB825FD582C44B147L, 0x9B7691BC5EDCB3BBL,
+ 0xC7EA619048FE6516L, 0x1063A61F817AF233L, 0x47D538683409A693L, 0x63C2CE984C6DED30L,
+ 0x2A9FDFD86C81D91DL, 0x7B1E3B06032A6694L, 0x666089EBFBD9FD83L, 0x0A598EE67375207BL,
+ 0x07449A140AFC495FL, 0x2CA8A571B6593234L, 0x1F986F8A45BBC2FBL, 0x381AA4A050B372C2L,
+ 0x5423A3ADD81FAF3AL, 0x17273C0B8B86BB6CL, 0xFE83258DC869B5A2L, 0x287902BFD1C980F1L,
+ 0xF5A94BD66B3837AFL, 0x88800A79B2CABA12L, 0x55504310083B0D4CL, 0xDF36940E07B9EEB2L,
+ 0x04D1A7CE6790B2C5L, 0x612413FFF125B4DCL, 0x26F12B97C52C124FL, 0x86082351A62F28ACL,
+ 0xEF93632F9937E5E7L, 0x3507B052293A1BE6L, 0xE72C30AE570A9C70L, 0xD3586041AE1425E0L,
+ 0xDE4574B3D79D4CC4L, 0x92BA228040C5685AL, 0xF00B0CA5DC8C271CL, 0xBE1287F1F69C5A6EL,
+ 0xF39E317FB1E0DC86L, 0x495D114020EC342DL, 0x699B407E3F18CD4BL, 0xDCA3A9D46AD51528L,
+ 0x0D1D14F279896924L, 0x0000000000000000L, 0x593EB75FA196C61EL, 0x2E4E78160B116BD8L,
+ 0x6D4AE7B058887F8EL, 0xE65FD013872E3E06L, 0x7A6DDBBBD30EC4E2L, 0xAC97FC89CAAEF1B1L,
+ 0x09CCB33C1E19DBE1L, 0x89F3EAC462EE1864L, 0x7770CF49AA87ADC6L, 0x56C57ECA6557F6D6L,
+ 0x03953DDA6D6CFB9AL, 0x36928D884456E07CL, 0x1EEB8F37959F608DL, 0x31D6179C4EAAA923L,
+ 0x6FAC3AD7E5C02662L, 0x43049FA653991456L, 0xABD3669DC052B8EEL, 0xAF02C153A7C20A2BL,
+ 0x3CCB036E3723C007L, 0x93C9C23D90E1CA2CL, 0xC33BC65E2F6ED7D3L, 0x4CFF56339758249EL,
+ 0xB1E94E64325D6AA6L, 0x37E16D359472420AL, 0x79F8E661BE623F78L, 0x5214D90402C74413L,
+ 0x482EF1FDF0C8965BL, 0x13F69BC5EC1609A9L, 0x0E88292814E592BEL, 0x4E198B542A107D72L,
+ 0xCCC00FCBEBAFE71BL, 0x1B49C844222B703EL, 0x2564164DA840E9D5L, 0x20C6513E1FF4F966L,
+ 0xBAC3203F910CE8ABL, 0xF2EDD1C261C47EF0L, 0x814CB945ACD361F3L, 0x95FEB8944A392105L,
+ 0x5C9CF02C1622D6ADL, 0x971865F3F77178E9L, 0xBD87BA2B9BF0A1F4L, 0x444005B259655D09L,
+ 0xED75BE48247FBC0BL, 0x7596122E17CFF42AL, 0xB44B091785E97A15L, 0x966B854E2755DA9FL,
+ 0xEEE0839249134791L, 0x32432A4623C652B9L, 0xA8465B47AD3E4374L, 0xF8B45F2412B15E8BL,
+ 0x2417F6F078644BA3L, 0xFB2162FE7FDDA511L, 0x4BBBCC279DA46DC1L, 0x0173E0BDD024A276L,
+ 0x22208C59A2BCA08AL, 0x8FC4906DB836F34DL, 0xE4B90D743A6667EAL, 0x7147B5E0705F46EFL,
+ 0x2782CB2A1508B039L, 0xEC065EF5F45B1E7DL, 0x21B5B183CFD05B10L, 0xDBE733C060295C77L,
+ 0x9FA73672394C017EL, 0xCF55321186C31C81L, 0xD8720E1A0D45A7EDL, 0x3B8F997A3DDF8958L,
+ 0x3AFC79C7EDFB2B2EL, 0xE9A4198643EF0ECEL, 0x5F09CDF67B4E2D37L, 0x4F6A6BE9FA34DF04L,
+ 0xB6ADD47038A123F9L, 0x8D224D0A057EAAA1L, 0xC96248B85C1BF7A8L, 0xE3FD9760309A2EB5L,
+ 0x0B2A6E5BA351820DL, 0xEB42C4E1FEA75722L, 0x948D58299A1D8373L, 0x7FCF9CC864BAD451L,
+ 0xA55B4FB5D4B72A50L, 0x08BF5381CE3D7997L, 0x46A6D8D5E42D04E5L, 0xD22B80FC7E308796L,
+ 0x57B69E77B57354A0L, 0x3969441D8097D0B4L, 0x3330CAFBF3E2F0CFL, 0xE28E77DDE0BE8CC3L,
+ 0x62B12E259C494F46L, 0xA6CE726FB9DBD1CAL, 0x41E242C1EED14DBAL, 0x76032FF47AA30FB0L
+ },
+ new ulong[]{
+ 0x45B268A93ACDE4CCL, 0xAF7F0BE884549D08L, 0x048354B3C1468263L, 0x925435C2C80EFED2L,
+ 0xEE4E37F27FDFFBA7L, 0x167A33920C60F14DL, 0xFB123B52EA03E584L, 0x4A0CAB53FDBB9007L,
+ 0x9DEAF6380F788A19L, 0xCB48EC558F0CB32AL, 0xB59DC4B2D6FEF7E0L, 0xDCDBCA22F4F3ECB6L,
+ 0x11DF5813549A9C40L, 0xE33FDEDF568ACED3L, 0xA0C1C8124322E9C3L, 0x07A56B8158FA6D0DL,
+ 0x77279579B1E1F3DDL, 0xD9B18B74422AC004L, 0xB8EC2D9FFFABC294L, 0xF4ACF8A82D75914FL,
+ 0x7BBF69B1EF2B6878L, 0xC4F62FAF487AC7E1L, 0x76CE809CC67E5D0CL, 0x6711D88F92E4C14CL,
+ 0x627B99D9243DEDFEL, 0x234AA5C3DFB68B51L, 0x909B1F15262DBF6DL, 0x4F66EA054B62BCB5L,
+ 0x1AE2CF5A52AA6AE8L, 0xBEA053FBD0CE0148L, 0xED6808C0E66314C9L, 0x43FE16CD15A82710L,
+ 0xCD049231A06970F6L, 0xE7BC8A6C97CC4CB0L, 0x337CE835FCB3B9C0L, 0x65DEF2587CC780F3L,
+ 0x52214EDE4132BB50L, 0x95F15E4390F493DFL, 0x870839625DD2E0F1L, 0x41313C1AFB8B66AFL,
+ 0x91720AF051B211BCL, 0x477D427ED4EEA573L, 0x2E3B4CEEF6E3BE25L, 0x82627834EB0BCC43L,
+ 0x9C03E3DD78E724C8L, 0x2877328AD9867DF9L, 0x14B51945E243B0F2L, 0x574B0F88F7EB97E2L,
+ 0x88B6FA989AA4943AL, 0x19C4F068CB168586L, 0x50EE6409AF11FAEFL, 0x7DF317D5C04EABA4L,
+ 0x7A567C5498B4C6A9L, 0xB6BBFB804F42188EL, 0x3CC22BCF3BC5CD0BL, 0xD04336EAAA397713L,
+ 0xF02FAC1BEC33132CL, 0x2506DBA7F0D3488DL, 0xD7E65D6BF2C31A1EL, 0x5EB9B2161FF820F5L,
+ 0x842E0650C46E0F9FL, 0x716BEB1D9E843001L, 0xA933758CAB315ED4L, 0x3FE414FDA2792265L,
+ 0x27C9F1701EF00932L, 0x73A4C1CA70A771BEL, 0x94184BA6E76B3D0EL, 0x40D829FF8C14C87EL,
+ 0x0FBEC3FAC77674CBL, 0x3616A9634A6A9572L, 0x8F139119C25EF937L, 0xF545ED4D5AEA3F9EL,
+ 0xE802499650BA387BL, 0x6437E7BD0B582E22L, 0xE6559F89E053E261L, 0x80AD52E305288DFCL,
+ 0x6DC55A23E34B9935L, 0xDE14E0F51AD0AD09L, 0xC6390578A659865EL, 0x96D7617109487CB1L,
+ 0xE2D6CB3A21156002L, 0x01E915E5779FAED1L, 0xADB0213F6A77DCB7L, 0x9880B76EB9A1A6ABL,
+ 0x5D9F8D248644CF9BL, 0xFD5E4536C5662658L, 0xF1C6B9FE9BACBDFDL, 0xEACD6341BE9979C4L,
+ 0xEFA7221708405576L, 0x510771ECD88E543EL, 0xC2BA51CB671F043DL, 0x0AD482AC71AF5879L,
+ 0xFE787A045CDAC936L, 0xB238AF338E049AEDL, 0xBD866CC94972EE26L, 0x615DA6EBBD810290L,
+ 0x3295FDD08B2C1711L, 0xF834046073BF0AEAL, 0xF3099329758FFC42L, 0x1CAEB13E7DCFA934L,
+ 0xBA2307481188832BL, 0x24EFCE42874CE65CL, 0x0E57D61FB0E9DA1AL, 0xB3D1BAD6F99B343CL,
+ 0xC0757B1C893C4582L, 0x2B510DB8403A9297L, 0x5C7698C1F1DB614AL, 0x3E0D0118D5E68CB4L,
+ 0xD60F488E855CB4CFL, 0xAE961E0DF3CB33D9L, 0x3A8E55AB14A00ED7L, 0x42170328623789C1L,
+ 0x838B6DD19C946292L, 0x895FEF7DED3B3AEBL, 0xCFCBB8E64E4A3149L, 0x064C7E642F65C3DCL,
+ 0x3D2B3E2A4C5A63DAL, 0x5BD3F340A9210C47L, 0xB474D157A1615931L, 0xAC5934DA1DE87266L,
+ 0x6EE365117AF7765BL, 0xC86ED36716B05C44L, 0x9BA6885C201D49C5L, 0xB905387A88346C45L,
+ 0x131072C4BAB9DDFFL, 0xBF49461EA751AF99L, 0xD52977BC1CE05BA1L, 0xB0F785E46027DB52L,
+ 0x546D30BA6E57788CL, 0x305AD707650F56AEL, 0xC987C682612FF295L, 0xA5AB8944F5FBC571L,
+ 0x7ED528E759F244CAL, 0x8DDCBBCE2C7DB888L, 0xAA154ABE328DB1BAL, 0x1E619BE993ECE88BL,
+ 0x09F2BD9EE813B717L, 0x7401AA4B285D1CB3L, 0x21858F143195CAEEL, 0x48C381841398D1B8L,
+ 0xFCB750D3B2F98889L, 0x39A86A998D1CE1B9L, 0x1F888E0CE473465AL, 0x7899568376978716L,
+ 0x02CF2AD7EE2341BFL, 0x85C713B5B3F1A14EL, 0xFF916FE12B4567E7L, 0x7C1A0230B7D10575L,
+ 0x0C98FCC85ECA9BA5L, 0xA3E7F720DA9E06ADL, 0x6A6031A2BBB1F438L, 0x973E74947ED7D260L,
+ 0x2CF4663918C0FF9AL, 0x5F50A7F368678E24L, 0x34D983B4A449D4CDL, 0x68AF1B755592B587L,
+ 0x7F3C3D022E6DEA1BL, 0xABFC5F5B45121F6BL, 0x0D71E92D29553574L, 0xDFFDF5106D4F03D8L,
+ 0x081BA87B9F8C19C6L, 0xDB7EA1A3AC0981BBL, 0xBBCA12AD66172DFAL, 0x79704366010829C7L,
+ 0x179326777BFF5F9CL, 0x0000000000000000L, 0xEB2476A4C906D715L, 0x724DD42F0738DF6FL,
+ 0xB752EE6538DDB65FL, 0x37FFBC863DF53BA3L, 0x8EFA84FCB5C157E6L, 0xE9EB5C73272596AAL,
+ 0x1B0BDABF2535C439L, 0x86E12C872A4D4E20L, 0x9969A28BCE3E087AL, 0xFAFB2EB79D9C4B55L,
+ 0x056A4156B6D92CB2L, 0x5A3AE6A5DEBEA296L, 0x22A3B026A8292580L, 0x53C85B3B36AD1581L,
+ 0xB11E900117B87583L, 0xC51F3A4A3FE56930L, 0xE019E1EDCF3621BDL, 0xEC811D2591FCBA18L,
+ 0x445B7D4C4D524A1DL, 0xA8DA6069DCAEF005L, 0x58F5CC72309DE329L, 0xD4C062596B7FF570L,
+ 0xCE22AD0339D59F98L, 0x591CD99747024DF8L, 0x8B90C5AA03187B54L, 0xF663D27FC356D0F0L,
+ 0xD8589E9135B56ED5L, 0x35309651D3D67A1CL, 0x12F96721CD26732EL, 0xD28C1C3D441A36ACL,
+ 0x492A946164077F69L, 0x2D1D73DC6F5F514BL, 0x6F0A70F40D68D88AL, 0x60B4B30ECA1EAC41L,
+ 0xD36509D83385987DL, 0x0B3D97490630F6A8L, 0x9ECCC90A96C46577L, 0xA20EE2C5AD01A87CL,
+ 0xE49AB55E0E70A3DEL, 0xA4429CA182646BA0L, 0xDA97B446DB962F6AL, 0xCCED87D4D7F6DE27L,
+ 0x2AB8185D37A53C46L, 0x9F25DCEFE15BCBA6L, 0xC19C6EF9FEA3EB53L, 0xA764A3931BD884CEL,
+ 0x2FD2590B817C10F4L, 0x56A21A6D80743933L, 0xE573A0BB79EF0D0FL, 0x155C0CA095DC1E23L,
+ 0x6C2C4FC694D437E4L, 0x10364DF623053291L, 0xDD32DFC7836C4267L, 0x03263F3299BCEF6EL,
+ 0x66F8CD6AE57B6F9DL, 0x8C35AE2B5BE21659L, 0x31B3C2E21290F87FL, 0x93BD2027BF915003L,
+ 0x69460E90220D1B56L, 0x299E276FAE19D328L, 0x63928C3C53A2432FL, 0x7082FEF8E91B9ED0L,
+ 0xBC6F792C3EED40F7L, 0x4C40D537D2DE53DBL, 0x75E8BFAE5FC2B262L, 0x4DA9C0D2A541FD0AL,
+ 0x4E8FFFE03CFD1264L, 0x2620E495696FA7E3L, 0xE1F0F408B8A98F6CL, 0xD1AA230FDDA6D9C2L,
+ 0xC7D0109DD1C6288FL, 0x8A79D04F7487D585L, 0x4694579BA3710BA2L, 0x38417F7CFA834F68L,
+ 0x1D47A4DB0A5007E5L, 0x206C9AF1460A643FL, 0xA128DDF734BD4712L, 0x8144470672B7232DL,
+ 0xF2E086CC02105293L, 0x182DE58DBC892B57L, 0xCAA1F9B0F8931DFBL, 0x6B892447CC2E5AE9L,
+ 0xF9DD11850420A43BL, 0x4BE5BEB68A243ED6L, 0x5584255F19C8D65DL, 0x3B67404E633FA006L,
+ 0xA68DB6766C472A1FL, 0xF78AC79AB4C97E21L, 0xC353442E1080AAECL, 0x9A4F9DB95782E714L
+ },
+ new ulong[] {
+ 0x05BA7BC82C9B3220L, 0x31A54665F8B65E4FL, 0xB1B651F77547F4D4L, 0x8BFA0D857BA46682L,
+ 0x85A96C5AA16A98BBL, 0x990FAEF908EB79C9L, 0xA15E37A247F4A62DL, 0x76857DCD5D27741EL,
+ 0xF8C50B800A1820BCL, 0xBE65DCB201F7A2B4L, 0x666D1B986F9426E7L, 0x4CC921BF53C4E648L,
+ 0x95410A0F93D9CA42L, 0x20CDCCAA647BA4EFL, 0x429A4060890A1871L, 0x0C4EA4F69B32B38BL,
+ 0xCCDA362DDE354CD3L, 0x96DC23BC7C5B2FA9L, 0xC309BB68AA851AB3L, 0xD26131A73648E013L,
+ 0x021DC52941FC4DB2L, 0xCD5ADAB7704BE48AL, 0xA77965D984ED71E6L, 0x32386FD61734BBA4L,
+ 0xE82D6DD538AB7245L, 0x5C2147EA6177B4B1L, 0x5DA1AB70CF091CE8L, 0xAC907FCE72B8BDFFL,
+ 0x57C85DFD972278A8L, 0xA4E44C6A6B6F940DL, 0x3851995B4F1FDFE4L, 0x62578CCAED71BC9EL,
+ 0xD9882BB0C01D2C0AL, 0x917B9D5D113C503BL, 0xA2C31E11A87643C6L, 0xE463C923A399C1CEL,
+ 0xF71686C57EA876DCL, 0x87B4A973E096D509L, 0xAF0D567D9D3A5814L, 0xB40C2A3F59DCC6F4L,
+ 0x3602F88495D121DDL, 0xD3E1DD3D9836484AL, 0xF945E71AA46688E5L, 0x7518547EB2A591F5L,
+ 0x9366587450C01D89L, 0x9EA81018658C065BL, 0x4F54080CBC4603A3L, 0x2D0384C65137BF3DL,
+ 0xDC325078EC861E2AL, 0xEA30A8FC79573FF7L, 0x214D2030CA050CB6L, 0x65F0322B8016C30CL,
+ 0x69BE96DD1B247087L, 0xDB95EE9981E161B8L, 0xD1FC1814D9CA05F8L, 0x820ED2BBCC0DE729L,
+ 0x63D76050430F14C7L, 0x3BCCB0E8A09D3A0FL, 0x8E40764D573F54A2L, 0x39D175C1E16177BDL,
+ 0x12F5A37C734F1F4BL, 0xAB37C12F1FDFC26DL, 0x5648B167395CD0F1L, 0x6C04ED1537BF42A7L,
+ 0xED97161D14304065L, 0x7D6C67DAAB72B807L, 0xEC17FA87BA4EE83CL, 0xDFAF79CB0304FBC1L,
+ 0x733F060571BC463EL, 0x78D61C1287E98A27L, 0xD07CF48E77B4ADA1L, 0xB9C262536C90DD26L,
+ 0xE2449B5860801605L, 0x8FC09AD7F941FCFBL, 0xFAD8CEA94BE46D0EL, 0xA343F28B0608EB9FL,
+ 0x9B126BD04917347BL, 0x9A92874AE7699C22L, 0x1B017C42C4E69EE0L, 0x3A4C5C720EE39256L,
+ 0x4B6E9F5E3EA399DAL, 0x6BA353F45AD83D35L, 0xE7FEE0904C1B2425L, 0x22D009832587E95DL,
+ 0x842980C00F1430E2L, 0xC6B3C0A0861E2893L, 0x087433A419D729F2L, 0x341F3DADD42D6C6FL,
+ 0xEE0A3FAEFBB2A58EL, 0x4AEE73C490DD3183L, 0xAAB72DB5B1A16A34L, 0xA92A04065E238FDFL,
+ 0x7B4B35A1686B6FCCL, 0x6A23BF6EF4A6956CL, 0x191CB96B851AD352L, 0x55D598D4D6DE351AL,
+ 0xC9604DE5F2AE7EF3L, 0x1CA6C2A3A981E172L, 0xDE2F9551AD7A5398L, 0x3025AAFF56C8F616L,
+ 0x15521D9D1E2860D9L, 0x506FE31CFA45073AL, 0x189C55F12B647B0BL, 0x0180EC9AAE7EA859L,
+ 0x7CEC8B40050C105EL, 0x2350E5198BF94104L, 0xEF8AD33455CC0DD7L, 0x07A7BEE16D677F92L,
+ 0xE5E325B90DE76997L, 0x5A061591A26E637AL, 0xB611EF1618208B46L, 0x09F4DF3EB7A981ABL,
+ 0x1EBB078AE87DACC0L, 0xB791038CB65E231FL, 0x0FD38D4574B05660L, 0x67EDF702C1EA8EBEL,
+ 0xBA5F4BE0831238CDL, 0xE3C477C2CEFEBE5CL, 0x0DCE486C354C1BD2L, 0x8C5DB36416C31910L,
+ 0x26EA9ED1A7627324L, 0x039D29B3EF82E5EBL, 0x9F28FC82CBF2AE02L, 0xA8AAE89CF05D2786L,
+ 0x431AACFA2774B028L, 0xCF471F9E31B7A938L, 0x581BD0B8E3922EC8L, 0xBC78199B400BEF06L,
+ 0x90FB71C7BF42F862L, 0x1F3BEB1046030499L, 0x683E7A47B55AD8DEL, 0x988F4263A695D190L,
+ 0xD808C72A6E638453L, 0x0627527BC319D7CBL, 0xEBB04466D72997AEL, 0xE67E0C0AE2658C7CL,
+ 0x14D2F107B056C880L, 0x7122C32C30400B8CL, 0x8A7AE11FD5DACEDBL, 0xA0DEDB38E98A0E74L,
+ 0xAD109354DCC615A6L, 0x0BE91A17F655CC19L, 0x8DDD5FFEB8BDB149L, 0xBFE53028AF890AEDL,
+ 0xD65BA6F5B4AD7A6AL, 0x7956F0882997227EL, 0x10E8665532B352F9L, 0x0E5361DFDACEFE39L,
+ 0xCEC7F3049FC90161L, 0xFF62B561677F5F2EL, 0x975CCF26D22587F0L, 0x51EF0F86543BAF63L,
+ 0x2F1E41EF10CBF28FL, 0x52722635BBB94A88L, 0xAE8DBAE73344F04DL, 0x410769D36688FD9AL,
+ 0xB3AB94DE34BBB966L, 0x801317928DF1AA9BL, 0xA564A0F0C5113C54L, 0xF131D4BEBDB1A117L,
+ 0x7F71A2F3EA8EF5B5L, 0x40878549C8F655C3L, 0x7EF14E6944F05DECL, 0xD44663DCF55137D8L,
+ 0xF2ACFD0D523344FCL, 0x0000000000000000L, 0x5FBC6E598EF5515AL, 0x16CF342EF1AA8532L,
+ 0xB036BD6DDB395C8DL, 0x13754FE6DD31B712L, 0xBBDFA77A2D6C9094L, 0x89E7C8AC3A582B30L,
+ 0x3C6B0E09CDFA459DL, 0xC4AE0589C7E26521L, 0x49735A777F5FD468L, 0xCAFD64561D2C9B18L,
+ 0xDA1502032F9FC9E1L, 0x8867243694268369L, 0x3782141E3BAF8984L, 0x9CB5D53124704BE9L,
+ 0xD7DB4A6F1AD3D233L, 0xA6F989432A93D9BFL, 0x9D3539AB8A0EE3B0L, 0x53F2CAAF15C7E2D1L,
+ 0x6E19283C76430F15L, 0x3DEBE2936384EDC4L, 0x5E3C82C3208BF903L, 0x33B8834CB94A13FDL,
+ 0x6470DEB12E686B55L, 0x359FD1377A53C436L, 0x61CAA57902F35975L, 0x043A975282E59A79L,
+ 0xFD7F70482683129CL, 0xC52EE913699CCD78L, 0x28B9FF0E7DAC8D1DL, 0x5455744E78A09D43L,
+ 0xCB7D88CCB3523341L, 0x44BD121B4A13CFBAL, 0x4D49CD25FDBA4E11L, 0x3E76CB208C06082FL,
+ 0x3FF627BA2278A076L, 0xC28957F204FBB2EAL, 0x453DFE81E46D67E3L, 0x94C1E6953DA7621BL,
+ 0x2C83685CFF491764L, 0xF32C1197FC4DECA5L, 0x2B24D6BD922E68F6L, 0xB22B78449AC5113FL,
+ 0x48F3B6EDD1217C31L, 0x2E9EAD75BEB55AD6L, 0x174FD8B45FD42D6BL, 0x4ED4E4961238ABFAL,
+ 0x92E6B4EEFEBEB5D0L, 0x46A0D7320BEF8208L, 0x47203BA8A5912A51L, 0x24F75BF8E69E3E96L,
+ 0xF0B1382413CF094EL, 0xFEE259FBC901F777L, 0x276A724B091CDB7DL, 0xBDF8F501EE75475FL,
+ 0x599B3C224DEC8691L, 0x6D84018F99C1EAFEL, 0x7498B8E41CDB39ACL, 0xE0595E71217C5BB7L,
+ 0x2AA43A273C50C0AFL, 0xF50B43EC3F543B6EL, 0x838E3E2162734F70L, 0xC09492DB4507FF58L,
+ 0x72BFEA9FDFC2EE67L, 0x11688ACF9CCDFAA0L, 0x1A8190D86A9836B9L, 0x7ACBD93BC615C795L,
+ 0xC7332C3A286080CAL, 0x863445E94EE87D50L, 0xF6966A5FD0D6DE85L, 0xE9AD814F96D5DA1CL,
+ 0x70A22FB69E3EA3D5L, 0x0A69F68D582B6440L, 0xB8428EC9C2EE757FL, 0x604A49E3AC8DF12CL,
+ 0x5B86F90B0C10CB23L, 0xE1D9B2EB8F02F3EEL, 0x29391394D3D22544L, 0xC8E0A17F5CD0D6AAL,
+ 0xB58CC6A5F7A26EADL, 0x8193FB08238F02C2L, 0xD5C68F465B2F9F81L, 0xFCFF9CD288FDBAC5L,
+ 0x77059157F359DC47L, 0x1D262E3907FF492BL, 0xFB582233E59AC557L, 0xDDB2BCE242F8B673L,
+ 0x2577B76248E096CFL, 0x6F99C4A6D83DA74CL, 0xC1147E41EB795701L, 0xF48BAF76912A9337L
+ },
+ new ulong[] {
+ 0x3EF29D249B2C0A19L, 0xE9E16322B6F8622FL, 0x5536994047757F7AL, 0x9F4D56D5A47B0B33L,
+ 0x822567466AA1174CL, 0xB8F5057DEB082FB2L, 0xCC48C10BF4475F53L, 0x373088D4275DEC3AL,
+ 0x968F4325180AED10L, 0x173D232CF7016151L, 0xAE4ED09F946FCC13L, 0xFD4B4741C4539873L,
+ 0x1B5B3F0DD9933765L, 0x2FFCB0967B644052L, 0xE02376D20A89840CL, 0xA3AE3A70329B18D7L,
+ 0x419CBD2335DE8526L, 0xFAFEBF115B7C3199L, 0x0397074F85AA9B0DL, 0xC58AD4FB4836B970L,
+ 0xBEC60BE3FC4104A8L, 0x1EFF36DC4B708772L, 0x131FDC33ED8453B6L, 0x0844E33E341764D3L,
+ 0x0FF11B6EAB38CD39L, 0x64351F0A7761B85AL, 0x3B5694F509CFBA0EL, 0x30857084B87245D0L,
+ 0x47AFB3BD2297AE3CL, 0xF2BA5C2F6F6B554AL, 0x74BDC4761F4F70E1L, 0xCFDFC64471EDC45EL,
+ 0xE610784C1DC0AF16L, 0x7ACA29D63C113F28L, 0x2DED411776A859AFL, 0xAC5F211E99A3D5EEL,
+ 0xD484F949A87EF33BL, 0x3CE36CA596E013E4L, 0xD120F0983A9D432CL, 0x6BC40464DC597563L,
+ 0x69D5F5E5D1956C9EL, 0x9AE95F043698BB24L, 0xC9ECC8DA66A4EF44L, 0xD69508C8A5B2EAC6L,
+ 0xC40C2235C0503B80L, 0x38C193BA8C652103L, 0x1CEEC75D46BC9E8FL, 0xD331011937515AD1L,
+ 0xD8E2E56886ECA50FL, 0xB137108D5779C991L, 0x709F3B6905CA4206L, 0x4FEB50831680CAEFL,
+ 0xEC456AF3241BD238L, 0x58D673AFE181ABBEL, 0x242F54E7CAD9BF8CL, 0x0211F1810DCC19FDL,
+ 0x90BC4DBB0F43C60AL, 0x9518446A9DA0761DL, 0xA1BFCBF13F57012AL, 0x2BDE4F8961E172B5L,
+ 0x27B853A84F732481L, 0xB0B1E643DF1F4B61L, 0x18CC38425C39AC68L, 0xD2B7F7D7BF37D821L,
+ 0x3103864A3014C720L, 0x14AA246372ABFA5CL, 0x6E600DB54EBAC574L, 0x394765740403A3F3L,
+ 0x09C215F0BC71E623L, 0x2A58B947E987F045L, 0x7B4CDF18B477BDD8L, 0x9709B5EB906C6FE0L,
+ 0x73083C268060D90BL, 0xFEDC400E41F9037EL, 0x284948C6E44BE9B8L, 0x728ECAE808065BFBL,
+ 0x06330E9E17492B1AL, 0x5950856169E7294EL, 0xBAE4F4FCE6C4364FL, 0xCA7BCF95E30E7449L,
+ 0x7D7FD186A33E96C2L, 0x52836110D85AD690L, 0x4DFAA1021B4CD312L, 0x913ABB75872544FAL,
+ 0xDD46ECB9140F1518L, 0x3D659A6B1E869114L, 0xC23F2CABD719109AL, 0xD713FE062DD46836L,
+ 0xD0A60656B2FBC1DCL, 0x221C5A79DD909496L, 0xEFD26DBCA1B14935L, 0x0E77EDA0235E4FC9L,
+ 0xCBFD395B6B68F6B9L, 0x0DE0EAEFA6F4D4C4L, 0x0422FF1F1A8532E7L, 0xF969B85EDED6AA94L,
+ 0x7F6E2007AEF28F3FL, 0x3AD0623B81A938FEL, 0x6624EE8B7AADA1A7L, 0xB682E8DDC856607BL,
+ 0xA78CC56F281E2A30L, 0xC79B257A45FAA08DL, 0x5B4174E0642B30B3L, 0x5F638BFF7EAE0254L,
+ 0x4BC9AF9C0C05F808L, 0xCE59308AF98B46AEL, 0x8FC58DA9CC55C388L, 0x803496C7676D0EB1L,
+ 0xF33CAAE1E70DD7BAL, 0xBB6202326EA2B4BFL, 0xD5020F87201871CBL, 0x9D5CA754A9B712CEL,
+ 0x841669D87DE83C56L, 0x8A6184785EB6739FL, 0x420BBA6CB0741E2BL, 0xF12D5B60EAC1CE47L,
+ 0x76AC35F71283691CL, 0x2C6BB7D9FECEDB5FL, 0xFCCDB18F4C351A83L, 0x1F79C012C3160582L,
+ 0xF0ABADAE62A74CB7L, 0xE1A5801C82EF06FCL, 0x67A21845F2CB2357L, 0x5114665F5DF04D9DL,
+ 0xBF40FD2D74278658L, 0xA0393D3FB73183DAL, 0x05A409D192E3B017L, 0xA9FB28CF0B4065F9L,
+ 0x25A9A22942BF3D7CL, 0xDB75E22703463E02L, 0xB326E10C5AB5D06CL, 0xE7968E8295A62DE6L,
+ 0xB973F3B3636EAD42L, 0xDF571D3819C30CE5L, 0xEE549B7229D7CBC5L, 0x12992AFD65E2D146L,
+ 0xF8EF4E9056B02864L, 0xB7041E134030E28BL, 0xC02EDD2ADAD50967L, 0x932B4AF48AE95D07L,
+ 0x6FE6FB7BC6DC4784L, 0x239AACB755F61666L, 0x401A4BEDBDB807D6L, 0x485EA8D389AF6305L,
+ 0xA41BC220ADB4B13DL, 0x753B32B89729F211L, 0x997E584BB3322029L, 0x1D683193CEDA1C7FL,
+ 0xFF5AB6C0C99F818EL, 0x16BBD5E27F67E3A1L, 0xA59D34EE25D233CDL, 0x98F8AE853B54A2D9L,
+ 0x6DF70AFACB105E79L, 0x795D2E99B9BBA425L, 0x8E437B6744334178L, 0x0186F6CE886682F0L,
+ 0xEBF092A3BB347BD2L, 0xBCD7FA62F18D1D55L, 0xADD9D7D011C5571EL, 0x0BD3E471B1BDFFDEL,
+ 0xAA6C2F808EEAFEF4L, 0x5EE57D31F6C880A4L, 0xF50FA47FF044FCA0L, 0x1ADDC9C351F5B595L,
+ 0xEA76646D3352F922L, 0x0000000000000000L, 0x85909F16F58EBEA6L, 0x46294573AAF12CCCL,
+ 0x0A5512BF39DB7D2EL, 0x78DBD85731DD26D5L, 0x29CFBE086C2D6B48L, 0x218B5D36583A0F9BL,
+ 0x152CD2ADFACD78ACL, 0x83A39188E2C795BCL, 0xC3B9DA655F7F926AL, 0x9ECBA01B2C1D89C3L,
+ 0x07B5F8509F2FA9EAL, 0x7EE8D6C926940DCFL, 0x36B67E1AAF3B6ECAL, 0x86079859702425ABL,
+ 0xFB7849DFD31AB369L, 0x4C7C57CC932A51E2L, 0xD96413A60E8A27FFL, 0x263EA566C715A671L,
+ 0x6C71FC344376DC89L, 0x4A4F595284637AF8L, 0xDAF314E98B20BCF2L, 0x572768C14AB96687L,
+ 0x1088DB7C682EC8BBL, 0x887075F9537A6A62L, 0x2E7A4658F302C2A2L, 0x619116DBE582084DL,
+ 0xA87DDE018326E709L, 0xDCC01A779C6997E8L, 0xEDC39C3DAC7D50C8L, 0xA60A33A1A078A8C0L,
+ 0xC1A82BE452B38B97L, 0x3F746BEA134A88E9L, 0xA228CCBEBAFD9A27L, 0xABEAD94E068C7C04L,
+ 0xF48952B178227E50L, 0x5CF48CB0FB049959L, 0x6017E0156DE48ABDL, 0x4438B4F2A73D3531L,
+ 0x8C528AE649FF5885L, 0xB515EF924DFCFB76L, 0x0C661C212E925634L, 0xB493195CC59A7986L,
+ 0x9CDA519A21D1903EL, 0x32948105B5BE5C2DL, 0x194ACE8CD45F2E98L, 0x438D4CA238129CDBL,
+ 0x9B6FA9CABEFE39D4L, 0x81B26009EF0B8C41L, 0xDED1EBF691A58E15L, 0x4E6DA64D9EE6481FL,
+ 0x54B06F8ECF13FD8AL, 0x49D85E1D01C9E1F5L, 0xAFC826511C094EE3L, 0xF698A33075EE67ADL,
+ 0x5AC7822EEC4DB243L, 0x8DD47C28C199DA75L, 0x89F68337DB1CE892L, 0xCDCE37C57C21DDA3L,
+ 0x530597DE503C5460L, 0x6A42F2AA543FF793L, 0x5D727A7E73621BA9L, 0xE232875307459DF1L,
+ 0x56A19E0FC2DFE477L, 0xC61DD3B4CD9C227DL, 0xE5877F03986A341BL, 0x949EB2A415C6F4EDL,
+ 0x6206119460289340L, 0x6380E75AE84E11B0L, 0x8BE772B6D6D0F16FL, 0x50929091D596CF6DL,
+ 0xE86795EC3E9EE0DFL, 0x7CF927482B581432L, 0xC86A3E14EEC26DB4L, 0x7119CDA78DACC0F6L,
+ 0xE40189CD100CB6EBL, 0x92ADBC3A028FDFF7L, 0xB2A017C2D2D3529CL, 0x200DABF8D05C8D6BL,
+ 0x34A78F9BA2F77737L, 0xE3B4719D8F231F01L, 0x45BE423C2F5BB7C1L, 0xF71E55FEFD88E55DL,
+ 0x6853032B59F3EE6EL, 0x65B3E9C4FF073AAAL, 0x772AC3399AE5EBECL, 0x87816E97F842A75BL,
+ 0x110E2DB2E0484A4BL, 0x331277CB3DD8DEDDL, 0xBD510CAC79EB9FA5L, 0x352179552A91F5C7L
+ },
+ new ulong[] {
+ 0x8AB0A96846E06A6DL, 0x43C7E80B4BF0B33AL, 0x08C9B3546B161EE5L, 0x39F1C235EBA990BEL,
+ 0xC1BEF2376606C7B2L, 0x2C209233614569AAL, 0xEB01523B6FC3289AL, 0x946953AB935ACEDDL,
+ 0x272838F63E13340EL, 0x8B0455ECA12BA052L, 0x77A1B2C4978FF8A2L, 0xA55122CA13E54086L,
+ 0x2276135862D3F1CDL, 0xDB8DDFDE08B76CFEL, 0x5D1E12C89E4A178AL, 0x0E56816B03969867L,
+ 0xEE5F79953303ED59L, 0xAFED748BAB78D71DL, 0x6D929F2DF93E53EEL, 0xF5D8A8F8BA798C2AL,
+ 0xF619B1698E39CF6BL, 0x95DDAF2F749104E2L, 0xEC2A9C80E0886427L, 0xCE5C8FD8825B95EAL,
+ 0xC4E0D9993AC60271L, 0x4699C3A5173076F9L, 0x3D1B151F50A29F42L, 0x9ED505EA2BC75946L,
+ 0x34665ACFDC7F4B98L, 0x61B1FB53292342F7L, 0xC721C0080E864130L, 0x8693CD1696FD7B74L,
+ 0x872731927136B14BL, 0xD3446C8A63A1721BL, 0x669A35E8A6680E4AL, 0xCAB658F239509A16L,
+ 0xA4E5DE4EF42E8AB9L, 0x37A7435EE83F08D9L, 0x134E6239E26C7F96L, 0x82791A3C2DF67488L,
+ 0x3F6EF00A8329163CL, 0x8E5A7E42FDEB6591L, 0x5CAAEE4C7981DDB5L, 0x19F234785AF1E80DL,
+ 0x255DDDE3ED98BD70L, 0x50898A32A99CCCACL, 0x28CA4519DA4E6656L, 0xAE59880F4CB31D22L,
+ 0x0D9798FA37D6DB26L, 0x32F968F0B4FFCD1AL, 0xA00F09644F258545L, 0xFA3AD5175E24DE72L,
+ 0xF46C547C5DB24615L, 0x713E80FBFF0F7E20L, 0x7843CF2B73D2AAFAL, 0xBD17EA36AEDF62B4L,
+ 0xFD111BACD16F92CFL, 0x4ABAA7DBC72D67E0L, 0xB3416B5DAD49FAD3L, 0xBCA316B24914A88BL,
+ 0x15D150068AECF914L, 0xE27C1DEBE31EFC40L, 0x4FE48C759BEDA223L, 0x7EDCFD141B522C78L,
+ 0x4E5070F17C26681CL, 0xE696CAC15815F3BCL, 0x35D2A64B3BB481A7L, 0x800CFF29FE7DFDF6L,
+ 0x1ED9FAC3D5BAA4B0L, 0x6C2663A91EF599D1L, 0x03C1199134404341L, 0xF7AD4DED69F20554L,
+ 0xCD9D9649B61BD6ABL, 0xC8C3BDE7EADB1368L, 0xD131899FB02AFB65L, 0x1D18E352E1FAE7F1L,
+ 0xDA39235AEF7CA6C1L, 0xA1BBF5E0A8EE4F7AL, 0x91377805CF9A0B1EL, 0x3138716180BF8E5BL,
+ 0xD9F83ACBDB3CE580L, 0x0275E515D38B897EL, 0x472D3F21F0FBBCC6L, 0x2D946EB7868EA395L,
+ 0xBA3C248D21942E09L, 0xE7223645BFDE3983L, 0xFF64FEB902E41BB1L, 0xC97741630D10D957L,
+ 0xC3CB1722B58D4ECCL, 0xA27AEC719CAE0C3BL, 0x99FECB51A48C15FBL, 0x1465AC826D27332BL,
+ 0xE1BD047AD75EBF01L, 0x79F733AF941960C5L, 0x672EC96C41A3C475L, 0xC27FEBA6524684F3L,
+ 0x64EFD0FD75E38734L, 0xED9E60040743AE18L, 0xFB8E2993B9EF144DL, 0x38453EB10C625A81L,
+ 0x6978480742355C12L, 0x48CF42CE14A6EE9EL, 0x1CAC1FD606312DCEL, 0x7B82D6BA4792E9BBL,
+ 0x9D141C7B1F871A07L, 0x5616B80DC11C4A2EL, 0xB849C198F21FA777L, 0x7CA91801C8D9A506L,
+ 0xB1348E487EC273ADL, 0x41B20D1E987B3A44L, 0x7460AB55A3CFBBE3L, 0x84E628034576F20AL,
+ 0x1B87D16D897A6173L, 0x0FE27DEFE45D5258L, 0x83CDE6B8CA3DBEB7L, 0x0C23647ED01D1119L,
+ 0x7A362A3EA0592384L, 0xB61F40F3F1893F10L, 0x75D457D1440471DCL, 0x4558DA34237035B8L,
+ 0xDCA6116587FC2043L, 0x8D9B67D3C9AB26D0L, 0x2B0B5C88EE0E2517L, 0x6FE77A382AB5DA90L,
+ 0x269CC472D9D8FE31L, 0x63C41E46FAA8CB89L, 0xB7ABBC771642F52FL, 0x7D1DE4852F126F39L,
+ 0xA8C6BA3024339BA0L, 0x600507D7CEE888C8L, 0x8FEE82C61A20AFAEL, 0x57A2448926D78011L,
+ 0xFCA5E72836A458F0L, 0x072BCEBB8F4B4CBDL, 0x497BBE4AF36D24A1L, 0x3CAFE99BB769557DL,
+ 0x12FA9EBD05A7B5A9L, 0xE8C04BAA5B836BDBL, 0x4273148FAC3B7905L, 0x908384812851C121L,
+ 0xE557D3506C55B0FDL, 0x72FF996ACB4F3D61L, 0x3EDA0C8E64E2DC03L, 0xF0868356E6B949E9L,
+ 0x04EAD72ABB0B0FFCL, 0x17A4B5135967706AL, 0xE3C8E16F04D5367FL, 0xF84F30028DAF570CL,
+ 0x1846C8FCBD3A2232L, 0x5B8120F7F6CA9108L, 0xD46FA231ECEA3EA6L, 0x334D947453340725L,
+ 0x58403966C28AD249L, 0xBED6F3A79A9F21F5L, 0x68CCB483A5FE962DL, 0xD085751B57E1315AL,
+ 0xFED0023DE52FD18EL, 0x4B0E5B5F20E6ADDFL, 0x1A332DE96EB1AB4CL, 0xA3CE10F57B65C604L,
+ 0x108F7BA8D62C3CD7L, 0xAB07A3A11073D8E1L, 0x6B0DAD1291BED56CL, 0xF2F366433532C097L,
+ 0x2E557726B2CEE0D4L, 0x0000000000000000L, 0xCB02A476DE9B5029L, 0xE4E32FD48B9E7AC2L,
+ 0x734B65EE2C84F75EL, 0x6E5386BCCD7E10AFL, 0x01B4FC84E7CBCA3FL, 0xCFE8735C65905FD5L,
+ 0x3613BFDA0FF4C2E6L, 0x113B872C31E7F6E8L, 0x2FE18BA255052AEBL, 0xE974B72EBC48A1E4L,
+ 0x0ABC5641B89D979BL, 0xB46AA5E62202B66EL, 0x44EC26B0C4BBFF87L, 0xA6903B5B27A503C7L,
+ 0x7F680190FC99E647L, 0x97A84A3AA71A8D9CL, 0xDD12EDE16037EA7CL, 0xC554251DDD0DC84EL,
+ 0x88C54C7D956BE313L, 0x4D91696048662B5DL, 0xB08072CC9909B992L, 0xB5DE5962C5C97C51L,
+ 0x81B803AD19B637C9L, 0xB2F597D94A8230ECL, 0x0B08AAC55F565DA4L, 0xF1327FD2017283D6L,
+ 0xAD98919E78F35E63L, 0x6AB9519676751F53L, 0x24E921670A53774FL, 0xB9FD3D1C15D46D48L,
+ 0x92F66194FBDA485FL, 0x5A35DC7311015B37L, 0xDED3F4705477A93DL, 0xC00A0EB381CD0D8DL,
+ 0xBB88D809C65FE436L, 0x16104997BEACBA55L, 0x21B70AC95693B28CL, 0x59F4C5E225411876L,
+ 0xD5DB5EB50B21F499L, 0x55D7A19CF55C096FL, 0xA97246B4C3F8519FL, 0x8552D487A2BD3835L,
+ 0x54635D181297C350L, 0x23C2EFDC85183BF2L, 0x9F61F96ECC0C9379L, 0x534893A39DDC8FEDL,
+ 0x5EDF0B59AA0A54CBL, 0xAC2C6D1A9F38945CL, 0xD7AEBBA0D8AA7DE7L, 0x2ABFA00C09C5EF28L,
+ 0xD84CC64F3CF72FBFL, 0x2003F64DB15878B3L, 0xA724C7DFC06EC9F8L, 0x069F323F68808682L,
+ 0xCC296ACD51D01C94L, 0x055E2BAE5CC0C5C3L, 0x6270E2C21D6301B6L, 0x3B842720382219C0L,
+ 0xD2F0900E846AB824L, 0x52FC6F277A1745D2L, 0xC6953C8CE94D8B0FL, 0xE009F8FE3095753EL,
+ 0x655B2C7992284D0BL, 0x984A37D54347DFC4L, 0xEAB5AEBF8808E2A5L, 0x9A3FD2C090CC56BAL,
+ 0x9CA0E0FFF84CD038L, 0x4C2595E4AFADE162L, 0xDF6708F4B3BC6302L, 0xBF620F237D54EBCAL,
+ 0x93429D101C118260L, 0x097D4FD08CDDD4DAL, 0x8C2F9B572E60ECEFL, 0x708A7C7F18C4B41FL,
+ 0x3A30DBA4DFE9D3FFL, 0x4006F19A7FB0F07BL, 0x5F6BF7DD4DC19EF4L, 0x1F6D064732716E8FL,
+ 0xF9FBCC866A649D33L, 0x308C8DE567744464L, 0x8971B0F972A0292CL, 0xD61A47243F61B7D8L,
+ 0xEFEB8511D4C82766L, 0x961CB6BE40D147A3L, 0xAAB35F25F7B812DEL, 0x76154E407044329DL,
+ 0x513D76B64E570693L, 0xF3479AC7D2F90AA8L, 0x9B8B2E4477079C85L, 0x297EB99D3D85AC69L
+ },
+ new ulong[] {
+ 0x7E37E62DFC7D40C3L, 0x776F25A4EE939E5BL, 0xE045C850DD8FB5ADL, 0x86ED5BA711FF1952L,
+ 0xE91D0BD9CF616B35L, 0x37E0AB256E408FFBL, 0x9607F6C031025A7AL, 0x0B02F5E116D23C9DL,
+ 0xF3D8486BFB50650CL, 0x621CFF27C40875F5L, 0x7D40CB71FA5FD34AL, 0x6DAA6616DAA29062L,
+ 0x9F5F354923EC84E2L, 0xEC847C3DC507C3B3L, 0x025A3668043CE205L, 0xA8BF9E6C4DAC0B19L,
+ 0xFA808BE2E9BEBB94L, 0xB5B99C5277C74FA3L, 0x78D9BC95F0397BCCL, 0xE332E50CDBAD2624L,
+ 0xC74FCE129332797EL, 0x1729ECEB2EA709ABL, 0xC2D6B9F69954D1F8L, 0x5D898CBFBAB8551AL,
+ 0x859A76FB17DD8ADBL, 0x1BE85886362F7FB5L, 0xF6413F8FF136CD8AL, 0xD3110FA5BBB7E35CL,
+ 0x0A2FEED514CC4D11L, 0xE83010EDCD7F1AB9L, 0xA1E75DE55F42D581L, 0xEEDE4A55C13B21B6L,
+ 0xF2F5535FF94E1480L, 0x0CC1B46D1888761EL, 0xBCE15FDB6529913BL, 0x2D25E8975A7181C2L,
+ 0x71817F1CE2D7A554L, 0x2E52C5CB5C53124BL, 0xF9F7A6BEEF9C281DL, 0x9E722E7D21F2F56EL,
+ 0xCE170D9B81DCA7E6L, 0x0E9B82051CB4941BL, 0x1E712F623C49D733L, 0x21E45CFA42F9F7DCL,
+ 0xCB8E7A7F8BBA0F60L, 0x8E98831A010FB646L, 0x474CCF0D8E895B23L, 0xA99285584FB27A95L,
+ 0x8CC2B57205335443L, 0x42D5B8E984EFF3A5L, 0x012D1B34021E718CL, 0x57A6626AAE74180BL,
+ 0xFF19FC06E3D81312L, 0x35BA9D4D6A7C6DFEL, 0xC9D44C178F86ED65L, 0x506523E6A02E5288L,
+ 0x03772D5C06229389L, 0x8B01F4FE0B691EC0L, 0xF8DABD8AED825991L, 0x4C4E3AEC985B67BEL,
+ 0xB10DF0827FBF96A9L, 0x6A69279AD4F8DAE1L, 0xE78689DCD3D5FF2EL, 0x812E1A2B1FA553D1L,
+ 0xFBAD90D6EBA0CA18L, 0x1AC543B234310E39L, 0x1604F7DF2CB97827L, 0xA6241C6951189F02L,
+ 0x753513CCEAAF7C5EL, 0x64F2A59FC84C4EFAL, 0x247D2B1E489F5F5AL, 0xDB64D718AB474C48L,
+ 0x79F4A7A1F2270A40L, 0x1573DA832A9BEBAEL, 0x3497867968621C72L, 0x514838D2A2302304L,
+ 0xF0AF6537FD72F685L, 0x1D06023E3A6B44BAL, 0x678588C3CE6EDD73L, 0x66A893F7CC70ACFFL,
+ 0xD4D24E29B5EDA9DFL, 0x3856321470EA6A6CL, 0x07C3418C0E5A4A83L, 0x2BCBB22F5635BACDL,
+ 0x04B46CD00878D90AL, 0x06EE5AB80C443B0FL, 0x3B211F4876C8F9E5L, 0x0958C38912EEDE98L,
+ 0xD14B39CDBF8B0159L, 0x397B292072F41BE0L, 0x87C0409313E168DEL, 0xAD26E98847CAA39FL,
+ 0x4E140C849C6785BBL, 0xD5FF551DB7F3D853L, 0xA0CA46D15D5CA40DL, 0xCD6020C787FE346FL,
+ 0x84B76DCF15C3FB57L, 0xDEFDA0FCA121E4CEL, 0x4B8D7B6096012D3DL, 0x9AC642AD298A2C64L,
+ 0x0875D8BD10F0AF14L, 0xB357C6EA7B8374ACL, 0x4D6321D89A451632L, 0xEDA96709C719B23FL,
+ 0xF76C24BBF328BC06L, 0xC662D526912C08F2L, 0x3CE25EC47892B366L, 0xB978283F6F4F39BDL,
+ 0xC08C8F9E9D6833FDL, 0x4F3917B09E79F437L, 0x593DE06FB2C08C10L, 0xD6887841B1D14BDAL,
+ 0x19B26EEE32139DB0L, 0xB494876675D93E2FL, 0x825937771987C058L, 0x90E9AC783D466175L,
+ 0xF1827E03FF6C8709L, 0x945DC0A8353EB87FL, 0x4516F9658AB5B926L, 0x3F9573987EB020EFL,
+ 0xB855330B6D514831L, 0x2AE6A91B542BCB41L, 0x6331E413C6160479L, 0x408F8E8180D311A0L,
+ 0xEFF35161C325503AL, 0xD06622F9BD9570D5L, 0x8876D9A20D4B8D49L, 0xA5533135573A0C8BL,
+ 0xE168D364DF91C421L, 0xF41B09E7F50A2F8FL, 0x12B09B0F24C1A12DL, 0xDA49CC2CA9593DC4L,
+ 0x1F5C34563E57A6BFL, 0x54D14F36A8568B82L, 0xAF7CDFE043F6419AL, 0xEA6A2685C943F8BCL,
+ 0xE5DCBFB4D7E91D2BL, 0xB27ADDDE799D0520L, 0x6B443CAED6E6AB6DL, 0x7BAE91C9F61BE845L,
+ 0x3EB868AC7CAE5163L, 0x11C7B65322E332A4L, 0xD23C1491B9A992D0L, 0x8FB5982E0311C7CAL,
+ 0x70AC6428E0C9D4D8L, 0x895BC2960F55FCC5L, 0x76423E90EC8DEFD7L, 0x6FF0507EDE9E7267L,
+ 0x3DCF45F07A8CC2EAL, 0x4AA06054941F5CB1L, 0x5810FB5BB0DEFD9CL, 0x5EFEA1E3BC9AC693L,
+ 0x6EDD4B4ADC8003EBL, 0x741808F8E8B10DD2L, 0x145EC1B728859A22L, 0x28BC9F7350172944L,
+ 0x270A06424EBDCCD3L, 0x972AEDF4331C2BF6L, 0x059977E40A66A886L, 0x2550302A4A812ED6L,
+ 0xDD8A8DA0A7037747L, 0xC515F87A970E9B7BL, 0x3023EAA9601AC578L, 0xB7E3AA3A73FBADA6L,
+ 0x0FB699311EAAE597L, 0x0000000000000000L, 0x310EF19D6204B4F4L, 0x229371A644DB6455L,
+ 0x0DECAF591A960792L, 0x5CA4978BB8A62496L, 0x1C2B190A38753536L, 0x41A295B582CD602CL,
+ 0x3279DCC16426277DL, 0xC1A194AA9F764271L, 0x139D803B26DFD0A1L, 0xAE51C4D441E83016L,
+ 0xD813FA44AD65DFC1L, 0xAC0BF2BC45D4D213L, 0x23BE6A9246C515D9L, 0x49D74D08923DCF38L,
+ 0x9D05032127D066E7L, 0x2F7FDEFF5E4D63C7L, 0xA47E2A0155247D07L, 0x99B16FF12FA8BFEDL,
+ 0x4661D4398C972AAFL, 0xDFD0BBC8A33F9542L, 0xDCA79694A51D06CBL, 0xB020EBB67DA1E725L,
+ 0xBA0F0563696DAA34L, 0xE4F1A480D5F76CA7L, 0xC438E34E9510EAF7L, 0x939E81243B64F2FCL,
+ 0x8DEFAE46072D25CFL, 0x2C08F3A3586FF04EL, 0xD7A56375B3CF3A56L, 0x20C947CE40E78650L,
+ 0x43F8A3DD86F18229L, 0x568B795EAC6A6987L, 0x8003011F1DBB225DL, 0xF53612D3F7145E03L,
+ 0x189F75DA300DEC3CL, 0x9570DB9C3720C9F3L, 0xBB221E576B73DBB8L, 0x72F65240E4F536DDL,
+ 0x443BE25188ABC8AAL, 0xE21FFE38D9B357A8L, 0xFD43CA6EE7E4F117L, 0xCAA3614B89A47EECL,
+ 0xFE34E732E1C6629EL, 0x83742C431B99B1D4L, 0xCF3A16AF83C2D66AL, 0xAAE5A8044990E91CL,
+ 0x26271D764CA3BD5FL, 0x91C4B74C3F5810F9L, 0x7C6DD045F841A2C6L, 0x7F1AFD19FE63314FL,
+ 0xC8F957238D989CE9L, 0xA709075D5306EE8EL, 0x55FC5402AA48FA0EL, 0x48FA563C9023BEB4L,
+ 0x65DFBEABCA523F76L, 0x6C877D22D8BCE1EEL, 0xCC4D3BF385E045E3L, 0xBEBB69B36115733EL,
+ 0x10EAAD6720FD4328L, 0xB6CEB10E71E5DC2AL, 0xBDCC44EF6737E0B7L, 0x523F158EA412B08DL,
+ 0x989C74C52DB6CE61L, 0x9BEB59992B945DE8L, 0x8A2CEFCA09776F4CL, 0xA3BD6B8D5B7E3784L,
+ 0xEB473DB1CB5D8930L, 0xC3FBA2C29B4AA074L, 0x9C28181525CE176BL, 0x683311F2D0C438E4L,
+ 0x5FD3BAD7BE84B71FL, 0xFC6ED15AE5FA809BL, 0x36CDB0116C5EFE77L, 0x29918447520958C8L,
+ 0xA29070B959604608L, 0x53120EBAA60CC101L, 0x3A0C047C74D68869L, 0x691E0AC6D2DA4968L,
+ 0x73DB4974E6EB4751L, 0x7A838AFDF40599C9L, 0x5A4ACD33B4E21F99L, 0x6046C94FC03497F0L,
+ 0xE6AB92E8D1CB8EA2L, 0x3354C7F5663856F1L, 0xD93EE170AF7BAE4DL, 0x616BD27BC22AE67CL,
+ 0x92B39A10397A8370L, 0xABC8B3304B8E9890L, 0xBF967287630B02B2L, 0x5B67D607B6FC6E15L
+ },
+ new ulong[] {
+ 0xD031C397CE553FE6L, 0x16BA5B01B006B525L, 0xA89BADE6296E70C8L, 0x6A1F525D77D3435BL,
+ 0x6E103570573DFA0BL, 0x660EFB2A17FC95ABL, 0x76327A9E97634BF6L, 0x4BAD9D6462458BF5L,
+ 0xF1830CAEDBC3F748L, 0xC5C8F542669131FFL, 0x95044A1CDC48B0CBL, 0x892962DF3CF8B866L,
+ 0xB0B9E208E930C135L, 0xA14FB3F0611A767CL, 0x8D2605F21C160136L, 0xD6B71922FECC549EL,
+ 0x37089438A5907D8BL, 0x0B5DA38E5803D49CL, 0x5A5BCC9CEA6F3CBCL, 0xEDAE246D3B73FFE5L,
+ 0xD2B87E0FDE22EDCEL, 0x5E54ABB1CA8185ECL, 0x1DE7F88FE80561B9L, 0xAD5E1A870135A08CL,
+ 0x2F2ADBD665CECC76L, 0x5780B5A782F58358L, 0x3EDC8A2EEDE47B3FL, 0xC9D95C3506BEE70FL,
+ 0x83BE111D6C4E05EEL, 0xA603B90959367410L, 0x103C81B4809FDE5DL, 0x2C69B6027D0C774AL,
+ 0x399080D7D5C87953L, 0x09D41E16487406B4L, 0xCDD63B1826505E5FL, 0xF99DC2F49B0298E8L,
+ 0x9CD0540A943CB67FL, 0xBCA84B7F891F17C5L, 0x723D1DB3B78DF2A6L, 0x78AA6E71E73B4F2EL,
+ 0x1433E699A071670DL, 0x84F21BE454620782L, 0x98DF3327B4D20F2FL, 0xF049DCE2D3769E5CL,
+ 0xDB6C60199656EB7AL, 0x648746B2078B4783L, 0x32CD23598DCBADCFL, 0x1EA4955BF0C7DA85L,
+ 0xE9A143401B9D46B5L, 0xFD92A5D9BBEC21B8L, 0xC8138C790E0B8E1BL, 0x2EE00B9A6D7BA562L,
+ 0xF85712B893B7F1FCL, 0xEB28FED80BEA949DL, 0x564A65EB8A40EA4CL, 0x6C9988E8474A2823L,
+ 0x4535898B121D8F2DL, 0xABD8C03231ACCBF4L, 0xBA2E91CAB9867CBDL, 0x7960BE3DEF8E263AL,
+ 0x0C11A977602FD6F0L, 0xCB50E1AD16C93527L, 0xEAE22E94035FFD89L, 0x2866D12F5DE2CE1AL,
+ 0xFF1B1841AB9BF390L, 0x9F9339DE8CFE0D43L, 0x964727C8C48A0BF7L, 0x524502C6AAAE531CL,
+ 0x9B9C5EF3AC10B413L, 0x4FA2FA4942AB32A5L, 0x3F165A62E551122BL, 0xC74148DA76E6E3D7L,
+ 0x924840E5E464B2A7L, 0xD372AE43D69784DAL, 0x233B72A105E11A86L, 0xA48A04914941A638L,
+ 0xB4B68525C9DE7865L, 0xDDEABAACA6CF8002L, 0x0A9773C250B6BD88L, 0xC284FFBB5EBD3393L,
+ 0x8BA0DF472C8F6A4EL, 0x2AEF6CB74D951C32L, 0x427983722A318D41L, 0x73F7CDFFBF389BB2L,
+ 0x074C0AF9382C026CL, 0x8A6A0F0B243A035AL, 0x6FDAE53C5F88931FL, 0xC68B98967E538AC3L,
+ 0x44FF59C71AA8E639L, 0xE2FCE0CE439E9229L, 0xA20CDE2479D8CD40L, 0x19E89FA2C8EBD8E9L,
+ 0xF446BBCFF398270CL, 0x43B3533E2284E455L, 0xD82F0DCD8E945046L, 0x51066F12B26CE820L,
+ 0xE73957AF6BC5426DL, 0x081ECE5A40C16FA0L, 0x3B193D4FC5BFAB7BL, 0x7FE66488DF174D42L,
+ 0x0E9814EF705804D8L, 0x8137AC857C39D7C6L, 0xB1733244E185A821L, 0x695C3F896F11F867L,
+ 0xF6CF0657E3EFF524L, 0x1AABF276D02963D5L, 0x2DA3664E75B91E5EL, 0x0289BD981077D228L,
+ 0x90C1FD7DF413608FL, 0x3C5537B6FD93A917L, 0xAA12107E3919A2E0L, 0x0686DAB530996B78L,
+ 0xDAA6B0559EE3826EL, 0xC34E2FF756085A87L, 0x6D5358A44FFF4137L, 0xFC587595B35948ACL,
+ 0x7CA5095CC7D5F67EL, 0xFB147F6C8B754AC0L, 0xBFEB26AB91DDACF9L, 0x6896EFC567A49173L,
+ 0xCA9A31E11E7C5C33L, 0xBBE44186B13315A9L, 0x0DDB793B689ABFE4L, 0x70B4A02BA7FA208EL,
+ 0xE47A3A7B7307F951L, 0x8CECD5BE14A36822L, 0xEEED49B923B144D9L, 0x17708B4DB8B3DC31L,
+ 0x6088219F2765FED3L, 0xB3FA8FDCF1F27A09L, 0x910B2D31FCA6099BL, 0x0F52C4A378ED6DCCL,
+ 0x50CCBF5EBAD98134L, 0x6BD582117F662A4FL, 0x94CE9A50D4FDD9DFL, 0x2B25BCFB45207526L,
+ 0x67C42B661F49FCBFL, 0x492420FC723259DDL, 0x03436DD418C2BB3CL, 0x1F6E4517F872B391L,
+ 0xA08563BC69AF1F68L, 0xD43EA4BAEEBB86B6L, 0x01CAD04C08B56914L, 0xAC94CACB0980C998L,
+ 0x54C3D8739A373864L, 0x26FEC5C02DBACAC2L, 0xDEA9D778BE0D3B3EL, 0x040F672D20EEB950L,
+ 0xE5B0EA377BB29045L, 0xF30AB136CBB42560L, 0x62019C0737122CFBL, 0xE86B930C13282FA1L,
+ 0xCC1CEB542EE5374BL, 0x538FD28AA21B3A08L, 0x1B61223AD89C0AC1L, 0x36C24474AD25149FL,
+ 0x7A23D3E9F74C9D06L, 0xBE21F6E79968C5EDL, 0xCF5F868036278C77L, 0xF705D61BEB5A9C30L,
+ 0x4D2B47D152DCE08DL, 0x5F9E7BFDC234ECF8L, 0x247778583DCD18EAL, 0x867BA67C4415D5AAL,
+ 0x4CE1979D5A698999L, 0x0000000000000000L, 0xEC64F42133C696F1L, 0xB57C5569C16B1171L,
+ 0xC1C7926F467F88AFL, 0x654D96FE0F3E2E97L, 0x15F936D5A8C40E19L, 0xB8A72C52A9F1AE95L,
+ 0xA9517DAA21DB19DCL, 0x58D27104FA18EE94L, 0x5918A148F2AD8780L, 0x5CDD1629DAF657C4L,
+ 0x8274C15164FB6CFAL, 0xD1FB13DBC6E056F2L, 0x7D6FD910CF609F6AL, 0xB63F38BDD9A9AA4DL,
+ 0x3D9FE7FAF526C003L, 0x74BBC706871499DEL, 0xDF630734B6B8522AL, 0x3AD3ED03CD0AC26FL,
+ 0xFADEAF2083C023D4L, 0xC00D42234ECAE1BBL, 0x8538CBA85CD76E96L, 0xC402250E6E2458EBL,
+ 0x47BC3413026A5D05L, 0xAFD7A71F114272A4L, 0x978DF784CC3F62E3L, 0xB96DFC1EA144C781L,
+ 0x21B2CF391596C8AEL, 0x318E4E8D950916F3L, 0xCE9556CC3E92E563L, 0x385A509BDD7D1047L,
+ 0x358129A0B5E7AFA3L, 0xE6F387E363702B79L, 0xE0755D5653E94001L, 0x7BE903A5FFF9F412L,
+ 0x12B53C2C90E80C75L, 0x3307F315857EC4DBL, 0x8FAFB86A0C61D31EL, 0xD9E5DD8186213952L,
+ 0x77F8AAD29FD622E2L, 0x25BDA814357871FEL, 0x7571174A8FA1F0CAL, 0x137FEC60985D6561L,
+ 0x30449EC19DBC7FE7L, 0xA540D4DD41F4CF2CL, 0xDC206AE0AE7AE916L, 0x5B911CD0E2DA55A8L,
+ 0xB2305F90F947131DL, 0x344BF9ECBD52C6B7L, 0x5D17C665D2433ED0L, 0x18224FEEC05EB1FDL,
+ 0x9E59E992844B6457L, 0x9A568EBFA4A5DD07L, 0xA3C60E68716DA454L, 0x7E2CB4C4D7A22456L,
+ 0x87B176304CA0BCBEL, 0x413AEEA632F3367DL, 0x9915E36BBC67663BL, 0x40F03EEA3A465F69L,
+ 0x1C2D28C3E0B008ADL, 0x4E682A054A1E5BB1L, 0x05C5B761285BD044L, 0xE1BF8D1A5B5C2915L,
+ 0xF2C0617AC3014C74L, 0xB7F5E8F1D11CC359L, 0x63CB4C4B3FA745EFL, 0x9D1A84469C89DF6BL,
+ 0xE33630824B2BFB3DL, 0xD5F474F6E60EEFA2L, 0xF58C6B83FB2D4E18L, 0x4676E45F0ADF3411L,
+ 0x20781F751D23A1BAL, 0xBD629B3381AA7ED1L, 0xAE1D775319F71BB0L, 0xFED1C80DA32E9A84L,
+ 0x5509083F92825170L, 0x29AC01635557A70EL, 0xA7C9694551831D04L, 0x8E65682604D4BA0AL,
+ 0x11F651F8882AB749L, 0xD77DC96EF6793D8AL, 0xEF2799F52B042DCDL, 0x48EEF0B07A8730C9L,
+ 0x22F1A2ED0D547392L, 0x6142F1D32FD097C7L, 0x4A674D286AF0E2E1L, 0x80FD7CC9748CBED2L,
+ 0x717E7067AF4F499AL, 0x938290A9ECD1DBB3L, 0x88E3B293344DD172L, 0x2734158C250FA3D6L
+ }
+ };
+
+
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/GOST3411_2012_256Digest.cs b/bc-sharp-crypto/src/crypto/digests/GOST3411_2012_256Digest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8686851e27bbea1b4e82c6a0159e8208e7a97d8a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/GOST3411_2012_256Digest.cs
@@ -0,0 +1,54 @@
+using System;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ public class GOST3411_2012_256Digest : GOST3411_2012Digest
+ {
+ private readonly static byte[] IV = {
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
+ };
+
+ public override string AlgorithmName
+ {
+ get { return "GOST3411-2012-256"; }
+ }
+
+ public GOST3411_2012_256Digest() : base(IV)
+ {
+
+ }
+
+ public GOST3411_2012_256Digest(GOST3411_2012_256Digest other) : base(IV)
+ {
+ Reset(other);
+ }
+
+ public override int GetDigestSize()
+ {
+ return 32;
+ }
+
+ public override int DoFinal(byte[] output, int outOff)
+ {
+ byte[] result = new byte[64];
+ base.DoFinal(result, 0);
+
+ Array.Copy(result, 32, output, outOff, 32);
+
+ return 32;
+ }
+
+ public override IMemoable Copy()
+ {
+ return new GOST3411_2012_256Digest(this);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/GOST3411_2012_512Digest.cs b/bc-sharp-crypto/src/crypto/digests/GOST3411_2012_512Digest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..eb40aba1d6ebcca2b834792cea042d559753336f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/GOST3411_2012_512Digest.cs
@@ -0,0 +1,43 @@
+using System;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ public class GOST3411_2012_512Digest:GOST3411_2012Digest
+ {
+ private readonly static byte[] IV = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ public override string AlgorithmName
+ {
+ get { return "GOST3411-2012-512"; }
+ }
+
+ public GOST3411_2012_512Digest():base(IV)
+ {
+ }
+
+ public GOST3411_2012_512Digest(GOST3411_2012_512Digest other) : base(IV)
+ {
+ Reset(other);
+ }
+
+ public override int GetDigestSize()
+ {
+ return 64;
+ }
+
+ public override IMemoable Copy()
+ {
+ return new GOST3411_2012_512Digest(this);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/GeneralDigest.cs b/bc-sharp-crypto/src/crypto/digests/GeneralDigest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d40ad28bbc8b175066e06ef31893008f33404cf7
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/GeneralDigest.cs
@@ -0,0 +1,133 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * base implementation of MD4 family style digest as outlined in
+ * "Handbook of Applied Cryptography", pages 344 - 347.
+ */
+ public abstract class GeneralDigest
+ : IDigest, IMemoable
+ {
+ private const int BYTE_LENGTH = 64;
+
+ private byte[] xBuf;
+ private int xBufOff;
+
+ private long byteCount;
+
+ internal GeneralDigest()
+ {
+ xBuf = new byte[4];
+ }
+
+ internal GeneralDigest(GeneralDigest t)
+ {
+ xBuf = new byte[t.xBuf.Length];
+ CopyIn(t);
+ }
+
+ protected void CopyIn(GeneralDigest t)
+ {
+ Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length);
+
+ xBufOff = t.xBufOff;
+ byteCount = t.byteCount;
+ }
+
+ public void Update(byte input)
+ {
+ xBuf[xBufOff++] = input;
+
+ if (xBufOff == xBuf.Length)
+ {
+ ProcessWord(xBuf, 0);
+ xBufOff = 0;
+ }
+
+ byteCount++;
+ }
+
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ length = System.Math.Max(0, length);
+
+ //
+ // fill the current word
+ //
+ int i = 0;
+ if (xBufOff != 0)
+ {
+ while (i < length)
+ {
+ xBuf[xBufOff++] = input[inOff + i++];
+ if (xBufOff == 4)
+ {
+ ProcessWord(xBuf, 0);
+ xBufOff = 0;
+ break;
+ }
+ }
+ }
+
+ //
+ // process whole words.
+ //
+ int limit = ((length - i) & ~3) + i;
+ for (; i < limit; i += 4)
+ {
+ ProcessWord(input, inOff + i);
+ }
+
+ //
+ // load in the remainder.
+ //
+ while (i < length)
+ {
+ xBuf[xBufOff++] = input[inOff + i++];
+ }
+
+ byteCount += length;
+ }
+
+ public void Finish()
+ {
+ long bitLength = (byteCount << 3);
+
+ //
+ // add the pad bytes.
+ //
+ Update((byte)128);
+
+ while (xBufOff != 0) Update((byte)0);
+ ProcessLength(bitLength);
+ ProcessBlock();
+ }
+
+ public virtual void Reset()
+ {
+ byteCount = 0;
+ xBufOff = 0;
+ Array.Clear(xBuf, 0, xBuf.Length);
+ }
+
+ public int GetByteLength()
+ {
+ return BYTE_LENGTH;
+ }
+
+ internal abstract void ProcessWord(byte[] input, int inOff);
+ internal abstract void ProcessLength(long bitLength);
+ internal abstract void ProcessBlock();
+ public abstract string AlgorithmName { get; }
+ public abstract int GetDigestSize();
+ public abstract int DoFinal(byte[] output, int outOff);
+ public abstract IMemoable Copy();
+ public abstract void Reset(IMemoable t);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/KeccakDigest.cs b/bc-sharp-crypto/src/crypto/digests/KeccakDigest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8b16e5d3a042149f318088fcd9678b2582eb52f7
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/KeccakDigest.cs
@@ -0,0 +1,479 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ ///
+ /// Implementation of Keccak based on following KeccakNISTInterface.c from http://keccak.noekeon.org/
+ ///
+ ///
+ /// Following the naming conventions used in the C source code to enable easy review of the implementation.
+ ///
+ public class KeccakDigest
+ : IDigest, IMemoable
+ {
+ private static readonly ulong[] KeccakRoundConstants = KeccakInitializeRoundConstants();
+
+ private static readonly int[] KeccakRhoOffsets = KeccakInitializeRhoOffsets();
+
+ private static ulong[] KeccakInitializeRoundConstants()
+ {
+ ulong[] keccakRoundConstants = new ulong[24];
+ byte LFSRState = 0x01;
+
+ for (int i = 0; i < 24; i++)
+ {
+ keccakRoundConstants[i] = 0;
+ for (int j = 0; j < 7; j++)
+ {
+ int bitPosition = (1 << j) - 1;
+
+ // LFSR86540
+
+ bool loBit = (LFSRState & 0x01) != 0;
+ if (loBit)
+ {
+ keccakRoundConstants[i] ^= 1UL << bitPosition;
+ }
+
+ bool hiBit = (LFSRState & 0x80) != 0;
+ LFSRState <<= 1;
+ if (hiBit)
+ {
+ LFSRState ^= 0x71;
+ }
+
+ }
+ }
+
+ return keccakRoundConstants;
+ }
+
+ private static int[] KeccakInitializeRhoOffsets()
+ {
+ int[] keccakRhoOffsets = new int[25];
+ int x, y, t, newX, newY;
+
+ int rhoOffset = 0;
+ keccakRhoOffsets[0] = rhoOffset;
+ x = 1;
+ y = 0;
+ for (t = 1; t < 25; t++)
+ {
+ rhoOffset = (rhoOffset + t) & 63;
+ keccakRhoOffsets[(((x) % 5) + 5 * ((y) % 5))] = rhoOffset;
+ newX = (0 * x + 1 * y) % 5;
+ newY = (2 * x + 3 * y) % 5;
+ x = newX;
+ y = newY;
+ }
+
+ return keccakRhoOffsets;
+ }
+
+ private static readonly int STATE_LENGTH = (1600 / 8);
+
+ private ulong[] state = new ulong[STATE_LENGTH / 8];
+ protected byte[] dataQueue = new byte[1536 / 8];
+ protected int rate;
+ protected int bitsInQueue;
+ protected int fixedOutputLength;
+ protected bool squeezing;
+ protected int bitsAvailableForSqueezing;
+
+ public KeccakDigest()
+ : this(288)
+ {
+ }
+
+ public KeccakDigest(int bitLength)
+ {
+ Init(bitLength);
+ }
+
+ public KeccakDigest(KeccakDigest source)
+ {
+ CopyIn(source);
+ }
+
+ private void CopyIn(KeccakDigest source)
+ {
+ Array.Copy(source.state, 0, this.state, 0, source.state.Length);
+ Array.Copy(source.dataQueue, 0, this.dataQueue, 0, source.dataQueue.Length);
+ this.rate = source.rate;
+ this.bitsInQueue = source.bitsInQueue;
+ this.fixedOutputLength = source.fixedOutputLength;
+ this.squeezing = source.squeezing;
+ this.bitsAvailableForSqueezing = source.bitsAvailableForSqueezing;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Keccak-" + fixedOutputLength; }
+ }
+
+ public virtual int GetDigestSize()
+ {
+ return fixedOutputLength >> 3;
+ }
+
+ public virtual void Update(byte input)
+ {
+ Absorb(new byte[]{ input }, 0, 1);
+ }
+
+ public virtual void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ Absorb(input, inOff, len);
+ }
+
+ public virtual int DoFinal(byte[] output, int outOff)
+ {
+ Squeeze(output, outOff, fixedOutputLength >> 3);
+
+ Reset();
+
+ return GetDigestSize();
+ }
+
+ /*
+ * TODO Possible API change to support partial-byte suffixes.
+ */
+ protected virtual int DoFinal(byte[] output, int outOff, byte partialByte, int partialBits)
+ {
+ if (partialBits > 0)
+ {
+ AbsorbBits(partialByte, partialBits);
+ }
+
+ Squeeze(output, outOff, fixedOutputLength >> 3);
+
+ Reset();
+
+ return GetDigestSize();
+ }
+
+ public virtual void Reset()
+ {
+ Init(fixedOutputLength);
+ }
+
+ /**
+ * Return the size of block that the compression function is applied to in bytes.
+ *
+ * @return internal byte length of a block.
+ */
+ public virtual int GetByteLength()
+ {
+ return rate >> 3;
+ }
+
+ private void Init(int bitLength)
+ {
+ switch (bitLength)
+ {
+ case 128:
+ case 224:
+ case 256:
+ case 288:
+ case 384:
+ case 512:
+ InitSponge(1600 - (bitLength << 1));
+ break;
+ default:
+ throw new ArgumentException("must be one of 128, 224, 256, 288, 384, or 512.", "bitLength");
+ }
+ }
+
+ private void InitSponge(int rate)
+ {
+ if (rate <= 0 || rate >= 1600 || (rate & 63) != 0)
+ throw new InvalidOperationException("invalid rate value");
+
+ this.rate = rate;
+ Array.Clear(state, 0, state.Length);
+ Arrays.Fill(this.dataQueue, (byte)0);
+ this.bitsInQueue = 0;
+ this.squeezing = false;
+ this.bitsAvailableForSqueezing = 0;
+ this.fixedOutputLength = (1600 - rate) >> 1;
+ }
+
+ protected void Absorb(byte[] data, int off, int len)
+ {
+ if ((bitsInQueue & 7) != 0)
+ throw new InvalidOperationException("attempt to absorb with odd length queue");
+ if (squeezing)
+ throw new InvalidOperationException("attempt to absorb while squeezing");
+
+ int bytesInQueue = bitsInQueue >> 3;
+ int rateBytes = rate >> 3;
+
+ int count = 0;
+ while (count < len)
+ {
+ if (bytesInQueue == 0 && count <= (len - rateBytes))
+ {
+ do
+ {
+ KeccakAbsorb(data, off + count);
+ count += rateBytes;
+ }
+ while (count <= (len - rateBytes));
+ }
+ else
+ {
+ int partialBlock = System.Math.Min(rateBytes - bytesInQueue, len - count);
+ Array.Copy(data, off + count, dataQueue, bytesInQueue, partialBlock);
+
+ bytesInQueue += partialBlock;
+ count += partialBlock;
+
+ if (bytesInQueue == rateBytes)
+ {
+ KeccakAbsorb(dataQueue, 0);
+ bytesInQueue = 0;
+ }
+ }
+ }
+
+ bitsInQueue = bytesInQueue << 3;
+ }
+
+ protected void AbsorbBits(int data, int bits)
+ {
+ if (bits < 1 || bits > 7)
+ throw new ArgumentException("must be in the range 1 to 7", "bits");
+ if ((bitsInQueue & 7) != 0)
+ throw new InvalidOperationException("attempt to absorb with odd length queue");
+ if (squeezing)
+ throw new InvalidOperationException("attempt to absorb while squeezing");
+
+ int mask = (1 << bits) - 1;
+ dataQueue[bitsInQueue >> 3] = (byte)(data & mask);
+
+ // NOTE: After this, bitsInQueue is no longer a multiple of 8, so no more absorbs will work
+ bitsInQueue += bits;
+ }
+
+ private void PadAndSwitchToSqueezingPhase()
+ {
+ Debug.Assert(bitsInQueue < rate);
+
+ dataQueue[bitsInQueue >> 3] |= (byte)(1U << (bitsInQueue & 7));
+
+ if (++bitsInQueue == rate)
+ {
+ KeccakAbsorb(dataQueue, 0);
+ bitsInQueue = 0;
+ }
+
+ {
+ int full = bitsInQueue >> 6, partial = bitsInQueue & 63;
+ int off = 0;
+ for (int i = 0; i < full; ++i)
+ {
+ state[i] ^= Pack.LE_To_UInt64(dataQueue, off);
+ off += 8;
+ }
+ if (partial > 0)
+ {
+ ulong mask = (1UL << partial) - 1UL;
+ state[full] ^= Pack.LE_To_UInt64(dataQueue, off) & mask;
+ }
+ state[(rate - 1) >> 6] ^= (1UL << 63);
+ }
+
+ KeccakPermutation();
+ KeccakExtract();
+ bitsAvailableForSqueezing = rate;
+
+ bitsInQueue = 0;
+ squeezing = true;
+ }
+
+ protected void Squeeze(byte[] output, int off, int len)
+ {
+ if (!squeezing)
+ {
+ PadAndSwitchToSqueezingPhase();
+ }
+
+ long outputLength = (long)len << 3;
+ long i = 0;
+ while (i < outputLength)
+ {
+ if (bitsAvailableForSqueezing == 0)
+ {
+ KeccakPermutation();
+ KeccakExtract();
+ bitsAvailableForSqueezing = rate;
+ }
+
+ int partialBlock = (int)System.Math.Min((long)bitsAvailableForSqueezing, outputLength - i);
+ Array.Copy(dataQueue, (rate - bitsAvailableForSqueezing) >> 3, output, off + (int)(i >> 3), partialBlock >> 3);
+ bitsAvailableForSqueezing -= partialBlock;
+ i += partialBlock;
+ }
+ }
+
+ private void KeccakAbsorb(byte[] data, int off)
+ {
+ int count = rate >> 6;
+ for (int i = 0; i < count; ++i)
+ {
+ state[i] ^= Pack.LE_To_UInt64(data, off);
+ off += 8;
+ }
+
+ KeccakPermutation();
+ }
+
+ private void KeccakExtract()
+ {
+ Pack.UInt64_To_LE(state, 0, rate >> 6, dataQueue, 0);
+ }
+
+ private void KeccakPermutation()
+ {
+ for (int i = 0; i < 24; i++)
+ {
+ Theta(state);
+ Rho(state);
+ Pi(state);
+ Chi(state);
+ Iota(state, i);
+ }
+ }
+
+ private static ulong leftRotate(ulong v, int r)
+ {
+ return (v << r) | (v >> -r);
+ }
+
+ private static void Theta(ulong[] A)
+ {
+ ulong C0 = A[0 + 0] ^ A[0 + 5] ^ A[0 + 10] ^ A[0 + 15] ^ A[0 + 20];
+ ulong C1 = A[1 + 0] ^ A[1 + 5] ^ A[1 + 10] ^ A[1 + 15] ^ A[1 + 20];
+ ulong C2 = A[2 + 0] ^ A[2 + 5] ^ A[2 + 10] ^ A[2 + 15] ^ A[2 + 20];
+ ulong C3 = A[3 + 0] ^ A[3 + 5] ^ A[3 + 10] ^ A[3 + 15] ^ A[3 + 20];
+ ulong C4 = A[4 + 0] ^ A[4 + 5] ^ A[4 + 10] ^ A[4 + 15] ^ A[4 + 20];
+
+ ulong dX = leftRotate(C1, 1) ^ C4;
+
+ A[0] ^= dX;
+ A[5] ^= dX;
+ A[10] ^= dX;
+ A[15] ^= dX;
+ A[20] ^= dX;
+
+ dX = leftRotate(C2, 1) ^ C0;
+
+ A[1] ^= dX;
+ A[6] ^= dX;
+ A[11] ^= dX;
+ A[16] ^= dX;
+ A[21] ^= dX;
+
+ dX = leftRotate(C3, 1) ^ C1;
+
+ A[2] ^= dX;
+ A[7] ^= dX;
+ A[12] ^= dX;
+ A[17] ^= dX;
+ A[22] ^= dX;
+
+ dX = leftRotate(C4, 1) ^ C2;
+
+ A[3] ^= dX;
+ A[8] ^= dX;
+ A[13] ^= dX;
+ A[18] ^= dX;
+ A[23] ^= dX;
+
+ dX = leftRotate(C0, 1) ^ C3;
+
+ A[4] ^= dX;
+ A[9] ^= dX;
+ A[14] ^= dX;
+ A[19] ^= dX;
+ A[24] ^= dX;
+ }
+
+ private static void Rho(ulong[] A)
+ {
+ // KeccakRhoOffsets[0] == 0
+ for (int x = 1; x < 25; x++)
+ {
+ A[x] = leftRotate(A[x], KeccakRhoOffsets[x]);
+ }
+ }
+
+ private static void Pi(ulong[] A)
+ {
+ ulong a1 = A[1];
+ A[1] = A[6];
+ A[6] = A[9];
+ A[9] = A[22];
+ A[22] = A[14];
+ A[14] = A[20];
+ A[20] = A[2];
+ A[2] = A[12];
+ A[12] = A[13];
+ A[13] = A[19];
+ A[19] = A[23];
+ A[23] = A[15];
+ A[15] = A[4];
+ A[4] = A[24];
+ A[24] = A[21];
+ A[21] = A[8];
+ A[8] = A[16];
+ A[16] = A[5];
+ A[5] = A[3];
+ A[3] = A[18];
+ A[18] = A[17];
+ A[17] = A[11];
+ A[11] = A[7];
+ A[7] = A[10];
+ A[10] = a1;
+ }
+
+ private static void Chi(ulong[] A)
+ {
+ ulong chiC0, chiC1, chiC2, chiC3, chiC4;
+
+ for (int yBy5 = 0; yBy5 < 25; yBy5 += 5)
+ {
+ chiC0 = A[0 + yBy5] ^ ((~A[(((0 + 1) % 5) + yBy5)]) & A[(((0 + 2) % 5) + yBy5)]);
+ chiC1 = A[1 + yBy5] ^ ((~A[(((1 + 1) % 5) + yBy5)]) & A[(((1 + 2) % 5) + yBy5)]);
+ chiC2 = A[2 + yBy5] ^ ((~A[(((2 + 1) % 5) + yBy5)]) & A[(((2 + 2) % 5) + yBy5)]);
+ chiC3 = A[3 + yBy5] ^ ((~A[(((3 + 1) % 5) + yBy5)]) & A[(((3 + 2) % 5) + yBy5)]);
+ chiC4 = A[4 + yBy5] ^ ((~A[(((4 + 1) % 5) + yBy5)]) & A[(((4 + 2) % 5) + yBy5)]);
+
+ A[0 + yBy5] = chiC0;
+ A[1 + yBy5] = chiC1;
+ A[2 + yBy5] = chiC2;
+ A[3 + yBy5] = chiC3;
+ A[4 + yBy5] = chiC4;
+ }
+ }
+
+ private static void Iota(ulong[] A, int indexRound)
+ {
+ A[0] ^= KeccakRoundConstants[indexRound];
+ }
+
+ public virtual IMemoable Copy()
+ {
+ return new KeccakDigest(this);
+ }
+
+ public virtual void Reset(IMemoable other)
+ {
+ CopyIn((KeccakDigest)other);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/LongDigest.cs b/bc-sharp-crypto/src/crypto/digests/LongDigest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9ee9bcd5713b5bd1f8be458ae63ed608bce226fd
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/LongDigest.cs
@@ -0,0 +1,355 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * Base class for SHA-384 and SHA-512.
+ */
+ public abstract class LongDigest
+ : IDigest, IMemoable
+ {
+ private int MyByteLength = 128;
+
+ private byte[] xBuf;
+ private int xBufOff;
+
+ private long byteCount1;
+ private long byteCount2;
+
+ internal ulong H1, H2, H3, H4, H5, H6, H7, H8;
+
+ private ulong[] W = new ulong[80];
+ private int wOff;
+
+ /**
+ * Constructor for variable length word
+ */
+ internal LongDigest()
+ {
+ xBuf = new byte[8];
+
+ Reset();
+ }
+
+ /**
+ * Copy constructor. We are using copy constructors in place
+ * of the object.Clone() interface as this interface is not
+ * supported by J2ME.
+ */
+ internal LongDigest(
+ LongDigest t)
+ {
+ xBuf = new byte[t.xBuf.Length];
+
+ CopyIn(t);
+ }
+
+ protected void CopyIn(LongDigest t)
+ {
+ Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length);
+
+ xBufOff = t.xBufOff;
+ byteCount1 = t.byteCount1;
+ byteCount2 = t.byteCount2;
+
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+ H5 = t.H5;
+ H6 = t.H6;
+ H7 = t.H7;
+ H8 = t.H8;
+
+ Array.Copy(t.W, 0, W, 0, t.W.Length);
+ wOff = t.wOff;
+ }
+
+ public void Update(
+ byte input)
+ {
+ xBuf[xBufOff++] = input;
+
+ if (xBufOff == xBuf.Length)
+ {
+ ProcessWord(xBuf, 0);
+ xBufOff = 0;
+ }
+
+ byteCount1++;
+ }
+
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ //
+ // fill the current word
+ //
+ while ((xBufOff != 0) && (length > 0))
+ {
+ Update(input[inOff]);
+
+ inOff++;
+ length--;
+ }
+
+ //
+ // process whole words.
+ //
+ while (length > xBuf.Length)
+ {
+ ProcessWord(input, inOff);
+
+ inOff += xBuf.Length;
+ length -= xBuf.Length;
+ byteCount1 += xBuf.Length;
+ }
+
+ //
+ // load in the remainder.
+ //
+ while (length > 0)
+ {
+ Update(input[inOff]);
+
+ inOff++;
+ length--;
+ }
+ }
+
+ public void Finish()
+ {
+ AdjustByteCounts();
+
+ long lowBitLength = byteCount1 << 3;
+ long hiBitLength = byteCount2;
+
+ //
+ // add the pad bytes.
+ //
+ Update((byte)128);
+
+ while (xBufOff != 0)
+ {
+ Update((byte)0);
+ }
+
+ ProcessLength(lowBitLength, hiBitLength);
+
+ ProcessBlock();
+ }
+
+ public virtual void Reset()
+ {
+ byteCount1 = 0;
+ byteCount2 = 0;
+
+ xBufOff = 0;
+ for ( int i = 0; i < xBuf.Length; i++ )
+ {
+ xBuf[i] = 0;
+ }
+
+ wOff = 0;
+ Array.Clear(W, 0, W.Length);
+ }
+
+ internal void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ W[wOff] = Pack.BE_To_UInt64(input, inOff);
+
+ if (++wOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ /**
+ * adjust the byte counts so that byteCount2 represents the
+ * upper long (less 3 bits) word of the byte count.
+ */
+ private void AdjustByteCounts()
+ {
+ if (byteCount1 > 0x1fffffffffffffffL)
+ {
+ byteCount2 += (long) ((ulong) byteCount1 >> 61);
+ byteCount1 &= 0x1fffffffffffffffL;
+ }
+ }
+
+ internal void ProcessLength(
+ long lowW,
+ long hiW)
+ {
+ if (wOff > 14)
+ {
+ ProcessBlock();
+ }
+
+ W[14] = (ulong)hiW;
+ W[15] = (ulong)lowW;
+ }
+
+ internal void ProcessBlock()
+ {
+ AdjustByteCounts();
+
+ //
+ // expand 16 word block into 80 word blocks.
+ //
+ for (int ti = 16; ti <= 79; ++ti)
+ {
+ W[ti] = Sigma1(W[ti - 2]) + W[ti - 7] + Sigma0(W[ti - 15]) + W[ti - 16];
+ }
+
+ //
+ // set up working variables.
+ //
+ ulong a = H1;
+ ulong b = H2;
+ ulong c = H3;
+ ulong d = H4;
+ ulong e = H5;
+ ulong f = H6;
+ ulong g = H7;
+ ulong h = H8;
+
+ int t = 0;
+ for(int i = 0; i < 10; i ++)
+ {
+ // t = 8 * i
+ h += Sum1(e) + Ch(e, f, g) + K[t] + W[t++];
+ d += h;
+ h += Sum0(a) + Maj(a, b, c);
+
+ // t = 8 * i + 1
+ g += Sum1(d) + Ch(d, e, f) + K[t] + W[t++];
+ c += g;
+ g += Sum0(h) + Maj(h, a, b);
+
+ // t = 8 * i + 2
+ f += Sum1(c) + Ch(c, d, e) + K[t] + W[t++];
+ b += f;
+ f += Sum0(g) + Maj(g, h, a);
+
+ // t = 8 * i + 3
+ e += Sum1(b) + Ch(b, c, d) + K[t] + W[t++];
+ a += e;
+ e += Sum0(f) + Maj(f, g, h);
+
+ // t = 8 * i + 4
+ d += Sum1(a) + Ch(a, b, c) + K[t] + W[t++];
+ h += d;
+ d += Sum0(e) + Maj(e, f, g);
+
+ // t = 8 * i + 5
+ c += Sum1(h) + Ch(h, a, b) + K[t] + W[t++];
+ g += c;
+ c += Sum0(d) + Maj(d, e, f);
+
+ // t = 8 * i + 6
+ b += Sum1(g) + Ch(g, h, a) + K[t] + W[t++];
+ f += b;
+ b += Sum0(c) + Maj(c, d, e);
+
+ // t = 8 * i + 7
+ a += Sum1(f) + Ch(f, g, h) + K[t] + W[t++];
+ e += a;
+ a += Sum0(b) + Maj(b, c, d);
+ }
+
+ H1 += a;
+ H2 += b;
+ H3 += c;
+ H4 += d;
+ H5 += e;
+ H6 += f;
+ H7 += g;
+ H8 += h;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ wOff = 0;
+ Array.Clear(W, 0, 16);
+ }
+
+ /* SHA-384 and SHA-512 functions (as for SHA-256 but for longs) */
+ private static ulong Ch(ulong x, ulong y, ulong z)
+ {
+ return (x & y) ^ (~x & z);
+ }
+
+ private static ulong Maj(ulong x, ulong y, ulong z)
+ {
+ return (x & y) ^ (x & z) ^ (y & z);
+ }
+
+ private static ulong Sum0(ulong x)
+ {
+ return ((x << 36) | (x >> 28)) ^ ((x << 30) | (x >> 34)) ^ ((x << 25) | (x >> 39));
+ }
+
+ private static ulong Sum1(ulong x)
+ {
+ return ((x << 50) | (x >> 14)) ^ ((x << 46) | (x >> 18)) ^ ((x << 23) | (x >> 41));
+ }
+
+ private static ulong Sigma0(ulong x)
+ {
+ return ((x << 63) | (x >> 1)) ^ ((x << 56) | (x >> 8)) ^ (x >> 7);
+ }
+
+ private static ulong Sigma1(ulong x)
+ {
+ return ((x << 45) | (x >> 19)) ^ ((x << 3) | (x >> 61)) ^ (x >> 6);
+ }
+
+ /* SHA-384 and SHA-512 Constants
+ * (represent the first 64 bits of the fractional parts of the
+ * cube roots of the first sixty-four prime numbers)
+ */
+ internal static readonly ulong[] K =
+ {
+ 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
+ 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
+ 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
+ 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
+ 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
+ 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
+ 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
+ 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
+ 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
+ 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
+ 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
+ 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
+ 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
+ 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
+ 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
+ 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
+ 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
+ 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
+ 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
+ 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
+ };
+
+ public int GetByteLength()
+ {
+ return MyByteLength;
+ }
+
+ public abstract string AlgorithmName { get; }
+ public abstract int GetDigestSize();
+ public abstract int DoFinal(byte[] output, int outOff);
+ public abstract IMemoable Copy();
+ public abstract void Reset(IMemoable t);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/MD2Digest.cs b/bc-sharp-crypto/src/crypto/digests/MD2Digest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6d90f3f9dc0b8b2eccff10a78cf706c55de15f8a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/MD2Digest.cs
@@ -0,0 +1,269 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+
+ /**
+ * implementation of MD2
+ * as outlined in RFC1319 by B.Kaliski from RSA Laboratories April 1992
+ */
+ public class MD2Digest
+ : IDigest, IMemoable
+ {
+ private const int DigestLength = 16;
+ private const int BYTE_LENGTH = 16;
+
+ /* X buffer */
+ private byte[] X = new byte[48];
+ private int xOff;
+
+ /* M buffer */
+
+ private byte[] M = new byte[16];
+ private int mOff;
+
+ /* check sum */
+
+ private byte[] C = new byte[16];
+ private int COff;
+
+ public MD2Digest()
+ {
+ Reset();
+ }
+
+ public MD2Digest(MD2Digest t)
+ {
+ CopyIn(t);
+ }
+
+ private void CopyIn(MD2Digest t)
+ {
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ Array.Copy(t.M, 0, M, 0, t.M.Length);
+ mOff = t.mOff;
+ Array.Copy(t.C, 0, C, 0, t.C.Length);
+ COff = t.COff;
+ }
+
+ /**
+ * return the algorithm name
+ *
+ * @return the algorithm name
+ */
+ public string AlgorithmName
+ {
+ get { return "MD2"; }
+ }
+
+ public int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ public int GetByteLength()
+ {
+ return BYTE_LENGTH;
+ }
+
+ /**
+ * Close the digest, producing the final digest value. The doFinal
+ * call leaves the digest reset.
+ *
+ * @param out the array the digest is to be copied into.
+ * @param outOff the offset into the out array the digest is to start at.
+ */
+ public int DoFinal(byte[] output, int outOff)
+ {
+ // add padding
+ byte paddingByte = (byte)(M.Length - mOff);
+ for (int i=mOff;i 0))
+ {
+ Update(input[inOff]);
+ inOff++;
+ length--;
+ }
+
+ //
+ // process whole words.
+ //
+ while (length > 16)
+ {
+ Array.Copy(input,inOff,M,0,16);
+ ProcessChecksum(M);
+ ProcessBlock(M);
+ length -= 16;
+ inOff += 16;
+ }
+
+ //
+ // load in the remainder.
+ //
+ while (length > 0)
+ {
+ Update(input[inOff]);
+ inOff++;
+ length--;
+ }
+ }
+
+ internal void ProcessChecksum(byte[] m)
+ {
+ int L = C[15];
+ for (int i=0;i<16;i++)
+ {
+ C[i] ^= S[(m[i] ^ L) & 0xff];
+ L = C[i];
+ }
+ }
+ internal void ProcessBlock(byte[] m)
+ {
+ for (int i=0;i<16;i++)
+ {
+ X[i+16] = m[i];
+ X[i+32] = (byte)(m[i] ^ X[i]);
+ }
+ // encrypt block
+ int t = 0;
+
+ for (int j=0;j<18;j++)
+ {
+ for (int k=0;k<48;k++)
+ {
+ t = X[k] ^= S[t];
+ t = t & 0xff;
+ }
+ t = (t + j)%256;
+ }
+ }
+
+
+
+ // 256-byte random permutation constructed from the digits of PI
+ private static readonly byte[] S = {
+ (byte)41,(byte)46,(byte)67,(byte)201,(byte)162,(byte)216,(byte)124,
+ (byte)1,(byte)61,(byte)54,(byte)84,(byte)161,(byte)236,(byte)240,
+ (byte)6,(byte)19,(byte)98,(byte)167,(byte)5,(byte)243,(byte)192,
+ (byte)199,(byte)115,(byte)140,(byte)152,(byte)147,(byte)43,(byte)217,
+ (byte)188,(byte)76,(byte)130,(byte)202,(byte)30,(byte)155,(byte)87,
+ (byte)60,(byte)253,(byte)212,(byte)224,(byte)22,(byte)103,(byte)66,
+ (byte)111,(byte)24,(byte)138,(byte)23,(byte)229,(byte)18,(byte)190,
+ (byte)78,(byte)196,(byte)214,(byte)218,(byte)158,(byte)222,(byte)73,
+ (byte)160,(byte)251,(byte)245,(byte)142,(byte)187,(byte)47,(byte)238,
+ (byte)122,(byte)169,(byte)104,(byte)121,(byte)145,(byte)21,(byte)178,
+ (byte)7,(byte)63,(byte)148,(byte)194,(byte)16,(byte)137,(byte)11,
+ (byte)34,(byte)95,(byte)33,(byte)128,(byte)127,(byte)93,(byte)154,
+ (byte)90,(byte)144,(byte)50,(byte)39,(byte)53,(byte)62,(byte)204,
+ (byte)231,(byte)191,(byte)247,(byte)151,(byte)3,(byte)255,(byte)25,
+ (byte)48,(byte)179,(byte)72,(byte)165,(byte)181,(byte)209,(byte)215,
+ (byte)94,(byte)146,(byte)42,(byte)172,(byte)86,(byte)170,(byte)198,
+ (byte)79,(byte)184,(byte)56,(byte)210,(byte)150,(byte)164,(byte)125,
+ (byte)182,(byte)118,(byte)252,(byte)107,(byte)226,(byte)156,(byte)116,
+ (byte)4,(byte)241,(byte)69,(byte)157,(byte)112,(byte)89,(byte)100,
+ (byte)113,(byte)135,(byte)32,(byte)134,(byte)91,(byte)207,(byte)101,
+ (byte)230,(byte)45,(byte)168,(byte)2,(byte)27,(byte)96,(byte)37,
+ (byte)173,(byte)174,(byte)176,(byte)185,(byte)246,(byte)28,(byte)70,
+ (byte)97,(byte)105,(byte)52,(byte)64,(byte)126,(byte)15,(byte)85,
+ (byte)71,(byte)163,(byte)35,(byte)221,(byte)81,(byte)175,(byte)58,
+ (byte)195,(byte)92,(byte)249,(byte)206,(byte)186,(byte)197,(byte)234,
+ (byte)38,(byte)44,(byte)83,(byte)13,(byte)110,(byte)133,(byte)40,
+ (byte)132, 9,(byte)211,(byte)223,(byte)205,(byte)244,(byte)65,
+ (byte)129,(byte)77,(byte)82,(byte)106,(byte)220,(byte)55,(byte)200,
+ (byte)108,(byte)193,(byte)171,(byte)250,(byte)36,(byte)225,(byte)123,
+ (byte)8,(byte)12,(byte)189,(byte)177,(byte)74,(byte)120,(byte)136,
+ (byte)149,(byte)139,(byte)227,(byte)99,(byte)232,(byte)109,(byte)233,
+ (byte)203,(byte)213,(byte)254,(byte)59,(byte)0,(byte)29,(byte)57,
+ (byte)242,(byte)239,(byte)183,(byte)14,(byte)102,(byte)88,(byte)208,
+ (byte)228,(byte)166,(byte)119,(byte)114,(byte)248,(byte)235,(byte)117,
+ (byte)75,(byte)10,(byte)49,(byte)68,(byte)80,(byte)180,(byte)143,
+ (byte)237,(byte)31,(byte)26,(byte)219,(byte)153,(byte)141,(byte)51,
+ (byte)159,(byte)17,(byte)131,(byte)20
+ };
+
+ public IMemoable Copy()
+ {
+ return new MD2Digest(this);
+ }
+
+ public void Reset(IMemoable other)
+ {
+ MD2Digest d = (MD2Digest)other;
+
+ CopyIn(d);
+ }
+
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/MD4Digest.cs b/bc-sharp-crypto/src/crypto/digests/MD4Digest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8743f7dad75870cacfc8b75cd509cf36dd4ba1de
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/MD4Digest.cs
@@ -0,0 +1,292 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * implementation of MD4 as RFC 1320 by R. Rivest, MIT Laboratory for
+ * Computer Science and RSA Data Security, Inc.
+ *
+ * NOTE : This algorithm is only included for backwards compatibility
+ * with legacy applications, it's not secure, don't use it for anything new!
+ */
+ public class MD4Digest
+ : GeneralDigest
+ {
+ private const int DigestLength = 16;
+
+ private int H1, H2, H3, H4; // IV's
+
+ private int[] X = new int[16];
+ private int xOff;
+
+ /**
+ * Standard constructor
+ */
+ public MD4Digest()
+ {
+ Reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public MD4Digest(MD4Digest t) : base(t)
+ {
+ CopyIn(t);
+ }
+
+ private void CopyIn(MD4Digest t)
+ {
+ base.CopyIn(t);
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "MD4"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ internal override void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8)
+ | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24);
+
+ if (xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ internal override void ProcessLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ ProcessBlock();
+ }
+
+ X[14] = (int)(bitLength & 0xffffffff);
+ X[15] = (int)((ulong) bitLength >> 32);
+ }
+
+ private void UnpackWord(
+ int word,
+ byte[] outBytes,
+ int outOff)
+ {
+ outBytes[outOff] = (byte)word;
+ outBytes[outOff + 1] = (byte)((uint) word >> 8);
+ outBytes[outOff + 2] = (byte)((uint) word >> 16);
+ outBytes[outOff + 3] = (byte)((uint) word >> 24);
+ }
+
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ UnpackWord(H1, output, outOff);
+ UnpackWord(H2, output, outOff + 4);
+ UnpackWord(H3, output, outOff + 8);
+ UnpackWord(H4, output, outOff + 12);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /**
+ * reset the chaining variables to the IV values.
+ */
+ public override void Reset()
+ {
+ base.Reset();
+
+ H1 = unchecked((int) 0x67452301);
+ H2 = unchecked((int) 0xefcdab89);
+ H3 = unchecked((int) 0x98badcfe);
+ H4 = unchecked((int) 0x10325476);
+
+ xOff = 0;
+
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ //
+ // round 1 left rotates
+ //
+ private const int S11 = 3;
+ private const int S12 = 7;
+ private const int S13 = 11;
+ private const int S14 = 19;
+
+ //
+ // round 2 left rotates
+ //
+ private const int S21 = 3;
+ private const int S22 = 5;
+ private const int S23 = 9;
+ private const int S24 = 13;
+
+ //
+ // round 3 left rotates
+ //
+ private const int S31 = 3;
+ private const int S32 = 9;
+ private const int S33 = 11;
+ private const int S34 = 15;
+
+ /*
+ * rotate int x left n bits.
+ */
+ private int RotateLeft(
+ int x,
+ int n)
+ {
+ return (x << n) | (int) ((uint) x >> (32 - n));
+ }
+
+ /*
+ * F, G, H and I are the basic MD4 functions.
+ */
+ private int F(
+ int u,
+ int v,
+ int w)
+ {
+ return (u & v) | (~u & w);
+ }
+
+ private int G(
+ int u,
+ int v,
+ int w)
+ {
+ return (u & v) | (u & w) | (v & w);
+ }
+
+ private int H(
+ int u,
+ int v,
+ int w)
+ {
+ return u ^ v ^ w;
+ }
+
+ internal override void ProcessBlock()
+ {
+ int a = H1;
+ int b = H2;
+ int c = H3;
+ int d = H4;
+
+ //
+ // Round 1 - F cycle, 16 times.
+ //
+ a = RotateLeft((a + F(b, c, d) + X[ 0]), S11);
+ d = RotateLeft((d + F(a, b, c) + X[ 1]), S12);
+ c = RotateLeft((c + F(d, a, b) + X[ 2]), S13);
+ b = RotateLeft((b + F(c, d, a) + X[ 3]), S14);
+ a = RotateLeft((a + F(b, c, d) + X[ 4]), S11);
+ d = RotateLeft((d + F(a, b, c) + X[ 5]), S12);
+ c = RotateLeft((c + F(d, a, b) + X[ 6]), S13);
+ b = RotateLeft((b + F(c, d, a) + X[ 7]), S14);
+ a = RotateLeft((a + F(b, c, d) + X[ 8]), S11);
+ d = RotateLeft((d + F(a, b, c) + X[ 9]), S12);
+ c = RotateLeft((c + F(d, a, b) + X[10]), S13);
+ b = RotateLeft((b + F(c, d, a) + X[11]), S14);
+ a = RotateLeft((a + F(b, c, d) + X[12]), S11);
+ d = RotateLeft((d + F(a, b, c) + X[13]), S12);
+ c = RotateLeft((c + F(d, a, b) + X[14]), S13);
+ b = RotateLeft((b + F(c, d, a) + X[15]), S14);
+
+ //
+ // Round 2 - G cycle, 16 times.
+ //
+ a = RotateLeft((a + G(b, c, d) + X[ 0] + 0x5a827999), S21);
+ d = RotateLeft((d + G(a, b, c) + X[ 4] + 0x5a827999), S22);
+ c = RotateLeft((c + G(d, a, b) + X[ 8] + 0x5a827999), S23);
+ b = RotateLeft((b + G(c, d, a) + X[12] + 0x5a827999), S24);
+ a = RotateLeft((a + G(b, c, d) + X[ 1] + 0x5a827999), S21);
+ d = RotateLeft((d + G(a, b, c) + X[ 5] + 0x5a827999), S22);
+ c = RotateLeft((c + G(d, a, b) + X[ 9] + 0x5a827999), S23);
+ b = RotateLeft((b + G(c, d, a) + X[13] + 0x5a827999), S24);
+ a = RotateLeft((a + G(b, c, d) + X[ 2] + 0x5a827999), S21);
+ d = RotateLeft((d + G(a, b, c) + X[ 6] + 0x5a827999), S22);
+ c = RotateLeft((c + G(d, a, b) + X[10] + 0x5a827999), S23);
+ b = RotateLeft((b + G(c, d, a) + X[14] + 0x5a827999), S24);
+ a = RotateLeft((a + G(b, c, d) + X[ 3] + 0x5a827999), S21);
+ d = RotateLeft((d + G(a, b, c) + X[ 7] + 0x5a827999), S22);
+ c = RotateLeft((c + G(d, a, b) + X[11] + 0x5a827999), S23);
+ b = RotateLeft((b + G(c, d, a) + X[15] + 0x5a827999), S24);
+
+ //
+ // Round 3 - H cycle, 16 times.
+ //
+ a = RotateLeft((a + H(b, c, d) + X[ 0] + 0x6ed9eba1), S31);
+ d = RotateLeft((d + H(a, b, c) + X[ 8] + 0x6ed9eba1), S32);
+ c = RotateLeft((c + H(d, a, b) + X[ 4] + 0x6ed9eba1), S33);
+ b = RotateLeft((b + H(c, d, a) + X[12] + 0x6ed9eba1), S34);
+ a = RotateLeft((a + H(b, c, d) + X[ 2] + 0x6ed9eba1), S31);
+ d = RotateLeft((d + H(a, b, c) + X[10] + 0x6ed9eba1), S32);
+ c = RotateLeft((c + H(d, a, b) + X[ 6] + 0x6ed9eba1), S33);
+ b = RotateLeft((b + H(c, d, a) + X[14] + 0x6ed9eba1), S34);
+ a = RotateLeft((a + H(b, c, d) + X[ 1] + 0x6ed9eba1), S31);
+ d = RotateLeft((d + H(a, b, c) + X[ 9] + 0x6ed9eba1), S32);
+ c = RotateLeft((c + H(d, a, b) + X[ 5] + 0x6ed9eba1), S33);
+ b = RotateLeft((b + H(c, d, a) + X[13] + 0x6ed9eba1), S34);
+ a = RotateLeft((a + H(b, c, d) + X[ 3] + 0x6ed9eba1), S31);
+ d = RotateLeft((d + H(a, b, c) + X[11] + 0x6ed9eba1), S32);
+ c = RotateLeft((c + H(d, a, b) + X[ 7] + 0x6ed9eba1), S33);
+ b = RotateLeft((b + H(c, d, a) + X[15] + 0x6ed9eba1), S34);
+
+ H1 += a;
+ H2 += b;
+ H3 += c;
+ H4 += d;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ xOff = 0;
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ public override IMemoable Copy()
+ {
+ return new MD4Digest(this);
+ }
+
+ public override void Reset(IMemoable other)
+ {
+ MD4Digest d = (MD4Digest)other;
+
+ CopyIn(d);
+ }
+
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/MD5Digest.cs b/bc-sharp-crypto/src/crypto/digests/MD5Digest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c60ac92a377e4cb33c6e45da3eb5810dd3b72b20
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/MD5Digest.cs
@@ -0,0 +1,313 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * implementation of MD5 as outlined in "Handbook of Applied Cryptography", pages 346 - 347.
+ */
+ public class MD5Digest
+ : GeneralDigest
+ {
+ private const int DigestLength = 16;
+
+ private uint H1, H2, H3, H4; // IV's
+
+ private uint[] X = new uint[16];
+ private int xOff;
+
+ public MD5Digest()
+ {
+ Reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public MD5Digest(MD5Digest t)
+ : base(t)
+ {
+ CopyIn(t);
+ }
+
+ private void CopyIn(MD5Digest t)
+ {
+ base.CopyIn(t);
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "MD5"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ internal override void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ X[xOff] = Pack.LE_To_UInt32(input, inOff);
+
+ if (++xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ internal override void ProcessLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ if (xOff == 15)
+ X[15] = 0;
+
+ ProcessBlock();
+ }
+
+ for (int i = xOff; i < 14; ++i)
+ {
+ X[i] = 0;
+ }
+
+ X[14] = (uint)((ulong)bitLength);
+ X[15] = (uint)((ulong)bitLength >> 32);
+ }
+
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ Pack.UInt32_To_LE(H1, output, outOff);
+ Pack.UInt32_To_LE(H2, output, outOff + 4);
+ Pack.UInt32_To_LE(H3, output, outOff + 8);
+ Pack.UInt32_To_LE(H4, output, outOff + 12);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /**
+ * reset the chaining variables to the IV values.
+ */
+ public override void Reset()
+ {
+ base.Reset();
+
+ H1 = 0x67452301;
+ H2 = 0xefcdab89;
+ H3 = 0x98badcfe;
+ H4 = 0x10325476;
+
+ xOff = 0;
+
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ //
+ // round 1 left rotates
+ //
+ private static readonly int S11 = 7;
+ private static readonly int S12 = 12;
+ private static readonly int S13 = 17;
+ private static readonly int S14 = 22;
+
+ //
+ // round 2 left rotates
+ //
+ private static readonly int S21 = 5;
+ private static readonly int S22 = 9;
+ private static readonly int S23 = 14;
+ private static readonly int S24 = 20;
+
+ //
+ // round 3 left rotates
+ //
+ private static readonly int S31 = 4;
+ private static readonly int S32 = 11;
+ private static readonly int S33 = 16;
+ private static readonly int S34 = 23;
+
+ //
+ // round 4 left rotates
+ //
+ private static readonly int S41 = 6;
+ private static readonly int S42 = 10;
+ private static readonly int S43 = 15;
+ private static readonly int S44 = 21;
+
+ /*
+ * rotate int x left n bits.
+ */
+ private static uint RotateLeft(
+ uint x,
+ int n)
+ {
+ return (x << n) | (x >> (32 - n));
+ }
+
+ /*
+ * F, G, H and I are the basic MD5 functions.
+ */
+ private static uint F(
+ uint u,
+ uint v,
+ uint w)
+ {
+ return (u & v) | (~u & w);
+ }
+
+ private static uint G(
+ uint u,
+ uint v,
+ uint w)
+ {
+ return (u & w) | (v & ~w);
+ }
+
+ private static uint H(
+ uint u,
+ uint v,
+ uint w)
+ {
+ return u ^ v ^ w;
+ }
+
+ private static uint K(
+ uint u,
+ uint v,
+ uint w)
+ {
+ return v ^ (u | ~w);
+ }
+
+ internal override void ProcessBlock()
+ {
+ uint a = H1;
+ uint b = H2;
+ uint c = H3;
+ uint d = H4;
+
+ //
+ // Round 1 - F cycle, 16 times.
+ //
+ a = RotateLeft((a + F(b, c, d) + X[0] + 0xd76aa478), S11) + b;
+ d = RotateLeft((d + F(a, b, c) + X[1] + 0xe8c7b756), S12) + a;
+ c = RotateLeft((c + F(d, a, b) + X[2] + 0x242070db), S13) + d;
+ b = RotateLeft((b + F(c, d, a) + X[3] + 0xc1bdceee), S14) + c;
+ a = RotateLeft((a + F(b, c, d) + X[4] + 0xf57c0faf), S11) + b;
+ d = RotateLeft((d + F(a, b, c) + X[5] + 0x4787c62a), S12) + a;
+ c = RotateLeft((c + F(d, a, b) + X[6] + 0xa8304613), S13) + d;
+ b = RotateLeft((b + F(c, d, a) + X[7] + 0xfd469501), S14) + c;
+ a = RotateLeft((a + F(b, c, d) + X[8] + 0x698098d8), S11) + b;
+ d = RotateLeft((d + F(a, b, c) + X[9] + 0x8b44f7af), S12) + a;
+ c = RotateLeft((c + F(d, a, b) + X[10] + 0xffff5bb1), S13) + d;
+ b = RotateLeft((b + F(c, d, a) + X[11] + 0x895cd7be), S14) + c;
+ a = RotateLeft((a + F(b, c, d) + X[12] + 0x6b901122), S11) + b;
+ d = RotateLeft((d + F(a, b, c) + X[13] + 0xfd987193), S12) + a;
+ c = RotateLeft((c + F(d, a, b) + X[14] + 0xa679438e), S13) + d;
+ b = RotateLeft((b + F(c, d, a) + X[15] + 0x49b40821), S14) + c;
+
+ //
+ // Round 2 - G cycle, 16 times.
+ //
+ a = RotateLeft((a + G(b, c, d) + X[1] + 0xf61e2562), S21) + b;
+ d = RotateLeft((d + G(a, b, c) + X[6] + 0xc040b340), S22) + a;
+ c = RotateLeft((c + G(d, a, b) + X[11] + 0x265e5a51), S23) + d;
+ b = RotateLeft((b + G(c, d, a) + X[0] + 0xe9b6c7aa), S24) + c;
+ a = RotateLeft((a + G(b, c, d) + X[5] + 0xd62f105d), S21) + b;
+ d = RotateLeft((d + G(a, b, c) + X[10] + 0x02441453), S22) + a;
+ c = RotateLeft((c + G(d, a, b) + X[15] + 0xd8a1e681), S23) + d;
+ b = RotateLeft((b + G(c, d, a) + X[4] + 0xe7d3fbc8), S24) + c;
+ a = RotateLeft((a + G(b, c, d) + X[9] + 0x21e1cde6), S21) + b;
+ d = RotateLeft((d + G(a, b, c) + X[14] + 0xc33707d6), S22) + a;
+ c = RotateLeft((c + G(d, a, b) + X[3] + 0xf4d50d87), S23) + d;
+ b = RotateLeft((b + G(c, d, a) + X[8] + 0x455a14ed), S24) + c;
+ a = RotateLeft((a + G(b, c, d) + X[13] + 0xa9e3e905), S21) + b;
+ d = RotateLeft((d + G(a, b, c) + X[2] + 0xfcefa3f8), S22) + a;
+ c = RotateLeft((c + G(d, a, b) + X[7] + 0x676f02d9), S23) + d;
+ b = RotateLeft((b + G(c, d, a) + X[12] + 0x8d2a4c8a), S24) + c;
+
+ //
+ // Round 3 - H cycle, 16 times.
+ //
+ a = RotateLeft((a + H(b, c, d) + X[5] + 0xfffa3942), S31) + b;
+ d = RotateLeft((d + H(a, b, c) + X[8] + 0x8771f681), S32) + a;
+ c = RotateLeft((c + H(d, a, b) + X[11] + 0x6d9d6122), S33) + d;
+ b = RotateLeft((b + H(c, d, a) + X[14] + 0xfde5380c), S34) + c;
+ a = RotateLeft((a + H(b, c, d) + X[1] + 0xa4beea44), S31) + b;
+ d = RotateLeft((d + H(a, b, c) + X[4] + 0x4bdecfa9), S32) + a;
+ c = RotateLeft((c + H(d, a, b) + X[7] + 0xf6bb4b60), S33) + d;
+ b = RotateLeft((b + H(c, d, a) + X[10] + 0xbebfbc70), S34) + c;
+ a = RotateLeft((a + H(b, c, d) + X[13] + 0x289b7ec6), S31) + b;
+ d = RotateLeft((d + H(a, b, c) + X[0] + 0xeaa127fa), S32) + a;
+ c = RotateLeft((c + H(d, a, b) + X[3] + 0xd4ef3085), S33) + d;
+ b = RotateLeft((b + H(c, d, a) + X[6] + 0x04881d05), S34) + c;
+ a = RotateLeft((a + H(b, c, d) + X[9] + 0xd9d4d039), S31) + b;
+ d = RotateLeft((d + H(a, b, c) + X[12] + 0xe6db99e5), S32) + a;
+ c = RotateLeft((c + H(d, a, b) + X[15] + 0x1fa27cf8), S33) + d;
+ b = RotateLeft((b + H(c, d, a) + X[2] + 0xc4ac5665), S34) + c;
+
+ //
+ // Round 4 - K cycle, 16 times.
+ //
+ a = RotateLeft((a + K(b, c, d) + X[0] + 0xf4292244), S41) + b;
+ d = RotateLeft((d + K(a, b, c) + X[7] + 0x432aff97), S42) + a;
+ c = RotateLeft((c + K(d, a, b) + X[14] + 0xab9423a7), S43) + d;
+ b = RotateLeft((b + K(c, d, a) + X[5] + 0xfc93a039), S44) + c;
+ a = RotateLeft((a + K(b, c, d) + X[12] + 0x655b59c3), S41) + b;
+ d = RotateLeft((d + K(a, b, c) + X[3] + 0x8f0ccc92), S42) + a;
+ c = RotateLeft((c + K(d, a, b) + X[10] + 0xffeff47d), S43) + d;
+ b = RotateLeft((b + K(c, d, a) + X[1] + 0x85845dd1), S44) + c;
+ a = RotateLeft((a + K(b, c, d) + X[8] + 0x6fa87e4f), S41) + b;
+ d = RotateLeft((d + K(a, b, c) + X[15] + 0xfe2ce6e0), S42) + a;
+ c = RotateLeft((c + K(d, a, b) + X[6] + 0xa3014314), S43) + d;
+ b = RotateLeft((b + K(c, d, a) + X[13] + 0x4e0811a1), S44) + c;
+ a = RotateLeft((a + K(b, c, d) + X[4] + 0xf7537e82), S41) + b;
+ d = RotateLeft((d + K(a, b, c) + X[11] + 0xbd3af235), S42) + a;
+ c = RotateLeft((c + K(d, a, b) + X[2] + 0x2ad7d2bb), S43) + d;
+ b = RotateLeft((b + K(c, d, a) + X[9] + 0xeb86d391), S44) + c;
+
+ H1 += a;
+ H2 += b;
+ H3 += c;
+ H4 += d;
+
+ xOff = 0;
+ }
+
+ public override IMemoable Copy()
+ {
+ return new MD5Digest(this);
+ }
+
+ public override void Reset(IMemoable other)
+ {
+ MD5Digest d = (MD5Digest)other;
+
+ CopyIn(d);
+ }
+
+ }
+
+}
+
diff --git a/bc-sharp-crypto/src/crypto/digests/NonMemoableDigest.cs b/bc-sharp-crypto/src/crypto/digests/NonMemoableDigest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..02c49b887d3631e6f3385db4aa9b43756f0fb97d
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/NonMemoableDigest.cs
@@ -0,0 +1,62 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * Wrapper removes exposure to the IMemoable interface on an IDigest implementation.
+ */
+ public class NonMemoableDigest
+ : IDigest
+ {
+ protected readonly IDigest mBaseDigest;
+
+ /**
+ * Base constructor.
+ *
+ * @param baseDigest underlying digest to use.
+ * @exception IllegalArgumentException if baseDigest is null
+ */
+ public NonMemoableDigest(IDigest baseDigest)
+ {
+ if (baseDigest == null)
+ throw new ArgumentNullException("baseDigest");
+
+ this.mBaseDigest = baseDigest;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return mBaseDigest.AlgorithmName; }
+ }
+
+ public virtual int GetDigestSize()
+ {
+ return mBaseDigest.GetDigestSize();
+ }
+
+ public virtual void Update(byte input)
+ {
+ mBaseDigest.Update(input);
+ }
+
+ public virtual void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ mBaseDigest.BlockUpdate(input, inOff, len);
+ }
+
+ public virtual int DoFinal(byte[] output, int outOff)
+ {
+ return mBaseDigest.DoFinal(output, outOff);
+ }
+
+ public virtual void Reset()
+ {
+ mBaseDigest.Reset();
+ }
+
+ public virtual int GetByteLength()
+ {
+ return mBaseDigest.GetByteLength();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/NullDigest.cs b/bc-sharp-crypto/src/crypto/digests/NullDigest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e598cb145d60ea4218799ed205aa1f861d797045
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/NullDigest.cs
@@ -0,0 +1,49 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ public class NullDigest : IDigest
+ {
+ private readonly MemoryStream bOut = new MemoryStream();
+
+ public string AlgorithmName
+ {
+ get { return "NULL"; }
+ }
+
+ public int GetByteLength()
+ {
+ // TODO Is this okay?
+ return 0;
+ }
+
+ public int GetDigestSize()
+ {
+ return (int) bOut.Length;
+ }
+
+ public void Update(byte b)
+ {
+ bOut.WriteByte(b);
+ }
+
+ public void BlockUpdate(byte[] inBytes, int inOff, int len)
+ {
+ bOut.Write(inBytes, inOff, len);
+ }
+
+ public int DoFinal(byte[] outBytes, int outOff)
+ {
+ byte[] res = bOut.ToArray();
+ res.CopyTo(outBytes, outOff);
+ Reset();
+ return res.Length;
+ }
+
+ public void Reset()
+ {
+ bOut.SetLength(0);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/RipeMD128Digest.cs b/bc-sharp-crypto/src/crypto/digests/RipeMD128Digest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e8a0331cadd88422db581bcdcae8ea4604054b9a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/RipeMD128Digest.cs
@@ -0,0 +1,484 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * implementation of RipeMD128
+ */
+ public class RipeMD128Digest
+ : GeneralDigest
+ {
+ private const int DigestLength = 16;
+
+ private int H0, H1, H2, H3; // IV's
+
+ private int[] X = new int[16];
+ private int xOff;
+
+ /**
+ * Standard constructor
+ */
+ public RipeMD128Digest()
+ {
+ Reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public RipeMD128Digest(RipeMD128Digest t) : base(t)
+ {
+ CopyIn(t);
+ }
+
+ private void CopyIn(RipeMD128Digest t)
+ {
+ base.CopyIn(t);
+
+ H0 = t.H0;
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "RIPEMD128"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ internal override void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8)
+ | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24);
+
+ if (xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ internal override void ProcessLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ ProcessBlock();
+ }
+
+ X[14] = (int)(bitLength & 0xffffffff);
+ X[15] = (int)((ulong) bitLength >> 32);
+ }
+
+ private void UnpackWord(
+ int word,
+ byte[] outBytes,
+ int outOff)
+ {
+ outBytes[outOff] = (byte)word;
+ outBytes[outOff + 1] = (byte)((uint) word >> 8);
+ outBytes[outOff + 2] = (byte)((uint) word >> 16);
+ outBytes[outOff + 3] = (byte)((uint) word >> 24);
+ }
+
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ UnpackWord(H0, output, outOff);
+ UnpackWord(H1, output, outOff + 4);
+ UnpackWord(H2, output, outOff + 8);
+ UnpackWord(H3, output, outOff + 12);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /**
+ * reset the chaining variables to the IV values.
+ */
+ public override void Reset()
+ {
+ base.Reset();
+
+ H0 = unchecked((int) 0x67452301);
+ H1 = unchecked((int) 0xefcdab89);
+ H2 = unchecked((int) 0x98badcfe);
+ H3 = unchecked((int) 0x10325476);
+
+ xOff = 0;
+
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ /*
+ * rotate int x left n bits.
+ */
+ private int RL(
+ int x,
+ int n)
+ {
+ return (x << n) | (int) ((uint) x >> (32 - n));
+ }
+
+ /*
+ * f1,f2,f3,f4 are the basic RipeMD128 functions.
+ */
+
+ /*
+ * F
+ */
+ private int F1(
+ int x,
+ int y,
+ int z)
+ {
+ return x ^ y ^ z;
+ }
+
+ /*
+ * G
+ */
+ private int F2(
+ int x,
+ int y,
+ int z)
+ {
+ return (x & y) | (~x & z);
+ }
+
+ /*
+ * H
+ */
+ private int F3(
+ int x,
+ int y,
+ int z)
+ {
+ return (x | ~y) ^ z;
+ }
+
+ /*
+ * I
+ */
+ private int F4(
+ int x,
+ int y,
+ int z)
+ {
+ return (x & z) | (y & ~z);
+ }
+
+ private int F1(
+ int a,
+ int b,
+ int c,
+ int d,
+ int x,
+ int s)
+ {
+ return RL(a + F1(b, c, d) + x, s);
+ }
+
+ private int F2(
+ int a,
+ int b,
+ int c,
+ int d,
+ int x,
+ int s)
+ {
+ return RL(a + F2(b, c, d) + x + unchecked((int) 0x5a827999), s);
+ }
+
+ private int F3(
+ int a,
+ int b,
+ int c,
+ int d,
+ int x,
+ int s)
+ {
+ return RL(a + F3(b, c, d) + x + unchecked((int) 0x6ed9eba1), s);
+ }
+
+ private int F4(
+ int a,
+ int b,
+ int c,
+ int d,
+ int x,
+ int s)
+ {
+ return RL(a + F4(b, c, d) + x + unchecked((int) 0x8f1bbcdc), s);
+ }
+
+ private int FF1(
+ int a,
+ int b,
+ int c,
+ int d,
+ int x,
+ int s)
+ {
+ return RL(a + F1(b, c, d) + x, s);
+ }
+
+ private int FF2(
+ int a,
+ int b,
+ int c,
+ int d,
+ int x,
+ int s)
+ {
+ return RL(a + F2(b, c, d) + x + unchecked((int) 0x6d703ef3), s);
+ }
+
+ private int FF3(
+ int a,
+ int b,
+ int c,
+ int d,
+ int x,
+ int s)
+ {
+ return RL(a + F3(b, c, d) + x + unchecked((int) 0x5c4dd124), s);
+ }
+
+ private int FF4(
+ int a,
+ int b,
+ int c,
+ int d,
+ int x,
+ int s)
+ {
+ return RL(a + F4(b, c, d) + x + unchecked((int) 0x50a28be6), s);
+ }
+
+ internal override void ProcessBlock()
+ {
+ int a, aa;
+ int b, bb;
+ int c, cc;
+ int d, dd;
+
+ a = aa = H0;
+ b = bb = H1;
+ c = cc = H2;
+ d = dd = H3;
+
+ //
+ // Round 1
+ //
+ a = F1(a, b, c, d, X[ 0], 11);
+ d = F1(d, a, b, c, X[ 1], 14);
+ c = F1(c, d, a, b, X[ 2], 15);
+ b = F1(b, c, d, a, X[ 3], 12);
+ a = F1(a, b, c, d, X[ 4], 5);
+ d = F1(d, a, b, c, X[ 5], 8);
+ c = F1(c, d, a, b, X[ 6], 7);
+ b = F1(b, c, d, a, X[ 7], 9);
+ a = F1(a, b, c, d, X[ 8], 11);
+ d = F1(d, a, b, c, X[ 9], 13);
+ c = F1(c, d, a, b, X[10], 14);
+ b = F1(b, c, d, a, X[11], 15);
+ a = F1(a, b, c, d, X[12], 6);
+ d = F1(d, a, b, c, X[13], 7);
+ c = F1(c, d, a, b, X[14], 9);
+ b = F1(b, c, d, a, X[15], 8);
+
+ //
+ // Round 2
+ //
+ a = F2(a, b, c, d, X[ 7], 7);
+ d = F2(d, a, b, c, X[ 4], 6);
+ c = F2(c, d, a, b, X[13], 8);
+ b = F2(b, c, d, a, X[ 1], 13);
+ a = F2(a, b, c, d, X[10], 11);
+ d = F2(d, a, b, c, X[ 6], 9);
+ c = F2(c, d, a, b, X[15], 7);
+ b = F2(b, c, d, a, X[ 3], 15);
+ a = F2(a, b, c, d, X[12], 7);
+ d = F2(d, a, b, c, X[ 0], 12);
+ c = F2(c, d, a, b, X[ 9], 15);
+ b = F2(b, c, d, a, X[ 5], 9);
+ a = F2(a, b, c, d, X[ 2], 11);
+ d = F2(d, a, b, c, X[14], 7);
+ c = F2(c, d, a, b, X[11], 13);
+ b = F2(b, c, d, a, X[ 8], 12);
+
+ //
+ // Round 3
+ //
+ a = F3(a, b, c, d, X[ 3], 11);
+ d = F3(d, a, b, c, X[10], 13);
+ c = F3(c, d, a, b, X[14], 6);
+ b = F3(b, c, d, a, X[ 4], 7);
+ a = F3(a, b, c, d, X[ 9], 14);
+ d = F3(d, a, b, c, X[15], 9);
+ c = F3(c, d, a, b, X[ 8], 13);
+ b = F3(b, c, d, a, X[ 1], 15);
+ a = F3(a, b, c, d, X[ 2], 14);
+ d = F3(d, a, b, c, X[ 7], 8);
+ c = F3(c, d, a, b, X[ 0], 13);
+ b = F3(b, c, d, a, X[ 6], 6);
+ a = F3(a, b, c, d, X[13], 5);
+ d = F3(d, a, b, c, X[11], 12);
+ c = F3(c, d, a, b, X[ 5], 7);
+ b = F3(b, c, d, a, X[12], 5);
+
+ //
+ // Round 4
+ //
+ a = F4(a, b, c, d, X[ 1], 11);
+ d = F4(d, a, b, c, X[ 9], 12);
+ c = F4(c, d, a, b, X[11], 14);
+ b = F4(b, c, d, a, X[10], 15);
+ a = F4(a, b, c, d, X[ 0], 14);
+ d = F4(d, a, b, c, X[ 8], 15);
+ c = F4(c, d, a, b, X[12], 9);
+ b = F4(b, c, d, a, X[ 4], 8);
+ a = F4(a, b, c, d, X[13], 9);
+ d = F4(d, a, b, c, X[ 3], 14);
+ c = F4(c, d, a, b, X[ 7], 5);
+ b = F4(b, c, d, a, X[15], 6);
+ a = F4(a, b, c, d, X[14], 8);
+ d = F4(d, a, b, c, X[ 5], 6);
+ c = F4(c, d, a, b, X[ 6], 5);
+ b = F4(b, c, d, a, X[ 2], 12);
+
+ //
+ // Parallel round 1
+ //
+ aa = FF4(aa, bb, cc, dd, X[ 5], 8);
+ dd = FF4(dd, aa, bb, cc, X[14], 9);
+ cc = FF4(cc, dd, aa, bb, X[ 7], 9);
+ bb = FF4(bb, cc, dd, aa, X[ 0], 11);
+ aa = FF4(aa, bb, cc, dd, X[ 9], 13);
+ dd = FF4(dd, aa, bb, cc, X[ 2], 15);
+ cc = FF4(cc, dd, aa, bb, X[11], 15);
+ bb = FF4(bb, cc, dd, aa, X[ 4], 5);
+ aa = FF4(aa, bb, cc, dd, X[13], 7);
+ dd = FF4(dd, aa, bb, cc, X[ 6], 7);
+ cc = FF4(cc, dd, aa, bb, X[15], 8);
+ bb = FF4(bb, cc, dd, aa, X[ 8], 11);
+ aa = FF4(aa, bb, cc, dd, X[ 1], 14);
+ dd = FF4(dd, aa, bb, cc, X[10], 14);
+ cc = FF4(cc, dd, aa, bb, X[ 3], 12);
+ bb = FF4(bb, cc, dd, aa, X[12], 6);
+
+ //
+ // Parallel round 2
+ //
+ aa = FF3(aa, bb, cc, dd, X[ 6], 9);
+ dd = FF3(dd, aa, bb, cc, X[11], 13);
+ cc = FF3(cc, dd, aa, bb, X[ 3], 15);
+ bb = FF3(bb, cc, dd, aa, X[ 7], 7);
+ aa = FF3(aa, bb, cc, dd, X[ 0], 12);
+ dd = FF3(dd, aa, bb, cc, X[13], 8);
+ cc = FF3(cc, dd, aa, bb, X[ 5], 9);
+ bb = FF3(bb, cc, dd, aa, X[10], 11);
+ aa = FF3(aa, bb, cc, dd, X[14], 7);
+ dd = FF3(dd, aa, bb, cc, X[15], 7);
+ cc = FF3(cc, dd, aa, bb, X[ 8], 12);
+ bb = FF3(bb, cc, dd, aa, X[12], 7);
+ aa = FF3(aa, bb, cc, dd, X[ 4], 6);
+ dd = FF3(dd, aa, bb, cc, X[ 9], 15);
+ cc = FF3(cc, dd, aa, bb, X[ 1], 13);
+ bb = FF3(bb, cc, dd, aa, X[ 2], 11);
+
+ //
+ // Parallel round 3
+ //
+ aa = FF2(aa, bb, cc, dd, X[15], 9);
+ dd = FF2(dd, aa, bb, cc, X[ 5], 7);
+ cc = FF2(cc, dd, aa, bb, X[ 1], 15);
+ bb = FF2(bb, cc, dd, aa, X[ 3], 11);
+ aa = FF2(aa, bb, cc, dd, X[ 7], 8);
+ dd = FF2(dd, aa, bb, cc, X[14], 6);
+ cc = FF2(cc, dd, aa, bb, X[ 6], 6);
+ bb = FF2(bb, cc, dd, aa, X[ 9], 14);
+ aa = FF2(aa, bb, cc, dd, X[11], 12);
+ dd = FF2(dd, aa, bb, cc, X[ 8], 13);
+ cc = FF2(cc, dd, aa, bb, X[12], 5);
+ bb = FF2(bb, cc, dd, aa, X[ 2], 14);
+ aa = FF2(aa, bb, cc, dd, X[10], 13);
+ dd = FF2(dd, aa, bb, cc, X[ 0], 13);
+ cc = FF2(cc, dd, aa, bb, X[ 4], 7);
+ bb = FF2(bb, cc, dd, aa, X[13], 5);
+
+ //
+ // Parallel round 4
+ //
+ aa = FF1(aa, bb, cc, dd, X[ 8], 15);
+ dd = FF1(dd, aa, bb, cc, X[ 6], 5);
+ cc = FF1(cc, dd, aa, bb, X[ 4], 8);
+ bb = FF1(bb, cc, dd, aa, X[ 1], 11);
+ aa = FF1(aa, bb, cc, dd, X[ 3], 14);
+ dd = FF1(dd, aa, bb, cc, X[11], 14);
+ cc = FF1(cc, dd, aa, bb, X[15], 6);
+ bb = FF1(bb, cc, dd, aa, X[ 0], 14);
+ aa = FF1(aa, bb, cc, dd, X[ 5], 6);
+ dd = FF1(dd, aa, bb, cc, X[12], 9);
+ cc = FF1(cc, dd, aa, bb, X[ 2], 12);
+ bb = FF1(bb, cc, dd, aa, X[13], 9);
+ aa = FF1(aa, bb, cc, dd, X[ 9], 12);
+ dd = FF1(dd, aa, bb, cc, X[ 7], 5);
+ cc = FF1(cc, dd, aa, bb, X[10], 15);
+ bb = FF1(bb, cc, dd, aa, X[14], 8);
+
+ dd += c + H1; // final result for H0
+
+ //
+ // combine the results
+ //
+ H1 = H2 + d + aa;
+ H2 = H3 + a + bb;
+ H3 = H0 + b + cc;
+ H0 = dd;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ xOff = 0;
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ public override IMemoable Copy()
+ {
+ return new RipeMD128Digest(this);
+ }
+
+ public override void Reset(IMemoable other)
+ {
+ RipeMD128Digest d = (RipeMD128Digest)other;
+
+ CopyIn(d);
+ }
+
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/RipeMD160Digest.cs b/bc-sharp-crypto/src/crypto/digests/RipeMD160Digest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..af4aa44bb762b0ea430590e1c868fa449f322be4
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/RipeMD160Digest.cs
@@ -0,0 +1,445 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * implementation of RipeMD see,
+ * http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html
+ */
+ public class RipeMD160Digest
+ : GeneralDigest
+ {
+ private const int DigestLength = 20;
+
+ private int H0, H1, H2, H3, H4; // IV's
+
+ private int[] X = new int[16];
+ private int xOff;
+
+ /**
+ * Standard constructor
+ */
+ public RipeMD160Digest()
+ {
+ Reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public RipeMD160Digest(RipeMD160Digest t) : base(t)
+ {
+ CopyIn(t);
+ }
+
+ private void CopyIn(RipeMD160Digest t)
+ {
+ base.CopyIn(t);
+
+ H0 = t.H0;
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "RIPEMD160"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ internal override void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8)
+ | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24);
+
+ if (xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ internal override void ProcessLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ ProcessBlock();
+ }
+
+ X[14] = (int)(bitLength & 0xffffffff);
+ X[15] = (int)((ulong) bitLength >> 32);
+ }
+
+ private void UnpackWord(
+ int word,
+ byte[] outBytes,
+ int outOff)
+ {
+ outBytes[outOff] = (byte)word;
+ outBytes[outOff + 1] = (byte)((uint) word >> 8);
+ outBytes[outOff + 2] = (byte)((uint) word >> 16);
+ outBytes[outOff + 3] = (byte)((uint) word >> 24);
+ }
+
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ UnpackWord(H0, output, outOff);
+ UnpackWord(H1, output, outOff + 4);
+ UnpackWord(H2, output, outOff + 8);
+ UnpackWord(H3, output, outOff + 12);
+ UnpackWord(H4, output, outOff + 16);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /**
+ * reset the chaining variables to the IV values.
+ */
+ public override void Reset()
+ {
+ base.Reset();
+
+ H0 = unchecked((int) 0x67452301);
+ H1 = unchecked((int) 0xefcdab89);
+ H2 = unchecked((int) 0x98badcfe);
+ H3 = unchecked((int) 0x10325476);
+ H4 = unchecked((int) 0xc3d2e1f0);
+
+ xOff = 0;
+
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ /*
+ * rotate int x left n bits.
+ */
+ private int RL(
+ int x,
+ int n)
+ {
+ return (x << n) | (int) ((uint) x >> (32 - n));
+ }
+
+ /*
+ * f1,f2,f3,f4,f5 are the basic RipeMD160 functions.
+ */
+
+ /*
+ * rounds 0-15
+ */
+ private int F1(
+ int x,
+ int y,
+ int z)
+ {
+ return x ^ y ^ z;
+ }
+
+ /*
+ * rounds 16-31
+ */
+ private int F2(
+ int x,
+ int y,
+ int z)
+ {
+ return (x & y) | (~x & z);
+ }
+
+ /*
+ * rounds 32-47
+ */
+ private int F3(
+ int x,
+ int y,
+ int z)
+ {
+ return (x | ~y) ^ z;
+ }
+
+ /*
+ * rounds 48-63
+ */
+ private int F4(
+ int x,
+ int y,
+ int z)
+ {
+ return (x & z) | (y & ~z);
+ }
+
+ /*
+ * rounds 64-79
+ */
+ private int F5(
+ int x,
+ int y,
+ int z)
+ {
+ return x ^ (y | ~z);
+ }
+
+ internal override void ProcessBlock()
+ {
+ int a, aa;
+ int b, bb;
+ int c, cc;
+ int d, dd;
+ int e, ee;
+
+ a = aa = H0;
+ b = bb = H1;
+ c = cc = H2;
+ d = dd = H3;
+ e = ee = H4;
+
+ //
+ // Rounds 1 - 16
+ //
+ // left
+ a = RL(a + F1(b,c,d) + X[ 0], 11) + e; c = RL(c, 10);
+ e = RL(e + F1(a,b,c) + X[ 1], 14) + d; b = RL(b, 10);
+ d = RL(d + F1(e,a,b) + X[ 2], 15) + c; a = RL(a, 10);
+ c = RL(c + F1(d,e,a) + X[ 3], 12) + b; e = RL(e, 10);
+ b = RL(b + F1(c,d,e) + X[ 4], 5) + a; d = RL(d, 10);
+ a = RL(a + F1(b,c,d) + X[ 5], 8) + e; c = RL(c, 10);
+ e = RL(e + F1(a,b,c) + X[ 6], 7) + d; b = RL(b, 10);
+ d = RL(d + F1(e,a,b) + X[ 7], 9) + c; a = RL(a, 10);
+ c = RL(c + F1(d,e,a) + X[ 8], 11) + b; e = RL(e, 10);
+ b = RL(b + F1(c,d,e) + X[ 9], 13) + a; d = RL(d, 10);
+ a = RL(a + F1(b,c,d) + X[10], 14) + e; c = RL(c, 10);
+ e = RL(e + F1(a,b,c) + X[11], 15) + d; b = RL(b, 10);
+ d = RL(d + F1(e,a,b) + X[12], 6) + c; a = RL(a, 10);
+ c = RL(c + F1(d,e,a) + X[13], 7) + b; e = RL(e, 10);
+ b = RL(b + F1(c,d,e) + X[14], 9) + a; d = RL(d, 10);
+ a = RL(a + F1(b,c,d) + X[15], 8) + e; c = RL(c, 10);
+
+ // right
+ aa = RL(aa + F5(bb,cc,dd) + X[ 5] + unchecked((int) 0x50a28be6), 8) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F5(aa,bb,cc) + X[14] + unchecked((int) 0x50a28be6), 9) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F5(ee,aa,bb) + X[ 7] + unchecked((int) 0x50a28be6), 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F5(dd,ee,aa) + X[ 0] + unchecked((int) 0x50a28be6), 11) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F5(cc,dd,ee) + X[ 9] + unchecked((int) 0x50a28be6), 13) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F5(bb,cc,dd) + X[ 2] + unchecked((int) 0x50a28be6), 15) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F5(aa,bb,cc) + X[11] + unchecked((int) 0x50a28be6), 15) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F5(ee,aa,bb) + X[ 4] + unchecked((int) 0x50a28be6), 5) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F5(dd,ee,aa) + X[13] + unchecked((int) 0x50a28be6), 7) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F5(cc,dd,ee) + X[ 6] + unchecked((int) 0x50a28be6), 7) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F5(bb,cc,dd) + X[15] + unchecked((int) 0x50a28be6), 8) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F5(aa,bb,cc) + X[ 8] + unchecked((int) 0x50a28be6), 11) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F5(ee,aa,bb) + X[ 1] + unchecked((int) 0x50a28be6), 14) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F5(dd,ee,aa) + X[10] + unchecked((int) 0x50a28be6), 14) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F5(cc,dd,ee) + X[ 3] + unchecked((int) 0x50a28be6), 12) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F5(bb,cc,dd) + X[12] + unchecked((int) 0x50a28be6), 6) + ee; cc = RL(cc, 10);
+
+ //
+ // Rounds 16-31
+ //
+ // left
+ e = RL(e + F2(a,b,c) + X[ 7] + unchecked((int) 0x5a827999), 7) + d; b = RL(b, 10);
+ d = RL(d + F2(e,a,b) + X[ 4] + unchecked((int) 0x5a827999), 6) + c; a = RL(a, 10);
+ c = RL(c + F2(d,e,a) + X[13] + unchecked((int) 0x5a827999), 8) + b; e = RL(e, 10);
+ b = RL(b + F2(c,d,e) + X[ 1] + unchecked((int) 0x5a827999), 13) + a; d = RL(d, 10);
+ a = RL(a + F2(b,c,d) + X[10] + unchecked((int) 0x5a827999), 11) + e; c = RL(c, 10);
+ e = RL(e + F2(a,b,c) + X[ 6] + unchecked((int) 0x5a827999), 9) + d; b = RL(b, 10);
+ d = RL(d + F2(e,a,b) + X[15] + unchecked((int) 0x5a827999), 7) + c; a = RL(a, 10);
+ c = RL(c + F2(d,e,a) + X[ 3] + unchecked((int) 0x5a827999), 15) + b; e = RL(e, 10);
+ b = RL(b + F2(c,d,e) + X[12] + unchecked((int) 0x5a827999), 7) + a; d = RL(d, 10);
+ a = RL(a + F2(b,c,d) + X[ 0] + unchecked((int) 0x5a827999), 12) + e; c = RL(c, 10);
+ e = RL(e + F2(a,b,c) + X[ 9] + unchecked((int) 0x5a827999), 15) + d; b = RL(b, 10);
+ d = RL(d + F2(e,a,b) + X[ 5] + unchecked((int) 0x5a827999), 9) + c; a = RL(a, 10);
+ c = RL(c + F2(d,e,a) + X[ 2] + unchecked((int) 0x5a827999), 11) + b; e = RL(e, 10);
+ b = RL(b + F2(c,d,e) + X[14] + unchecked((int) 0x5a827999), 7) + a; d = RL(d, 10);
+ a = RL(a + F2(b,c,d) + X[11] + unchecked((int) 0x5a827999), 13) + e; c = RL(c, 10);
+ e = RL(e + F2(a,b,c) + X[ 8] + unchecked((int) 0x5a827999), 12) + d; b = RL(b, 10);
+
+ // right
+ ee = RL(ee + F4(aa,bb,cc) + X[ 6] + unchecked((int) 0x5c4dd124), 9) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F4(ee,aa,bb) + X[11] + unchecked((int) 0x5c4dd124), 13) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F4(dd,ee,aa) + X[ 3] + unchecked((int) 0x5c4dd124), 15) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F4(cc,dd,ee) + X[ 7] + unchecked((int) 0x5c4dd124), 7) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F4(bb,cc,dd) + X[ 0] + unchecked((int) 0x5c4dd124), 12) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F4(aa,bb,cc) + X[13] + unchecked((int) 0x5c4dd124), 8) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F4(ee,aa,bb) + X[ 5] + unchecked((int) 0x5c4dd124), 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F4(dd,ee,aa) + X[10] + unchecked((int) 0x5c4dd124), 11) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F4(cc,dd,ee) + X[14] + unchecked((int) 0x5c4dd124), 7) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F4(bb,cc,dd) + X[15] + unchecked((int) 0x5c4dd124), 7) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F4(aa,bb,cc) + X[ 8] + unchecked((int) 0x5c4dd124), 12) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F4(ee,aa,bb) + X[12] + unchecked((int) 0x5c4dd124), 7) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F4(dd,ee,aa) + X[ 4] + unchecked((int) 0x5c4dd124), 6) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F4(cc,dd,ee) + X[ 9] + unchecked((int) 0x5c4dd124), 15) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F4(bb,cc,dd) + X[ 1] + unchecked((int) 0x5c4dd124), 13) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F4(aa,bb,cc) + X[ 2] + unchecked((int) 0x5c4dd124), 11) + dd; bb = RL(bb, 10);
+
+ //
+ // Rounds 32-47
+ //
+ // left
+ d = RL(d + F3(e,a,b) + X[ 3] + unchecked((int) 0x6ed9eba1), 11) + c; a = RL(a, 10);
+ c = RL(c + F3(d,e,a) + X[10] + unchecked((int) 0x6ed9eba1), 13) + b; e = RL(e, 10);
+ b = RL(b + F3(c,d,e) + X[14] + unchecked((int) 0x6ed9eba1), 6) + a; d = RL(d, 10);
+ a = RL(a + F3(b,c,d) + X[ 4] + unchecked((int) 0x6ed9eba1), 7) + e; c = RL(c, 10);
+ e = RL(e + F3(a,b,c) + X[ 9] + unchecked((int) 0x6ed9eba1), 14) + d; b = RL(b, 10);
+ d = RL(d + F3(e,a,b) + X[15] + unchecked((int) 0x6ed9eba1), 9) + c; a = RL(a, 10);
+ c = RL(c + F3(d,e,a) + X[ 8] + unchecked((int) 0x6ed9eba1), 13) + b; e = RL(e, 10);
+ b = RL(b + F3(c,d,e) + X[ 1] + unchecked((int) 0x6ed9eba1), 15) + a; d = RL(d, 10);
+ a = RL(a + F3(b,c,d) + X[ 2] + unchecked((int) 0x6ed9eba1), 14) + e; c = RL(c, 10);
+ e = RL(e + F3(a,b,c) + X[ 7] + unchecked((int) 0x6ed9eba1), 8) + d; b = RL(b, 10);
+ d = RL(d + F3(e,a,b) + X[ 0] + unchecked((int) 0x6ed9eba1), 13) + c; a = RL(a, 10);
+ c = RL(c + F3(d,e,a) + X[ 6] + unchecked((int) 0x6ed9eba1), 6) + b; e = RL(e, 10);
+ b = RL(b + F3(c,d,e) + X[13] + unchecked((int) 0x6ed9eba1), 5) + a; d = RL(d, 10);
+ a = RL(a + F3(b,c,d) + X[11] + unchecked((int) 0x6ed9eba1), 12) + e; c = RL(c, 10);
+ e = RL(e + F3(a,b,c) + X[ 5] + unchecked((int) 0x6ed9eba1), 7) + d; b = RL(b, 10);
+ d = RL(d + F3(e,a,b) + X[12] + unchecked((int) 0x6ed9eba1), 5) + c; a = RL(a, 10);
+
+ // right
+ dd = RL(dd + F3(ee,aa,bb) + X[15] + unchecked((int) 0x6d703ef3), 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F3(dd,ee,aa) + X[ 5] + unchecked((int) 0x6d703ef3), 7) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F3(cc,dd,ee) + X[ 1] + unchecked((int) 0x6d703ef3), 15) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F3(bb,cc,dd) + X[ 3] + unchecked((int) 0x6d703ef3), 11) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F3(aa,bb,cc) + X[ 7] + unchecked((int) 0x6d703ef3), 8) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F3(ee,aa,bb) + X[14] + unchecked((int) 0x6d703ef3), 6) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F3(dd,ee,aa) + X[ 6] + unchecked((int) 0x6d703ef3), 6) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F3(cc,dd,ee) + X[ 9] + unchecked((int) 0x6d703ef3), 14) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F3(bb,cc,dd) + X[11] + unchecked((int) 0x6d703ef3), 12) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F3(aa,bb,cc) + X[ 8] + unchecked((int) 0x6d703ef3), 13) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F3(ee,aa,bb) + X[12] + unchecked((int) 0x6d703ef3), 5) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F3(dd,ee,aa) + X[ 2] + unchecked((int) 0x6d703ef3), 14) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F3(cc,dd,ee) + X[10] + unchecked((int) 0x6d703ef3), 13) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F3(bb,cc,dd) + X[ 0] + unchecked((int) 0x6d703ef3), 13) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F3(aa,bb,cc) + X[ 4] + unchecked((int) 0x6d703ef3), 7) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F3(ee,aa,bb) + X[13] + unchecked((int) 0x6d703ef3), 5) + cc; aa = RL(aa, 10);
+
+ //
+ // Rounds 48-63
+ //
+ // left
+ c = RL(c + F4(d,e,a) + X[ 1] + unchecked((int) 0x8f1bbcdc), 11) + b; e = RL(e, 10);
+ b = RL(b + F4(c,d,e) + X[ 9] + unchecked((int) 0x8f1bbcdc), 12) + a; d = RL(d, 10);
+ a = RL(a + F4(b,c,d) + X[11] + unchecked((int) 0x8f1bbcdc), 14) + e; c = RL(c, 10);
+ e = RL(e + F4(a,b,c) + X[10] + unchecked((int) 0x8f1bbcdc), 15) + d; b = RL(b, 10);
+ d = RL(d + F4(e,a,b) + X[ 0] + unchecked((int) 0x8f1bbcdc), 14) + c; a = RL(a, 10);
+ c = RL(c + F4(d,e,a) + X[ 8] + unchecked((int) 0x8f1bbcdc), 15) + b; e = RL(e, 10);
+ b = RL(b + F4(c,d,e) + X[12] + unchecked((int) 0x8f1bbcdc), 9) + a; d = RL(d, 10);
+ a = RL(a + F4(b,c,d) + X[ 4] + unchecked((int) 0x8f1bbcdc), 8) + e; c = RL(c, 10);
+ e = RL(e + F4(a,b,c) + X[13] + unchecked((int) 0x8f1bbcdc), 9) + d; b = RL(b, 10);
+ d = RL(d + F4(e,a,b) + X[ 3] + unchecked((int) 0x8f1bbcdc), 14) + c; a = RL(a, 10);
+ c = RL(c + F4(d,e,a) + X[ 7] + unchecked((int) 0x8f1bbcdc), 5) + b; e = RL(e, 10);
+ b = RL(b + F4(c,d,e) + X[15] + unchecked((int) 0x8f1bbcdc), 6) + a; d = RL(d, 10);
+ a = RL(a + F4(b,c,d) + X[14] + unchecked((int) 0x8f1bbcdc), 8) + e; c = RL(c, 10);
+ e = RL(e + F4(a,b,c) + X[ 5] + unchecked((int) 0x8f1bbcdc), 6) + d; b = RL(b, 10);
+ d = RL(d + F4(e,a,b) + X[ 6] + unchecked((int) 0x8f1bbcdc), 5) + c; a = RL(a, 10);
+ c = RL(c + F4(d,e,a) + X[ 2] + unchecked((int) 0x8f1bbcdc), 12) + b; e = RL(e, 10);
+
+ // right
+ cc = RL(cc + F2(dd,ee,aa) + X[ 8] + unchecked((int) 0x7a6d76e9), 15) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F2(cc,dd,ee) + X[ 6] + unchecked((int) 0x7a6d76e9), 5) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F2(bb,cc,dd) + X[ 4] + unchecked((int) 0x7a6d76e9), 8) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F2(aa,bb,cc) + X[ 1] + unchecked((int) 0x7a6d76e9), 11) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F2(ee,aa,bb) + X[ 3] + unchecked((int) 0x7a6d76e9), 14) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F2(dd,ee,aa) + X[11] + unchecked((int) 0x7a6d76e9), 14) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F2(cc,dd,ee) + X[15] + unchecked((int) 0x7a6d76e9), 6) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F2(bb,cc,dd) + X[ 0] + unchecked((int) 0x7a6d76e9), 14) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F2(aa,bb,cc) + X[ 5] + unchecked((int) 0x7a6d76e9), 6) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F2(ee,aa,bb) + X[12] + unchecked((int) 0x7a6d76e9), 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F2(dd,ee,aa) + X[ 2] + unchecked((int) 0x7a6d76e9), 12) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F2(cc,dd,ee) + X[13] + unchecked((int) 0x7a6d76e9), 9) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F2(bb,cc,dd) + X[ 9] + unchecked((int) 0x7a6d76e9), 12) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F2(aa,bb,cc) + X[ 7] + unchecked((int) 0x7a6d76e9), 5) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F2(ee,aa,bb) + X[10] + unchecked((int) 0x7a6d76e9), 15) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F2(dd,ee,aa) + X[14] + unchecked((int) 0x7a6d76e9), 8) + bb; ee = RL(ee, 10);
+
+ //
+ // Rounds 64-79
+ //
+ // left
+ b = RL(b + F5(c,d,e) + X[ 4] + unchecked((int) 0xa953fd4e), 9) + a; d = RL(d, 10);
+ a = RL(a + F5(b,c,d) + X[ 0] + unchecked((int) 0xa953fd4e), 15) + e; c = RL(c, 10);
+ e = RL(e + F5(a,b,c) + X[ 5] + unchecked((int) 0xa953fd4e), 5) + d; b = RL(b, 10);
+ d = RL(d + F5(e,a,b) + X[ 9] + unchecked((int) 0xa953fd4e), 11) + c; a = RL(a, 10);
+ c = RL(c + F5(d,e,a) + X[ 7] + unchecked((int) 0xa953fd4e), 6) + b; e = RL(e, 10);
+ b = RL(b + F5(c,d,e) + X[12] + unchecked((int) 0xa953fd4e), 8) + a; d = RL(d, 10);
+ a = RL(a + F5(b,c,d) + X[ 2] + unchecked((int) 0xa953fd4e), 13) + e; c = RL(c, 10);
+ e = RL(e + F5(a,b,c) + X[10] + unchecked((int) 0xa953fd4e), 12) + d; b = RL(b, 10);
+ d = RL(d + F5(e,a,b) + X[14] + unchecked((int) 0xa953fd4e), 5) + c; a = RL(a, 10);
+ c = RL(c + F5(d,e,a) + X[ 1] + unchecked((int) 0xa953fd4e), 12) + b; e = RL(e, 10);
+ b = RL(b + F5(c,d,e) + X[ 3] + unchecked((int) 0xa953fd4e), 13) + a; d = RL(d, 10);
+ a = RL(a + F5(b,c,d) + X[ 8] + unchecked((int) 0xa953fd4e), 14) + e; c = RL(c, 10);
+ e = RL(e + F5(a,b,c) + X[11] + unchecked((int) 0xa953fd4e), 11) + d; b = RL(b, 10);
+ d = RL(d + F5(e,a,b) + X[ 6] + unchecked((int) 0xa953fd4e), 8) + c; a = RL(a, 10);
+ c = RL(c + F5(d,e,a) + X[15] + unchecked((int) 0xa953fd4e), 5) + b; e = RL(e, 10);
+ b = RL(b + F5(c,d,e) + X[13] + unchecked((int) 0xa953fd4e), 6) + a; d = RL(d, 10);
+
+ // right
+ bb = RL(bb + F1(cc,dd,ee) + X[12], 8) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F1(bb,cc,dd) + X[15], 5) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F1(aa,bb,cc) + X[10], 12) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F1(ee,aa,bb) + X[ 4], 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F1(dd,ee,aa) + X[ 1], 12) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F1(cc,dd,ee) + X[ 5], 5) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F1(bb,cc,dd) + X[ 8], 14) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F1(aa,bb,cc) + X[ 7], 6) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F1(ee,aa,bb) + X[ 6], 8) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F1(dd,ee,aa) + X[ 2], 13) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F1(cc,dd,ee) + X[13], 6) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F1(bb,cc,dd) + X[14], 5) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F1(aa,bb,cc) + X[ 0], 15) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F1(ee,aa,bb) + X[ 3], 13) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F1(dd,ee,aa) + X[ 9], 11) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F1(cc,dd,ee) + X[11], 11) + aa; dd = RL(dd, 10);
+
+ dd += c + H1;
+ H1 = H2 + d + ee;
+ H2 = H3 + e + aa;
+ H3 = H4 + a + bb;
+ H4 = H0 + b + cc;
+ H0 = dd;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ xOff = 0;
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ public override IMemoable Copy()
+ {
+ return new RipeMD160Digest(this);
+ }
+
+ public override void Reset(IMemoable other)
+ {
+ RipeMD160Digest d = (RipeMD160Digest)other;
+
+ CopyIn(d);
+ }
+
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/RipeMD256Digest.cs b/bc-sharp-crypto/src/crypto/digests/RipeMD256Digest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..306275767d2efd1502f587619bd628800bf899b3
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/RipeMD256Digest.cs
@@ -0,0 +1,430 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ ///
+ /// Implementation of RipeMD256.
+ /// Note: this algorithm offers the same level of security as RipeMD128.
+ ///
+ public class RipeMD256Digest
+ : GeneralDigest
+ {
+ public override string AlgorithmName
+ {
+ get { return "RIPEMD256"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ private const int DigestLength = 32;
+
+ private int H0, H1, H2, H3, H4, H5, H6, H7; // IV's
+
+ private int[] X = new int[16];
+ private int xOff;
+
+ /// Standard constructor
+ public RipeMD256Digest()
+ {
+ Reset();
+ }
+
+ /// Copy constructor. This will copy the state of the provided
+ /// message digest.
+ ///
+ public RipeMD256Digest(RipeMD256Digest t):base(t)
+ {
+ CopyIn(t);
+ }
+
+ private void CopyIn(RipeMD256Digest t)
+ {
+ base.CopyIn(t);
+
+ H0 = t.H0;
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+ H5 = t.H5;
+ H6 = t.H6;
+ H7 = t.H7;
+
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ }
+
+ internal override void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8)
+ | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24);
+
+ if (xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ internal override void ProcessLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ ProcessBlock();
+ }
+
+ X[14] = (int)(bitLength & 0xffffffff);
+ X[15] = (int)((ulong)bitLength >> 32);
+ }
+
+ private void UnpackWord(
+ int word,
+ byte[] outBytes,
+ int outOff)
+ {
+ outBytes[outOff] = (byte)(uint)word;
+ outBytes[outOff + 1] = (byte)((uint)word >> 8);
+ outBytes[outOff + 2] = (byte)((uint)word >> 16);
+ outBytes[outOff + 3] = (byte)((uint)word >> 24);
+ }
+
+ public override int DoFinal(byte[] output, int outOff)
+ {
+ Finish();
+
+ UnpackWord(H0, output, outOff);
+ UnpackWord(H1, output, outOff + 4);
+ UnpackWord(H2, output, outOff + 8);
+ UnpackWord(H3, output, outOff + 12);
+ UnpackWord(H4, output, outOff + 16);
+ UnpackWord(H5, output, outOff + 20);
+ UnpackWord(H6, output, outOff + 24);
+ UnpackWord(H7, output, outOff + 28);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /// reset the chaining variables to the IV values.
+ public override void Reset()
+ {
+ base.Reset();
+
+ H0 = unchecked((int)0x67452301);
+ H1 = unchecked((int)0xefcdab89);
+ H2 = unchecked((int)0x98badcfe);
+ H3 = unchecked((int)0x10325476);
+ H4 = unchecked((int)0x76543210);
+ H5 = unchecked((int)0xFEDCBA98);
+ H6 = unchecked((int)0x89ABCDEF);
+ H7 = unchecked((int)0x01234567);
+
+ xOff = 0;
+
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ /*
+ * rotate int x left n bits.
+ */
+ private int RL(
+ int x,
+ int n)
+ {
+ return (x << n) | (int)((uint)x >> (32 - n));
+ }
+
+ /*
+ * f1,f2,f3,f4 are the basic RipeMD128 functions.
+ */
+
+ /*
+ * F
+ */
+ private int F1(int x, int y, int z)
+ {
+ return x ^ y ^ z;
+ }
+
+ /*
+ * G
+ */
+ private int F2(int x, int y, int z)
+ {
+ return (x & y) | (~ x & z);
+ }
+
+ /*
+ * H
+ */
+ private int F3(int x, int y, int z)
+ {
+ return (x | ~ y) ^ z;
+ }
+
+ /*
+ * I
+ */
+ private int F4(int x, int y, int z)
+ {
+ return (x & z) | (y & ~ z);
+ }
+
+ private int F1(int a, int b, int c, int d, int x, int s)
+ {
+ return RL(a + F1(b, c, d) + x, s);
+ }
+
+ private int F2(int a, int b, int c, int d, int x, int s)
+ {
+ return RL(a + F2(b, c, d) + x + unchecked((int)0x5a827999), s);
+ }
+
+ private int F3(int a, int b, int c, int d, int x, int s)
+ {
+ return RL(a + F3(b, c, d) + x + unchecked((int)0x6ed9eba1), s);
+ }
+
+ private int F4(int a, int b, int c, int d, int x, int s)
+ {
+ return RL(a + F4(b, c, d) + x + unchecked((int)0x8f1bbcdc), s);
+ }
+
+ private int FF1(int a, int b, int c, int d, int x, int s)
+ {
+ return RL(a + F1(b, c, d) + x, s);
+ }
+
+ private int FF2(int a, int b, int c, int d, int x, int s)
+ {
+ return RL(a + F2(b, c, d) + x + unchecked((int)0x6d703ef3), s);
+ }
+
+ private int FF3(int a, int b, int c, int d, int x, int s)
+ {
+ return RL(a + F3(b, c, d) + x + unchecked((int)0x5c4dd124), s);
+ }
+
+ private int FF4(int a, int b, int c, int d, int x, int s)
+ {
+ return RL(a + F4(b, c, d) + x + unchecked((int)0x50a28be6), s);
+ }
+
+ internal override void ProcessBlock()
+ {
+ int a, aa;
+ int b, bb;
+ int c, cc;
+ int d, dd;
+ int t;
+
+ a = H0;
+ b = H1;
+ c = H2;
+ d = H3;
+ aa = H4;
+ bb = H5;
+ cc = H6;
+ dd = H7;
+
+ //
+ // Round 1
+ //
+
+ a = F1(a, b, c, d, X[0], 11);
+ d = F1(d, a, b, c, X[1], 14);
+ c = F1(c, d, a, b, X[2], 15);
+ b = F1(b, c, d, a, X[3], 12);
+ a = F1(a, b, c, d, X[4], 5);
+ d = F1(d, a, b, c, X[5], 8);
+ c = F1(c, d, a, b, X[6], 7);
+ b = F1(b, c, d, a, X[7], 9);
+ a = F1(a, b, c, d, X[8], 11);
+ d = F1(d, a, b, c, X[9], 13);
+ c = F1(c, d, a, b, X[10], 14);
+ b = F1(b, c, d, a, X[11], 15);
+ a = F1(a, b, c, d, X[12], 6);
+ d = F1(d, a, b, c, X[13], 7);
+ c = F1(c, d, a, b, X[14], 9);
+ b = F1(b, c, d, a, X[15], 8);
+
+ aa = FF4(aa, bb, cc, dd, X[5], 8);
+ dd = FF4(dd, aa, bb, cc, X[14], 9);
+ cc = FF4(cc, dd, aa, bb, X[7], 9);
+ bb = FF4(bb, cc, dd, aa, X[0], 11);
+ aa = FF4(aa, bb, cc, dd, X[9], 13);
+ dd = FF4(dd, aa, bb, cc, X[2], 15);
+ cc = FF4(cc, dd, aa, bb, X[11], 15);
+ bb = FF4(bb, cc, dd, aa, X[4], 5);
+ aa = FF4(aa, bb, cc, dd, X[13], 7);
+ dd = FF4(dd, aa, bb, cc, X[6], 7);
+ cc = FF4(cc, dd, aa, bb, X[15], 8);
+ bb = FF4(bb, cc, dd, aa, X[8], 11);
+ aa = FF4(aa, bb, cc, dd, X[1], 14);
+ dd = FF4(dd, aa, bb, cc, X[10], 14);
+ cc = FF4(cc, dd, aa, bb, X[3], 12);
+ bb = FF4(bb, cc, dd, aa, X[12], 6);
+
+ t = a; a = aa; aa = t;
+
+ //
+ // Round 2
+ //
+ a = F2(a, b, c, d, X[7], 7);
+ d = F2(d, a, b, c, X[4], 6);
+ c = F2(c, d, a, b, X[13], 8);
+ b = F2(b, c, d, a, X[1], 13);
+ a = F2(a, b, c, d, X[10], 11);
+ d = F2(d, a, b, c, X[6], 9);
+ c = F2(c, d, a, b, X[15], 7);
+ b = F2(b, c, d, a, X[3], 15);
+ a = F2(a, b, c, d, X[12], 7);
+ d = F2(d, a, b, c, X[0], 12);
+ c = F2(c, d, a, b, X[9], 15);
+ b = F2(b, c, d, a, X[5], 9);
+ a = F2(a, b, c, d, X[2], 11);
+ d = F2(d, a, b, c, X[14], 7);
+ c = F2(c, d, a, b, X[11], 13);
+ b = F2(b, c, d, a, X[8], 12);
+
+ aa = FF3(aa, bb, cc, dd, X[6], 9);
+ dd = FF3(dd, aa, bb, cc, X[11], 13);
+ cc = FF3(cc, dd, aa, bb, X[3], 15);
+ bb = FF3(bb, cc, dd, aa, X[7], 7);
+ aa = FF3(aa, bb, cc, dd, X[0], 12);
+ dd = FF3(dd, aa, bb, cc, X[13], 8);
+ cc = FF3(cc, dd, aa, bb, X[5], 9);
+ bb = FF3(bb, cc, dd, aa, X[10], 11);
+ aa = FF3(aa, bb, cc, dd, X[14], 7);
+ dd = FF3(dd, aa, bb, cc, X[15], 7);
+ cc = FF3(cc, dd, aa, bb, X[8], 12);
+ bb = FF3(bb, cc, dd, aa, X[12], 7);
+ aa = FF3(aa, bb, cc, dd, X[4], 6);
+ dd = FF3(dd, aa, bb, cc, X[9], 15);
+ cc = FF3(cc, dd, aa, bb, X[1], 13);
+ bb = FF3(bb, cc, dd, aa, X[2], 11);
+
+ t = b; b = bb; bb = t;
+
+ //
+ // Round 3
+ //
+ a = F3(a, b, c, d, X[3], 11);
+ d = F3(d, a, b, c, X[10], 13);
+ c = F3(c, d, a, b, X[14], 6);
+ b = F3(b, c, d, a, X[4], 7);
+ a = F3(a, b, c, d, X[9], 14);
+ d = F3(d, a, b, c, X[15], 9);
+ c = F3(c, d, a, b, X[8], 13);
+ b = F3(b, c, d, a, X[1], 15);
+ a = F3(a, b, c, d, X[2], 14);
+ d = F3(d, a, b, c, X[7], 8);
+ c = F3(c, d, a, b, X[0], 13);
+ b = F3(b, c, d, a, X[6], 6);
+ a = F3(a, b, c, d, X[13], 5);
+ d = F3(d, a, b, c, X[11], 12);
+ c = F3(c, d, a, b, X[5], 7);
+ b = F3(b, c, d, a, X[12], 5);
+
+ aa = FF2(aa, bb, cc, dd, X[15], 9);
+ dd = FF2(dd, aa, bb, cc, X[5], 7);
+ cc = FF2(cc, dd, aa, bb, X[1], 15);
+ bb = FF2(bb, cc, dd, aa, X[3], 11);
+ aa = FF2(aa, bb, cc, dd, X[7], 8);
+ dd = FF2(dd, aa, bb, cc, X[14], 6);
+ cc = FF2(cc, dd, aa, bb, X[6], 6);
+ bb = FF2(bb, cc, dd, aa, X[9], 14);
+ aa = FF2(aa, bb, cc, dd, X[11], 12);
+ dd = FF2(dd, aa, bb, cc, X[8], 13);
+ cc = FF2(cc, dd, aa, bb, X[12], 5);
+ bb = FF2(bb, cc, dd, aa, X[2], 14);
+ aa = FF2(aa, bb, cc, dd, X[10], 13);
+ dd = FF2(dd, aa, bb, cc, X[0], 13);
+ cc = FF2(cc, dd, aa, bb, X[4], 7);
+ bb = FF2(bb, cc, dd, aa, X[13], 5);
+
+ t = c; c = cc; cc = t;
+
+ //
+ // Round 4
+ //
+ a = F4(a, b, c, d, X[1], 11);
+ d = F4(d, a, b, c, X[9], 12);
+ c = F4(c, d, a, b, X[11], 14);
+ b = F4(b, c, d, a, X[10], 15);
+ a = F4(a, b, c, d, X[0], 14);
+ d = F4(d, a, b, c, X[8], 15);
+ c = F4(c, d, a, b, X[12], 9);
+ b = F4(b, c, d, a, X[4], 8);
+ a = F4(a, b, c, d, X[13], 9);
+ d = F4(d, a, b, c, X[3], 14);
+ c = F4(c, d, a, b, X[7], 5);
+ b = F4(b, c, d, a, X[15], 6);
+ a = F4(a, b, c, d, X[14], 8);
+ d = F4(d, a, b, c, X[5], 6);
+ c = F4(c, d, a, b, X[6], 5);
+ b = F4(b, c, d, a, X[2], 12);
+
+ aa = FF1(aa, bb, cc, dd, X[8], 15);
+ dd = FF1(dd, aa, bb, cc, X[6], 5);
+ cc = FF1(cc, dd, aa, bb, X[4], 8);
+ bb = FF1(bb, cc, dd, aa, X[1], 11);
+ aa = FF1(aa, bb, cc, dd, X[3], 14);
+ dd = FF1(dd, aa, bb, cc, X[11], 14);
+ cc = FF1(cc, dd, aa, bb, X[15], 6);
+ bb = FF1(bb, cc, dd, aa, X[0], 14);
+ aa = FF1(aa, bb, cc, dd, X[5], 6);
+ dd = FF1(dd, aa, bb, cc, X[12], 9);
+ cc = FF1(cc, dd, aa, bb, X[2], 12);
+ bb = FF1(bb, cc, dd, aa, X[13], 9);
+ aa = FF1(aa, bb, cc, dd, X[9], 12);
+ dd = FF1(dd, aa, bb, cc, X[7], 5);
+ cc = FF1(cc, dd, aa, bb, X[10], 15);
+ bb = FF1(bb, cc, dd, aa, X[14], 8);
+
+ t = d; d = dd; dd = t;
+
+ H0 += a;
+ H1 += b;
+ H2 += c;
+ H3 += d;
+ H4 += aa;
+ H5 += bb;
+ H6 += cc;
+ H7 += dd;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ xOff = 0;
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ public override IMemoable Copy()
+ {
+ return new RipeMD256Digest(this);
+ }
+
+ public override void Reset(IMemoable other)
+ {
+ RipeMD256Digest d = (RipeMD256Digest)other;
+
+ CopyIn(d);
+ }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/RipeMD320Digest.cs b/bc-sharp-crypto/src/crypto/digests/RipeMD320Digest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..767d74dba16208b88b3857eaeee51b01086dd649
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/RipeMD320Digest.cs
@@ -0,0 +1,459 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ ///
+ /// Implementation of RipeMD 320.
+ /// Note: this algorithm offers the same level of security as RipeMD160.
+ ///
+ public class RipeMD320Digest
+ : GeneralDigest
+ {
+ public override string AlgorithmName
+ {
+ get { return "RIPEMD320"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ private const int DigestLength = 40;
+
+ private int H0, H1, H2, H3, H4, H5, H6, H7, H8, H9; // IV's
+
+ private int[] X = new int[16];
+ private int xOff;
+
+ /// Standard constructor
+ public RipeMD320Digest()
+ {
+ Reset();
+ }
+
+ /// Copy constructor. This will copy the state of the provided
+ /// message digest.
+ ///
+ public RipeMD320Digest(RipeMD320Digest t)
+ : base(t)
+ {
+ CopyIn(t);
+ }
+
+ private void CopyIn(RipeMD320Digest t)
+ {
+ base.CopyIn(t);
+
+ H0 = t.H0;
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+ H5 = t.H5;
+ H6 = t.H6;
+ H7 = t.H7;
+ H8 = t.H8;
+ H9 = t.H9;
+
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ }
+
+ internal override void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8)
+ | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24);
+
+ if (xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ internal override void ProcessLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ ProcessBlock();
+ }
+
+ X[14] = (int)(bitLength & 0xffffffff);
+ X[15] = (int)((ulong)bitLength >> 32);
+ }
+
+ private void UnpackWord(
+ int word,
+ byte[] outBytes,
+ int outOff)
+ {
+ outBytes[outOff] = (byte)word;
+ outBytes[outOff + 1] = (byte)((uint)word >> 8);
+ outBytes[outOff + 2] = (byte)((uint)word >> 16);
+ outBytes[outOff + 3] = (byte)((uint)word >> 24);
+ }
+
+ public override int DoFinal(byte[] output, int outOff)
+ {
+ Finish();
+
+ UnpackWord(H0, output, outOff);
+ UnpackWord(H1, output, outOff + 4);
+ UnpackWord(H2, output, outOff + 8);
+ UnpackWord(H3, output, outOff + 12);
+ UnpackWord(H4, output, outOff + 16);
+ UnpackWord(H5, output, outOff + 20);
+ UnpackWord(H6, output, outOff + 24);
+ UnpackWord(H7, output, outOff + 28);
+ UnpackWord(H8, output, outOff + 32);
+ UnpackWord(H9, output, outOff + 36);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /// reset the chaining variables to the IV values.
+ public override void Reset()
+ {
+ base.Reset();
+
+ H0 = unchecked((int) 0x67452301);
+ H1 = unchecked((int) 0xefcdab89);
+ H2 = unchecked((int) 0x98badcfe);
+ H3 = unchecked((int) 0x10325476);
+ H4 = unchecked((int) 0xc3d2e1f0);
+ H5 = unchecked((int) 0x76543210);
+ H6 = unchecked((int) 0xFEDCBA98);
+ H7 = unchecked((int) 0x89ABCDEF);
+ H8 = unchecked((int) 0x01234567);
+ H9 = unchecked((int) 0x3C2D1E0F);
+
+ xOff = 0;
+
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ /*
+ * rotate int x left n bits.
+ */
+ private int RL(
+ int x,
+ int n)
+ {
+ return (x << n) | (int)(((uint)x) >> (32 - n));
+ }
+
+ /*
+ * f1,f2,f3,f4,f5 are the basic RipeMD160 functions.
+ */
+
+ /*
+ * rounds 0-15
+ */
+ private int F1(int x, int y, int z)
+ {
+ return x ^ y ^ z;
+ }
+
+ /*
+ * rounds 16-31
+ */
+ private int F2(int x, int y, int z)
+ {
+ return (x & y) | (~ x & z);
+ }
+
+ /*
+ * rounds 32-47
+ */
+ private int F3(int x, int y, int z)
+ {
+ return (x | ~ y) ^ z;
+ }
+
+ /*
+ * rounds 48-63
+ */
+ private int F4(int x, int y, int z)
+ {
+ return (x & z) | (y & ~ z);
+ }
+
+ /*
+ * rounds 64-79
+ */
+ private int F5(int x, int y, int z)
+ {
+ return x ^ (y | ~z);
+ }
+
+ internal override void ProcessBlock()
+ {
+ int a, aa;
+ int b, bb;
+ int c, cc;
+ int d, dd;
+ int e, ee;
+ int t;
+
+ a = H0;
+ b = H1;
+ c = H2;
+ d = H3;
+ e = H4;
+ aa = H5;
+ bb = H6;
+ cc = H7;
+ dd = H8;
+ ee = H9;
+
+ //
+ // Rounds 1 - 16
+ //
+ // left
+ a = RL(a + F1(b, c, d) + X[0], 11) + e; c = RL(c, 10);
+ e = RL(e + F1(a, b, c) + X[1], 14) + d; b = RL(b, 10);
+ d = RL(d + F1(e, a, b) + X[2], 15) + c; a = RL(a, 10);
+ c = RL(c + F1(d, e, a) + X[3], 12) + b; e = RL(e, 10);
+ b = RL(b + F1(c, d, e) + X[4], 5) + a; d = RL(d, 10);
+ a = RL(a + F1(b, c, d) + X[5], 8) + e; c = RL(c, 10);
+ e = RL(e + F1(a, b, c) + X[6], 7) + d; b = RL(b, 10);
+ d = RL(d + F1(e, a, b) + X[7], 9) + c; a = RL(a, 10);
+ c = RL(c + F1(d, e, a) + X[8], 11) + b; e = RL(e, 10);
+ b = RL(b + F1(c, d, e) + X[9], 13) + a; d = RL(d, 10);
+ a = RL(a + F1(b, c, d) + X[10], 14) + e; c = RL(c, 10);
+ e = RL(e + F1(a, b, c) + X[11], 15) + d; b = RL(b, 10);
+ d = RL(d + F1(e, a, b) + X[12], 6) + c; a = RL(a, 10);
+ c = RL(c + F1(d, e, a) + X[13], 7) + b; e = RL(e, 10);
+ b = RL(b + F1(c, d, e) + X[14], 9) + a; d = RL(d, 10);
+ a = RL(a + F1(b, c, d) + X[15], 8) + e; c = RL(c, 10);
+
+ // right
+ aa = RL(aa + F5(bb, cc, dd) + X[5] + unchecked((int)0x50a28be6), 8) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F5(aa, bb, cc) + X[14] + unchecked((int)0x50a28be6), 9) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F5(ee, aa, bb) + X[7] + unchecked((int)0x50a28be6), 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F5(dd, ee, aa) + X[0] + unchecked((int)0x50a28be6), 11) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F5(cc, dd, ee) + X[9] + unchecked((int)0x50a28be6), 13) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F5(bb, cc, dd) + X[2] + unchecked((int)0x50a28be6), 15) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F5(aa, bb, cc) + X[11] + unchecked((int)0x50a28be6), 15) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F5(ee, aa, bb) + X[4] + unchecked((int)0x50a28be6), 5) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F5(dd, ee, aa) + X[13] + unchecked((int)0x50a28be6), 7) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F5(cc, dd, ee) + X[6] + unchecked((int)0x50a28be6), 7) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F5(bb, cc, dd) + X[15] + unchecked((int)0x50a28be6), 8) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F5(aa, bb, cc) + X[8] + unchecked((int)0x50a28be6), 11) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F5(ee, aa, bb) + X[1] + unchecked((int)0x50a28be6), 14) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F5(dd, ee, aa) + X[10] + unchecked((int)0x50a28be6), 14) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F5(cc, dd, ee) + X[3] + unchecked((int)0x50a28be6), 12) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F5(bb, cc, dd) + X[12] + unchecked((int)0x50a28be6), 6) + ee; cc = RL(cc, 10);
+
+ t = a; a = aa; aa = t;
+ //
+ // Rounds 16-31
+ //
+ // left
+ e = RL(e + F2(a, b, c) + X[7] + unchecked((int)0x5a827999), 7) + d; b = RL(b, 10);
+ d = RL(d + F2(e, a, b) + X[4] + unchecked((int)0x5a827999), 6) + c; a = RL(a, 10);
+ c = RL(c + F2(d, e, a) + X[13] + unchecked((int)0x5a827999), 8) + b; e = RL(e, 10);
+ b = RL(b + F2(c, d, e) + X[1] + unchecked((int)0x5a827999), 13) + a; d = RL(d, 10);
+ a = RL(a + F2(b, c, d) + X[10] + unchecked((int)0x5a827999), 11) + e; c = RL(c, 10);
+ e = RL(e + F2(a, b, c) + X[6] + unchecked((int)0x5a827999), 9) + d; b = RL(b, 10);
+ d = RL(d + F2(e, a, b) + X[15] + unchecked((int)0x5a827999), 7) + c; a = RL(a, 10);
+ c = RL(c + F2(d, e, a) + X[3] + unchecked((int)0x5a827999), 15) + b; e = RL(e, 10);
+ b = RL(b + F2(c, d, e) + X[12] + unchecked((int)0x5a827999), 7) + a; d = RL(d, 10);
+ a = RL(a + F2(b, c, d) + X[0] + unchecked((int)0x5a827999), 12) + e; c = RL(c, 10);
+ e = RL(e + F2(a, b, c) + X[9] + unchecked((int)0x5a827999), 15) + d; b = RL(b, 10);
+ d = RL(d + F2(e, a, b) + X[5] + unchecked((int)0x5a827999), 9) + c; a = RL(a, 10);
+ c = RL(c + F2(d, e, a) + X[2] + unchecked((int)0x5a827999), 11) + b; e = RL(e, 10);
+ b = RL(b + F2(c, d, e) + X[14] + unchecked((int)0x5a827999), 7) + a; d = RL(d, 10);
+ a = RL(a + F2(b, c, d) + X[11] + unchecked((int)0x5a827999), 13) + e; c = RL(c, 10);
+ e = RL(e + F2(a, b, c) + X[8] + unchecked((int)0x5a827999), 12) + d; b = RL(b, 10);
+
+ // right
+ ee = RL(ee + F4(aa, bb, cc) + X[6] + unchecked((int)0x5c4dd124), 9) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F4(ee, aa, bb) + X[11] + unchecked((int)0x5c4dd124), 13) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F4(dd, ee, aa) + X[3] + unchecked((int)0x5c4dd124), 15) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F4(cc, dd, ee) + X[7] + unchecked((int)0x5c4dd124), 7) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F4(bb, cc, dd) + X[0] + unchecked((int)0x5c4dd124), 12) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F4(aa, bb, cc) + X[13] + unchecked((int)0x5c4dd124), 8) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F4(ee, aa, bb) + X[5] + unchecked((int)0x5c4dd124), 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F4(dd, ee, aa) + X[10] + unchecked((int)0x5c4dd124), 11) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F4(cc, dd, ee) + X[14] + unchecked((int)0x5c4dd124), 7) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F4(bb, cc, dd) + X[15] + unchecked((int)0x5c4dd124), 7) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F4(aa, bb, cc) + X[8] + unchecked((int)0x5c4dd124), 12) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F4(ee, aa, bb) + X[12] + unchecked((int)0x5c4dd124), 7) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F4(dd, ee, aa) + X[4] + unchecked((int)0x5c4dd124), 6) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F4(cc, dd, ee) + X[9] + unchecked((int)0x5c4dd124), 15) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F4(bb, cc, dd) + X[1] + unchecked((int)0x5c4dd124), 13) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F4(aa, bb, cc) + X[2] + unchecked((int)0x5c4dd124), 11) + dd; bb = RL(bb, 10);
+
+ t = b; b = bb; bb = t;
+
+ //
+ // Rounds 32-47
+ //
+ // left
+ d = RL(d + F3(e, a, b) + X[3] + unchecked((int)0x6ed9eba1), 11) + c; a = RL(a, 10);
+ c = RL(c + F3(d, e, a) + X[10] + unchecked((int)0x6ed9eba1), 13) + b; e = RL(e, 10);
+ b = RL(b + F3(c, d, e) + X[14] + unchecked((int)0x6ed9eba1), 6) + a; d = RL(d, 10);
+ a = RL(a + F3(b, c, d) + X[4] + unchecked((int)0x6ed9eba1), 7) + e; c = RL(c, 10);
+ e = RL(e + F3(a, b, c) + X[9] + unchecked((int)0x6ed9eba1), 14) + d; b = RL(b, 10);
+ d = RL(d + F3(e, a, b) + X[15] + unchecked((int)0x6ed9eba1), 9) + c; a = RL(a, 10);
+ c = RL(c + F3(d, e, a) + X[8] + unchecked((int)0x6ed9eba1), 13) + b; e = RL(e, 10);
+ b = RL(b + F3(c, d, e) + X[1] + unchecked((int)0x6ed9eba1), 15) + a; d = RL(d, 10);
+ a = RL(a + F3(b, c, d) + X[2] + unchecked((int)0x6ed9eba1), 14) + e; c = RL(c, 10);
+ e = RL(e + F3(a, b, c) + X[7] + unchecked((int)0x6ed9eba1), 8) + d; b = RL(b, 10);
+ d = RL(d + F3(e, a, b) + X[0] + unchecked((int)0x6ed9eba1), 13) + c; a = RL(a, 10);
+ c = RL(c + F3(d, e, a) + X[6] + unchecked((int)0x6ed9eba1), 6) + b; e = RL(e, 10);
+ b = RL(b + F3(c, d, e) + X[13] + unchecked((int)0x6ed9eba1), 5) + a; d = RL(d, 10);
+ a = RL(a + F3(b, c, d) + X[11] + unchecked((int)0x6ed9eba1), 12) + e; c = RL(c, 10);
+ e = RL(e + F3(a, b, c) + X[5] + unchecked((int)0x6ed9eba1), 7) + d; b = RL(b, 10);
+ d = RL(d + F3(e, a, b) + X[12] + unchecked((int)0x6ed9eba1), 5) + c; a = RL(a, 10);
+
+ // right
+ dd = RL(dd + F3(ee, aa, bb) + X[15] + unchecked((int)0x6d703ef3), 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F3(dd, ee, aa) + X[5] + unchecked((int)0x6d703ef3), 7) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F3(cc, dd, ee) + X[1] + unchecked((int)0x6d703ef3), 15) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F3(bb, cc, dd) + X[3] + unchecked((int)0x6d703ef3), 11) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F3(aa, bb, cc) + X[7] + unchecked((int)0x6d703ef3), 8) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F3(ee, aa, bb) + X[14] + unchecked((int)0x6d703ef3), 6) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F3(dd, ee, aa) + X[6] + unchecked((int)0x6d703ef3), 6) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F3(cc, dd, ee) + X[9] + unchecked((int)0x6d703ef3), 14) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F3(bb, cc, dd) + X[11] + unchecked((int)0x6d703ef3), 12) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F3(aa, bb, cc) + X[8] + unchecked((int)0x6d703ef3), 13) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F3(ee, aa, bb) + X[12] + unchecked((int)0x6d703ef3), 5) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F3(dd, ee, aa) + X[2] + unchecked((int)0x6d703ef3), 14) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F3(cc, dd, ee) + X[10] + unchecked((int)0x6d703ef3), 13) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F3(bb, cc, dd) + X[0] + unchecked((int)0x6d703ef3), 13) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F3(aa, bb, cc) + X[4] + unchecked((int)0x6d703ef3), 7) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F3(ee, aa, bb) + X[13] + unchecked((int)0x6d703ef3), 5) + cc; aa = RL(aa, 10);
+
+ t = c; c = cc; cc = t;
+
+ //
+ // Rounds 48-63
+ //
+ // left
+ c = RL(c + F4(d, e, a) + X[1] + unchecked((int)0x8f1bbcdc), 11) + b; e = RL(e, 10);
+ b = RL(b + F4(c, d, e) + X[9] + unchecked((int)0x8f1bbcdc), 12) + a; d = RL(d, 10);
+ a = RL(a + F4(b, c, d) + X[11] + unchecked((int)0x8f1bbcdc), 14) + e; c = RL(c, 10);
+ e = RL(e + F4(a, b, c) + X[10] + unchecked((int)0x8f1bbcdc), 15) + d; b = RL(b, 10);
+ d = RL(d + F4(e, a, b) + X[0] + unchecked((int)0x8f1bbcdc), 14) + c; a = RL(a, 10);
+ c = RL(c + F4(d, e, a) + X[8] + unchecked((int)0x8f1bbcdc), 15) + b; e = RL(e, 10);
+ b = RL(b + F4(c, d, e) + X[12] + unchecked((int)0x8f1bbcdc), 9) + a; d = RL(d, 10);
+ a = RL(a + F4(b, c, d) + X[4] + unchecked((int)0x8f1bbcdc), 8) + e; c = RL(c, 10);
+ e = RL(e + F4(a, b, c) + X[13] + unchecked((int)0x8f1bbcdc), 9) + d; b = RL(b, 10);
+ d = RL(d + F4(e, a, b) + X[3] + unchecked((int)0x8f1bbcdc), 14) + c; a = RL(a, 10);
+ c = RL(c + F4(d, e, a) + X[7] + unchecked((int)0x8f1bbcdc), 5) + b; e = RL(e, 10);
+ b = RL(b + F4(c, d, e) + X[15] + unchecked((int)0x8f1bbcdc), 6) + a; d = RL(d, 10);
+ a = RL(a + F4(b, c, d) + X[14] + unchecked((int)0x8f1bbcdc), 8) + e; c = RL(c, 10);
+ e = RL(e + F4(a, b, c) + X[5] + unchecked((int)0x8f1bbcdc), 6) + d; b = RL(b, 10);
+ d = RL(d + F4(e, a, b) + X[6] + unchecked((int)0x8f1bbcdc), 5) + c; a = RL(a, 10);
+ c = RL(c + F4(d, e, a) + X[2] + unchecked((int)0x8f1bbcdc), 12) + b; e = RL(e, 10);
+
+ // right
+ cc = RL(cc + F2(dd, ee, aa) + X[8] + unchecked((int)0x7a6d76e9), 15) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F2(cc, dd, ee) + X[6] + unchecked((int)0x7a6d76e9), 5) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F2(bb, cc, dd) + X[4] + unchecked((int)0x7a6d76e9), 8) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F2(aa, bb, cc) + X[1] + unchecked((int)0x7a6d76e9), 11) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F2(ee, aa, bb) + X[3] + unchecked((int)0x7a6d76e9), 14) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F2(dd, ee, aa) + X[11] + unchecked((int)0x7a6d76e9), 14) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F2(cc, dd, ee) + X[15] + unchecked((int)0x7a6d76e9), 6) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F2(bb, cc, dd) + X[0] + unchecked((int)0x7a6d76e9), 14) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F2(aa, bb, cc) + X[5] + unchecked((int)0x7a6d76e9), 6) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F2(ee, aa, bb) + X[12] + unchecked((int)0x7a6d76e9), 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F2(dd, ee, aa) + X[2] + unchecked((int)0x7a6d76e9), 12) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F2(cc, dd, ee) + X[13] + unchecked((int)0x7a6d76e9), 9) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F2(bb, cc, dd) + X[9] + unchecked((int)0x7a6d76e9), 12) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F2(aa, bb, cc) + X[7] + unchecked((int)0x7a6d76e9), 5) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F2(ee, aa, bb) + X[10] + unchecked((int)0x7a6d76e9), 15) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F2(dd, ee, aa) + X[14] + unchecked((int)0x7a6d76e9), 8) + bb; ee = RL(ee, 10);
+
+ t = d; d = dd; dd = t;
+
+ //
+ // Rounds 64-79
+ //
+ // left
+ b = RL(b + F5(c, d, e) + X[4] + unchecked((int)0xa953fd4e), 9) + a; d = RL(d, 10);
+ a = RL(a + F5(b, c, d) + X[0] + unchecked((int)0xa953fd4e), 15) + e; c = RL(c, 10);
+ e = RL(e + F5(a, b, c) + X[5] + unchecked((int)0xa953fd4e), 5) + d; b = RL(b, 10);
+ d = RL(d + F5(e, a, b) + X[9] + unchecked((int)0xa953fd4e), 11) + c; a = RL(a, 10);
+ c = RL(c + F5(d, e, a) + X[7] + unchecked((int)0xa953fd4e), 6) + b; e = RL(e, 10);
+ b = RL(b + F5(c, d, e) + X[12] + unchecked((int)0xa953fd4e), 8) + a; d = RL(d, 10);
+ a = RL(a + F5(b, c, d) + X[2] + unchecked((int)0xa953fd4e), 13) + e; c = RL(c, 10);
+ e = RL(e + F5(a, b, c) + X[10] + unchecked((int)0xa953fd4e), 12) + d; b = RL(b, 10);
+ d = RL(d + F5(e, a, b) + X[14] + unchecked((int)0xa953fd4e), 5) + c; a = RL(a, 10);
+ c = RL(c + F5(d, e, a) + X[1] + unchecked((int)0xa953fd4e), 12) + b; e = RL(e, 10);
+ b = RL(b + F5(c, d, e) + X[3] + unchecked((int)0xa953fd4e), 13) + a; d = RL(d, 10);
+ a = RL(a + F5(b, c, d) + X[8] + unchecked((int)0xa953fd4e), 14) + e; c = RL(c, 10);
+ e = RL(e + F5(a, b, c) + X[11] + unchecked((int)0xa953fd4e), 11) + d; b = RL(b, 10);
+ d = RL(d + F5(e, a, b) + X[6] + unchecked((int)0xa953fd4e), 8) + c; a = RL(a, 10);
+ c = RL(c + F5(d, e, a) + X[15] + unchecked((int)0xa953fd4e), 5) + b; e = RL(e, 10);
+ b = RL(b + F5(c, d, e) + X[13] + unchecked((int)0xa953fd4e), 6) + a; d = RL(d, 10);
+
+ // right
+ bb = RL(bb + F1(cc, dd, ee) + X[12], 8) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F1(bb, cc, dd) + X[15], 5) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F1(aa, bb, cc) + X[10], 12) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F1(ee, aa, bb) + X[4], 9) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F1(dd, ee, aa) + X[1], 12) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F1(cc, dd, ee) + X[5], 5) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F1(bb, cc, dd) + X[8], 14) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F1(aa, bb, cc) + X[7], 6) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F1(ee, aa, bb) + X[6], 8) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F1(dd, ee, aa) + X[2], 13) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F1(cc, dd, ee) + X[13], 6) + aa; dd = RL(dd, 10);
+ aa = RL(aa + F1(bb, cc, dd) + X[14], 5) + ee; cc = RL(cc, 10);
+ ee = RL(ee + F1(aa, bb, cc) + X[0], 15) + dd; bb = RL(bb, 10);
+ dd = RL(dd + F1(ee, aa, bb) + X[3], 13) + cc; aa = RL(aa, 10);
+ cc = RL(cc + F1(dd, ee, aa) + X[9], 11) + bb; ee = RL(ee, 10);
+ bb = RL(bb + F1(cc, dd, ee) + X[11], 11) + aa; dd = RL(dd, 10);
+
+ //
+ // do (e, ee) swap as part of assignment.
+ //
+
+ H0 += a;
+ H1 += b;
+ H2 += c;
+ H3 += d;
+ H4 += ee;
+ H5 += aa;
+ H6 += bb;
+ H7 += cc;
+ H8 += dd;
+ H9 += e;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ xOff = 0;
+ for (int i = 0; i != X.Length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ public override IMemoable Copy()
+ {
+ return new RipeMD320Digest(this);
+ }
+
+ public override void Reset(IMemoable other)
+ {
+ RipeMD320Digest d = (RipeMD320Digest)other;
+
+ CopyIn(d);
+ }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/SHA3Digest.cs b/bc-sharp-crypto/src/crypto/digests/SHA3Digest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4683af5b3e269df1819d3910e6ccd9e239d087e5
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/SHA3Digest.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ ///
+ /// Implementation of SHA-3 based on following KeccakNISTInterface.c from http://keccak.noekeon.org/
+ ///
+ ///
+ /// Following the naming conventions used in the C source code to enable easy review of the implementation.
+ ///
+ public class Sha3Digest
+ : KeccakDigest
+ {
+ private static int CheckBitLength(int bitLength)
+ {
+ switch (bitLength)
+ {
+ case 224:
+ case 256:
+ case 384:
+ case 512:
+ return bitLength;
+ default:
+ throw new ArgumentException(bitLength + " not supported for SHA-3", "bitLength");
+ }
+ }
+
+ public Sha3Digest()
+ : this(256)
+ {
+ }
+
+ public Sha3Digest(int bitLength)
+ : base(CheckBitLength(bitLength))
+ {
+ }
+
+ public Sha3Digest(Sha3Digest source)
+ : base(source)
+ {
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "SHA3-" + fixedOutputLength; }
+ }
+
+ public override int DoFinal(byte[] output, int outOff)
+ {
+ AbsorbBits(0x02, 2);
+
+ return base.DoFinal(output, outOff);
+ }
+
+ /*
+ * TODO Possible API change to support partial-byte suffixes.
+ */
+ protected override int DoFinal(byte[] output, int outOff, byte partialByte, int partialBits)
+ {
+ if (partialBits < 0 || partialBits > 7)
+ throw new ArgumentException("must be in the range [0,7]", "partialBits");
+
+ int finalInput = (partialByte & ((1 << partialBits) - 1)) | (0x02 << partialBits);
+ Debug.Assert(finalInput >= 0);
+ int finalBits = partialBits + 2;
+
+ if (finalBits >= 8)
+ {
+ Absorb(new byte[]{ (byte)finalInput }, 0, 1);
+ finalBits -= 8;
+ finalInput >>= 8;
+ }
+
+ return base.DoFinal(output, outOff, (byte)finalInput, finalBits);
+ }
+
+ public override IMemoable Copy()
+ {
+ return new Sha3Digest(this);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/SM3Digest.cs b/bc-sharp-crypto/src/crypto/digests/SM3Digest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d81b2ddbf865b85d1705836529abc850afd294ce
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/SM3Digest.cs
@@ -0,0 +1,328 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+
+ ///
+ /// Implementation of Chinese SM3 digest as described at
+ /// http://tools.ietf.org/html/draft-shen-sm3-hash-00
+ /// and at .... ( Chinese PDF )
+ ///
+ ///
+ /// The specification says "process a bit stream",
+ /// but this is written to process bytes in blocks of 4,
+ /// meaning this will process 32-bit word groups.
+ /// But so do also most other digest specifications,
+ /// including the SHA-256 which was a origin for
+ /// this specification.
+ ///
+ public class SM3Digest
+ : GeneralDigest
+ {
+ private const int DIGEST_LENGTH = 32; // bytes
+ private const int BLOCK_SIZE = 64 / 4; // of 32 bit ints (16 ints)
+
+ private uint[] V = new uint[DIGEST_LENGTH / 4]; // in 32 bit ints (8 ints)
+ private uint[] inwords = new uint[BLOCK_SIZE];
+ private int xOff;
+
+ // Work-bufs used within processBlock()
+ private uint[] W = new uint[68];
+ private uint[] W1 = new uint[64];
+
+ // Round constant T for processBlock() which is 32 bit integer rolled left up to (63 MOD 32) bit positions.
+ private static readonly uint[] T = new uint[64];
+
+ static SM3Digest()
+ {
+ for (int i = 0; i < 16; ++i)
+ {
+ uint t = 0x79CC4519;
+ T[i] = (t << i) | (t >> (32 - i));
+ }
+ for (int i = 16; i < 64; ++i)
+ {
+ int n = i % 32;
+ uint t = 0x7A879D8A;
+ T[i] = (t << n) | (t >> (32 - n));
+ }
+ }
+
+
+ ///
+ /// Standard constructor
+ ///
+ public SM3Digest()
+ {
+ Reset();
+ }
+
+ ///
+ /// Copy constructor. This will copy the state of the provided
+ /// message digest.
+ ///
+ public SM3Digest(SM3Digest t)
+ : base(t)
+ {
+ CopyIn(t);
+ }
+
+ private void CopyIn(SM3Digest t)
+ {
+ Array.Copy(t.V, 0, this.V, 0, this.V.Length);
+ Array.Copy(t.inwords, 0, this.inwords, 0, this.inwords.Length);
+ xOff = t.xOff;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "SM3"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DIGEST_LENGTH;
+ }
+
+ public override IMemoable Copy()
+ {
+ return new SM3Digest(this);
+ }
+
+ public override void Reset(IMemoable other)
+ {
+ SM3Digest d = (SM3Digest)other;
+
+ base.CopyIn(d);
+ CopyIn(d);
+ }
+
+ ///
+ /// reset the chaining variables
+ ///
+ public override void Reset()
+ {
+ base.Reset();
+
+ this.V[0] = 0x7380166F;
+ this.V[1] = 0x4914B2B9;
+ this.V[2] = 0x172442D7;
+ this.V[3] = 0xDA8A0600;
+ this.V[4] = 0xA96F30BC;
+ this.V[5] = 0x163138AA;
+ this.V[6] = 0xE38DEE4D;
+ this.V[7] = 0xB0FB0E4E;
+
+ this.xOff = 0;
+ }
+
+
+ public override int DoFinal(byte[] output, int outOff)
+ {
+ Finish();
+
+ Pack.UInt32_To_BE(this.V[0], output, outOff + 0);
+ Pack.UInt32_To_BE(this.V[1], output, outOff + 4);
+ Pack.UInt32_To_BE(this.V[2], output, outOff + 8);
+ Pack.UInt32_To_BE(this.V[3], output, outOff + 12);
+ Pack.UInt32_To_BE(this.V[4], output, outOff + 16);
+ Pack.UInt32_To_BE(this.V[5], output, outOff + 20);
+ Pack.UInt32_To_BE(this.V[6], output, outOff + 24);
+ Pack.UInt32_To_BE(this.V[7], output, outOff + 28);
+
+ Reset();
+
+ return DIGEST_LENGTH;
+ }
+
+
+ internal override void ProcessWord(byte[] input,
+ int inOff)
+ {
+ uint n = Pack.BE_To_UInt32(input, inOff);
+ this.inwords[this.xOff] = n;
+ ++this.xOff;
+
+ if (this.xOff >= 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ internal override void ProcessLength(long bitLength)
+ {
+ if (this.xOff > (BLOCK_SIZE - 2))
+ {
+ // xOff == 15 --> can't fit the 64 bit length field at tail..
+ this.inwords[this.xOff] = 0; // fill with zero
+ ++this.xOff;
+
+ ProcessBlock();
+ }
+ // Fill with zero words, until reach 2nd to last slot
+ while (this.xOff < (BLOCK_SIZE - 2))
+ {
+ this.inwords[this.xOff] = 0;
+ ++this.xOff;
+ }
+
+ // Store input data length in BITS
+ this.inwords[this.xOff++] = (uint)(bitLength >> 32);
+ this.inwords[this.xOff++] = (uint)(bitLength);
+ }
+
+ /*
+
+ 3.4.2. Constants
+
+
+ Tj = 79cc4519 when 0 < = j < = 15
+ Tj = 7a879d8a when 16 < = j < = 63
+
+ 3.4.3. Boolean function
+
+
+ FFj(X;Y;Z) = X XOR Y XOR Z when 0 < = j < = 15
+ = (X AND Y) OR (X AND Z) OR (Y AND Z) when 16 < = j < = 63
+
+ GGj(X;Y;Z) = X XOR Y XOR Z when 0 < = j < = 15
+ = (X AND Y) OR (NOT X AND Z) when 16 < = j < = 63
+
+ The X, Y, Z in the fomular are words!GBP
+
+ 3.4.4. Permutation function
+
+
+ P0(X) = X XOR (X <<< 9) XOR (X <<< 17) ## ROLL, not SHIFT
+ P1(X) = X XOR (X <<< 15) XOR (X <<< 23) ## ROLL, not SHIFT
+
+ The X in the fomular are a word.
+
+ ----------
+
+ Each ROLL converted to Java expression:
+
+ ROLL 9 : ((x << 9) | (x >> (32-9))))
+ ROLL 17 : ((x << 17) | (x >> (32-17)))
+ ROLL 15 : ((x << 15) | (x >> (32-15)))
+ ROLL 23 : ((x << 23) | (x >> (32-23)))
+
+ */
+
+ private uint P0(uint x)
+ {
+ uint r9 = ((x << 9) | (x >> (32 - 9)));
+ uint r17 = ((x << 17) | (x >> (32 - 17)));
+ return (x ^ r9 ^ r17);
+ }
+
+ private uint P1(uint x)
+ {
+ uint r15 = ((x << 15) | (x >> (32 - 15)));
+ uint r23 = ((x << 23) | (x >> (32 - 23)));
+ return (x ^ r15 ^ r23);
+ }
+
+ private uint FF0(uint x, uint y, uint z)
+ {
+ return (x ^ y ^ z);
+ }
+
+ private uint FF1(uint x, uint y, uint z)
+ {
+ return ((x & y) | (x & z) | (y & z));
+ }
+
+ private uint GG0(uint x, uint y, uint z)
+ {
+ return (x ^ y ^ z);
+ }
+
+ private uint GG1(uint x, uint y, uint z)
+ {
+ return ((x & y) | ((~x) & z));
+ }
+
+
+ internal override void ProcessBlock()
+ {
+ for (int j = 0; j < 16; ++j)
+ {
+ this.W[j] = this.inwords[j];
+ }
+ for (int j = 16; j < 68; ++j)
+ {
+ uint wj3 = this.W[j - 3];
+ uint r15 = ((wj3 << 15) | (wj3 >> (32 - 15)));
+ uint wj13 = this.W[j - 13];
+ uint r7 = ((wj13 << 7) | (wj13 >> (32 - 7)));
+ this.W[j] = P1(this.W[j - 16] ^ this.W[j - 9] ^ r15) ^ r7 ^ this.W[j - 6];
+ }
+ for (int j = 0; j < 64; ++j)
+ {
+ this.W1[j] = this.W[j] ^ this.W[j + 4];
+ }
+
+ uint A = this.V[0];
+ uint B = this.V[1];
+ uint C = this.V[2];
+ uint D = this.V[3];
+ uint E = this.V[4];
+ uint F = this.V[5];
+ uint G = this.V[6];
+ uint H = this.V[7];
+
+
+ for (int j = 0; j < 16; ++j)
+ {
+ uint a12 = ((A << 12) | (A >> (32 - 12)));
+ uint s1_ = a12 + E + T[j];
+ uint SS1 = ((s1_ << 7) | (s1_ >> (32 - 7)));
+ uint SS2 = SS1 ^ a12;
+ uint TT1 = FF0(A, B, C) + D + SS2 + this.W1[j];
+ uint TT2 = GG0(E, F, G) + H + SS1 + this.W[j];
+ D = C;
+ C = ((B << 9) | (B >> (32 - 9)));
+ B = A;
+ A = TT1;
+ H = G;
+ G = ((F << 19) | (F >> (32 - 19)));
+ F = E;
+ E = P0(TT2);
+ }
+
+ // Different FF,GG functions on rounds 16..63
+ for (int j = 16; j < 64; ++j)
+ {
+ uint a12 = ((A << 12) | (A >> (32 - 12)));
+ uint s1_ = a12 + E + T[j];
+ uint SS1 = ((s1_ << 7) | (s1_ >> (32 - 7)));
+ uint SS2 = SS1 ^ a12;
+ uint TT1 = FF1(A, B, C) + D + SS2 + this.W1[j];
+ uint TT2 = GG1(E, F, G) + H + SS1 + this.W[j];
+ D = C;
+ C = ((B << 9) | (B >> (32 - 9)));
+ B = A;
+ A = TT1;
+ H = G;
+ G = ((F << 19) | (F >> (32 - 19)));
+ F = E;
+ E = P0(TT2);
+ }
+
+ this.V[0] ^= A;
+ this.V[1] ^= B;
+ this.V[2] ^= C;
+ this.V[3] ^= D;
+ this.V[4] ^= E;
+ this.V[5] ^= F;
+ this.V[6] ^= G;
+ this.V[7] ^= H;
+
+ this.xOff = 0;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/Sha1Digest.cs b/bc-sharp-crypto/src/crypto/digests/Sha1Digest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..60ec651d5aa044e0044122a5f52462a58a4fd9af
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/Sha1Digest.cs
@@ -0,0 +1,284 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+
+ /**
+ * implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349.
+ *
+ * It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5
+ * is the "endianness" of the word processing!
+ */
+ public class Sha1Digest
+ : GeneralDigest
+ {
+ private const int DigestLength = 20;
+
+ private uint H1, H2, H3, H4, H5;
+
+ private uint[] X = new uint[80];
+ private int xOff;
+
+ public Sha1Digest()
+ {
+ Reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public Sha1Digest(Sha1Digest t)
+ : base(t)
+ {
+ CopyIn(t);
+ }
+
+ private void CopyIn(Sha1Digest t)
+ {
+ base.CopyIn(t);
+
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+ H5 = t.H5;
+
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "SHA-1"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ internal override void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ X[xOff] = Pack.BE_To_UInt32(input, inOff);
+
+ if (++xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ internal override void ProcessLength(long bitLength)
+ {
+ if (xOff > 14)
+ {
+ ProcessBlock();
+ }
+
+ X[14] = (uint)((ulong)bitLength >> 32);
+ X[15] = (uint)((ulong)bitLength);
+ }
+
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ Pack.UInt32_To_BE(H1, output, outOff);
+ Pack.UInt32_To_BE(H2, output, outOff + 4);
+ Pack.UInt32_To_BE(H3, output, outOff + 8);
+ Pack.UInt32_To_BE(H4, output, outOff + 12);
+ Pack.UInt32_To_BE(H5, output, outOff + 16);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /**
+ * reset the chaining variables
+ */
+ public override void Reset()
+ {
+ base.Reset();
+
+ H1 = 0x67452301;
+ H2 = 0xefcdab89;
+ H3 = 0x98badcfe;
+ H4 = 0x10325476;
+ H5 = 0xc3d2e1f0;
+
+ xOff = 0;
+ Array.Clear(X, 0, X.Length);
+ }
+
+ //
+ // Additive constants
+ //
+ private const uint Y1 = 0x5a827999;
+ private const uint Y2 = 0x6ed9eba1;
+ private const uint Y3 = 0x8f1bbcdc;
+ private const uint Y4 = 0xca62c1d6;
+
+ private static uint F(uint u, uint v, uint w)
+ {
+ return (u & v) | (~u & w);
+ }
+
+ private static uint H(uint u, uint v, uint w)
+ {
+ return u ^ v ^ w;
+ }
+
+ private static uint G(uint u, uint v, uint w)
+ {
+ return (u & v) | (u & w) | (v & w);
+ }
+
+ internal override void ProcessBlock()
+ {
+ //
+ // expand 16 word block into 80 word block.
+ //
+ for (int i = 16; i < 80; i++)
+ {
+ uint t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16];
+ X[i] = t << 1 | t >> 31;
+ }
+
+ //
+ // set up working variables.
+ //
+ uint A = H1;
+ uint B = H2;
+ uint C = H3;
+ uint D = H4;
+ uint E = H5;
+
+ //
+ // round 1
+ //
+ int idx = 0;
+
+ for (int j = 0; j < 4; j++)
+ {
+ // E = rotateLeft(A, 5) + F(B, C, D) + E + X[idx++] + Y1
+ // B = rotateLeft(B, 30)
+ E += (A << 5 | (A >> 27)) + F(B, C, D) + X[idx++] + Y1;
+ B = B << 30 | (B >> 2);
+
+ D += (E << 5 | (E >> 27)) + F(A, B, C) + X[idx++] + Y1;
+ A = A << 30 | (A >> 2);
+
+ C += (D << 5 | (D >> 27)) + F(E, A, B) + X[idx++] + Y1;
+ E = E << 30 | (E >> 2);
+
+ B += (C << 5 | (C >> 27)) + F(D, E, A) + X[idx++] + Y1;
+ D = D << 30 | (D >> 2);
+
+ A += (B << 5 | (B >> 27)) + F(C, D, E) + X[idx++] + Y1;
+ C = C << 30 | (C >> 2);
+ }
+
+ //
+ // round 2
+ //
+ for (int j = 0; j < 4; j++)
+ {
+ // E = rotateLeft(A, 5) + H(B, C, D) + E + X[idx++] + Y2
+ // B = rotateLeft(B, 30)
+ E += (A << 5 | (A >> 27)) + H(B, C, D) + X[idx++] + Y2;
+ B = B << 30 | (B >> 2);
+
+ D += (E << 5 | (E >> 27)) + H(A, B, C) + X[idx++] + Y2;
+ A = A << 30 | (A >> 2);
+
+ C += (D << 5 | (D >> 27)) + H(E, A, B) + X[idx++] + Y2;
+ E = E << 30 | (E >> 2);
+
+ B += (C << 5 | (C >> 27)) + H(D, E, A) + X[idx++] + Y2;
+ D = D << 30 | (D >> 2);
+
+ A += (B << 5 | (B >> 27)) + H(C, D, E) + X[idx++] + Y2;
+ C = C << 30 | (C >> 2);
+ }
+
+ //
+ // round 3
+ //
+ for (int j = 0; j < 4; j++)
+ {
+ // E = rotateLeft(A, 5) + G(B, C, D) + E + X[idx++] + Y3
+ // B = rotateLeft(B, 30)
+ E += (A << 5 | (A >> 27)) + G(B, C, D) + X[idx++] + Y3;
+ B = B << 30 | (B >> 2);
+
+ D += (E << 5 | (E >> 27)) + G(A, B, C) + X[idx++] + Y3;
+ A = A << 30 | (A >> 2);
+
+ C += (D << 5 | (D >> 27)) + G(E, A, B) + X[idx++] + Y3;
+ E = E << 30 | (E >> 2);
+
+ B += (C << 5 | (C >> 27)) + G(D, E, A) + X[idx++] + Y3;
+ D = D << 30 | (D >> 2);
+
+ A += (B << 5 | (B >> 27)) + G(C, D, E) + X[idx++] + Y3;
+ C = C << 30 | (C >> 2);
+ }
+
+ //
+ // round 4
+ //
+ for (int j = 0; j < 4; j++)
+ {
+ // E = rotateLeft(A, 5) + H(B, C, D) + E + X[idx++] + Y4
+ // B = rotateLeft(B, 30)
+ E += (A << 5 | (A >> 27)) + H(B, C, D) + X[idx++] + Y4;
+ B = B << 30 | (B >> 2);
+
+ D += (E << 5 | (E >> 27)) + H(A, B, C) + X[idx++] + Y4;
+ A = A << 30 | (A >> 2);
+
+ C += (D << 5 | (D >> 27)) + H(E, A, B) + X[idx++] + Y4;
+ E = E << 30 | (E >> 2);
+
+ B += (C << 5 | (C >> 27)) + H(D, E, A) + X[idx++] + Y4;
+ D = D << 30 | (D >> 2);
+
+ A += (B << 5 | (B >> 27)) + H(C, D, E) + X[idx++] + Y4;
+ C = C << 30 | (C >> 2);
+ }
+
+ H1 += A;
+ H2 += B;
+ H3 += C;
+ H4 += D;
+ H5 += E;
+
+ //
+ // reset start of the buffer.
+ //
+ xOff = 0;
+ Array.Clear(X, 0, 16);
+ }
+
+ public override IMemoable Copy()
+ {
+ return new Sha1Digest(this);
+ }
+
+ public override void Reset(IMemoable other)
+ {
+ Sha1Digest d = (Sha1Digest)other;
+
+ CopyIn(d);
+ }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/Sha224Digest.cs b/bc-sharp-crypto/src/crypto/digests/Sha224Digest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b4e853745d18510673a6f0859e45273c97b25b1f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/Sha224Digest.cs
@@ -0,0 +1,289 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * SHA-224 as described in RFC 3874
+ *
+ * block word digest
+ * SHA-1 512 32 160
+ * SHA-224 512 32 224
+ * SHA-256 512 32 256
+ * SHA-384 1024 64 384
+ * SHA-512 1024 64 512
+ *
+ */
+ public class Sha224Digest
+ : GeneralDigest
+ {
+ private const int DigestLength = 28;
+
+ private uint H1, H2, H3, H4, H5, H6, H7, H8;
+
+ private uint[] X = new uint[64];
+ private int xOff;
+
+ /**
+ * Standard constructor
+ */
+ public Sha224Digest()
+ {
+ Reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public Sha224Digest(
+ Sha224Digest t)
+ : base(t)
+ {
+ CopyIn(t);
+ }
+
+ private void CopyIn(Sha224Digest t)
+ {
+ base.CopyIn(t);
+
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+ H5 = t.H5;
+ H6 = t.H6;
+ H7 = t.H7;
+ H8 = t.H8;
+
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "SHA-224"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ internal override void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ X[xOff] = Pack.BE_To_UInt32(input, inOff);
+
+ if (++xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ internal override void ProcessLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ ProcessBlock();
+ }
+
+ X[14] = (uint)((ulong)bitLength >> 32);
+ X[15] = (uint)((ulong)bitLength);
+ }
+
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ Pack.UInt32_To_BE(H1, output, outOff);
+ Pack.UInt32_To_BE(H2, output, outOff + 4);
+ Pack.UInt32_To_BE(H3, output, outOff + 8);
+ Pack.UInt32_To_BE(H4, output, outOff + 12);
+ Pack.UInt32_To_BE(H5, output, outOff + 16);
+ Pack.UInt32_To_BE(H6, output, outOff + 20);
+ Pack.UInt32_To_BE(H7, output, outOff + 24);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /**
+ * reset the chaining variables
+ */
+ public override void Reset()
+ {
+ base.Reset();
+
+ /* SHA-224 initial hash value
+ */
+ H1 = 0xc1059ed8;
+ H2 = 0x367cd507;
+ H3 = 0x3070dd17;
+ H4 = 0xf70e5939;
+ H5 = 0xffc00b31;
+ H6 = 0x68581511;
+ H7 = 0x64f98fa7;
+ H8 = 0xbefa4fa4;
+
+ xOff = 0;
+ Array.Clear(X, 0, X.Length);
+ }
+
+ internal override void ProcessBlock()
+ {
+ //
+ // expand 16 word block into 64 word blocks.
+ //
+ for (int ti = 16; ti <= 63; ti++)
+ {
+ X[ti] = Theta1(X[ti - 2]) + X[ti - 7] + Theta0(X[ti - 15]) + X[ti - 16];
+ }
+
+ //
+ // set up working variables.
+ //
+ uint a = H1;
+ uint b = H2;
+ uint c = H3;
+ uint d = H4;
+ uint e = H5;
+ uint f = H6;
+ uint g = H7;
+ uint h = H8;
+
+ int t = 0;
+ for(int i = 0; i < 8; i ++)
+ {
+ // t = 8 * i
+ h += Sum1(e) + Ch(e, f, g) + K[t] + X[t];
+ d += h;
+ h += Sum0(a) + Maj(a, b, c);
+ ++t;
+
+ // t = 8 * i + 1
+ g += Sum1(d) + Ch(d, e, f) + K[t] + X[t];
+ c += g;
+ g += Sum0(h) + Maj(h, a, b);
+ ++t;
+
+ // t = 8 * i + 2
+ f += Sum1(c) + Ch(c, d, e) + K[t] + X[t];
+ b += f;
+ f += Sum0(g) + Maj(g, h, a);
+ ++t;
+
+ // t = 8 * i + 3
+ e += Sum1(b) + Ch(b, c, d) + K[t] + X[t];
+ a += e;
+ e += Sum0(f) + Maj(f, g, h);
+ ++t;
+
+ // t = 8 * i + 4
+ d += Sum1(a) + Ch(a, b, c) + K[t] + X[t];
+ h += d;
+ d += Sum0(e) + Maj(e, f, g);
+ ++t;
+
+ // t = 8 * i + 5
+ c += Sum1(h) + Ch(h, a, b) + K[t] + X[t];
+ g += c;
+ c += Sum0(d) + Maj(d, e, f);
+ ++t;
+
+ // t = 8 * i + 6
+ b += Sum1(g) + Ch(g, h, a) + K[t] + X[t];
+ f += b;
+ b += Sum0(c) + Maj(c, d, e);
+ ++t;
+
+ // t = 8 * i + 7
+ a += Sum1(f) + Ch(f, g, h) + K[t] + X[t];
+ e += a;
+ a += Sum0(b) + Maj(b, c, d);
+ ++t;
+ }
+
+ H1 += a;
+ H2 += b;
+ H3 += c;
+ H4 += d;
+ H5 += e;
+ H6 += f;
+ H7 += g;
+ H8 += h;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ xOff = 0;
+ Array.Clear(X, 0, 16);
+ }
+
+ /* SHA-224 functions */
+ private static uint Ch(uint x, uint y, uint z)
+ {
+ return (x & y) ^ (~x & z);
+ }
+
+ private static uint Maj(uint x, uint y, uint z)
+ {
+ return (x & y) ^ (x & z) ^ (y & z);
+ }
+
+ private static uint Sum0(uint x)
+ {
+ return ((x >> 2) | (x << 30)) ^ ((x >> 13) | (x << 19)) ^ ((x >> 22) | (x << 10));
+ }
+
+ private static uint Sum1(uint x)
+ {
+ return ((x >> 6) | (x << 26)) ^ ((x >> 11) | (x << 21)) ^ ((x >> 25) | (x << 7));
+ }
+
+ private static uint Theta0(uint x)
+ {
+ return ((x >> 7) | (x << 25)) ^ ((x >> 18) | (x << 14)) ^ (x >> 3);
+ }
+
+ private static uint Theta1(uint x)
+ {
+ return ((x >> 17) | (x << 15)) ^ ((x >> 19) | (x << 13)) ^ (x >> 10);
+ }
+
+ /* SHA-224 Constants
+ * (represent the first 32 bits of the fractional parts of the
+ * cube roots of the first sixty-four prime numbers)
+ */
+ internal static readonly uint[] K = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+ };
+
+ public override IMemoable Copy()
+ {
+ return new Sha224Digest(this);
+ }
+
+ public override void Reset(IMemoable other)
+ {
+ Sha224Digest d = (Sha224Digest)other;
+
+ CopyIn(d);
+ }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/Sha256Digest.cs b/bc-sharp-crypto/src/crypto/digests/Sha256Digest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..98e10a34d5fc45fd161e136934046ddf82883eb9
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/Sha256Digest.cs
@@ -0,0 +1,330 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * Draft FIPS 180-2 implementation of SHA-256. Note: As this is
+ * based on a draft this implementation is subject to change.
+ *
+ *
+ * block word digest
+ * SHA-1 512 32 160
+ * SHA-256 512 32 256
+ * SHA-384 1024 64 384
+ * SHA-512 1024 64 512
+ *
+ */
+ public class Sha256Digest
+ : GeneralDigest
+ {
+ private const int DigestLength = 32;
+
+ private uint H1, H2, H3, H4, H5, H6, H7, H8;
+ private uint[] X = new uint[64];
+ private int xOff;
+
+ public Sha256Digest()
+ {
+ initHs();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public Sha256Digest(Sha256Digest t) : base(t)
+ {
+ CopyIn(t);
+ }
+
+ private void CopyIn(Sha256Digest t)
+ {
+ base.CopyIn(t);
+
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+ H5 = t.H5;
+ H6 = t.H6;
+ H7 = t.H7;
+ H8 = t.H8;
+
+ Array.Copy(t.X, 0, X, 0, t.X.Length);
+ xOff = t.xOff;
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "SHA-256"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ internal override void ProcessWord(
+ byte[] input,
+ int inOff)
+ {
+ X[xOff] = Pack.BE_To_UInt32(input, inOff);
+
+ if (++xOff == 16)
+ {
+ ProcessBlock();
+ }
+ }
+
+ internal override void ProcessLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ ProcessBlock();
+ }
+
+ X[14] = (uint)((ulong)bitLength >> 32);
+ X[15] = (uint)((ulong)bitLength);
+ }
+
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ Pack.UInt32_To_BE((uint)H1, output, outOff);
+ Pack.UInt32_To_BE((uint)H2, output, outOff + 4);
+ Pack.UInt32_To_BE((uint)H3, output, outOff + 8);
+ Pack.UInt32_To_BE((uint)H4, output, outOff + 12);
+ Pack.UInt32_To_BE((uint)H5, output, outOff + 16);
+ Pack.UInt32_To_BE((uint)H6, output, outOff + 20);
+ Pack.UInt32_To_BE((uint)H7, output, outOff + 24);
+ Pack.UInt32_To_BE((uint)H8, output, outOff + 28);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /**
+ * reset the chaining variables
+ */
+ public override void Reset()
+ {
+ base.Reset();
+
+ initHs();
+
+ xOff = 0;
+ Array.Clear(X, 0, X.Length);
+ }
+
+ private void initHs()
+ {
+ /* SHA-256 initial hash value
+ * The first 32 bits of the fractional parts of the square roots
+ * of the first eight prime numbers
+ */
+ H1 = 0x6a09e667;
+ H2 = 0xbb67ae85;
+ H3 = 0x3c6ef372;
+ H4 = 0xa54ff53a;
+ H5 = 0x510e527f;
+ H6 = 0x9b05688c;
+ H7 = 0x1f83d9ab;
+ H8 = 0x5be0cd19;
+ }
+
+ internal override void ProcessBlock()
+ {
+ //
+ // expand 16 word block into 64 word blocks.
+ //
+ for (int ti = 16; ti <= 63; ti++)
+ {
+ X[ti] = Theta1(X[ti - 2]) + X[ti - 7] + Theta0(X[ti - 15]) + X[ti - 16];
+ }
+
+ //
+ // set up working variables.
+ //
+ uint a = H1;
+ uint b = H2;
+ uint c = H3;
+ uint d = H4;
+ uint e = H5;
+ uint f = H6;
+ uint g = H7;
+ uint h = H8;
+
+ int t = 0;
+ for(int i = 0; i < 8; ++i)
+ {
+ // t = 8 * i
+ h += Sum1Ch(e, f, g) + K[t] + X[t];
+ d += h;
+ h += Sum0Maj(a, b, c);
+ ++t;
+
+ // t = 8 * i + 1
+ g += Sum1Ch(d, e, f) + K[t] + X[t];
+ c += g;
+ g += Sum0Maj(h, a, b);
+ ++t;
+
+ // t = 8 * i + 2
+ f += Sum1Ch(c, d, e) + K[t] + X[t];
+ b += f;
+ f += Sum0Maj(g, h, a);
+ ++t;
+
+ // t = 8 * i + 3
+ e += Sum1Ch(b, c, d) + K[t] + X[t];
+ a += e;
+ e += Sum0Maj(f, g, h);
+ ++t;
+
+ // t = 8 * i + 4
+ d += Sum1Ch(a, b, c) + K[t] + X[t];
+ h += d;
+ d += Sum0Maj(e, f, g);
+ ++t;
+
+ // t = 8 * i + 5
+ c += Sum1Ch(h, a, b) + K[t] + X[t];
+ g += c;
+ c += Sum0Maj(d, e, f);
+ ++t;
+
+ // t = 8 * i + 6
+ b += Sum1Ch(g, h, a) + K[t] + X[t];
+ f += b;
+ b += Sum0Maj(c, d, e);
+ ++t;
+
+ // t = 8 * i + 7
+ a += Sum1Ch(f, g, h) + K[t] + X[t];
+ e += a;
+ a += Sum0Maj(b, c, d);
+ ++t;
+ }
+
+ H1 += a;
+ H2 += b;
+ H3 += c;
+ H4 += d;
+ H5 += e;
+ H6 += f;
+ H7 += g;
+ H8 += h;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ xOff = 0;
+ Array.Clear(X, 0, 16);
+ }
+
+ private static uint Sum1Ch(
+ uint x,
+ uint y,
+ uint z)
+ {
+// return Sum1(x) + Ch(x, y, z);
+ return (((x >> 6) | (x << 26)) ^ ((x >> 11) | (x << 21)) ^ ((x >> 25) | (x << 7)))
+ + ((x & y) ^ ((~x) & z));
+ }
+
+ private static uint Sum0Maj(
+ uint x,
+ uint y,
+ uint z)
+ {
+// return Sum0(x) + Maj(x, y, z);
+ return (((x >> 2) | (x << 30)) ^ ((x >> 13) | (x << 19)) ^ ((x >> 22) | (x << 10)))
+ + ((x & y) ^ (x & z) ^ (y & z));
+ }
+
+// /* SHA-256 functions */
+// private static uint Ch(
+// uint x,
+// uint y,
+// uint z)
+// {
+// return ((x & y) ^ ((~x) & z));
+// }
+//
+// private static uint Maj(
+// uint x,
+// uint y,
+// uint z)
+// {
+// return ((x & y) ^ (x & z) ^ (y & z));
+// }
+//
+// private static uint Sum0(
+// uint x)
+// {
+// return ((x >> 2) | (x << 30)) ^ ((x >> 13) | (x << 19)) ^ ((x >> 22) | (x << 10));
+// }
+//
+// private static uint Sum1(
+// uint x)
+// {
+// return ((x >> 6) | (x << 26)) ^ ((x >> 11) | (x << 21)) ^ ((x >> 25) | (x << 7));
+// }
+
+ private static uint Theta0(
+ uint x)
+ {
+ return ((x >> 7) | (x << 25)) ^ ((x >> 18) | (x << 14)) ^ (x >> 3);
+ }
+
+ private static uint Theta1(
+ uint x)
+ {
+ return ((x >> 17) | (x << 15)) ^ ((x >> 19) | (x << 13)) ^ (x >> 10);
+ }
+
+ /* SHA-256 Constants
+ * (represent the first 32 bits of the fractional parts of the
+ * cube roots of the first sixty-four prime numbers)
+ */
+ private static readonly uint[] K = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+ };
+
+ public override IMemoable Copy()
+ {
+ return new Sha256Digest(this);
+ }
+
+ public override void Reset(IMemoable other)
+ {
+ Sha256Digest d = (Sha256Digest)other;
+
+ CopyIn(d);
+ }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/Sha384Digest.cs b/bc-sharp-crypto/src/crypto/digests/Sha384Digest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e6c9a9aa971d4e6e47ff8b35eb6728ea9ef69229
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/Sha384Digest.cs
@@ -0,0 +1,101 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * Draft FIPS 180-2 implementation of SHA-384. Note: As this is
+ * based on a draft this implementation is subject to change.
+ *
+ *
+ * block word digest
+ * SHA-1 512 32 160
+ * SHA-256 512 32 256
+ * SHA-384 1024 64 384
+ * SHA-512 1024 64 512
+ *
+ */
+ public class Sha384Digest
+ : LongDigest
+ {
+ private const int DigestLength = 48;
+
+ public Sha384Digest()
+ {
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public Sha384Digest(
+ Sha384Digest t)
+ : base(t)
+ {
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "SHA-384"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ Pack.UInt64_To_BE(H1, output, outOff);
+ Pack.UInt64_To_BE(H2, output, outOff + 8);
+ Pack.UInt64_To_BE(H3, output, outOff + 16);
+ Pack.UInt64_To_BE(H4, output, outOff + 24);
+ Pack.UInt64_To_BE(H5, output, outOff + 32);
+ Pack.UInt64_To_BE(H6, output, outOff + 40);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /**
+ * reset the chaining variables
+ */
+ public override void Reset()
+ {
+ base.Reset();
+
+ /* SHA-384 initial hash value
+ * The first 64 bits of the fractional parts of the square roots
+ * of the 9th through 16th prime numbers
+ */
+ H1 = 0xcbbb9d5dc1059ed8;
+ H2 = 0x629a292a367cd507;
+ H3 = 0x9159015a3070dd17;
+ H4 = 0x152fecd8f70e5939;
+ H5 = 0x67332667ffc00b31;
+ H6 = 0x8eb44a8768581511;
+ H7 = 0xdb0c2e0d64f98fa7;
+ H8 = 0x47b5481dbefa4fa4;
+ }
+
+ public override IMemoable Copy()
+ {
+ return new Sha384Digest(this);
+ }
+
+ public override void Reset(IMemoable other)
+ {
+ Sha384Digest d = (Sha384Digest)other;
+
+ CopyIn(d);
+ }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/Sha512Digest.cs b/bc-sharp-crypto/src/crypto/digests/Sha512Digest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2a0964fd368d497f3d1ed8ff5f5bae0a99846c60
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/Sha512Digest.cs
@@ -0,0 +1,104 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * Draft FIPS 180-2 implementation of SHA-512. Note: As this is
+ * based on a draft this implementation is subject to change.
+ *
+ *
+ * block word digest
+ * SHA-1 512 32 160
+ * SHA-256 512 32 256
+ * SHA-384 1024 64 384
+ * SHA-512 1024 64 512
+ *
+ */
+ public class Sha512Digest
+ : LongDigest
+ {
+ private const int DigestLength = 64;
+
+ public Sha512Digest()
+ {
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public Sha512Digest(
+ Sha512Digest t)
+ : base(t)
+ {
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "SHA-512"; }
+ }
+
+ public override int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ Pack.UInt64_To_BE(H1, output, outOff);
+ Pack.UInt64_To_BE(H2, output, outOff + 8);
+ Pack.UInt64_To_BE(H3, output, outOff + 16);
+ Pack.UInt64_To_BE(H4, output, outOff + 24);
+ Pack.UInt64_To_BE(H5, output, outOff + 32);
+ Pack.UInt64_To_BE(H6, output, outOff + 40);
+ Pack.UInt64_To_BE(H7, output, outOff + 48);
+ Pack.UInt64_To_BE(H8, output, outOff + 56);
+
+ Reset();
+
+ return DigestLength;
+
+ }
+
+ /**
+ * reset the chaining variables
+ */
+ public override void Reset()
+ {
+ base.Reset();
+
+ /* SHA-512 initial hash value
+ * The first 64 bits of the fractional parts of the square roots
+ * of the first eight prime numbers
+ */
+ H1 = 0x6a09e667f3bcc908;
+ H2 = 0xbb67ae8584caa73b;
+ H3 = 0x3c6ef372fe94f82b;
+ H4 = 0xa54ff53a5f1d36f1;
+ H5 = 0x510e527fade682d1;
+ H6 = 0x9b05688c2b3e6c1f;
+ H7 = 0x1f83d9abfb41bd6b;
+ H8 = 0x5be0cd19137e2179;
+ }
+
+ public override IMemoable Copy()
+ {
+ return new Sha512Digest(this);
+ }
+
+ public override void Reset(IMemoable other)
+ {
+ Sha512Digest d = (Sha512Digest)other;
+
+ CopyIn(d);
+ }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/Sha512tDigest.cs b/bc-sharp-crypto/src/crypto/digests/Sha512tDigest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2caefa7637b20379bef533f220286b67bc5c1448
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/Sha512tDigest.cs
@@ -0,0 +1,200 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * FIPS 180-4 implementation of SHA-512/t
+ */
+ public class Sha512tDigest
+ : LongDigest
+ {
+ private const ulong A5 = 0xa5a5a5a5a5a5a5a5UL;
+
+ private readonly int digestLength;
+
+ private ulong H1t, H2t, H3t, H4t, H5t, H6t, H7t, H8t;
+
+ /**
+ * Standard constructor
+ */
+ public Sha512tDigest(int bitLength)
+ {
+ if (bitLength >= 512)
+ throw new ArgumentException("cannot be >= 512", "bitLength");
+ if (bitLength % 8 != 0)
+ throw new ArgumentException("needs to be a multiple of 8", "bitLength");
+ if (bitLength == 384)
+ throw new ArgumentException("cannot be 384 use SHA384 instead", "bitLength");
+
+ this.digestLength = bitLength / 8;
+
+ tIvGenerate(digestLength * 8);
+
+ Reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public Sha512tDigest(Sha512tDigest t)
+ : base(t)
+ {
+ this.digestLength = t.digestLength;
+
+ Reset(t);
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "SHA-512/" + (digestLength * 8); }
+ }
+
+ public override int GetDigestSize()
+ {
+ return digestLength;
+ }
+
+ public override int DoFinal(byte[] output, int outOff)
+ {
+ Finish();
+
+ UInt64_To_BE(H1, output, outOff, digestLength);
+ UInt64_To_BE(H2, output, outOff + 8, digestLength - 8);
+ UInt64_To_BE(H3, output, outOff + 16, digestLength - 16);
+ UInt64_To_BE(H4, output, outOff + 24, digestLength - 24);
+ UInt64_To_BE(H5, output, outOff + 32, digestLength - 32);
+ UInt64_To_BE(H6, output, outOff + 40, digestLength - 40);
+ UInt64_To_BE(H7, output, outOff + 48, digestLength - 48);
+ UInt64_To_BE(H8, output, outOff + 56, digestLength - 56);
+
+ Reset();
+
+ return digestLength;
+ }
+
+ /**
+ * reset the chaining variables
+ */
+ public override void Reset()
+ {
+ base.Reset();
+
+ /*
+ * initial hash values use the iv generation algorithm for t.
+ */
+ H1 = H1t;
+ H2 = H2t;
+ H3 = H3t;
+ H4 = H4t;
+ H5 = H5t;
+ H6 = H6t;
+ H7 = H7t;
+ H8 = H8t;
+ }
+
+ private void tIvGenerate(int bitLength)
+ {
+ H1 = 0x6a09e667f3bcc908UL ^ A5;
+ H2 = 0xbb67ae8584caa73bUL ^ A5;
+ H3 = 0x3c6ef372fe94f82bUL ^ A5;
+ H4 = 0xa54ff53a5f1d36f1UL ^ A5;
+ H5 = 0x510e527fade682d1UL ^ A5;
+ H6 = 0x9b05688c2b3e6c1fUL ^ A5;
+ H7 = 0x1f83d9abfb41bd6bUL ^ A5;
+ H8 = 0x5be0cd19137e2179UL ^ A5;
+
+ Update(0x53);
+ Update(0x48);
+ Update(0x41);
+ Update(0x2D);
+ Update(0x35);
+ Update(0x31);
+ Update(0x32);
+ Update(0x2F);
+
+ if (bitLength > 100)
+ {
+ Update((byte)(bitLength / 100 + 0x30));
+ bitLength = bitLength % 100;
+ Update((byte)(bitLength / 10 + 0x30));
+ bitLength = bitLength % 10;
+ Update((byte)(bitLength + 0x30));
+ }
+ else if (bitLength > 10)
+ {
+ Update((byte)(bitLength / 10 + 0x30));
+ bitLength = bitLength % 10;
+ Update((byte)(bitLength + 0x30));
+ }
+ else
+ {
+ Update((byte)(bitLength + 0x30));
+ }
+
+ Finish();
+
+ H1t = H1;
+ H2t = H2;
+ H3t = H3;
+ H4t = H4;
+ H5t = H5;
+ H6t = H6;
+ H7t = H7;
+ H8t = H8;
+ }
+
+ private static void UInt64_To_BE(ulong n, byte[] bs, int off, int max)
+ {
+ if (max > 0)
+ {
+ UInt32_To_BE((uint)(n >> 32), bs, off, max);
+
+ if (max > 4)
+ {
+ UInt32_To_BE((uint)n, bs, off + 4, max - 4);
+ }
+ }
+ }
+
+ private static void UInt32_To_BE(uint n, byte[] bs, int off, int max)
+ {
+ int num = System.Math.Min(4, max);
+ while (--num >= 0)
+ {
+ int shift = 8 * (3 - num);
+ bs[off + num] = (byte)(n >> shift);
+ }
+ }
+
+ public override IMemoable Copy()
+ {
+ return new Sha512tDigest(this);
+ }
+
+ public override void Reset(IMemoable other)
+ {
+ Sha512tDigest t = (Sha512tDigest)other;
+
+ if (this.digestLength != t.digestLength)
+ {
+ throw new MemoableResetException("digestLength inappropriate in other");
+ }
+
+ base.CopyIn(t);
+
+ this.H1t = t.H1t;
+ this.H2t = t.H2t;
+ this.H3t = t.H3t;
+ this.H4t = t.H4t;
+ this.H5t = t.H5t;
+ this.H6t = t.H6t;
+ this.H7t = t.H7t;
+ this.H8t = t.H8t;
+ }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/ShakeDigest.cs b/bc-sharp-crypto/src/crypto/digests/ShakeDigest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..13e8838c1ac38dcbb156dc53e66ba22d32182eee
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/ShakeDigest.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ ///
+ /// Implementation of SHAKE based on following KeccakNISTInterface.c from http://keccak.noekeon.org/
+ ///
+ ///
+ /// Following the naming conventions used in the C source code to enable easy review of the implementation.
+ ///
+ public class ShakeDigest
+ : KeccakDigest, IXof
+ {
+ private static int CheckBitLength(int bitLength)
+ {
+ switch (bitLength)
+ {
+ case 128:
+ case 256:
+ return bitLength;
+ default:
+ throw new ArgumentException(bitLength + " not supported for SHAKE", "bitLength");
+ }
+ }
+
+ public ShakeDigest()
+ : this(128)
+ {
+ }
+
+ public ShakeDigest(int bitLength)
+ : base(CheckBitLength(bitLength))
+ {
+ }
+
+ public ShakeDigest(ShakeDigest source)
+ : base(source)
+ {
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "SHAKE" + fixedOutputLength; }
+ }
+
+ public override int DoFinal(byte[] output, int outOff)
+ {
+ return DoFinal(output, outOff, GetDigestSize());
+ }
+
+ public virtual int DoFinal(byte[] output, int outOff, int outLen)
+ {
+ DoOutput(output, outOff, outLen);
+
+ Reset();
+
+ return outLen;
+ }
+
+ public virtual int DoOutput(byte[] output, int outOff, int outLen)
+ {
+ if (!squeezing)
+ {
+ AbsorbBits(0x0F, 4);
+ }
+
+ Squeeze(output, outOff, outLen);
+
+ return outLen;
+ }
+
+ /*
+ * TODO Possible API change to support partial-byte suffixes.
+ */
+ protected override int DoFinal(byte[] output, int outOff, byte partialByte, int partialBits)
+ {
+ return DoFinal(output, outOff, GetDigestSize(), partialByte, partialBits);
+ }
+
+ /*
+ * TODO Possible API change to support partial-byte suffixes.
+ */
+ protected virtual int DoFinal(byte[] output, int outOff, int outLen, byte partialByte, int partialBits)
+ {
+ if (partialBits < 0 || partialBits > 7)
+ throw new ArgumentException("must be in the range [0,7]", "partialBits");
+
+ int finalInput = (partialByte & ((1 << partialBits) - 1)) | (0x0F << partialBits);
+ Debug.Assert(finalInput >= 0);
+ int finalBits = partialBits + 4;
+
+ if (finalBits >= 8)
+ {
+ Absorb(new byte[]{ (byte)finalInput }, 0, 1);
+ finalBits -= 8;
+ finalInput >>= 8;
+ }
+
+ if (finalBits > 0)
+ {
+ AbsorbBits(finalInput, finalBits);
+ }
+
+ Squeeze(output, outOff, outLen);
+
+ Reset();
+
+ return outLen;
+ }
+
+ public override IMemoable Copy()
+ {
+ return new ShakeDigest(this);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/ShortenedDigest.cs b/bc-sharp-crypto/src/crypto/digests/ShortenedDigest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9e4d99e7bbfda5e933ee14da12a665b403520fa0
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/ShortenedDigest.cs
@@ -0,0 +1,82 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * Wrapper class that reduces the output length of a particular digest to
+ * only the first n bytes of the digest function.
+ */
+ public class ShortenedDigest
+ : IDigest
+ {
+ private IDigest baseDigest;
+ private int length;
+
+ /**
+ * Base constructor.
+ *
+ * @param baseDigest underlying digest to use.
+ * @param length length in bytes of the output of doFinal.
+ * @exception ArgumentException if baseDigest is null, or length is greater than baseDigest.GetDigestSize().
+ */
+ public ShortenedDigest(
+ IDigest baseDigest,
+ int length)
+ {
+ if (baseDigest == null)
+ {
+ throw new ArgumentNullException("baseDigest");
+ }
+
+ if (length > baseDigest.GetDigestSize())
+ {
+ throw new ArgumentException("baseDigest output not large enough to support length");
+ }
+
+ this.baseDigest = baseDigest;
+ this.length = length;
+ }
+
+ public string AlgorithmName
+ {
+ get { return baseDigest.AlgorithmName + "(" + length * 8 + ")"; }
+ }
+
+ public int GetDigestSize()
+ {
+ return length;
+ }
+
+ public void Update(byte input)
+ {
+ baseDigest.Update(input);
+ }
+
+ public void BlockUpdate(byte[] input, int inOff, int length)
+ {
+ baseDigest.BlockUpdate(input, inOff, length);
+ }
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ byte[] tmp = new byte[baseDigest.GetDigestSize()];
+
+ baseDigest.DoFinal(tmp, 0);
+
+ Array.Copy(tmp, 0, output, outOff, length);
+
+ return length;
+ }
+
+ public void Reset()
+ {
+ baseDigest.Reset();
+ }
+
+ public int GetByteLength()
+ {
+ return baseDigest.GetByteLength();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/SkeinDigest.cs b/bc-sharp-crypto/src/crypto/digests/SkeinDigest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f826ce503e5dd92bbf53342fb028e7068c48e496
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/SkeinDigest.cs
@@ -0,0 +1,117 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+
+ ///
+ /// Implementation of the Skein parameterised hash function in 256, 512 and 1024 bit block sizes,
+ /// based on the Threefish tweakable block cipher.
+ ///
+ ///
+ /// This is the 1.3 version of Skein defined in the Skein hash function submission to the NIST SHA-3
+ /// competition in October 2010.
+ ///
+ /// Skein was designed by Niels Ferguson - Stefan Lucks - Bruce Schneier - Doug Whiting - Mihir
+ /// Bellare - Tadayoshi Kohno - Jon Callas - Jesse Walker.
+ ///
+ ///
+ ///
+ public class SkeinDigest
+ : IDigest, IMemoable
+ {
+ ///
+ /// 256 bit block size - Skein-256
+ ///
+ public const int SKEIN_256 = SkeinEngine.SKEIN_256;
+ ///
+ /// 512 bit block size - Skein-512
+ ///
+ public const int SKEIN_512 = SkeinEngine.SKEIN_512;
+ ///
+ /// 1024 bit block size - Skein-1024
+ ///
+ public const int SKEIN_1024 = SkeinEngine.SKEIN_1024;
+
+ private readonly SkeinEngine engine;
+
+ ///
+ /// Constructs a Skein digest with an internal state size and output size.
+ ///
+ /// the internal state size in bits - one of or
+ /// .
+ /// the output/digest size to produce in bits, which must be an integral number of
+ /// bytes.
+ public SkeinDigest(int stateSizeBits, int digestSizeBits)
+ {
+ this.engine = new SkeinEngine(stateSizeBits, digestSizeBits);
+ Init(null);
+ }
+
+ public SkeinDigest(SkeinDigest digest)
+ {
+ this.engine = new SkeinEngine(digest.engine);
+ }
+
+ public void Reset(IMemoable other)
+ {
+ SkeinDigest d = (SkeinDigest)other;
+ engine.Reset(d.engine);
+ }
+
+ public IMemoable Copy()
+ {
+ return new SkeinDigest(this);
+ }
+
+ public String AlgorithmName
+ {
+ get { return "Skein-" + (engine.BlockSize * 8) + "-" + (engine.OutputSize * 8); }
+ }
+
+ public int GetDigestSize()
+ {
+ return engine.OutputSize;
+ }
+
+ public int GetByteLength()
+ {
+ return engine.BlockSize;
+ }
+
+ ///
+ /// Optionally initialises the Skein digest with the provided parameters.
+ ///
+ /// See for details on the parameterisation of the Skein hash function.
+ /// the parameters to apply to this engine, or null
to use no parameters.
+ public void Init(SkeinParameters parameters)
+ {
+ engine.Init(parameters);
+ }
+
+ public void Reset()
+ {
+ engine.Reset();
+ }
+
+ public void Update(byte inByte)
+ {
+ engine.Update(inByte);
+ }
+
+ public void BlockUpdate(byte[] inBytes, int inOff, int len)
+ {
+ engine.Update(inBytes, inOff, len);
+ }
+
+ public int DoFinal(byte[] outBytes, int outOff)
+ {
+ return engine.DoFinal(outBytes, outOff);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/crypto/digests/SkeinEngine.cs b/bc-sharp-crypto/src/crypto/digests/SkeinEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cfedfadf36cea21381a96f108a301d67044be487
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/SkeinEngine.cs
@@ -0,0 +1,804 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+
+ ///
+ /// Implementation of the Skein family of parameterised hash functions in 256, 512 and 1024 bit block
+ /// sizes, based on the Threefish tweakable block cipher.
+ ///
+ ///
+ /// This is the 1.3 version of Skein defined in the Skein hash function submission to the NIST SHA-3
+ /// competition in October 2010.
+ ///
+ /// Skein was designed by Niels Ferguson - Stefan Lucks - Bruce Schneier - Doug Whiting - Mihir
+ /// Bellare - Tadayoshi Kohno - Jon Callas - Jesse Walker.
+ ///
+ /// This implementation is the basis for and , implementing the
+ /// parameter based configuration system that allows Skein to be adapted to multiple applications.
+ /// Initialising the engine with allows standard and arbitrary parameters to
+ /// be applied during the Skein hash function.
+ ///
+ /// Implemented:
+ ///
+ /// 256, 512 and 1024 bit internal states.
+ /// Full 96 bit input length.
+ /// Parameters defined in the Skein specification, and arbitrary other pre and post message
+ /// parameters.
+ /// Arbitrary output size in 1 byte intervals.
+ ///
+ ///
+ /// Not implemented:
+ ///
+ /// Sub-byte length input (bit padding).
+ /// Tree hashing.
+ ///
+ ///
+ ///
+ public class SkeinEngine
+ : IMemoable
+ {
+ ///
+ /// 256 bit block size - Skein-256
+ ///
+ public const int SKEIN_256 = ThreefishEngine.BLOCKSIZE_256;
+ ///
+ /// 512 bit block size - Skein-512
+ ///
+ public const int SKEIN_512 = ThreefishEngine.BLOCKSIZE_512;
+ ///
+ /// 1024 bit block size - Skein-1024
+ ///
+ public const int SKEIN_1024 = ThreefishEngine.BLOCKSIZE_1024;
+
+ // Minimal at present, but more complex when tree hashing is implemented
+ private class Configuration
+ {
+ private byte[] bytes = new byte[32];
+
+ public Configuration(long outputSizeBits)
+ {
+ // 0..3 = ASCII SHA3
+ bytes[0] = (byte)'S';
+ bytes[1] = (byte)'H';
+ bytes[2] = (byte)'A';
+ bytes[3] = (byte)'3';
+
+ // 4..5 = version number in LSB order
+ bytes[4] = 1;
+ bytes[5] = 0;
+
+ // 8..15 = output length
+ ThreefishEngine.WordToBytes((ulong)outputSizeBits, bytes, 8);
+ }
+
+ public byte[] Bytes
+ {
+ get { return bytes; }
+ }
+
+ }
+
+ public class Parameter
+ {
+ private int type;
+ private byte[] value;
+
+ public Parameter(int type, byte[] value)
+ {
+ this.type = type;
+ this.value = value;
+ }
+
+ public int Type
+ {
+ get { return type; }
+ }
+
+ public byte[] Value
+ {
+ get { return value; }
+ }
+
+ }
+
+ /**
+ * The parameter type for the Skein key.
+ */
+ private const int PARAM_TYPE_KEY = 0;
+
+ /**
+ * The parameter type for the Skein configuration block.
+ */
+ private const int PARAM_TYPE_CONFIG = 4;
+
+ /**
+ * The parameter type for the message.
+ */
+ private const int PARAM_TYPE_MESSAGE = 48;
+
+ /**
+ * The parameter type for the output transformation.
+ */
+ private const int PARAM_TYPE_OUTPUT = 63;
+
+ /**
+ * Precalculated UBI(CFG) states for common state/output combinations without key or other
+ * pre-message params.
+ */
+ private static readonly IDictionary INITIAL_STATES = Platform.CreateHashtable();
+
+ static SkeinEngine()
+ {
+ // From Appendix C of the Skein 1.3 NIST submission
+ InitialState(SKEIN_256, 128, new ulong[]{
+ 0xe1111906964d7260UL,
+ 0x883daaa77c8d811cUL,
+ 0x10080df491960f7aUL,
+ 0xccf7dde5b45bc1c2UL});
+
+ InitialState(SKEIN_256, 160, new ulong[]{
+ 0x1420231472825e98UL,
+ 0x2ac4e9a25a77e590UL,
+ 0xd47a58568838d63eUL,
+ 0x2dd2e4968586ab7dUL});
+
+ InitialState(SKEIN_256, 224, new ulong[]{
+ 0xc6098a8c9ae5ea0bUL,
+ 0x876d568608c5191cUL,
+ 0x99cb88d7d7f53884UL,
+ 0x384bddb1aeddb5deUL});
+
+ InitialState(SKEIN_256, 256, new ulong[]{
+ 0xfc9da860d048b449UL,
+ 0x2fca66479fa7d833UL,
+ 0xb33bc3896656840fUL,
+ 0x6a54e920fde8da69UL});
+
+ InitialState(SKEIN_512, 128, new ulong[]{
+ 0xa8bc7bf36fbf9f52UL,
+ 0x1e9872cebd1af0aaUL,
+ 0x309b1790b32190d3UL,
+ 0xbcfbb8543f94805cUL,
+ 0x0da61bcd6e31b11bUL,
+ 0x1a18ebead46a32e3UL,
+ 0xa2cc5b18ce84aa82UL,
+ 0x6982ab289d46982dUL});
+
+ InitialState(SKEIN_512, 160, new ulong[]{
+ 0x28b81a2ae013bd91UL,
+ 0xc2f11668b5bdf78fUL,
+ 0x1760d8f3f6a56f12UL,
+ 0x4fb747588239904fUL,
+ 0x21ede07f7eaf5056UL,
+ 0xd908922e63ed70b8UL,
+ 0xb8ec76ffeccb52faUL,
+ 0x01a47bb8a3f27a6eUL});
+
+ InitialState(SKEIN_512, 224, new ulong[]{
+ 0xccd0616248677224UL,
+ 0xcba65cf3a92339efUL,
+ 0x8ccd69d652ff4b64UL,
+ 0x398aed7b3ab890b4UL,
+ 0x0f59d1b1457d2bd0UL,
+ 0x6776fe6575d4eb3dUL,
+ 0x99fbc70e997413e9UL,
+ 0x9e2cfccfe1c41ef7UL});
+
+ InitialState(SKEIN_512, 384, new ulong[]{
+ 0xa3f6c6bf3a75ef5fUL,
+ 0xb0fef9ccfd84faa4UL,
+ 0x9d77dd663d770cfeUL,
+ 0xd798cbf3b468fddaUL,
+ 0x1bc4a6668a0e4465UL,
+ 0x7ed7d434e5807407UL,
+ 0x548fc1acd4ec44d6UL,
+ 0x266e17546aa18ff8UL});
+
+ InitialState(SKEIN_512, 512, new ulong[]{
+ 0x4903adff749c51ceUL,
+ 0x0d95de399746df03UL,
+ 0x8fd1934127c79bceUL,
+ 0x9a255629ff352cb1UL,
+ 0x5db62599df6ca7b0UL,
+ 0xeabe394ca9d5c3f4UL,
+ 0x991112c71a75b523UL,
+ 0xae18a40b660fcc33UL});
+ }
+
+ private static void InitialState(int blockSize, int outputSize, ulong[] state)
+ {
+ INITIAL_STATES.Add(VariantIdentifier(blockSize / 8, outputSize / 8), state);
+ }
+
+ private static int VariantIdentifier(int blockSizeBytes, int outputSizeBytes)
+ {
+ return (outputSizeBytes << 16) | blockSizeBytes;
+ }
+
+ private class UbiTweak
+ {
+ /**
+ * Point at which position might overflow long, so switch to add with carry logic
+ */
+ private const ulong LOW_RANGE = UInt64.MaxValue - UInt32.MaxValue;
+
+ /**
+ * Bit 127 = final
+ */
+ private const ulong T1_FINAL = 1UL << 63;
+
+ /**
+ * Bit 126 = first
+ */
+ private const ulong T1_FIRST = 1UL << 62;
+
+ /**
+ * UBI uses a 128 bit tweak
+ */
+ private ulong[] tweak = new ulong[2];
+
+ /**
+ * Whether 64 bit position exceeded
+ */
+ private bool extendedPosition;
+
+ public UbiTweak()
+ {
+ Reset();
+ }
+
+ public void Reset(UbiTweak tweak)
+ {
+ this.tweak = Arrays.Clone(tweak.tweak, this.tweak);
+ this.extendedPosition = tweak.extendedPosition;
+ }
+
+ public void Reset()
+ {
+ tweak[0] = 0;
+ tweak[1] = 0;
+ extendedPosition = false;
+ First = true;
+ }
+
+ public uint Type
+ {
+ get
+ {
+ return (uint)((tweak[1] >> 56) & 0x3FUL);
+ }
+
+ set
+ {
+ // Bits 120..125 = type
+ tweak[1] = (tweak[1] & 0xFFFFFFC000000000UL) | ((value & 0x3FUL) << 56);
+ }
+ }
+
+ public bool First
+ {
+ get
+ {
+ return ((tweak[1] & T1_FIRST) != 0);
+ }
+ set
+ {
+ if (value)
+ {
+ tweak[1] |= T1_FIRST;
+ }
+ else
+ {
+ tweak[1] &= ~T1_FIRST;
+ }
+ }
+ }
+
+ public bool Final
+ {
+ get
+ {
+ return ((tweak[1] & T1_FINAL) != 0);
+ }
+ set
+ {
+ if (value)
+ {
+ tweak[1] |= T1_FINAL;
+ }
+ else
+ {
+ tweak[1] &= ~T1_FINAL;
+ }
+ }
+ }
+
+ /**
+ * Advances the position in the tweak by the specified value.
+ */
+ public void AdvancePosition(int advance)
+ {
+ // Bits 0..95 = position
+ if (extendedPosition)
+ {
+ ulong[] parts = new ulong[3];
+ parts[0] = tweak[0] & 0xFFFFFFFFUL;
+ parts[1] = (tweak[0] >> 32) & 0xFFFFFFFFUL;
+ parts[2] = tweak[1] & 0xFFFFFFFFUL;
+
+ ulong carry = (ulong)advance;
+ for (int i = 0; i < parts.Length; i++)
+ {
+ carry += parts[i];
+ parts[i] = carry;
+ carry >>= 32;
+ }
+ tweak[0] = ((parts[1] & 0xFFFFFFFFUL) << 32) | (parts[0] & 0xFFFFFFFFUL);
+ tweak[1] = (tweak[1] & 0xFFFFFFFF00000000UL) | (parts[2] & 0xFFFFFFFFUL);
+ }
+ else
+ {
+ ulong position = tweak[0];
+ position += (uint)advance;
+ tweak[0] = position;
+ if (position > LOW_RANGE)
+ {
+ extendedPosition = true;
+ }
+ }
+ }
+
+ public ulong[] GetWords()
+ {
+ return tweak;
+ }
+
+ public override string ToString()
+ {
+ return Type + " first: " + First + ", final: " + Final;
+ }
+
+ }
+
+ /**
+ * The Unique Block Iteration chaining mode.
+ */
+ // TODO: This might be better as methods...
+ private class UBI
+ {
+ private readonly UbiTweak tweak = new UbiTweak();
+
+ private readonly SkeinEngine engine;
+
+ /**
+ * Buffer for the current block of message data
+ */
+ private byte[] currentBlock;
+
+ /**
+ * Offset into the current message block
+ */
+ private int currentOffset;
+
+ /**
+ * Buffer for message words for feedback into encrypted block
+ */
+ private ulong[] message;
+
+ public UBI(SkeinEngine engine, int blockSize)
+ {
+ this.engine = engine;
+ currentBlock = new byte[blockSize];
+ message = new ulong[currentBlock.Length / 8];
+ }
+
+ public void Reset(UBI ubi)
+ {
+ currentBlock = Arrays.Clone(ubi.currentBlock, currentBlock);
+ currentOffset = ubi.currentOffset;
+ message = Arrays.Clone(ubi.message, this.message);
+ tweak.Reset(ubi.tweak);
+ }
+
+ public void Reset(int type)
+ {
+ tweak.Reset();
+ tweak.Type = (uint)type;
+ currentOffset = 0;
+ }
+
+ public void Update(byte[] value, int offset, int len, ulong[] output)
+ {
+ /*
+ * Buffer complete blocks for the underlying Threefish cipher, only flushing when there
+ * are subsequent bytes (last block must be processed in doFinal() with final=true set).
+ */
+ int copied = 0;
+ while (len > copied)
+ {
+ if (currentOffset == currentBlock.Length)
+ {
+ ProcessBlock(output);
+ tweak.First = false;
+ currentOffset = 0;
+ }
+
+ int toCopy = System.Math.Min((len - copied), currentBlock.Length - currentOffset);
+ Array.Copy(value, offset + copied, currentBlock, currentOffset, toCopy);
+ copied += toCopy;
+ currentOffset += toCopy;
+ tweak.AdvancePosition(toCopy);
+ }
+ }
+
+ private void ProcessBlock(ulong[] output)
+ {
+ engine.threefish.Init(true, engine.chain, tweak.GetWords());
+ for (int i = 0; i < message.Length; i++)
+ {
+ message[i] = ThreefishEngine.BytesToWord(currentBlock, i * 8);
+ }
+
+ engine.threefish.ProcessBlock(message, output);
+
+ for (int i = 0; i < output.Length; i++)
+ {
+ output[i] ^= message[i];
+ }
+ }
+
+ public void DoFinal(ulong[] output)
+ {
+ // Pad remainder of current block with zeroes
+ for (int i = currentOffset; i < currentBlock.Length; i++)
+ {
+ currentBlock[i] = 0;
+ }
+
+ tweak.Final = true;
+ ProcessBlock(output);
+ }
+
+ }
+
+ /**
+ * Underlying Threefish tweakable block cipher
+ */
+ private readonly ThreefishEngine threefish;
+
+ /**
+ * Size of the digest output, in bytes
+ */
+ private readonly int outputSizeBytes;
+
+ /**
+ * The current chaining/state value
+ */
+ private ulong[] chain;
+
+ /**
+ * The initial state value
+ */
+ private ulong[] initialState;
+
+ /**
+ * The (optional) key parameter
+ */
+ private byte[] key;
+
+ /**
+ * Parameters to apply prior to the message
+ */
+ private Parameter[] preMessageParameters;
+
+ /**
+ * Parameters to apply after the message, but prior to output
+ */
+ private Parameter[] postMessageParameters;
+
+ /**
+ * The current UBI operation
+ */
+ private readonly UBI ubi;
+
+ /**
+ * Buffer for single byte update method
+ */
+ private readonly byte[] singleByte = new byte[1];
+
+ ///
+ /// Constructs a Skein digest with an internal state size and output size.
+ ///
+ /// the internal state size in bits - one of or
+ /// .
+ /// the output/digest size to produce in bits, which must be an integral number of
+ /// bytes.
+ public SkeinEngine(int blockSizeBits, int outputSizeBits)
+ {
+ if (outputSizeBits % 8 != 0)
+ {
+ throw new ArgumentException("Output size must be a multiple of 8 bits. :" + outputSizeBits);
+ }
+ // TODO: Prevent digest sizes > block size?
+ this.outputSizeBytes = outputSizeBits / 8;
+
+ this.threefish = new ThreefishEngine(blockSizeBits);
+ this.ubi = new UBI(this,threefish.GetBlockSize());
+ }
+
+ ///
+ /// Creates a SkeinEngine as an exact copy of an existing instance.
+ ///
+ public SkeinEngine(SkeinEngine engine)
+ : this(engine.BlockSize * 8, engine.OutputSize * 8)
+ {
+ CopyIn(engine);
+ }
+
+ private void CopyIn(SkeinEngine engine)
+ {
+ this.ubi.Reset(engine.ubi);
+ this.chain = Arrays.Clone(engine.chain, this.chain);
+ this.initialState = Arrays.Clone(engine.initialState, this.initialState);
+ this.key = Arrays.Clone(engine.key, this.key);
+ this.preMessageParameters = Clone(engine.preMessageParameters, this.preMessageParameters);
+ this.postMessageParameters = Clone(engine.postMessageParameters, this.postMessageParameters);
+ }
+
+ private static Parameter[] Clone(Parameter[] data, Parameter[] existing)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ if ((existing == null) || (existing.Length != data.Length))
+ {
+ existing = new Parameter[data.Length];
+ }
+ Array.Copy(data, 0, existing, 0, existing.Length);
+ return existing;
+ }
+
+ public IMemoable Copy()
+ {
+ return new SkeinEngine(this);
+ }
+
+ public void Reset(IMemoable other)
+ {
+ SkeinEngine s = (SkeinEngine)other;
+ if ((BlockSize != s.BlockSize) || (outputSizeBytes != s.outputSizeBytes))
+ {
+ throw new MemoableResetException("Incompatible parameters in provided SkeinEngine.");
+ }
+ CopyIn(s);
+ }
+
+ public int OutputSize
+ {
+ get { return outputSizeBytes; }
+ }
+
+ public int BlockSize
+ {
+ get { return threefish.GetBlockSize (); }
+ }
+
+ ///
+ /// Initialises the Skein engine with the provided parameters. See for
+ /// details on the parameterisation of the Skein hash function.
+ ///
+ /// the parameters to apply to this engine, or null
to use no parameters.
+ public void Init(SkeinParameters parameters)
+ {
+ this.chain = null;
+ this.key = null;
+ this.preMessageParameters = null;
+ this.postMessageParameters = null;
+
+ if (parameters != null)
+ {
+ byte[] key = parameters.GetKey();
+ if (key.Length < 16)
+ {
+ throw new ArgumentException("Skein key must be at least 128 bits.");
+ }
+ InitParams(parameters.GetParameters());
+ }
+ CreateInitialState();
+
+ // Initialise message block
+ UbiInit(PARAM_TYPE_MESSAGE);
+ }
+
+ private void InitParams(IDictionary parameters)
+ {
+ IEnumerator keys = parameters.Keys.GetEnumerator();
+ IList pre = Platform.CreateArrayList();
+ IList post = Platform.CreateArrayList();
+
+ while (keys.MoveNext())
+ {
+ int type = (int)keys.Current;
+ byte[] value = (byte[])parameters[type];
+
+ if (type == PARAM_TYPE_KEY)
+ {
+ this.key = value;
+ }
+ else if (type < PARAM_TYPE_MESSAGE)
+ {
+ pre.Add(new Parameter(type, value));
+ }
+ else
+ {
+ post.Add(new Parameter(type, value));
+ }
+ }
+ preMessageParameters = new Parameter[pre.Count];
+ pre.CopyTo(preMessageParameters, 0);
+ Array.Sort(preMessageParameters);
+
+ postMessageParameters = new Parameter[post.Count];
+ post.CopyTo(postMessageParameters, 0);
+ Array.Sort(postMessageParameters);
+ }
+
+ /**
+ * Calculate the initial (pre message block) chaining state.
+ */
+ private void CreateInitialState()
+ {
+ ulong[] precalc = (ulong[])INITIAL_STATES[VariantIdentifier(BlockSize, OutputSize)];
+ if ((key == null) && (precalc != null))
+ {
+ // Precalculated UBI(CFG)
+ chain = Arrays.Clone(precalc);
+ }
+ else
+ {
+ // Blank initial state
+ chain = new ulong[BlockSize / 8];
+
+ // Process key block
+ if (key != null)
+ {
+ UbiComplete(SkeinParameters.PARAM_TYPE_KEY, key);
+ }
+
+ // Process configuration block
+ UbiComplete(PARAM_TYPE_CONFIG, new Configuration(outputSizeBytes * 8).Bytes);
+ }
+
+ // Process additional pre-message parameters
+ if (preMessageParameters != null)
+ {
+ for (int i = 0; i < preMessageParameters.Length; i++)
+ {
+ Parameter param = preMessageParameters[i];
+ UbiComplete(param.Type, param.Value);
+ }
+ }
+ initialState = Arrays.Clone(chain);
+ }
+
+ ///
+ /// Reset the engine to the initial state (with the key and any pre-message parameters , ready to
+ /// accept message input.
+ ///
+ public void Reset()
+ {
+ Array.Copy(initialState, 0, chain, 0, chain.Length);
+
+ UbiInit(PARAM_TYPE_MESSAGE);
+ }
+
+ private void UbiComplete(int type, byte[] value)
+ {
+ UbiInit(type);
+ this.ubi.Update(value, 0, value.Length, chain);
+ UbiFinal();
+ }
+
+ private void UbiInit(int type)
+ {
+ this.ubi.Reset(type);
+ }
+
+ private void UbiFinal()
+ {
+ ubi.DoFinal(chain);
+ }
+
+ private void CheckInitialised()
+ {
+ if (this.ubi == null)
+ {
+ throw new ArgumentException("Skein engine is not initialised.");
+ }
+ }
+
+ public void Update(byte inByte)
+ {
+ singleByte[0] = inByte;
+ Update(singleByte, 0, 1);
+ }
+
+ public void Update(byte[] inBytes, int inOff, int len)
+ {
+ CheckInitialised();
+ ubi.Update(inBytes, inOff, len, chain);
+ }
+
+ public int DoFinal(byte[] outBytes, int outOff)
+ {
+ CheckInitialised();
+ if (outBytes.Length < (outOff + outputSizeBytes))
+ {
+ throw new DataLengthException("Output buffer is too short to hold output");
+ }
+
+ // Finalise message block
+ UbiFinal();
+
+ // Process additional post-message parameters
+ if (postMessageParameters != null)
+ {
+ for (int i = 0; i < postMessageParameters.Length; i++)
+ {
+ Parameter param = postMessageParameters[i];
+ UbiComplete(param.Type, param.Value);
+ }
+ }
+
+ // Perform the output transform
+ int blockSize = BlockSize;
+ int blocksRequired = ((outputSizeBytes + blockSize - 1) / blockSize);
+ for (int i = 0; i < blocksRequired; i++)
+ {
+ int toWrite = System.Math.Min(blockSize, outputSizeBytes - (i * blockSize));
+ Output((ulong)i, outBytes, outOff + (i * blockSize), toWrite);
+ }
+
+ Reset();
+
+ return outputSizeBytes;
+ }
+
+ private void Output(ulong outputSequence, byte[] outBytes, int outOff, int outputBytes)
+ {
+ byte[] currentBytes = new byte[8];
+ ThreefishEngine.WordToBytes(outputSequence, currentBytes, 0);
+
+ // Output is a sequence of UBI invocations all of which use and preserve the pre-output
+ // state
+ ulong[] outputWords = new ulong[chain.Length];
+ UbiInit(PARAM_TYPE_OUTPUT);
+ this.ubi.Update(currentBytes, 0, currentBytes.Length, outputWords);
+ ubi.DoFinal(outputWords);
+
+ int wordsRequired = ((outputBytes + 8 - 1) / 8);
+ for (int i = 0; i < wordsRequired; i++)
+ {
+ int toWrite = System.Math.Min(8, outputBytes - (i * 8));
+ if (toWrite == 8)
+ {
+ ThreefishEngine.WordToBytes(outputWords[i], outBytes, outOff + (i * 8));
+ }
+ else
+ {
+ ThreefishEngine.WordToBytes(outputWords[i], currentBytes, 0);
+ Array.Copy(currentBytes, 0, outBytes, outOff + (i * 8), toWrite);
+ }
+ }
+ }
+
+ }
+}
+
diff --git a/bc-sharp-crypto/src/crypto/digests/TigerDigest.cs b/bc-sharp-crypto/src/crypto/digests/TigerDigest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..059232de0711466079a64ab5007572115e7ef6ae
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/TigerDigest.cs
@@ -0,0 +1,883 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * implementation of Tiger based on:
+ *
+ * http://www.cs.technion.ac.il/~biham/Reports/Tiger
+ */
+ public class TigerDigest
+ : IDigest, IMemoable
+ {
+ private const int MyByteLength = 64;
+
+ /*
+ * S-Boxes.
+ */
+ private static readonly long[] t1 = {
+ unchecked((long) 0x02AAB17CF7E90C5EL) /* 0 */, unchecked((long) 0xAC424B03E243A8ECL) /* 1 */,
+ unchecked((long) 0x72CD5BE30DD5FCD3L) /* 2 */, unchecked((long) 0x6D019B93F6F97F3AL) /* 3 */,
+ unchecked((long) 0xCD9978FFD21F9193L) /* 4 */, unchecked((long) 0x7573A1C9708029E2L) /* 5 */,
+ unchecked((long) 0xB164326B922A83C3L) /* 6 */, unchecked((long) 0x46883EEE04915870L) /* 7 */,
+ unchecked((long) 0xEAACE3057103ECE6L) /* 8 */, unchecked((long) 0xC54169B808A3535CL) /* 9 */,
+ unchecked((long) 0x4CE754918DDEC47CL) /* 10 */, unchecked((long) 0x0AA2F4DFDC0DF40CL) /* 11 */,
+ unchecked((long) 0x10B76F18A74DBEFAL) /* 12 */, unchecked((long) 0xC6CCB6235AD1AB6AL) /* 13 */,
+ unchecked((long) 0x13726121572FE2FFL) /* 14 */, unchecked((long) 0x1A488C6F199D921EL) /* 15 */,
+ unchecked((long) 0x4BC9F9F4DA0007CAL) /* 16 */, unchecked((long) 0x26F5E6F6E85241C7L) /* 17 */,
+ unchecked((long) 0x859079DBEA5947B6L) /* 18 */, unchecked((long) 0x4F1885C5C99E8C92L) /* 19 */,
+ unchecked((long) 0xD78E761EA96F864BL) /* 20 */, unchecked((long) 0x8E36428C52B5C17DL) /* 21 */,
+ unchecked((long) 0x69CF6827373063C1L) /* 22 */, unchecked((long) 0xB607C93D9BB4C56EL) /* 23 */,
+ unchecked((long) 0x7D820E760E76B5EAL) /* 24 */, unchecked((long) 0x645C9CC6F07FDC42L) /* 25 */,
+ unchecked((long) 0xBF38A078243342E0L) /* 26 */, unchecked((long) 0x5F6B343C9D2E7D04L) /* 27 */,
+ unchecked((long) 0xF2C28AEB600B0EC6L) /* 28 */, unchecked((long) 0x6C0ED85F7254BCACL) /* 29 */,
+ unchecked((long) 0x71592281A4DB4FE5L) /* 30 */, unchecked((long) 0x1967FA69CE0FED9FL) /* 31 */,
+ unchecked((long) 0xFD5293F8B96545DBL) /* 32 */, unchecked((long) 0xC879E9D7F2A7600BL) /* 33 */,
+ unchecked((long) 0x860248920193194EL) /* 34 */, unchecked((long) 0xA4F9533B2D9CC0B3L) /* 35 */,
+ unchecked((long) 0x9053836C15957613L) /* 36 */, unchecked((long) 0xDB6DCF8AFC357BF1L) /* 37 */,
+ unchecked((long) 0x18BEEA7A7A370F57L) /* 38 */, unchecked((long) 0x037117CA50B99066L) /* 39 */,
+ unchecked((long) 0x6AB30A9774424A35L) /* 40 */, unchecked((long) 0xF4E92F02E325249BL) /* 41 */,
+ unchecked((long) 0x7739DB07061CCAE1L) /* 42 */, unchecked((long) 0xD8F3B49CECA42A05L) /* 43 */,
+ unchecked((long) 0xBD56BE3F51382F73L) /* 44 */, unchecked((long) 0x45FAED5843B0BB28L) /* 45 */,
+ unchecked((long) 0x1C813D5C11BF1F83L) /* 46 */, unchecked((long) 0x8AF0E4B6D75FA169L) /* 47 */,
+ unchecked((long) 0x33EE18A487AD9999L) /* 48 */, unchecked((long) 0x3C26E8EAB1C94410L) /* 49 */,
+ unchecked((long) 0xB510102BC0A822F9L) /* 50 */, unchecked((long) 0x141EEF310CE6123BL) /* 51 */,
+ unchecked((long) 0xFC65B90059DDB154L) /* 52 */, unchecked((long) 0xE0158640C5E0E607L) /* 53 */,
+ unchecked((long) 0x884E079826C3A3CFL) /* 54 */, unchecked((long) 0x930D0D9523C535FDL) /* 55 */,
+ unchecked((long) 0x35638D754E9A2B00L) /* 56 */, unchecked((long) 0x4085FCCF40469DD5L) /* 57 */,
+ unchecked((long) 0xC4B17AD28BE23A4CL) /* 58 */, unchecked((long) 0xCAB2F0FC6A3E6A2EL) /* 59 */,
+ unchecked((long) 0x2860971A6B943FCDL) /* 60 */, unchecked((long) 0x3DDE6EE212E30446L) /* 61 */,
+ unchecked((long) 0x6222F32AE01765AEL) /* 62 */, unchecked((long) 0x5D550BB5478308FEL) /* 63 */,
+ unchecked((long) 0xA9EFA98DA0EDA22AL) /* 64 */, unchecked((long) 0xC351A71686C40DA7L) /* 65 */,
+ unchecked((long) 0x1105586D9C867C84L) /* 66 */, unchecked((long) 0xDCFFEE85FDA22853L) /* 67 */,
+ unchecked((long) 0xCCFBD0262C5EEF76L) /* 68 */, unchecked((long) 0xBAF294CB8990D201L) /* 69 */,
+ unchecked((long) 0xE69464F52AFAD975L) /* 70 */, unchecked((long) 0x94B013AFDF133E14L) /* 71 */,
+ unchecked((long) 0x06A7D1A32823C958L) /* 72 */, unchecked((long) 0x6F95FE5130F61119L) /* 73 */,
+ unchecked((long) 0xD92AB34E462C06C0L) /* 74 */, unchecked((long) 0xED7BDE33887C71D2L) /* 75 */,
+ unchecked((long) 0x79746D6E6518393EL) /* 76 */, unchecked((long) 0x5BA419385D713329L) /* 77 */,
+ unchecked((long) 0x7C1BA6B948A97564L) /* 78 */, unchecked((long) 0x31987C197BFDAC67L) /* 79 */,
+ unchecked((long) 0xDE6C23C44B053D02L) /* 80 */, unchecked((long) 0x581C49FED002D64DL) /* 81 */,
+ unchecked((long) 0xDD474D6338261571L) /* 82 */, unchecked((long) 0xAA4546C3E473D062L) /* 83 */,
+ unchecked((long) 0x928FCE349455F860L) /* 84 */, unchecked((long) 0x48161BBACAAB94D9L) /* 85 */,
+ unchecked((long) 0x63912430770E6F68L) /* 86 */, unchecked((long) 0x6EC8A5E602C6641CL) /* 87 */,
+ unchecked((long) 0x87282515337DDD2BL) /* 88 */, unchecked((long) 0x2CDA6B42034B701BL) /* 89 */,
+ unchecked((long) 0xB03D37C181CB096DL) /* 90 */, unchecked((long) 0xE108438266C71C6FL) /* 91 */,
+ unchecked((long) 0x2B3180C7EB51B255L) /* 92 */, unchecked((long) 0xDF92B82F96C08BBCL) /* 93 */,
+ unchecked((long) 0x5C68C8C0A632F3BAL) /* 94 */, unchecked((long) 0x5504CC861C3D0556L) /* 95 */,
+ unchecked((long) 0xABBFA4E55FB26B8FL) /* 96 */, unchecked((long) 0x41848B0AB3BACEB4L) /* 97 */,
+ unchecked((long) 0xB334A273AA445D32L) /* 98 */, unchecked((long) 0xBCA696F0A85AD881L) /* 99 */,
+ unchecked((long) 0x24F6EC65B528D56CL) /* 100 */, unchecked((long) 0x0CE1512E90F4524AL) /* 101 */,
+ unchecked((long) 0x4E9DD79D5506D35AL) /* 102 */, unchecked((long) 0x258905FAC6CE9779L) /* 103 */,
+ unchecked((long) 0x2019295B3E109B33L) /* 104 */, unchecked((long) 0xF8A9478B73A054CCL) /* 105 */,
+ unchecked((long) 0x2924F2F934417EB0L) /* 106 */, unchecked((long) 0x3993357D536D1BC4L) /* 107 */,
+ unchecked((long) 0x38A81AC21DB6FF8BL) /* 108 */, unchecked((long) 0x47C4FBF17D6016BFL) /* 109 */,
+ unchecked((long) 0x1E0FAADD7667E3F5L) /* 110 */, unchecked((long) 0x7ABCFF62938BEB96L) /* 111 */,
+ unchecked((long) 0xA78DAD948FC179C9L) /* 112 */, unchecked((long) 0x8F1F98B72911E50DL) /* 113 */,
+ unchecked((long) 0x61E48EAE27121A91L) /* 114 */, unchecked((long) 0x4D62F7AD31859808L) /* 115 */,
+ unchecked((long) 0xECEBA345EF5CEAEBL) /* 116 */, unchecked((long) 0xF5CEB25EBC9684CEL) /* 117 */,
+ unchecked((long) 0xF633E20CB7F76221L) /* 118 */, unchecked((long) 0xA32CDF06AB8293E4L) /* 119 */,
+ unchecked((long) 0x985A202CA5EE2CA4L) /* 120 */, unchecked((long) 0xCF0B8447CC8A8FB1L) /* 121 */,
+ unchecked((long) 0x9F765244979859A3L) /* 122 */, unchecked((long) 0xA8D516B1A1240017L) /* 123 */,
+ unchecked((long) 0x0BD7BA3EBB5DC726L) /* 124 */, unchecked((long) 0xE54BCA55B86ADB39L) /* 125 */,
+ unchecked((long) 0x1D7A3AFD6C478063L) /* 126 */, unchecked((long) 0x519EC608E7669EDDL) /* 127 */,
+ unchecked((long) 0x0E5715A2D149AA23L) /* 128 */, unchecked((long) 0x177D4571848FF194L) /* 129 */,
+ unchecked((long) 0xEEB55F3241014C22L) /* 130 */, unchecked((long) 0x0F5E5CA13A6E2EC2L) /* 131 */,
+ unchecked((long) 0x8029927B75F5C361L) /* 132 */, unchecked((long) 0xAD139FABC3D6E436L) /* 133 */,
+ unchecked((long) 0x0D5DF1A94CCF402FL) /* 134 */, unchecked((long) 0x3E8BD948BEA5DFC8L) /* 135 */,
+ unchecked((long) 0xA5A0D357BD3FF77EL) /* 136 */, unchecked((long) 0xA2D12E251F74F645L) /* 137 */,
+ unchecked((long) 0x66FD9E525E81A082L) /* 138 */, unchecked((long) 0x2E0C90CE7F687A49L) /* 139 */,
+ unchecked((long) 0xC2E8BCBEBA973BC5L) /* 140 */, unchecked((long) 0x000001BCE509745FL) /* 141 */,
+ unchecked((long) 0x423777BBE6DAB3D6L) /* 142 */, unchecked((long) 0xD1661C7EAEF06EB5L) /* 143 */,
+ unchecked((long) 0xA1781F354DAACFD8L) /* 144 */, unchecked((long) 0x2D11284A2B16AFFCL) /* 145 */,
+ unchecked((long) 0xF1FC4F67FA891D1FL) /* 146 */, unchecked((long) 0x73ECC25DCB920ADAL) /* 147 */,
+ unchecked((long) 0xAE610C22C2A12651L) /* 148 */, unchecked((long) 0x96E0A810D356B78AL) /* 149 */,
+ unchecked((long) 0x5A9A381F2FE7870FL) /* 150 */, unchecked((long) 0xD5AD62EDE94E5530L) /* 151 */,
+ unchecked((long) 0xD225E5E8368D1427L) /* 152 */, unchecked((long) 0x65977B70C7AF4631L) /* 153 */,
+ unchecked((long) 0x99F889B2DE39D74FL) /* 154 */, unchecked((long) 0x233F30BF54E1D143L) /* 155 */,
+ unchecked((long) 0x9A9675D3D9A63C97L) /* 156 */, unchecked((long) 0x5470554FF334F9A8L) /* 157 */,
+ unchecked((long) 0x166ACB744A4F5688L) /* 158 */, unchecked((long) 0x70C74CAAB2E4AEADL) /* 159 */,
+ unchecked((long) 0xF0D091646F294D12L) /* 160 */, unchecked((long) 0x57B82A89684031D1L) /* 161 */,
+ unchecked((long) 0xEFD95A5A61BE0B6BL) /* 162 */, unchecked((long) 0x2FBD12E969F2F29AL) /* 163 */,
+ unchecked((long) 0x9BD37013FEFF9FE8L) /* 164 */, unchecked((long) 0x3F9B0404D6085A06L) /* 165 */,
+ unchecked((long) 0x4940C1F3166CFE15L) /* 166 */, unchecked((long) 0x09542C4DCDF3DEFBL) /* 167 */,
+ unchecked((long) 0xB4C5218385CD5CE3L) /* 168 */, unchecked((long) 0xC935B7DC4462A641L) /* 169 */,
+ unchecked((long) 0x3417F8A68ED3B63FL) /* 170 */, unchecked((long) 0xB80959295B215B40L) /* 171 */,
+ unchecked((long) 0xF99CDAEF3B8C8572L) /* 172 */, unchecked((long) 0x018C0614F8FCB95DL) /* 173 */,
+ unchecked((long) 0x1B14ACCD1A3ACDF3L) /* 174 */, unchecked((long) 0x84D471F200BB732DL) /* 175 */,
+ unchecked((long) 0xC1A3110E95E8DA16L) /* 176 */, unchecked((long) 0x430A7220BF1A82B8L) /* 177 */,
+ unchecked((long) 0xB77E090D39DF210EL) /* 178 */, unchecked((long) 0x5EF4BD9F3CD05E9DL) /* 179 */,
+ unchecked((long) 0x9D4FF6DA7E57A444L) /* 180 */, unchecked((long) 0xDA1D60E183D4A5F8L) /* 181 */,
+ unchecked((long) 0xB287C38417998E47L) /* 182 */, unchecked((long) 0xFE3EDC121BB31886L) /* 183 */,
+ unchecked((long) 0xC7FE3CCC980CCBEFL) /* 184 */, unchecked((long) 0xE46FB590189BFD03L) /* 185 */,
+ unchecked((long) 0x3732FD469A4C57DCL) /* 186 */, unchecked((long) 0x7EF700A07CF1AD65L) /* 187 */,
+ unchecked((long) 0x59C64468A31D8859L) /* 188 */, unchecked((long) 0x762FB0B4D45B61F6L) /* 189 */,
+ unchecked((long) 0x155BAED099047718L) /* 190 */, unchecked((long) 0x68755E4C3D50BAA6L) /* 191 */,
+ unchecked((long) 0xE9214E7F22D8B4DFL) /* 192 */, unchecked((long) 0x2ADDBF532EAC95F4L) /* 193 */,
+ unchecked((long) 0x32AE3909B4BD0109L) /* 194 */, unchecked((long) 0x834DF537B08E3450L) /* 195 */,
+ unchecked((long) 0xFA209DA84220728DL) /* 196 */, unchecked((long) 0x9E691D9B9EFE23F7L) /* 197 */,
+ unchecked((long) 0x0446D288C4AE8D7FL) /* 198 */, unchecked((long) 0x7B4CC524E169785BL) /* 199 */,
+ unchecked((long) 0x21D87F0135CA1385L) /* 200 */, unchecked((long) 0xCEBB400F137B8AA5L) /* 201 */,
+ unchecked((long) 0x272E2B66580796BEL) /* 202 */, unchecked((long) 0x3612264125C2B0DEL) /* 203 */,
+ unchecked((long) 0x057702BDAD1EFBB2L) /* 204 */, unchecked((long) 0xD4BABB8EACF84BE9L) /* 205 */,
+ unchecked((long) 0x91583139641BC67BL) /* 206 */, unchecked((long) 0x8BDC2DE08036E024L) /* 207 */,
+ unchecked((long) 0x603C8156F49F68EDL) /* 208 */, unchecked((long) 0xF7D236F7DBEF5111L) /* 209 */,
+ unchecked((long) 0x9727C4598AD21E80L) /* 210 */, unchecked((long) 0xA08A0896670A5FD7L) /* 211 */,
+ unchecked((long) 0xCB4A8F4309EBA9CBL) /* 212 */, unchecked((long) 0x81AF564B0F7036A1L) /* 213 */,
+ unchecked((long) 0xC0B99AA778199ABDL) /* 214 */, unchecked((long) 0x959F1EC83FC8E952L) /* 215 */,
+ unchecked((long) 0x8C505077794A81B9L) /* 216 */, unchecked((long) 0x3ACAAF8F056338F0L) /* 217 */,
+ unchecked((long) 0x07B43F50627A6778L) /* 218 */, unchecked((long) 0x4A44AB49F5ECCC77L) /* 219 */,
+ unchecked((long) 0x3BC3D6E4B679EE98L) /* 220 */, unchecked((long) 0x9CC0D4D1CF14108CL) /* 221 */,
+ unchecked((long) 0x4406C00B206BC8A0L) /* 222 */, unchecked((long) 0x82A18854C8D72D89L) /* 223 */,
+ unchecked((long) 0x67E366B35C3C432CL) /* 224 */, unchecked((long) 0xB923DD61102B37F2L) /* 225 */,
+ unchecked((long) 0x56AB2779D884271DL) /* 226 */, unchecked((long) 0xBE83E1B0FF1525AFL) /* 227 */,
+ unchecked((long) 0xFB7C65D4217E49A9L) /* 228 */, unchecked((long) 0x6BDBE0E76D48E7D4L) /* 229 */,
+ unchecked((long) 0x08DF828745D9179EL) /* 230 */, unchecked((long) 0x22EA6A9ADD53BD34L) /* 231 */,
+ unchecked((long) 0xE36E141C5622200AL) /* 232 */, unchecked((long) 0x7F805D1B8CB750EEL) /* 233 */,
+ unchecked((long) 0xAFE5C7A59F58E837L) /* 234 */, unchecked((long) 0xE27F996A4FB1C23CL) /* 235 */,
+ unchecked((long) 0xD3867DFB0775F0D0L) /* 236 */, unchecked((long) 0xD0E673DE6E88891AL) /* 237 */,
+ unchecked((long) 0x123AEB9EAFB86C25L) /* 238 */, unchecked((long) 0x30F1D5D5C145B895L) /* 239 */,
+ unchecked((long) 0xBB434A2DEE7269E7L) /* 240 */, unchecked((long) 0x78CB67ECF931FA38L) /* 241 */,
+ unchecked((long) 0xF33B0372323BBF9CL) /* 242 */, unchecked((long) 0x52D66336FB279C74L) /* 243 */,
+ unchecked((long) 0x505F33AC0AFB4EAAL) /* 244 */, unchecked((long) 0xE8A5CD99A2CCE187L) /* 245 */,
+ unchecked((long) 0x534974801E2D30BBL) /* 246 */, unchecked((long) 0x8D2D5711D5876D90L) /* 247 */,
+ unchecked((long) 0x1F1A412891BC038EL) /* 248 */, unchecked((long) 0xD6E2E71D82E56648L) /* 249 */,
+ unchecked((long) 0x74036C3A497732B7L) /* 250 */, unchecked((long) 0x89B67ED96361F5ABL) /* 251 */,
+ unchecked((long) 0xFFED95D8F1EA02A2L) /* 252 */, unchecked((long) 0xE72B3BD61464D43DL) /* 253 */,
+ unchecked((long) 0xA6300F170BDC4820L) /* 254 */, unchecked((long) 0xEBC18760ED78A77AL) /* 255 */,
+ };
+
+ private static readonly long[] t2 = {
+ unchecked((long) 0xE6A6BE5A05A12138L) /* 256 */, unchecked((long) 0xB5A122A5B4F87C98L) /* 257 */,
+ unchecked((long) 0x563C6089140B6990L) /* 258 */, unchecked((long) 0x4C46CB2E391F5DD5L) /* 259 */,
+ unchecked((long) 0xD932ADDBC9B79434L) /* 260 */, unchecked((long) 0x08EA70E42015AFF5L) /* 261 */,
+ unchecked((long) 0xD765A6673E478CF1L) /* 262 */, unchecked((long) 0xC4FB757EAB278D99L) /* 263 */,
+ unchecked((long) 0xDF11C6862D6E0692L) /* 264 */, unchecked((long) 0xDDEB84F10D7F3B16L) /* 265 */,
+ unchecked((long) 0x6F2EF604A665EA04L) /* 266 */, unchecked((long) 0x4A8E0F0FF0E0DFB3L) /* 267 */,
+ unchecked((long) 0xA5EDEEF83DBCBA51L) /* 268 */, unchecked((long) 0xFC4F0A2A0EA4371EL) /* 269 */,
+ unchecked((long) 0xE83E1DA85CB38429L) /* 270 */, unchecked((long) 0xDC8FF882BA1B1CE2L) /* 271 */,
+ unchecked((long) 0xCD45505E8353E80DL) /* 272 */, unchecked((long) 0x18D19A00D4DB0717L) /* 273 */,
+ unchecked((long) 0x34A0CFEDA5F38101L) /* 274 */, unchecked((long) 0x0BE77E518887CAF2L) /* 275 */,
+ unchecked((long) 0x1E341438B3C45136L) /* 276 */, unchecked((long) 0xE05797F49089CCF9L) /* 277 */,
+ unchecked((long) 0xFFD23F9DF2591D14L) /* 278 */, unchecked((long) 0x543DDA228595C5CDL) /* 279 */,
+ unchecked((long) 0x661F81FD99052A33L) /* 280 */, unchecked((long) 0x8736E641DB0F7B76L) /* 281 */,
+ unchecked((long) 0x15227725418E5307L) /* 282 */, unchecked((long) 0xE25F7F46162EB2FAL) /* 283 */,
+ unchecked((long) 0x48A8B2126C13D9FEL) /* 284 */, unchecked((long) 0xAFDC541792E76EEAL) /* 285 */,
+ unchecked((long) 0x03D912BFC6D1898FL) /* 286 */, unchecked((long) 0x31B1AAFA1B83F51BL) /* 287 */,
+ unchecked((long) 0xF1AC2796E42AB7D9L) /* 288 */, unchecked((long) 0x40A3A7D7FCD2EBACL) /* 289 */,
+ unchecked((long) 0x1056136D0AFBBCC5L) /* 290 */, unchecked((long) 0x7889E1DD9A6D0C85L) /* 291 */,
+ unchecked((long) 0xD33525782A7974AAL) /* 292 */, unchecked((long) 0xA7E25D09078AC09BL) /* 293 */,
+ unchecked((long) 0xBD4138B3EAC6EDD0L) /* 294 */, unchecked((long) 0x920ABFBE71EB9E70L) /* 295 */,
+ unchecked((long) 0xA2A5D0F54FC2625CL) /* 296 */, unchecked((long) 0xC054E36B0B1290A3L) /* 297 */,
+ unchecked((long) 0xF6DD59FF62FE932BL) /* 298 */, unchecked((long) 0x3537354511A8AC7DL) /* 299 */,
+ unchecked((long) 0xCA845E9172FADCD4L) /* 300 */, unchecked((long) 0x84F82B60329D20DCL) /* 301 */,
+ unchecked((long) 0x79C62CE1CD672F18L) /* 302 */, unchecked((long) 0x8B09A2ADD124642CL) /* 303 */,
+ unchecked((long) 0xD0C1E96A19D9E726L) /* 304 */, unchecked((long) 0x5A786A9B4BA9500CL) /* 305 */,
+ unchecked((long) 0x0E020336634C43F3L) /* 306 */, unchecked((long) 0xC17B474AEB66D822L) /* 307 */,
+ unchecked((long) 0x6A731AE3EC9BAAC2L) /* 308 */, unchecked((long) 0x8226667AE0840258L) /* 309 */,
+ unchecked((long) 0x67D4567691CAECA5L) /* 310 */, unchecked((long) 0x1D94155C4875ADB5L) /* 311 */,
+ unchecked((long) 0x6D00FD985B813FDFL) /* 312 */, unchecked((long) 0x51286EFCB774CD06L) /* 313 */,
+ unchecked((long) 0x5E8834471FA744AFL) /* 314 */, unchecked((long) 0xF72CA0AEE761AE2EL) /* 315 */,
+ unchecked((long) 0xBE40E4CDAEE8E09AL) /* 316 */, unchecked((long) 0xE9970BBB5118F665L) /* 317 */,
+ unchecked((long) 0x726E4BEB33DF1964L) /* 318 */, unchecked((long) 0x703B000729199762L) /* 319 */,
+ unchecked((long) 0x4631D816F5EF30A7L) /* 320 */, unchecked((long) 0xB880B5B51504A6BEL) /* 321 */,
+ unchecked((long) 0x641793C37ED84B6CL) /* 322 */, unchecked((long) 0x7B21ED77F6E97D96L) /* 323 */,
+ unchecked((long) 0x776306312EF96B73L) /* 324 */, unchecked((long) 0xAE528948E86FF3F4L) /* 325 */,
+ unchecked((long) 0x53DBD7F286A3F8F8L) /* 326 */, unchecked((long) 0x16CADCE74CFC1063L) /* 327 */,
+ unchecked((long) 0x005C19BDFA52C6DDL) /* 328 */, unchecked((long) 0x68868F5D64D46AD3L) /* 329 */,
+ unchecked((long) 0x3A9D512CCF1E186AL) /* 330 */, unchecked((long) 0x367E62C2385660AEL) /* 331 */,
+ unchecked((long) 0xE359E7EA77DCB1D7L) /* 332 */, unchecked((long) 0x526C0773749ABE6EL) /* 333 */,
+ unchecked((long) 0x735AE5F9D09F734BL) /* 334 */, unchecked((long) 0x493FC7CC8A558BA8L) /* 335 */,
+ unchecked((long) 0xB0B9C1533041AB45L) /* 336 */, unchecked((long) 0x321958BA470A59BDL) /* 337 */,
+ unchecked((long) 0x852DB00B5F46C393L) /* 338 */, unchecked((long) 0x91209B2BD336B0E5L) /* 339 */,
+ unchecked((long) 0x6E604F7D659EF19FL) /* 340 */, unchecked((long) 0xB99A8AE2782CCB24L) /* 341 */,
+ unchecked((long) 0xCCF52AB6C814C4C7L) /* 342 */, unchecked((long) 0x4727D9AFBE11727BL) /* 343 */,
+ unchecked((long) 0x7E950D0C0121B34DL) /* 344 */, unchecked((long) 0x756F435670AD471FL) /* 345 */,
+ unchecked((long) 0xF5ADD442615A6849L) /* 346 */, unchecked((long) 0x4E87E09980B9957AL) /* 347 */,
+ unchecked((long) 0x2ACFA1DF50AEE355L) /* 348 */, unchecked((long) 0xD898263AFD2FD556L) /* 349 */,
+ unchecked((long) 0xC8F4924DD80C8FD6L) /* 350 */, unchecked((long) 0xCF99CA3D754A173AL) /* 351 */,
+ unchecked((long) 0xFE477BACAF91BF3CL) /* 352 */, unchecked((long) 0xED5371F6D690C12DL) /* 353 */,
+ unchecked((long) 0x831A5C285E687094L) /* 354 */, unchecked((long) 0xC5D3C90A3708A0A4L) /* 355 */,
+ unchecked((long) 0x0F7F903717D06580L) /* 356 */, unchecked((long) 0x19F9BB13B8FDF27FL) /* 357 */,
+ unchecked((long) 0xB1BD6F1B4D502843L) /* 358 */, unchecked((long) 0x1C761BA38FFF4012L) /* 359 */,
+ unchecked((long) 0x0D1530C4E2E21F3BL) /* 360 */, unchecked((long) 0x8943CE69A7372C8AL) /* 361 */,
+ unchecked((long) 0xE5184E11FEB5CE66L) /* 362 */, unchecked((long) 0x618BDB80BD736621L) /* 363 */,
+ unchecked((long) 0x7D29BAD68B574D0BL) /* 364 */, unchecked((long) 0x81BB613E25E6FE5BL) /* 365 */,
+ unchecked((long) 0x071C9C10BC07913FL) /* 366 */, unchecked((long) 0xC7BEEB7909AC2D97L) /* 367 */,
+ unchecked((long) 0xC3E58D353BC5D757L) /* 368 */, unchecked((long) 0xEB017892F38F61E8L) /* 369 */,
+ unchecked((long) 0xD4EFFB9C9B1CC21AL) /* 370 */, unchecked((long) 0x99727D26F494F7ABL) /* 371 */,
+ unchecked((long) 0xA3E063A2956B3E03L) /* 372 */, unchecked((long) 0x9D4A8B9A4AA09C30L) /* 373 */,
+ unchecked((long) 0x3F6AB7D500090FB4L) /* 374 */, unchecked((long) 0x9CC0F2A057268AC0L) /* 375 */,
+ unchecked((long) 0x3DEE9D2DEDBF42D1L) /* 376 */, unchecked((long) 0x330F49C87960A972L) /* 377 */,
+ unchecked((long) 0xC6B2720287421B41L) /* 378 */, unchecked((long) 0x0AC59EC07C00369CL) /* 379 */,
+ unchecked((long) 0xEF4EAC49CB353425L) /* 380 */, unchecked((long) 0xF450244EEF0129D8L) /* 381 */,
+ unchecked((long) 0x8ACC46E5CAF4DEB6L) /* 382 */, unchecked((long) 0x2FFEAB63989263F7L) /* 383 */,
+ unchecked((long) 0x8F7CB9FE5D7A4578L) /* 384 */, unchecked((long) 0x5BD8F7644E634635L) /* 385 */,
+ unchecked((long) 0x427A7315BF2DC900L) /* 386 */, unchecked((long) 0x17D0C4AA2125261CL) /* 387 */,
+ unchecked((long) 0x3992486C93518E50L) /* 388 */, unchecked((long) 0xB4CBFEE0A2D7D4C3L) /* 389 */,
+ unchecked((long) 0x7C75D6202C5DDD8DL) /* 390 */, unchecked((long) 0xDBC295D8E35B6C61L) /* 391 */,
+ unchecked((long) 0x60B369D302032B19L) /* 392 */, unchecked((long) 0xCE42685FDCE44132L) /* 393 */,
+ unchecked((long) 0x06F3DDB9DDF65610L) /* 394 */, unchecked((long) 0x8EA4D21DB5E148F0L) /* 395 */,
+ unchecked((long) 0x20B0FCE62FCD496FL) /* 396 */, unchecked((long) 0x2C1B912358B0EE31L) /* 397 */,
+ unchecked((long) 0xB28317B818F5A308L) /* 398 */, unchecked((long) 0xA89C1E189CA6D2CFL) /* 399 */,
+ unchecked((long) 0x0C6B18576AAADBC8L) /* 400 */, unchecked((long) 0xB65DEAA91299FAE3L) /* 401 */,
+ unchecked((long) 0xFB2B794B7F1027E7L) /* 402 */, unchecked((long) 0x04E4317F443B5BEBL) /* 403 */,
+ unchecked((long) 0x4B852D325939D0A6L) /* 404 */, unchecked((long) 0xD5AE6BEEFB207FFCL) /* 405 */,
+ unchecked((long) 0x309682B281C7D374L) /* 406 */, unchecked((long) 0xBAE309A194C3B475L) /* 407 */,
+ unchecked((long) 0x8CC3F97B13B49F05L) /* 408 */, unchecked((long) 0x98A9422FF8293967L) /* 409 */,
+ unchecked((long) 0x244B16B01076FF7CL) /* 410 */, unchecked((long) 0xF8BF571C663D67EEL) /* 411 */,
+ unchecked((long) 0x1F0D6758EEE30DA1L) /* 412 */, unchecked((long) 0xC9B611D97ADEB9B7L) /* 413 */,
+ unchecked((long) 0xB7AFD5887B6C57A2L) /* 414 */, unchecked((long) 0x6290AE846B984FE1L) /* 415 */,
+ unchecked((long) 0x94DF4CDEACC1A5FDL) /* 416 */, unchecked((long) 0x058A5BD1C5483AFFL) /* 417 */,
+ unchecked((long) 0x63166CC142BA3C37L) /* 418 */, unchecked((long) 0x8DB8526EB2F76F40L) /* 419 */,
+ unchecked((long) 0xE10880036F0D6D4EL) /* 420 */, unchecked((long) 0x9E0523C9971D311DL) /* 421 */,
+ unchecked((long) 0x45EC2824CC7CD691L) /* 422 */, unchecked((long) 0x575B8359E62382C9L) /* 423 */,
+ unchecked((long) 0xFA9E400DC4889995L) /* 424 */, unchecked((long) 0xD1823ECB45721568L) /* 425 */,
+ unchecked((long) 0xDAFD983B8206082FL) /* 426 */, unchecked((long) 0xAA7D29082386A8CBL) /* 427 */,
+ unchecked((long) 0x269FCD4403B87588L) /* 428 */, unchecked((long) 0x1B91F5F728BDD1E0L) /* 429 */,
+ unchecked((long) 0xE4669F39040201F6L) /* 430 */, unchecked((long) 0x7A1D7C218CF04ADEL) /* 431 */,
+ unchecked((long) 0x65623C29D79CE5CEL) /* 432 */, unchecked((long) 0x2368449096C00BB1L) /* 433 */,
+ unchecked((long) 0xAB9BF1879DA503BAL) /* 434 */, unchecked((long) 0xBC23ECB1A458058EL) /* 435 */,
+ unchecked((long) 0x9A58DF01BB401ECCL) /* 436 */, unchecked((long) 0xA070E868A85F143DL) /* 437 */,
+ unchecked((long) 0x4FF188307DF2239EL) /* 438 */, unchecked((long) 0x14D565B41A641183L) /* 439 */,
+ unchecked((long) 0xEE13337452701602L) /* 440 */, unchecked((long) 0x950E3DCF3F285E09L) /* 441 */,
+ unchecked((long) 0x59930254B9C80953L) /* 442 */, unchecked((long) 0x3BF299408930DA6DL) /* 443 */,
+ unchecked((long) 0xA955943F53691387L) /* 444 */, unchecked((long) 0xA15EDECAA9CB8784L) /* 445 */,
+ unchecked((long) 0x29142127352BE9A0L) /* 446 */, unchecked((long) 0x76F0371FFF4E7AFBL) /* 447 */,
+ unchecked((long) 0x0239F450274F2228L) /* 448 */, unchecked((long) 0xBB073AF01D5E868BL) /* 449 */,
+ unchecked((long) 0xBFC80571C10E96C1L) /* 450 */, unchecked((long) 0xD267088568222E23L) /* 451 */,
+ unchecked((long) 0x9671A3D48E80B5B0L) /* 452 */, unchecked((long) 0x55B5D38AE193BB81L) /* 453 */,
+ unchecked((long) 0x693AE2D0A18B04B8L) /* 454 */, unchecked((long) 0x5C48B4ECADD5335FL) /* 455 */,
+ unchecked((long) 0xFD743B194916A1CAL) /* 456 */, unchecked((long) 0x2577018134BE98C4L) /* 457 */,
+ unchecked((long) 0xE77987E83C54A4ADL) /* 458 */, unchecked((long) 0x28E11014DA33E1B9L) /* 459 */,
+ unchecked((long) 0x270CC59E226AA213L) /* 460 */, unchecked((long) 0x71495F756D1A5F60L) /* 461 */,
+ unchecked((long) 0x9BE853FB60AFEF77L) /* 462 */, unchecked((long) 0xADC786A7F7443DBFL) /* 463 */,
+ unchecked((long) 0x0904456173B29A82L) /* 464 */, unchecked((long) 0x58BC7A66C232BD5EL) /* 465 */,
+ unchecked((long) 0xF306558C673AC8B2L) /* 466 */, unchecked((long) 0x41F639C6B6C9772AL) /* 467 */,
+ unchecked((long) 0x216DEFE99FDA35DAL) /* 468 */, unchecked((long) 0x11640CC71C7BE615L) /* 469 */,
+ unchecked((long) 0x93C43694565C5527L) /* 470 */, unchecked((long) 0xEA038E6246777839L) /* 471 */,
+ unchecked((long) 0xF9ABF3CE5A3E2469L) /* 472 */, unchecked((long) 0x741E768D0FD312D2L) /* 473 */,
+ unchecked((long) 0x0144B883CED652C6L) /* 474 */, unchecked((long) 0xC20B5A5BA33F8552L) /* 475 */,
+ unchecked((long) 0x1AE69633C3435A9DL) /* 476 */, unchecked((long) 0x97A28CA4088CFDECL) /* 477 */,
+ unchecked((long) 0x8824A43C1E96F420L) /* 478 */, unchecked((long) 0x37612FA66EEEA746L) /* 479 */,
+ unchecked((long) 0x6B4CB165F9CF0E5AL) /* 480 */, unchecked((long) 0x43AA1C06A0ABFB4AL) /* 481 */,
+ unchecked((long) 0x7F4DC26FF162796BL) /* 482 */, unchecked((long) 0x6CBACC8E54ED9B0FL) /* 483 */,
+ unchecked((long) 0xA6B7FFEFD2BB253EL) /* 484 */, unchecked((long) 0x2E25BC95B0A29D4FL) /* 485 */,
+ unchecked((long) 0x86D6A58BDEF1388CL) /* 486 */, unchecked((long) 0xDED74AC576B6F054L) /* 487 */,
+ unchecked((long) 0x8030BDBC2B45805DL) /* 488 */, unchecked((long) 0x3C81AF70E94D9289L) /* 489 */,
+ unchecked((long) 0x3EFF6DDA9E3100DBL) /* 490 */, unchecked((long) 0xB38DC39FDFCC8847L) /* 491 */,
+ unchecked((long) 0x123885528D17B87EL) /* 492 */, unchecked((long) 0xF2DA0ED240B1B642L) /* 493 */,
+ unchecked((long) 0x44CEFADCD54BF9A9L) /* 494 */, unchecked((long) 0x1312200E433C7EE6L) /* 495 */,
+ unchecked((long) 0x9FFCC84F3A78C748L) /* 496 */, unchecked((long) 0xF0CD1F72248576BBL) /* 497 */,
+ unchecked((long) 0xEC6974053638CFE4L) /* 498 */, unchecked((long) 0x2BA7B67C0CEC4E4CL) /* 499 */,
+ unchecked((long) 0xAC2F4DF3E5CE32EDL) /* 500 */, unchecked((long) 0xCB33D14326EA4C11L) /* 501 */,
+ unchecked((long) 0xA4E9044CC77E58BCL) /* 502 */, unchecked((long) 0x5F513293D934FCEFL) /* 503 */,
+ unchecked((long) 0x5DC9645506E55444L) /* 504 */, unchecked((long) 0x50DE418F317DE40AL) /* 505 */,
+ unchecked((long) 0x388CB31A69DDE259L) /* 506 */, unchecked((long) 0x2DB4A83455820A86L) /* 507 */,
+ unchecked((long) 0x9010A91E84711AE9L) /* 508 */, unchecked((long) 0x4DF7F0B7B1498371L) /* 509 */,
+ unchecked((long) 0xD62A2EABC0977179L) /* 510 */, unchecked((long) 0x22FAC097AA8D5C0EL) /* 511 */,
+ };
+
+ private static readonly long[] t3 = {
+ unchecked((long) 0xF49FCC2FF1DAF39BL) /* 512 */, unchecked((long) 0x487FD5C66FF29281L) /* 513 */,
+ unchecked((long) 0xE8A30667FCDCA83FL) /* 514 */, unchecked((long) 0x2C9B4BE3D2FCCE63L) /* 515 */,
+ unchecked((long) 0xDA3FF74B93FBBBC2L) /* 516 */, unchecked((long) 0x2FA165D2FE70BA66L) /* 517 */,
+ unchecked((long) 0xA103E279970E93D4L) /* 518 */, unchecked((long) 0xBECDEC77B0E45E71L) /* 519 */,
+ unchecked((long) 0xCFB41E723985E497L) /* 520 */, unchecked((long) 0xB70AAA025EF75017L) /* 521 */,
+ unchecked((long) 0xD42309F03840B8E0L) /* 522 */, unchecked((long) 0x8EFC1AD035898579L) /* 523 */,
+ unchecked((long) 0x96C6920BE2B2ABC5L) /* 524 */, unchecked((long) 0x66AF4163375A9172L) /* 525 */,
+ unchecked((long) 0x2174ABDCCA7127FBL) /* 526 */, unchecked((long) 0xB33CCEA64A72FF41L) /* 527 */,
+ unchecked((long) 0xF04A4933083066A5L) /* 528 */, unchecked((long) 0x8D970ACDD7289AF5L) /* 529 */,
+ unchecked((long) 0x8F96E8E031C8C25EL) /* 530 */, unchecked((long) 0xF3FEC02276875D47L) /* 531 */,
+ unchecked((long) 0xEC7BF310056190DDL) /* 532 */, unchecked((long) 0xF5ADB0AEBB0F1491L) /* 533 */,
+ unchecked((long) 0x9B50F8850FD58892L) /* 534 */, unchecked((long) 0x4975488358B74DE8L) /* 535 */,
+ unchecked((long) 0xA3354FF691531C61L) /* 536 */, unchecked((long) 0x0702BBE481D2C6EEL) /* 537 */,
+ unchecked((long) 0x89FB24057DEDED98L) /* 538 */, unchecked((long) 0xAC3075138596E902L) /* 539 */,
+ unchecked((long) 0x1D2D3580172772EDL) /* 540 */, unchecked((long) 0xEB738FC28E6BC30DL) /* 541 */,
+ unchecked((long) 0x5854EF8F63044326L) /* 542 */, unchecked((long) 0x9E5C52325ADD3BBEL) /* 543 */,
+ unchecked((long) 0x90AA53CF325C4623L) /* 544 */, unchecked((long) 0xC1D24D51349DD067L) /* 545 */,
+ unchecked((long) 0x2051CFEEA69EA624L) /* 546 */, unchecked((long) 0x13220F0A862E7E4FL) /* 547 */,
+ unchecked((long) 0xCE39399404E04864L) /* 548 */, unchecked((long) 0xD9C42CA47086FCB7L) /* 549 */,
+ unchecked((long) 0x685AD2238A03E7CCL) /* 550 */, unchecked((long) 0x066484B2AB2FF1DBL) /* 551 */,
+ unchecked((long) 0xFE9D5D70EFBF79ECL) /* 552 */, unchecked((long) 0x5B13B9DD9C481854L) /* 553 */,
+ unchecked((long) 0x15F0D475ED1509ADL) /* 554 */, unchecked((long) 0x0BEBCD060EC79851L) /* 555 */,
+ unchecked((long) 0xD58C6791183AB7F8L) /* 556 */, unchecked((long) 0xD1187C5052F3EEE4L) /* 557 */,
+ unchecked((long) 0xC95D1192E54E82FFL) /* 558 */, unchecked((long) 0x86EEA14CB9AC6CA2L) /* 559 */,
+ unchecked((long) 0x3485BEB153677D5DL) /* 560 */, unchecked((long) 0xDD191D781F8C492AL) /* 561 */,
+ unchecked((long) 0xF60866BAA784EBF9L) /* 562 */, unchecked((long) 0x518F643BA2D08C74L) /* 563 */,
+ unchecked((long) 0x8852E956E1087C22L) /* 564 */, unchecked((long) 0xA768CB8DC410AE8DL) /* 565 */,
+ unchecked((long) 0x38047726BFEC8E1AL) /* 566 */, unchecked((long) 0xA67738B4CD3B45AAL) /* 567 */,
+ unchecked((long) 0xAD16691CEC0DDE19L) /* 568 */, unchecked((long) 0xC6D4319380462E07L) /* 569 */,
+ unchecked((long) 0xC5A5876D0BA61938L) /* 570 */, unchecked((long) 0x16B9FA1FA58FD840L) /* 571 */,
+ unchecked((long) 0x188AB1173CA74F18L) /* 572 */, unchecked((long) 0xABDA2F98C99C021FL) /* 573 */,
+ unchecked((long) 0x3E0580AB134AE816L) /* 574 */, unchecked((long) 0x5F3B05B773645ABBL) /* 575 */,
+ unchecked((long) 0x2501A2BE5575F2F6L) /* 576 */, unchecked((long) 0x1B2F74004E7E8BA9L) /* 577 */,
+ unchecked((long) 0x1CD7580371E8D953L) /* 578 */, unchecked((long) 0x7F6ED89562764E30L) /* 579 */,
+ unchecked((long) 0xB15926FF596F003DL) /* 580 */, unchecked((long) 0x9F65293DA8C5D6B9L) /* 581 */,
+ unchecked((long) 0x6ECEF04DD690F84CL) /* 582 */, unchecked((long) 0x4782275FFF33AF88L) /* 583 */,
+ unchecked((long) 0xE41433083F820801L) /* 584 */, unchecked((long) 0xFD0DFE409A1AF9B5L) /* 585 */,
+ unchecked((long) 0x4325A3342CDB396BL) /* 586 */, unchecked((long) 0x8AE77E62B301B252L) /* 587 */,
+ unchecked((long) 0xC36F9E9F6655615AL) /* 588 */, unchecked((long) 0x85455A2D92D32C09L) /* 589 */,
+ unchecked((long) 0xF2C7DEA949477485L) /* 590 */, unchecked((long) 0x63CFB4C133A39EBAL) /* 591 */,
+ unchecked((long) 0x83B040CC6EBC5462L) /* 592 */, unchecked((long) 0x3B9454C8FDB326B0L) /* 593 */,
+ unchecked((long) 0x56F56A9E87FFD78CL) /* 594 */, unchecked((long) 0x2DC2940D99F42BC6L) /* 595 */,
+ unchecked((long) 0x98F7DF096B096E2DL) /* 596 */, unchecked((long) 0x19A6E01E3AD852BFL) /* 597 */,
+ unchecked((long) 0x42A99CCBDBD4B40BL) /* 598 */, unchecked((long) 0xA59998AF45E9C559L) /* 599 */,
+ unchecked((long) 0x366295E807D93186L) /* 600 */, unchecked((long) 0x6B48181BFAA1F773L) /* 601 */,
+ unchecked((long) 0x1FEC57E2157A0A1DL) /* 602 */, unchecked((long) 0x4667446AF6201AD5L) /* 603 */,
+ unchecked((long) 0xE615EBCACFB0F075L) /* 604 */, unchecked((long) 0xB8F31F4F68290778L) /* 605 */,
+ unchecked((long) 0x22713ED6CE22D11EL) /* 606 */, unchecked((long) 0x3057C1A72EC3C93BL) /* 607 */,
+ unchecked((long) 0xCB46ACC37C3F1F2FL) /* 608 */, unchecked((long) 0xDBB893FD02AAF50EL) /* 609 */,
+ unchecked((long) 0x331FD92E600B9FCFL) /* 610 */, unchecked((long) 0xA498F96148EA3AD6L) /* 611 */,
+ unchecked((long) 0xA8D8426E8B6A83EAL) /* 612 */, unchecked((long) 0xA089B274B7735CDCL) /* 613 */,
+ unchecked((long) 0x87F6B3731E524A11L) /* 614 */, unchecked((long) 0x118808E5CBC96749L) /* 615 */,
+ unchecked((long) 0x9906E4C7B19BD394L) /* 616 */, unchecked((long) 0xAFED7F7E9B24A20CL) /* 617 */,
+ unchecked((long) 0x6509EADEEB3644A7L) /* 618 */, unchecked((long) 0x6C1EF1D3E8EF0EDEL) /* 619 */,
+ unchecked((long) 0xB9C97D43E9798FB4L) /* 620 */, unchecked((long) 0xA2F2D784740C28A3L) /* 621 */,
+ unchecked((long) 0x7B8496476197566FL) /* 622 */, unchecked((long) 0x7A5BE3E6B65F069DL) /* 623 */,
+ unchecked((long) 0xF96330ED78BE6F10L) /* 624 */, unchecked((long) 0xEEE60DE77A076A15L) /* 625 */,
+ unchecked((long) 0x2B4BEE4AA08B9BD0L) /* 626 */, unchecked((long) 0x6A56A63EC7B8894EL) /* 627 */,
+ unchecked((long) 0x02121359BA34FEF4L) /* 628 */, unchecked((long) 0x4CBF99F8283703FCL) /* 629 */,
+ unchecked((long) 0x398071350CAF30C8L) /* 630 */, unchecked((long) 0xD0A77A89F017687AL) /* 631 */,
+ unchecked((long) 0xF1C1A9EB9E423569L) /* 632 */, unchecked((long) 0x8C7976282DEE8199L) /* 633 */,
+ unchecked((long) 0x5D1737A5DD1F7ABDL) /* 634 */, unchecked((long) 0x4F53433C09A9FA80L) /* 635 */,
+ unchecked((long) 0xFA8B0C53DF7CA1D9L) /* 636 */, unchecked((long) 0x3FD9DCBC886CCB77L) /* 637 */,
+ unchecked((long) 0xC040917CA91B4720L) /* 638 */, unchecked((long) 0x7DD00142F9D1DCDFL) /* 639 */,
+ unchecked((long) 0x8476FC1D4F387B58L) /* 640 */, unchecked((long) 0x23F8E7C5F3316503L) /* 641 */,
+ unchecked((long) 0x032A2244E7E37339L) /* 642 */, unchecked((long) 0x5C87A5D750F5A74BL) /* 643 */,
+ unchecked((long) 0x082B4CC43698992EL) /* 644 */, unchecked((long) 0xDF917BECB858F63CL) /* 645 */,
+ unchecked((long) 0x3270B8FC5BF86DDAL) /* 646 */, unchecked((long) 0x10AE72BB29B5DD76L) /* 647 */,
+ unchecked((long) 0x576AC94E7700362BL) /* 648 */, unchecked((long) 0x1AD112DAC61EFB8FL) /* 649 */,
+ unchecked((long) 0x691BC30EC5FAA427L) /* 650 */, unchecked((long) 0xFF246311CC327143L) /* 651 */,
+ unchecked((long) 0x3142368E30E53206L) /* 652 */, unchecked((long) 0x71380E31E02CA396L) /* 653 */,
+ unchecked((long) 0x958D5C960AAD76F1L) /* 654 */, unchecked((long) 0xF8D6F430C16DA536L) /* 655 */,
+ unchecked((long) 0xC8FFD13F1BE7E1D2L) /* 656 */, unchecked((long) 0x7578AE66004DDBE1L) /* 657 */,
+ unchecked((long) 0x05833F01067BE646L) /* 658 */, unchecked((long) 0xBB34B5AD3BFE586DL) /* 659 */,
+ unchecked((long) 0x095F34C9A12B97F0L) /* 660 */, unchecked((long) 0x247AB64525D60CA8L) /* 661 */,
+ unchecked((long) 0xDCDBC6F3017477D1L) /* 662 */, unchecked((long) 0x4A2E14D4DECAD24DL) /* 663 */,
+ unchecked((long) 0xBDB5E6D9BE0A1EEBL) /* 664 */, unchecked((long) 0x2A7E70F7794301ABL) /* 665 */,
+ unchecked((long) 0xDEF42D8A270540FDL) /* 666 */, unchecked((long) 0x01078EC0A34C22C1L) /* 667 */,
+ unchecked((long) 0xE5DE511AF4C16387L) /* 668 */, unchecked((long) 0x7EBB3A52BD9A330AL) /* 669 */,
+ unchecked((long) 0x77697857AA7D6435L) /* 670 */, unchecked((long) 0x004E831603AE4C32L) /* 671 */,
+ unchecked((long) 0xE7A21020AD78E312L) /* 672 */, unchecked((long) 0x9D41A70C6AB420F2L) /* 673 */,
+ unchecked((long) 0x28E06C18EA1141E6L) /* 674 */, unchecked((long) 0xD2B28CBD984F6B28L) /* 675 */,
+ unchecked((long) 0x26B75F6C446E9D83L) /* 676 */, unchecked((long) 0xBA47568C4D418D7FL) /* 677 */,
+ unchecked((long) 0xD80BADBFE6183D8EL) /* 678 */, unchecked((long) 0x0E206D7F5F166044L) /* 679 */,
+ unchecked((long) 0xE258A43911CBCA3EL) /* 680 */, unchecked((long) 0x723A1746B21DC0BCL) /* 681 */,
+ unchecked((long) 0xC7CAA854F5D7CDD3L) /* 682 */, unchecked((long) 0x7CAC32883D261D9CL) /* 683 */,
+ unchecked((long) 0x7690C26423BA942CL) /* 684 */, unchecked((long) 0x17E55524478042B8L) /* 685 */,
+ unchecked((long) 0xE0BE477656A2389FL) /* 686 */, unchecked((long) 0x4D289B5E67AB2DA0L) /* 687 */,
+ unchecked((long) 0x44862B9C8FBBFD31L) /* 688 */, unchecked((long) 0xB47CC8049D141365L) /* 689 */,
+ unchecked((long) 0x822C1B362B91C793L) /* 690 */, unchecked((long) 0x4EB14655FB13DFD8L) /* 691 */,
+ unchecked((long) 0x1ECBBA0714E2A97BL) /* 692 */, unchecked((long) 0x6143459D5CDE5F14L) /* 693 */,
+ unchecked((long) 0x53A8FBF1D5F0AC89L) /* 694 */, unchecked((long) 0x97EA04D81C5E5B00L) /* 695 */,
+ unchecked((long) 0x622181A8D4FDB3F3L) /* 696 */, unchecked((long) 0xE9BCD341572A1208L) /* 697 */,
+ unchecked((long) 0x1411258643CCE58AL) /* 698 */, unchecked((long) 0x9144C5FEA4C6E0A4L) /* 699 */,
+ unchecked((long) 0x0D33D06565CF620FL) /* 700 */, unchecked((long) 0x54A48D489F219CA1L) /* 701 */,
+ unchecked((long) 0xC43E5EAC6D63C821L) /* 702 */, unchecked((long) 0xA9728B3A72770DAFL) /* 703 */,
+ unchecked((long) 0xD7934E7B20DF87EFL) /* 704 */, unchecked((long) 0xE35503B61A3E86E5L) /* 705 */,
+ unchecked((long) 0xCAE321FBC819D504L) /* 706 */, unchecked((long) 0x129A50B3AC60BFA6L) /* 707 */,
+ unchecked((long) 0xCD5E68EA7E9FB6C3L) /* 708 */, unchecked((long) 0xB01C90199483B1C7L) /* 709 */,
+ unchecked((long) 0x3DE93CD5C295376CL) /* 710 */, unchecked((long) 0xAED52EDF2AB9AD13L) /* 711 */,
+ unchecked((long) 0x2E60F512C0A07884L) /* 712 */, unchecked((long) 0xBC3D86A3E36210C9L) /* 713 */,
+ unchecked((long) 0x35269D9B163951CEL) /* 714 */, unchecked((long) 0x0C7D6E2AD0CDB5FAL) /* 715 */,
+ unchecked((long) 0x59E86297D87F5733L) /* 716 */, unchecked((long) 0x298EF221898DB0E7L) /* 717 */,
+ unchecked((long) 0x55000029D1A5AA7EL) /* 718 */, unchecked((long) 0x8BC08AE1B5061B45L) /* 719 */,
+ unchecked((long) 0xC2C31C2B6C92703AL) /* 720 */, unchecked((long) 0x94CC596BAF25EF42L) /* 721 */,
+ unchecked((long) 0x0A1D73DB22540456L) /* 722 */, unchecked((long) 0x04B6A0F9D9C4179AL) /* 723 */,
+ unchecked((long) 0xEFFDAFA2AE3D3C60L) /* 724 */, unchecked((long) 0xF7C8075BB49496C4L) /* 725 */,
+ unchecked((long) 0x9CC5C7141D1CD4E3L) /* 726 */, unchecked((long) 0x78BD1638218E5534L) /* 727 */,
+ unchecked((long) 0xB2F11568F850246AL) /* 728 */, unchecked((long) 0xEDFABCFA9502BC29L) /* 729 */,
+ unchecked((long) 0x796CE5F2DA23051BL) /* 730 */, unchecked((long) 0xAAE128B0DC93537CL) /* 731 */,
+ unchecked((long) 0x3A493DA0EE4B29AEL) /* 732 */, unchecked((long) 0xB5DF6B2C416895D7L) /* 733 */,
+ unchecked((long) 0xFCABBD25122D7F37L) /* 734 */, unchecked((long) 0x70810B58105DC4B1L) /* 735 */,
+ unchecked((long) 0xE10FDD37F7882A90L) /* 736 */, unchecked((long) 0x524DCAB5518A3F5CL) /* 737 */,
+ unchecked((long) 0x3C9E85878451255BL) /* 738 */, unchecked((long) 0x4029828119BD34E2L) /* 739 */,
+ unchecked((long) 0x74A05B6F5D3CECCBL) /* 740 */, unchecked((long) 0xB610021542E13ECAL) /* 741 */,
+ unchecked((long) 0x0FF979D12F59E2ACL) /* 742 */, unchecked((long) 0x6037DA27E4F9CC50L) /* 743 */,
+ unchecked((long) 0x5E92975A0DF1847DL) /* 744 */, unchecked((long) 0xD66DE190D3E623FEL) /* 745 */,
+ unchecked((long) 0x5032D6B87B568048L) /* 746 */, unchecked((long) 0x9A36B7CE8235216EL) /* 747 */,
+ unchecked((long) 0x80272A7A24F64B4AL) /* 748 */, unchecked((long) 0x93EFED8B8C6916F7L) /* 749 */,
+ unchecked((long) 0x37DDBFF44CCE1555L) /* 750 */, unchecked((long) 0x4B95DB5D4B99BD25L) /* 751 */,
+ unchecked((long) 0x92D3FDA169812FC0L) /* 752 */, unchecked((long) 0xFB1A4A9A90660BB6L) /* 753 */,
+ unchecked((long) 0x730C196946A4B9B2L) /* 754 */, unchecked((long) 0x81E289AA7F49DA68L) /* 755 */,
+ unchecked((long) 0x64669A0F83B1A05FL) /* 756 */, unchecked((long) 0x27B3FF7D9644F48BL) /* 757 */,
+ unchecked((long) 0xCC6B615C8DB675B3L) /* 758 */, unchecked((long) 0x674F20B9BCEBBE95L) /* 759 */,
+ unchecked((long) 0x6F31238275655982L) /* 760 */, unchecked((long) 0x5AE488713E45CF05L) /* 761 */,
+ unchecked((long) 0xBF619F9954C21157L) /* 762 */, unchecked((long) 0xEABAC46040A8EAE9L) /* 763 */,
+ unchecked((long) 0x454C6FE9F2C0C1CDL) /* 764 */, unchecked((long) 0x419CF6496412691CL) /* 765 */,
+ unchecked((long) 0xD3DC3BEF265B0F70L) /* 766 */, unchecked((long) 0x6D0E60F5C3578A9EL) /* 767 */,
+ };
+
+ private static readonly long[] t4 = {
+ unchecked((long) 0x5B0E608526323C55L) /* 768 */, unchecked((long) 0x1A46C1A9FA1B59F5L) /* 769 */,
+ unchecked((long) 0xA9E245A17C4C8FFAL) /* 770 */, unchecked((long) 0x65CA5159DB2955D7L) /* 771 */,
+ unchecked((long) 0x05DB0A76CE35AFC2L) /* 772 */, unchecked((long) 0x81EAC77EA9113D45L) /* 773 */,
+ unchecked((long) 0x528EF88AB6AC0A0DL) /* 774 */, unchecked((long) 0xA09EA253597BE3FFL) /* 775 */,
+ unchecked((long) 0x430DDFB3AC48CD56L) /* 776 */, unchecked((long) 0xC4B3A67AF45CE46FL) /* 777 */,
+ unchecked((long) 0x4ECECFD8FBE2D05EL) /* 778 */, unchecked((long) 0x3EF56F10B39935F0L) /* 779 */,
+ unchecked((long) 0x0B22D6829CD619C6L) /* 780 */, unchecked((long) 0x17FD460A74DF2069L) /* 781 */,
+ unchecked((long) 0x6CF8CC8E8510ED40L) /* 782 */, unchecked((long) 0xD6C824BF3A6ECAA7L) /* 783 */,
+ unchecked((long) 0x61243D581A817049L) /* 784 */, unchecked((long) 0x048BACB6BBC163A2L) /* 785 */,
+ unchecked((long) 0xD9A38AC27D44CC32L) /* 786 */, unchecked((long) 0x7FDDFF5BAAF410ABL) /* 787 */,
+ unchecked((long) 0xAD6D495AA804824BL) /* 788 */, unchecked((long) 0xE1A6A74F2D8C9F94L) /* 789 */,
+ unchecked((long) 0xD4F7851235DEE8E3L) /* 790 */, unchecked((long) 0xFD4B7F886540D893L) /* 791 */,
+ unchecked((long) 0x247C20042AA4BFDAL) /* 792 */, unchecked((long) 0x096EA1C517D1327CL) /* 793 */,
+ unchecked((long) 0xD56966B4361A6685L) /* 794 */, unchecked((long) 0x277DA5C31221057DL) /* 795 */,
+ unchecked((long) 0x94D59893A43ACFF7L) /* 796 */, unchecked((long) 0x64F0C51CCDC02281L) /* 797 */,
+ unchecked((long) 0x3D33BCC4FF6189DBL) /* 798 */, unchecked((long) 0xE005CB184CE66AF1L) /* 799 */,
+ unchecked((long) 0xFF5CCD1D1DB99BEAL) /* 800 */, unchecked((long) 0xB0B854A7FE42980FL) /* 801 */,
+ unchecked((long) 0x7BD46A6A718D4B9FL) /* 802 */, unchecked((long) 0xD10FA8CC22A5FD8CL) /* 803 */,
+ unchecked((long) 0xD31484952BE4BD31L) /* 804 */, unchecked((long) 0xC7FA975FCB243847L) /* 805 */,
+ unchecked((long) 0x4886ED1E5846C407L) /* 806 */, unchecked((long) 0x28CDDB791EB70B04L) /* 807 */,
+ unchecked((long) 0xC2B00BE2F573417FL) /* 808 */, unchecked((long) 0x5C9590452180F877L) /* 809 */,
+ unchecked((long) 0x7A6BDDFFF370EB00L) /* 810 */, unchecked((long) 0xCE509E38D6D9D6A4L) /* 811 */,
+ unchecked((long) 0xEBEB0F00647FA702L) /* 812 */, unchecked((long) 0x1DCC06CF76606F06L) /* 813 */,
+ unchecked((long) 0xE4D9F28BA286FF0AL) /* 814 */, unchecked((long) 0xD85A305DC918C262L) /* 815 */,
+ unchecked((long) 0x475B1D8732225F54L) /* 816 */, unchecked((long) 0x2D4FB51668CCB5FEL) /* 817 */,
+ unchecked((long) 0xA679B9D9D72BBA20L) /* 818 */, unchecked((long) 0x53841C0D912D43A5L) /* 819 */,
+ unchecked((long) 0x3B7EAA48BF12A4E8L) /* 820 */, unchecked((long) 0x781E0E47F22F1DDFL) /* 821 */,
+ unchecked((long) 0xEFF20CE60AB50973L) /* 822 */, unchecked((long) 0x20D261D19DFFB742L) /* 823 */,
+ unchecked((long) 0x16A12B03062A2E39L) /* 824 */, unchecked((long) 0x1960EB2239650495L) /* 825 */,
+ unchecked((long) 0x251C16FED50EB8B8L) /* 826 */, unchecked((long) 0x9AC0C330F826016EL) /* 827 */,
+ unchecked((long) 0xED152665953E7671L) /* 828 */, unchecked((long) 0x02D63194A6369570L) /* 829 */,
+ unchecked((long) 0x5074F08394B1C987L) /* 830 */, unchecked((long) 0x70BA598C90B25CE1L) /* 831 */,
+ unchecked((long) 0x794A15810B9742F6L) /* 832 */, unchecked((long) 0x0D5925E9FCAF8C6CL) /* 833 */,
+ unchecked((long) 0x3067716CD868744EL) /* 834 */, unchecked((long) 0x910AB077E8D7731BL) /* 835 */,
+ unchecked((long) 0x6A61BBDB5AC42F61L) /* 836 */, unchecked((long) 0x93513EFBF0851567L) /* 837 */,
+ unchecked((long) 0xF494724B9E83E9D5L) /* 838 */, unchecked((long) 0xE887E1985C09648DL) /* 839 */,
+ unchecked((long) 0x34B1D3C675370CFDL) /* 840 */, unchecked((long) 0xDC35E433BC0D255DL) /* 841 */,
+ unchecked((long) 0xD0AAB84234131BE0L) /* 842 */, unchecked((long) 0x08042A50B48B7EAFL) /* 843 */,
+ unchecked((long) 0x9997C4EE44A3AB35L) /* 844 */, unchecked((long) 0x829A7B49201799D0L) /* 845 */,
+ unchecked((long) 0x263B8307B7C54441L) /* 846 */, unchecked((long) 0x752F95F4FD6A6CA6L) /* 847 */,
+ unchecked((long) 0x927217402C08C6E5L) /* 848 */, unchecked((long) 0x2A8AB754A795D9EEL) /* 849 */,
+ unchecked((long) 0xA442F7552F72943DL) /* 850 */, unchecked((long) 0x2C31334E19781208L) /* 851 */,
+ unchecked((long) 0x4FA98D7CEAEE6291L) /* 852 */, unchecked((long) 0x55C3862F665DB309L) /* 853 */,
+ unchecked((long) 0xBD0610175D53B1F3L) /* 854 */, unchecked((long) 0x46FE6CB840413F27L) /* 855 */,
+ unchecked((long) 0x3FE03792DF0CFA59L) /* 856 */, unchecked((long) 0xCFE700372EB85E8FL) /* 857 */,
+ unchecked((long) 0xA7BE29E7ADBCE118L) /* 858 */, unchecked((long) 0xE544EE5CDE8431DDL) /* 859 */,
+ unchecked((long) 0x8A781B1B41F1873EL) /* 860 */, unchecked((long) 0xA5C94C78A0D2F0E7L) /* 861 */,
+ unchecked((long) 0x39412E2877B60728L) /* 862 */, unchecked((long) 0xA1265EF3AFC9A62CL) /* 863 */,
+ unchecked((long) 0xBCC2770C6A2506C5L) /* 864 */, unchecked((long) 0x3AB66DD5DCE1CE12L) /* 865 */,
+ unchecked((long) 0xE65499D04A675B37L) /* 866 */, unchecked((long) 0x7D8F523481BFD216L) /* 867 */,
+ unchecked((long) 0x0F6F64FCEC15F389L) /* 868 */, unchecked((long) 0x74EFBE618B5B13C8L) /* 869 */,
+ unchecked((long) 0xACDC82B714273E1DL) /* 870 */, unchecked((long) 0xDD40BFE003199D17L) /* 871 */,
+ unchecked((long) 0x37E99257E7E061F8L) /* 872 */, unchecked((long) 0xFA52626904775AAAL) /* 873 */,
+ unchecked((long) 0x8BBBF63A463D56F9L) /* 874 */, unchecked((long) 0xF0013F1543A26E64L) /* 875 */,
+ unchecked((long) 0xA8307E9F879EC898L) /* 876 */, unchecked((long) 0xCC4C27A4150177CCL) /* 877 */,
+ unchecked((long) 0x1B432F2CCA1D3348L) /* 878 */, unchecked((long) 0xDE1D1F8F9F6FA013L) /* 879 */,
+ unchecked((long) 0x606602A047A7DDD6L) /* 880 */, unchecked((long) 0xD237AB64CC1CB2C7L) /* 881 */,
+ unchecked((long) 0x9B938E7225FCD1D3L) /* 882 */, unchecked((long) 0xEC4E03708E0FF476L) /* 883 */,
+ unchecked((long) 0xFEB2FBDA3D03C12DL) /* 884 */, unchecked((long) 0xAE0BCED2EE43889AL) /* 885 */,
+ unchecked((long) 0x22CB8923EBFB4F43L) /* 886 */, unchecked((long) 0x69360D013CF7396DL) /* 887 */,
+ unchecked((long) 0x855E3602D2D4E022L) /* 888 */, unchecked((long) 0x073805BAD01F784CL) /* 889 */,
+ unchecked((long) 0x33E17A133852F546L) /* 890 */, unchecked((long) 0xDF4874058AC7B638L) /* 891 */,
+ unchecked((long) 0xBA92B29C678AA14AL) /* 892 */, unchecked((long) 0x0CE89FC76CFAADCDL) /* 893 */,
+ unchecked((long) 0x5F9D4E0908339E34L) /* 894 */, unchecked((long) 0xF1AFE9291F5923B9L) /* 895 */,
+ unchecked((long) 0x6E3480F60F4A265FL) /* 896 */, unchecked((long) 0xEEBF3A2AB29B841CL) /* 897 */,
+ unchecked((long) 0xE21938A88F91B4ADL) /* 898 */, unchecked((long) 0x57DFEFF845C6D3C3L) /* 899 */,
+ unchecked((long) 0x2F006B0BF62CAAF2L) /* 900 */, unchecked((long) 0x62F479EF6F75EE78L) /* 901 */,
+ unchecked((long) 0x11A55AD41C8916A9L) /* 902 */, unchecked((long) 0xF229D29084FED453L) /* 903 */,
+ unchecked((long) 0x42F1C27B16B000E6L) /* 904 */, unchecked((long) 0x2B1F76749823C074L) /* 905 */,
+ unchecked((long) 0x4B76ECA3C2745360L) /* 906 */, unchecked((long) 0x8C98F463B91691BDL) /* 907 */,
+ unchecked((long) 0x14BCC93CF1ADE66AL) /* 908 */, unchecked((long) 0x8885213E6D458397L) /* 909 */,
+ unchecked((long) 0x8E177DF0274D4711L) /* 910 */, unchecked((long) 0xB49B73B5503F2951L) /* 911 */,
+ unchecked((long) 0x10168168C3F96B6BL) /* 912 */, unchecked((long) 0x0E3D963B63CAB0AEL) /* 913 */,
+ unchecked((long) 0x8DFC4B5655A1DB14L) /* 914 */, unchecked((long) 0xF789F1356E14DE5CL) /* 915 */,
+ unchecked((long) 0x683E68AF4E51DAC1L) /* 916 */, unchecked((long) 0xC9A84F9D8D4B0FD9L) /* 917 */,
+ unchecked((long) 0x3691E03F52A0F9D1L) /* 918 */, unchecked((long) 0x5ED86E46E1878E80L) /* 919 */,
+ unchecked((long) 0x3C711A0E99D07150L) /* 920 */, unchecked((long) 0x5A0865B20C4E9310L) /* 921 */,
+ unchecked((long) 0x56FBFC1FE4F0682EL) /* 922 */, unchecked((long) 0xEA8D5DE3105EDF9BL) /* 923 */,
+ unchecked((long) 0x71ABFDB12379187AL) /* 924 */, unchecked((long) 0x2EB99DE1BEE77B9CL) /* 925 */,
+ unchecked((long) 0x21ECC0EA33CF4523L) /* 926 */, unchecked((long) 0x59A4D7521805C7A1L) /* 927 */,
+ unchecked((long) 0x3896F5EB56AE7C72L) /* 928 */, unchecked((long) 0xAA638F3DB18F75DCL) /* 929 */,
+ unchecked((long) 0x9F39358DABE9808EL) /* 930 */, unchecked((long) 0xB7DEFA91C00B72ACL) /* 931 */,
+ unchecked((long) 0x6B5541FD62492D92L) /* 932 */, unchecked((long) 0x6DC6DEE8F92E4D5BL) /* 933 */,
+ unchecked((long) 0x353F57ABC4BEEA7EL) /* 934 */, unchecked((long) 0x735769D6DA5690CEL) /* 935 */,
+ unchecked((long) 0x0A234AA642391484L) /* 936 */, unchecked((long) 0xF6F9508028F80D9DL) /* 937 */,
+ unchecked((long) 0xB8E319A27AB3F215L) /* 938 */, unchecked((long) 0x31AD9C1151341A4DL) /* 939 */,
+ unchecked((long) 0x773C22A57BEF5805L) /* 940 */, unchecked((long) 0x45C7561A07968633L) /* 941 */,
+ unchecked((long) 0xF913DA9E249DBE36L) /* 942 */, unchecked((long) 0xDA652D9B78A64C68L) /* 943 */,
+ unchecked((long) 0x4C27A97F3BC334EFL) /* 944 */, unchecked((long) 0x76621220E66B17F4L) /* 945 */,
+ unchecked((long) 0x967743899ACD7D0BL) /* 946 */, unchecked((long) 0xF3EE5BCAE0ED6782L) /* 947 */,
+ unchecked((long) 0x409F753600C879FCL) /* 948 */, unchecked((long) 0x06D09A39B5926DB6L) /* 949 */,
+ unchecked((long) 0x6F83AEB0317AC588L) /* 950 */, unchecked((long) 0x01E6CA4A86381F21L) /* 951 */,
+ unchecked((long) 0x66FF3462D19F3025L) /* 952 */, unchecked((long) 0x72207C24DDFD3BFBL) /* 953 */,
+ unchecked((long) 0x4AF6B6D3E2ECE2EBL) /* 954 */, unchecked((long) 0x9C994DBEC7EA08DEL) /* 955 */,
+ unchecked((long) 0x49ACE597B09A8BC4L) /* 956 */, unchecked((long) 0xB38C4766CF0797BAL) /* 957 */,
+ unchecked((long) 0x131B9373C57C2A75L) /* 958 */, unchecked((long) 0xB1822CCE61931E58L) /* 959 */,
+ unchecked((long) 0x9D7555B909BA1C0CL) /* 960 */, unchecked((long) 0x127FAFDD937D11D2L) /* 961 */,
+ unchecked((long) 0x29DA3BADC66D92E4L) /* 962 */, unchecked((long) 0xA2C1D57154C2ECBCL) /* 963 */,
+ unchecked((long) 0x58C5134D82F6FE24L) /* 964 */, unchecked((long) 0x1C3AE3515B62274FL) /* 965 */,
+ unchecked((long) 0xE907C82E01CB8126L) /* 966 */, unchecked((long) 0xF8ED091913E37FCBL) /* 967 */,
+ unchecked((long) 0x3249D8F9C80046C9L) /* 968 */, unchecked((long) 0x80CF9BEDE388FB63L) /* 969 */,
+ unchecked((long) 0x1881539A116CF19EL) /* 970 */, unchecked((long) 0x5103F3F76BD52457L) /* 971 */,
+ unchecked((long) 0x15B7E6F5AE47F7A8L) /* 972 */, unchecked((long) 0xDBD7C6DED47E9CCFL) /* 973 */,
+ unchecked((long) 0x44E55C410228BB1AL) /* 974 */, unchecked((long) 0xB647D4255EDB4E99L) /* 975 */,
+ unchecked((long) 0x5D11882BB8AAFC30L) /* 976 */, unchecked((long) 0xF5098BBB29D3212AL) /* 977 */,
+ unchecked((long) 0x8FB5EA14E90296B3L) /* 978 */, unchecked((long) 0x677B942157DD025AL) /* 979 */,
+ unchecked((long) 0xFB58E7C0A390ACB5L) /* 980 */, unchecked((long) 0x89D3674C83BD4A01L) /* 981 */,
+ unchecked((long) 0x9E2DA4DF4BF3B93BL) /* 982 */, unchecked((long) 0xFCC41E328CAB4829L) /* 983 */,
+ unchecked((long) 0x03F38C96BA582C52L) /* 984 */, unchecked((long) 0xCAD1BDBD7FD85DB2L) /* 985 */,
+ unchecked((long) 0xBBB442C16082AE83L) /* 986 */, unchecked((long) 0xB95FE86BA5DA9AB0L) /* 987 */,
+ unchecked((long) 0xB22E04673771A93FL) /* 988 */, unchecked((long) 0x845358C9493152D8L) /* 989 */,
+ unchecked((long) 0xBE2A488697B4541EL) /* 990 */, unchecked((long) 0x95A2DC2DD38E6966L) /* 991 */,
+ unchecked((long) 0xC02C11AC923C852BL) /* 992 */, unchecked((long) 0x2388B1990DF2A87BL) /* 993 */,
+ unchecked((long) 0x7C8008FA1B4F37BEL) /* 994 */, unchecked((long) 0x1F70D0C84D54E503L) /* 995 */,
+ unchecked((long) 0x5490ADEC7ECE57D4L) /* 996 */, unchecked((long) 0x002B3C27D9063A3AL) /* 997 */,
+ unchecked((long) 0x7EAEA3848030A2BFL) /* 998 */, unchecked((long) 0xC602326DED2003C0L) /* 999 */,
+ unchecked((long) 0x83A7287D69A94086L) /* 1000 */, unchecked((long) 0xC57A5FCB30F57A8AL) /* 1001 */,
+ unchecked((long) 0xB56844E479EBE779L) /* 1002 */, unchecked((long) 0xA373B40F05DCBCE9L) /* 1003 */,
+ unchecked((long) 0xD71A786E88570EE2L) /* 1004 */, unchecked((long) 0x879CBACDBDE8F6A0L) /* 1005 */,
+ unchecked((long) 0x976AD1BCC164A32FL) /* 1006 */, unchecked((long) 0xAB21E25E9666D78BL) /* 1007 */,
+ unchecked((long) 0x901063AAE5E5C33CL) /* 1008 */, unchecked((long) 0x9818B34448698D90L) /* 1009 */,
+ unchecked((long) 0xE36487AE3E1E8ABBL) /* 1010 */, unchecked((long) 0xAFBDF931893BDCB4L) /* 1011 */,
+ unchecked((long) 0x6345A0DC5FBBD519L) /* 1012 */, unchecked((long) 0x8628FE269B9465CAL) /* 1013 */,
+ unchecked((long) 0x1E5D01603F9C51ECL) /* 1014 */, unchecked((long) 0x4DE44006A15049B7L) /* 1015 */,
+ unchecked((long) 0xBF6C70E5F776CBB1L) /* 1016 */, unchecked((long) 0x411218F2EF552BEDL) /* 1017 */,
+ unchecked((long) 0xCB0C0708705A36A3L) /* 1018 */, unchecked((long) 0xE74D14754F986044L) /* 1019 */,
+ unchecked((long) 0xCD56D9430EA8280EL) /* 1020 */, unchecked((long) 0xC12591D7535F5065L) /* 1021 */,
+ unchecked((long) 0xC83223F1720AEF96L) /* 1022 */, unchecked((long) 0xC3A0396F7363A51FL) /* 1023 */
+ };
+
+ private const int DigestLength = 24;
+
+ //
+ // registers
+ //
+ private long a, b, c;
+ private long byteCount;
+
+ //
+ // buffers
+ //
+ private byte[] Buffer = new byte[8];
+ private int bOff;
+
+ private long[] x = new long[8];
+ private int xOff;
+
+ /**
+ * Standard constructor
+ */
+ public TigerDigest()
+ {
+ Reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public TigerDigest(TigerDigest t)
+ {
+ Reset(t);
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Tiger"; }
+ }
+
+ public int GetDigestSize()
+ {
+ return DigestLength;
+ }
+
+ public int GetByteLength()
+ {
+ return MyByteLength;
+ }
+
+ private void ProcessWord(
+ byte[] b,
+ int off)
+ {
+ x[xOff++] = ((long)(b[off + 7] & 0xff) << 56)
+ | ((long)(b[off + 6] & 0xff) << 48)
+ | ((long)(b[off + 5] & 0xff) << 40)
+ | ((long)(b[off + 4] & 0xff) << 32)
+ | ((long)(b[off + 3] & 0xff) << 24)
+ | ((long)(b[off + 2] & 0xff) << 16)
+ | ((long)(b[off + 1] & 0xff) << 8)
+ | ((uint)(b[off + 0] & 0xff));
+
+ if (xOff == x.Length)
+ {
+ ProcessBlock();
+ }
+
+ bOff = 0;
+ }
+
+ public void Update(
+ byte input)
+ {
+ Buffer[bOff++] = input;
+
+ if (bOff == Buffer.Length)
+ {
+ ProcessWord(Buffer, 0);
+ }
+
+ byteCount++;
+ }
+
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ //
+ // fill the current word
+ //
+ while ((bOff != 0) && (length > 0))
+ {
+ Update(input[inOff]);
+
+ inOff++;
+ length--;
+ }
+
+ //
+ // process whole words.
+ //
+ while (length > 8)
+ {
+ ProcessWord(input, inOff);
+
+ inOff += 8;
+ length -= 8;
+ byteCount += 8;
+ }
+
+ //
+ // load in the remainder.
+ //
+ while (length > 0)
+ {
+ Update(input[inOff]);
+
+ inOff++;
+ length--;
+ }
+ }
+
+ private void RoundABC(
+ long x,
+ long mul)
+ {
+ c ^= x ;
+ a -= t1[(int)c & 0xff] ^ t2[(int)(c >> 16) & 0xff]
+ ^ t3[(int)(c >> 32) & 0xff] ^ t4[(int)(c >> 48) & 0xff];
+ b += t4[(int)(c >> 8) & 0xff] ^ t3[(int)(c >> 24) & 0xff]
+ ^ t2[(int)(c >> 40) & 0xff] ^ t1[(int)(c >> 56) & 0xff];
+ b *= mul;
+ }
+
+ private void RoundBCA(
+ long x,
+ long mul)
+ {
+ a ^= x ;
+ b -= t1[(int)a & 0xff] ^ t2[(int)(a >> 16) & 0xff]
+ ^ t3[(int)(a >> 32) & 0xff] ^ t4[(int)(a >> 48) & 0xff];
+ c += t4[(int)(a >> 8) & 0xff] ^ t3[(int)(a >> 24) & 0xff]
+ ^ t2[(int)(a >> 40) & 0xff] ^ t1[(int)(a >> 56) & 0xff];
+ c *= mul;
+ }
+
+ private void RoundCAB(
+ long x,
+ long mul)
+ {
+ b ^= x ;
+ c -= t1[(int)b & 0xff] ^ t2[(int)(b >> 16) & 0xff]
+ ^ t3[(int)(b >> 32) & 0xff] ^ t4[(int)(b >> 48) & 0xff];
+ a += t4[(int)(b >> 8) & 0xff] ^ t3[(int)(b >> 24) & 0xff]
+ ^ t2[(int)(b >> 40) & 0xff] ^ t1[(int)(b >> 56) & 0xff];
+ a *= mul;
+ }
+
+ private void KeySchedule()
+ {
+ x[0] -= x[7] ^ unchecked ((long) 0xA5A5A5A5A5A5A5A5L);
+ x[1] ^= x[0];
+ x[2] += x[1];
+ x[3] -= x[2] ^ ((~x[1]) << 19);
+ x[4] ^= x[3];
+ x[5] += x[4];
+ x[6] -= x[5] ^ (long) ((ulong) (~x[4]) >> 23);
+ x[7] ^= x[6];
+ x[0] += x[7];
+ x[1] -= x[0] ^ ((~x[7]) << 19);
+ x[2] ^= x[1];
+ x[3] += x[2];
+ x[4] -= x[3] ^ (long) ((ulong) (~x[2]) >> 23);
+ x[5] ^= x[4];
+ x[6] += x[5];
+ x[7] -= x[6] ^ 0x0123456789ABCDEFL;
+ }
+
+ private void ProcessBlock()
+ {
+ //
+ // save abc
+ //
+ long aa = a;
+ long bb = b;
+ long cc = c;
+
+ //
+ // rounds and schedule
+ //
+ RoundABC(x[0], 5);
+ RoundBCA(x[1], 5);
+ RoundCAB(x[2], 5);
+ RoundABC(x[3], 5);
+ RoundBCA(x[4], 5);
+ RoundCAB(x[5], 5);
+ RoundABC(x[6], 5);
+ RoundBCA(x[7], 5);
+
+ KeySchedule();
+
+ RoundCAB(x[0], 7);
+ RoundABC(x[1], 7);
+ RoundBCA(x[2], 7);
+ RoundCAB(x[3], 7);
+ RoundABC(x[4], 7);
+ RoundBCA(x[5], 7);
+ RoundCAB(x[6], 7);
+ RoundABC(x[7], 7);
+
+ KeySchedule();
+
+ RoundBCA(x[0], 9);
+ RoundCAB(x[1], 9);
+ RoundABC(x[2], 9);
+ RoundBCA(x[3], 9);
+ RoundCAB(x[4], 9);
+ RoundABC(x[5], 9);
+ RoundBCA(x[6], 9);
+ RoundCAB(x[7], 9);
+
+ //
+ // feed forward
+ //
+ a ^= aa;
+ b -= bb;
+ c += cc;
+
+ //
+ // clear the x buffer
+ //
+ xOff = 0;
+ for (int i = 0; i != x.Length; i++)
+ {
+ x[i] = 0;
+ }
+ }
+
+ private void UnpackWord(
+ long r,
+ byte[] output,
+ int outOff)
+ {
+ output[outOff + 7] = (byte)(r >> 56);
+ output[outOff + 6] = (byte)(r >> 48);
+ output[outOff + 5] = (byte)(r >> 40);
+ output[outOff + 4] = (byte)(r >> 32);
+ output[outOff + 3] = (byte)(r >> 24);
+ output[outOff + 2] = (byte)(r >> 16);
+ output[outOff + 1] = (byte)(r >> 8);
+ output[outOff] = (byte)r;
+ }
+
+ private void ProcessLength(
+ long bitLength)
+ {
+ x[7] = bitLength;
+ }
+
+ private void Finish()
+ {
+ long bitLength = (byteCount << 3);
+
+ Update((byte)0x01);
+
+ while (bOff != 0)
+ {
+ Update((byte)0);
+ }
+
+ ProcessLength(bitLength);
+
+ ProcessBlock();
+ }
+
+ public int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ Finish();
+
+ UnpackWord(a, output, outOff);
+ UnpackWord(b, output, outOff + 8);
+ UnpackWord(c, output, outOff + 16);
+
+ Reset();
+
+ return DigestLength;
+ }
+
+ /**
+ * reset the chaining variables
+ */
+ public void Reset()
+ {
+ a = unchecked((long) 0x0123456789ABCDEFL);
+ b = unchecked((long) 0xFEDCBA9876543210L);
+ c = unchecked((long) 0xF096A5B4C3B2E187L);
+
+ xOff = 0;
+ for (int i = 0; i != x.Length; i++)
+ {
+ x[i] = 0;
+ }
+
+ bOff = 0;
+ for (int i = 0; i != Buffer.Length; i++)
+ {
+ Buffer[i] = 0;
+ }
+
+ byteCount = 0;
+ }
+
+ public IMemoable Copy()
+ {
+ return new TigerDigest(this);
+ }
+
+ public void Reset(IMemoable other)
+ {
+ TigerDigest t = (TigerDigest)other;
+
+ a = t.a;
+ b = t.b;
+ c = t.c;
+
+ Array.Copy(t.x, 0, x, 0, t.x.Length);
+ xOff = t.xOff;
+
+ Array.Copy(t.Buffer, 0, Buffer, 0, t.Buffer.Length);
+ bOff = t.bOff;
+
+ byteCount = t.byteCount;
+ }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/digests/WhirlpoolDigest.cs b/bc-sharp-crypto/src/crypto/digests/WhirlpoolDigest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..55b71205e655927bb6219bb8a6e01b2ffadba2de
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/digests/WhirlpoolDigest.cs
@@ -0,0 +1,413 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+ /**
+ * Implementation of WhirlpoolDigest, based on Java source published by Barreto
+ * and Rijmen.
+ *
+ */
+ public sealed class WhirlpoolDigest
+ : IDigest, IMemoable
+ {
+ private const int BYTE_LENGTH = 64;
+
+ private const int DIGEST_LENGTH_BYTES = 512 / 8;
+ private const int ROUNDS = 10;
+ private const int REDUCTION_POLYNOMIAL = 0x011d; // 2^8 + 2^4 + 2^3 + 2 + 1;
+
+ private static readonly int[] SBOX =
+ {
+ 0x18, 0x23, 0xc6, 0xe8, 0x87, 0xb8, 0x01, 0x4f, 0x36, 0xa6, 0xd2, 0xf5, 0x79, 0x6f, 0x91, 0x52,
+ 0x60, 0xbc, 0x9b, 0x8e, 0xa3, 0x0c, 0x7b, 0x35, 0x1d, 0xe0, 0xd7, 0xc2, 0x2e, 0x4b, 0xfe, 0x57,
+ 0x15, 0x77, 0x37, 0xe5, 0x9f, 0xf0, 0x4a, 0xda, 0x58, 0xc9, 0x29, 0x0a, 0xb1, 0xa0, 0x6b, 0x85,
+ 0xbd, 0x5d, 0x10, 0xf4, 0xcb, 0x3e, 0x05, 0x67, 0xe4, 0x27, 0x41, 0x8b, 0xa7, 0x7d, 0x95, 0xd8,
+ 0xfb, 0xee, 0x7c, 0x66, 0xdd, 0x17, 0x47, 0x9e, 0xca, 0x2d, 0xbf, 0x07, 0xad, 0x5a, 0x83, 0x33,
+ 0x63, 0x02, 0xaa, 0x71, 0xc8, 0x19, 0x49, 0xd9, 0xf2, 0xe3, 0x5b, 0x88, 0x9a, 0x26, 0x32, 0xb0,
+ 0xe9, 0x0f, 0xd5, 0x80, 0xbe, 0xcd, 0x34, 0x48, 0xff, 0x7a, 0x90, 0x5f, 0x20, 0x68, 0x1a, 0xae,
+ 0xb4, 0x54, 0x93, 0x22, 0x64, 0xf1, 0x73, 0x12, 0x40, 0x08, 0xc3, 0xec, 0xdb, 0xa1, 0x8d, 0x3d,
+ 0x97, 0x00, 0xcf, 0x2b, 0x76, 0x82, 0xd6, 0x1b, 0xb5, 0xaf, 0x6a, 0x50, 0x45, 0xf3, 0x30, 0xef,
+ 0x3f, 0x55, 0xa2, 0xea, 0x65, 0xba, 0x2f, 0xc0, 0xde, 0x1c, 0xfd, 0x4d, 0x92, 0x75, 0x06, 0x8a,
+ 0xb2, 0xe6, 0x0e, 0x1f, 0x62, 0xd4, 0xa8, 0x96, 0xf9, 0xc5, 0x25, 0x59, 0x84, 0x72, 0x39, 0x4c,
+ 0x5e, 0x78, 0x38, 0x8c, 0xd1, 0xa5, 0xe2, 0x61, 0xb3, 0x21, 0x9c, 0x1e, 0x43, 0xc7, 0xfc, 0x04,
+ 0x51, 0x99, 0x6d, 0x0d, 0xfa, 0xdf, 0x7e, 0x24, 0x3b, 0xab, 0xce, 0x11, 0x8f, 0x4e, 0xb7, 0xeb,
+ 0x3c, 0x81, 0x94, 0xf7, 0xb9, 0x13, 0x2c, 0xd3, 0xe7, 0x6e, 0xc4, 0x03, 0x56, 0x44, 0x7f, 0xa9,
+ 0x2a, 0xbb, 0xc1, 0x53, 0xdc, 0x0b, 0x9d, 0x6c, 0x31, 0x74, 0xf6, 0x46, 0xac, 0x89, 0x14, 0xe1,
+ 0x16, 0x3a, 0x69, 0x09, 0x70, 0xb6, 0xd0, 0xed, 0xcc, 0x42, 0x98, 0xa4, 0x28, 0x5c, 0xf8, 0x86
+ };
+
+ private static readonly long[] C0 = new long[256];
+ private static readonly long[] C1 = new long[256];
+ private static readonly long[] C2 = new long[256];
+ private static readonly long[] C3 = new long[256];
+ private static readonly long[] C4 = new long[256];
+ private static readonly long[] C5 = new long[256];
+ private static readonly long[] C6 = new long[256];
+ private static readonly long[] C7 = new long[256];
+
+ private readonly long[] _rc = new long[ROUNDS + 1];
+
+ /*
+ * increment() can be implemented in this way using 2 arrays or
+ * by having some temporary variables that are used to set the
+ * value provided by EIGHT[i] and carry within the loop.
+ *
+ * not having done any timing, this seems likely to be faster
+ * at the slight expense of 32*(sizeof short) bytes
+ */
+ private static readonly short[] EIGHT = new short[BITCOUNT_ARRAY_SIZE];
+
+ static WhirlpoolDigest()
+ {
+ EIGHT[BITCOUNT_ARRAY_SIZE - 1] = 8;
+
+ for (int i = 0; i < 256; i++)
+ {
+ int v1 = SBOX[i];
+ int v2 = maskWithReductionPolynomial(v1 << 1);
+ int v4 = maskWithReductionPolynomial(v2 << 1);
+ int v5 = v4 ^ v1;
+ int v8 = maskWithReductionPolynomial(v4 << 1);
+ int v9 = v8 ^ v1;
+
+ C0[i] = packIntoLong(v1, v1, v4, v1, v8, v5, v2, v9);
+ C1[i] = packIntoLong(v9, v1, v1, v4, v1, v8, v5, v2);
+ C2[i] = packIntoLong(v2, v9, v1, v1, v4, v1, v8, v5);
+ C3[i] = packIntoLong(v5, v2, v9, v1, v1, v4, v1, v8);
+ C4[i] = packIntoLong(v8, v5, v2, v9, v1, v1, v4, v1);
+ C5[i] = packIntoLong(v1, v8, v5, v2, v9, v1, v1, v4);
+ C6[i] = packIntoLong(v4, v1, v8, v5, v2, v9, v1, v1);
+ C7[i] = packIntoLong(v1, v4, v1, v8, v5, v2, v9, v1);
+ }
+ }
+
+ public WhirlpoolDigest()
+ {
+ _rc[0] = 0L;
+ for (int r = 1; r <= ROUNDS; r++)
+ {
+ int i = 8 * (r - 1);
+ _rc[r] = (long)((ulong)C0[i] & 0xff00000000000000L) ^
+ (C1[i + 1] & (long) 0x00ff000000000000L) ^
+ (C2[i + 2] & (long) 0x0000ff0000000000L) ^
+ (C3[i + 3] & (long) 0x000000ff00000000L) ^
+ (C4[i + 4] & (long) 0x00000000ff000000L) ^
+ (C5[i + 5] & (long) 0x0000000000ff0000L) ^
+ (C6[i + 6] & (long) 0x000000000000ff00L) ^
+ (C7[i + 7] & (long) 0x00000000000000ffL);
+ }
+ }
+
+ private static long packIntoLong(int b7, int b6, int b5, int b4, int b3, int b2, int b1, int b0)
+ {
+ return
+ ((long)b7 << 56) ^
+ ((long)b6 << 48) ^
+ ((long)b5 << 40) ^
+ ((long)b4 << 32) ^
+ ((long)b3 << 24) ^
+ ((long)b2 << 16) ^
+ ((long)b1 << 8) ^
+ b0;
+ }
+
+ /*
+ * int's are used to prevent sign extension. The values that are really being used are
+ * actually just 0..255
+ */
+ private static int maskWithReductionPolynomial(int input)
+ {
+ int rv = input;
+ if (rv >= 0x100L) // high bit set
+ {
+ rv ^= REDUCTION_POLYNOMIAL; // reduced by the polynomial
+ }
+ return rv;
+ }
+
+ // --------------------------------------------------------------------------------------//
+
+ // -- buffer information --
+ private const int BITCOUNT_ARRAY_SIZE = 32;
+ private byte[] _buffer = new byte[64];
+ private int _bufferPos;
+ private short[] _bitCount = new short[BITCOUNT_ARRAY_SIZE];
+
+ // -- internal hash state --
+ private long[] _hash = new long[8];
+ private long[] _K = new long[8]; // the round key
+ private long[] _L = new long[8];
+ private long[] _block = new long[8]; // mu (buffer)
+ private long[] _state = new long[8]; // the current "cipher" state
+
+
+
+ /**
+ * Copy constructor. This will copy the state of the provided message
+ * digest.
+ */
+ public WhirlpoolDigest(WhirlpoolDigest originalDigest)
+ {
+ Reset(originalDigest);
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Whirlpool"; }
+ }
+
+ public int GetDigestSize()
+ {
+ return DIGEST_LENGTH_BYTES;
+ }
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ // sets output[outOff] .. output[outOff+DIGEST_LENGTH_BYTES]
+ finish();
+
+ for (int i = 0; i < 8; i++)
+ {
+ convertLongToByteArray(_hash[i], output, outOff + (i * 8));
+ }
+
+ Reset();
+
+ return GetDigestSize();
+ }
+
+ /**
+ * Reset the chaining variables
+ */
+ public void Reset()
+ {
+ // set variables to null, blank, whatever
+ _bufferPos = 0;
+ Array.Clear(_bitCount, 0, _bitCount.Length);
+ Array.Clear(_buffer, 0, _buffer.Length);
+ Array.Clear(_hash, 0, _hash.Length);
+ Array.Clear(_K, 0, _K.Length);
+ Array.Clear(_L, 0, _L.Length);
+ Array.Clear(_block, 0, _block.Length);
+ Array.Clear(_state, 0, _state.Length);
+ }
+
+ // this takes a buffer of information and fills the block
+ private void processFilledBuffer()
+ {
+ // copies into the block...
+ for (int i = 0; i < _state.Length; i++)
+ {
+ _block[i] = bytesToLongFromBuffer(_buffer, i * 8);
+ }
+ processBlock();
+ _bufferPos = 0;
+ Array.Clear(_buffer, 0, _buffer.Length);
+ }
+
+ private static long bytesToLongFromBuffer(byte[] buffer, int startPos)
+ {
+ long rv = (((buffer[startPos + 0] & 0xffL) << 56) |
+ ((buffer[startPos + 1] & 0xffL) << 48) |
+ ((buffer[startPos + 2] & 0xffL) << 40) |
+ ((buffer[startPos + 3] & 0xffL) << 32) |
+ ((buffer[startPos + 4] & 0xffL) << 24) |
+ ((buffer[startPos + 5] & 0xffL) << 16) |
+ ((buffer[startPos + 6] & 0xffL) << 8) |
+ ((buffer[startPos + 7]) & 0xffL));
+
+ return rv;
+ }
+
+ private static void convertLongToByteArray(long inputLong, byte[] outputArray, int offSet)
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ outputArray[offSet + i] = (byte)((inputLong >> (56 - (i * 8))) & 0xff);
+ }
+ }
+
+ private void processBlock()
+ {
+ // buffer contents have been transferred to the _block[] array via
+ // processFilledBuffer
+
+ // compute and apply K^0
+ for (int i = 0; i < 8; i++)
+ {
+ _state[i] = _block[i] ^ (_K[i] = _hash[i]);
+ }
+
+ // iterate over the rounds
+ for (int round = 1; round <= ROUNDS; round++)
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ _L[i] = 0;
+ _L[i] ^= C0[(int)(_K[(i - 0) & 7] >> 56) & 0xff];
+ _L[i] ^= C1[(int)(_K[(i - 1) & 7] >> 48) & 0xff];
+ _L[i] ^= C2[(int)(_K[(i - 2) & 7] >> 40) & 0xff];
+ _L[i] ^= C3[(int)(_K[(i - 3) & 7] >> 32) & 0xff];
+ _L[i] ^= C4[(int)(_K[(i - 4) & 7] >> 24) & 0xff];
+ _L[i] ^= C5[(int)(_K[(i - 5) & 7] >> 16) & 0xff];
+ _L[i] ^= C6[(int)(_K[(i - 6) & 7] >> 8) & 0xff];
+ _L[i] ^= C7[(int)(_K[(i - 7) & 7]) & 0xff];
+ }
+
+ Array.Copy(_L, 0, _K, 0, _K.Length);
+
+ _K[0] ^= _rc[round];
+
+ // apply the round transformation
+ for (int i = 0; i < 8; i++)
+ {
+ _L[i] = _K[i];
+
+ _L[i] ^= C0[(int)(_state[(i - 0) & 7] >> 56) & 0xff];
+ _L[i] ^= C1[(int)(_state[(i - 1) & 7] >> 48) & 0xff];
+ _L[i] ^= C2[(int)(_state[(i - 2) & 7] >> 40) & 0xff];
+ _L[i] ^= C3[(int)(_state[(i - 3) & 7] >> 32) & 0xff];
+ _L[i] ^= C4[(int)(_state[(i - 4) & 7] >> 24) & 0xff];
+ _L[i] ^= C5[(int)(_state[(i - 5) & 7] >> 16) & 0xff];
+ _L[i] ^= C6[(int)(_state[(i - 6) & 7] >> 8) & 0xff];
+ _L[i] ^= C7[(int)(_state[(i - 7) & 7]) & 0xff];
+ }
+
+ // save the current state
+ Array.Copy(_L, 0, _state, 0, _state.Length);
+ }
+
+ // apply Miuaguchi-Preneel compression
+ for (int i = 0; i < 8; i++)
+ {
+ _hash[i] ^= _state[i] ^ _block[i];
+ }
+
+ }
+
+ public void Update(byte input)
+ {
+ _buffer[_bufferPos] = input;
+
+ //Console.WriteLine("adding to buffer = "+_buffer[_bufferPos]);
+
+ ++_bufferPos;
+
+ if (_bufferPos == _buffer.Length)
+ {
+ processFilledBuffer();
+ }
+
+ increment();
+ }
+
+ private void increment()
+ {
+ int carry = 0;
+ for (int i = _bitCount.Length - 1; i >= 0; i--)
+ {
+ int sum = (_bitCount[i] & 0xff) + EIGHT[i] + carry;
+
+ carry = sum >> 8;
+ _bitCount[i] = (short)(sum & 0xff);
+ }
+ }
+
+ public void BlockUpdate(byte[] input, int inOff, int length)
+ {
+ while (length > 0)
+ {
+ Update(input[inOff]);
+ ++inOff;
+ --length;
+ }
+
+ }
+
+ private void finish()
+ {
+ /*
+ * this makes a copy of the current bit length. at the expense of an
+ * object creation of 32 bytes rather than providing a _stopCounting
+ * boolean which was the alternative I could think of.
+ */
+ byte[] bitLength = copyBitLength();
+
+ _buffer[_bufferPos++] |= 0x80;
+
+ if (_bufferPos == _buffer.Length)
+ {
+ processFilledBuffer();
+ }
+
+ /*
+ * Final block contains
+ * [ ... data .... ][0][0][0][ length ]
+ *
+ * if [ length ] cannot fit. Need to create a new block.
+ */
+ if (_bufferPos > 32)
+ {
+ while (_bufferPos != 0)
+ {
+ Update((byte)0);
+ }
+ }
+
+ while (_bufferPos <= 32)
+ {
+ Update((byte)0);
+ }
+
+ // copy the length information to the final 32 bytes of the
+ // 64 byte block....
+ Array.Copy(bitLength, 0, _buffer, 32, bitLength.Length);
+
+ processFilledBuffer();
+ }
+
+ private byte[] copyBitLength()
+ {
+ byte[] rv = new byte[BITCOUNT_ARRAY_SIZE];
+ for (int i = 0; i < rv.Length; i++)
+ {
+ rv[i] = (byte)(_bitCount[i] & 0xff);
+ }
+ return rv;
+ }
+
+ public int GetByteLength()
+ {
+ return BYTE_LENGTH;
+ }
+
+ public IMemoable Copy()
+ {
+ return new WhirlpoolDigest(this);
+ }
+
+ public void Reset(IMemoable other)
+ {
+ WhirlpoolDigest originalDigest = (WhirlpoolDigest)other;
+
+ Array.Copy(originalDigest._rc, 0, _rc, 0, _rc.Length);
+
+ Array.Copy(originalDigest._buffer, 0, _buffer, 0, _buffer.Length);
+
+ this._bufferPos = originalDigest._bufferPos;
+ Array.Copy(originalDigest._bitCount, 0, _bitCount, 0, _bitCount.Length);
+
+ // -- internal hash state --
+ Array.Copy(originalDigest._hash, 0, _hash, 0, _hash.Length);
+ Array.Copy(originalDigest._K, 0, _K, 0, _K.Length);
+ Array.Copy(originalDigest._L, 0, _L, 0, _L.Length);
+ Array.Copy(originalDigest._block, 0, _block, 0, _block.Length);
+ Array.Copy(originalDigest._state, 0, _state, 0, _state.Length);
+ }
+
+
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/ec/CustomNamedCurves.cs b/bc-sharp-crypto/src/crypto/ec/CustomNamedCurves.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4b7600e09bb7743f15ceff8fdb130b0e60c156fb
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/ec/CustomNamedCurves.cs
@@ -0,0 +1,913 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.GM;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.EC.Custom.Djb;
+using Org.BouncyCastle.Math.EC.Custom.GM;
+using Org.BouncyCastle.Math.EC.Custom.Sec;
+using Org.BouncyCastle.Math.EC.Endo;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.EC
+{
+ public sealed class CustomNamedCurves
+ {
+ private CustomNamedCurves()
+ {
+ }
+
+ private static BigInteger FromHex(string hex)
+ {
+ return new BigInteger(1, Hex.Decode(hex));
+ }
+
+ private static ECCurve ConfigureCurve(ECCurve curve)
+ {
+ return curve;
+ }
+
+ private static ECCurve ConfigureCurveGlv(ECCurve c, GlvTypeBParameters p)
+ {
+ return c.Configure().SetEndomorphism(new GlvTypeBEndomorphism(c, p)).Create();
+ }
+
+ /*
+ * curve25519
+ */
+ internal class Curve25519Holder
+ : X9ECParametersHolder
+ {
+ private Curve25519Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new Curve25519Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = null;
+ ECCurve curve = ConfigureCurve(new Curve25519());
+
+ /*
+ * NOTE: Curve25519 was specified in Montgomery form. Rewriting in Weierstrass form
+ * involves substitution of variables, so the base-point x coordinate is 9 + (486662 / 3).
+ *
+ * The Curve25519 paper doesn't say which of the two possible y values the base
+ * point has. The choice here is guided by language in the Ed25519 paper.
+ *
+ * (The other possible y value is 5F51E65E475F794B1FE122D388B72EB36DC2B28192839E4DD6163A5D81312C14)
+ */
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD245A"
+ + "20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9"));
+
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ }
+
+ /*
+ * secp128r1
+ */
+ internal class SecP128R1Holder
+ : X9ECParametersHolder
+ {
+ private SecP128R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecP128R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("000E0D4D696E6768756151750CC03A4473D03679");
+ ECCurve curve = ConfigureCurve(new SecP128R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "161FF7528B899B2D0C28607CA52C5B86"
+ + "CF5AC8395BAFEB13C02DA292DDED7A83"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * secp160k1
+ */
+ internal class SecP160K1Holder
+ : X9ECParametersHolder
+ {
+ private SecP160K1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecP160K1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = null;
+ GlvTypeBParameters glv = new GlvTypeBParameters(
+ new BigInteger("9ba48cba5ebcb9b6bd33b92830b2a2e0e192f10a", 16),
+ new BigInteger("c39c6c3b3a36d7701b9c71a1f5804ae5d0003f4", 16),
+ new BigInteger[]{
+ new BigInteger("9162fbe73984472a0a9e", 16),
+ new BigInteger("-96341f1138933bc2f505", 16) },
+ new BigInteger[]{
+ new BigInteger("127971af8721782ecffa3", 16),
+ new BigInteger("9162fbe73984472a0a9e", 16) },
+ new BigInteger("9162fbe73984472a0a9d0590", 16),
+ new BigInteger("96341f1138933bc2f503fd44", 16),
+ 176);
+ ECCurve curve = ConfigureCurveGlv(new SecP160K1Curve(), glv);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"
+ + "938CF935318FDCED6BC28286531733C3F03C4FEE"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * secp160r1
+ */
+ internal class SecP160R1Holder
+ : X9ECParametersHolder
+ {
+ private SecP160R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecP160R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("1053CDE42C14D696E67687561517533BF3F83345");
+ ECCurve curve = ConfigureCurve(new SecP160R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "4A96B5688EF573284664698968C38BB913CBFC82"
+ + "23A628553168947D59DCC912042351377AC5FB32"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * secp160r2
+ */
+ internal class SecP160R2Holder
+ : X9ECParametersHolder
+ {
+ private SecP160R2Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecP160R2Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("B99B99B099B323E02709A4D696E6768756151751");
+ ECCurve curve = ConfigureCurve(new SecP160R2Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "52DCB034293A117E1F4FF11B30F7199D3144CE6D"
+ + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * secp192k1
+ */
+ internal class SecP192K1Holder
+ : X9ECParametersHolder
+ {
+ private SecP192K1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecP192K1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = null;
+ GlvTypeBParameters glv = new GlvTypeBParameters(
+ new BigInteger("bb85691939b869c1d087f601554b96b80cb4f55b35f433c2", 16),
+ new BigInteger("3d84f26c12238d7b4f3d516613c1759033b1a5800175d0b1", 16),
+ new BigInteger[]{
+ new BigInteger("71169be7330b3038edb025f1", 16),
+ new BigInteger("-b3fb3400dec5c4adceb8655c", 16) },
+ new BigInteger[]{
+ new BigInteger("12511cfe811d0f4e6bc688b4d", 16),
+ new BigInteger("71169be7330b3038edb025f1", 16) },
+ new BigInteger("71169be7330b3038edb025f1d0f9", 16),
+ new BigInteger("b3fb3400dec5c4adceb8655d4c94", 16),
+ 208);
+ ECCurve curve = ConfigureCurveGlv(new SecP192K1Curve(), glv);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"
+ + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ }
+
+ /*
+ * secp192r1
+ */
+ internal class SecP192R1Holder
+ : X9ECParametersHolder
+ {
+ private SecP192R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecP192R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("3045AE6FC8422F64ED579528D38120EAE12196D5");
+ ECCurve curve = ConfigureCurve(new SecP192R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"
+ + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ }
+
+ /*
+ * secp224k1
+ */
+ internal class SecP224K1Holder
+ : X9ECParametersHolder
+ {
+ private SecP224K1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecP224K1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = null;
+ GlvTypeBParameters glv = new GlvTypeBParameters(
+ new BigInteger("fe0e87005b4e83761908c5131d552a850b3f58b749c37cf5b84d6768", 16),
+ new BigInteger("60dcd2104c4cbc0be6eeefc2bdd610739ec34e317f9b33046c9e4788", 16),
+ new BigInteger[]{
+ new BigInteger("6b8cf07d4ca75c88957d9d670591", 16),
+ new BigInteger("-b8adf1378a6eb73409fa6c9c637d", 16) },
+ new BigInteger[]{
+ new BigInteger("1243ae1b4d71613bc9f780a03690e", 16),
+ new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) },
+ new BigInteger("6b8cf07d4ca75c88957d9d67059037a4", 16),
+ new BigInteger("b8adf1378a6eb73409fa6c9c637ba7f5", 16),
+ 240);
+ ECCurve curve = ConfigureCurveGlv(new SecP224K1Curve(), glv);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"
+ + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ }
+
+ /*
+ * secp224r1
+ */
+ internal class SecP224R1Holder
+ : X9ECParametersHolder
+ {
+ private SecP224R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecP224R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5");
+ ECCurve curve = ConfigureCurve(new SecP224R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
+ + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ }
+
+ /*
+ * secp256k1
+ */
+ internal class SecP256K1Holder
+ : X9ECParametersHolder
+ {
+ private SecP256K1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new SecP256K1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = null;
+ GlvTypeBParameters glv = new GlvTypeBParameters(
+ new BigInteger("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee", 16),
+ new BigInteger("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72", 16),
+ new BigInteger[]{
+ new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16),
+ new BigInteger("-e4437ed6010e88286f547fa90abfe4c3", 16) },
+ new BigInteger[]{
+ new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16),
+ new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) },
+ new BigInteger("3086d221a7d46bcde86c90e49284eb153dab", 16),
+ new BigInteger("e4437ed6010e88286f547fa90abfe4c42212", 16),
+ 272);
+ ECCurve curve = ConfigureCurveGlv(new SecP256K1Curve(), glv);
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
+ + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ }
+
+ /*
+ * secp256r1
+ */
+ internal class SecP256R1Holder
+ : X9ECParametersHolder
+ {
+ private SecP256R1Holder() {}
+
+ internal static readonly X9ECParametersHolder Instance = new SecP256R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("C49D360886E704936A6678E1139D26B7819F7E90");
+ ECCurve curve = ConfigureCurve(new SecP256R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
+ + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ }
+
+ /*
+ * secp384r1
+ */
+ internal class SecP384R1Holder
+ : X9ECParametersHolder
+ {
+ private SecP384R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecP384R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("A335926AA319A27A1D00896A6773A4827ACDAC73");
+ ECCurve curve = ConfigureCurve(new SecP384R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"
+ + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ }
+
+ /*
+ * secp521r1
+ */
+ internal class SecP521R1Holder
+ : X9ECParametersHolder
+ {
+ private SecP521R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecP521R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("D09E8800291CB85396CC6717393284AAA0DA64BA");
+ ECCurve curve = ConfigureCurve(new SecP521R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"
+ + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ }
+
+ /*
+ * sect113r1
+ */
+ internal class SecT113R1Holder
+ : X9ECParametersHolder
+ {
+ private SecT113R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT113R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("10E723AB14D696E6768756151756FEBF8FCB49A9");
+ ECCurve curve = ConfigureCurve(new SecT113R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "009D73616F35F4AB1407D73562C10F"
+ + "00A52830277958EE84D1315ED31886"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect113r2
+ */
+ internal class SecT113R2Holder
+ : X9ECParametersHolder
+ {
+ private SecT113R2Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT113R2Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("10C0FB15760860DEF1EEF4D696E676875615175D");
+ ECCurve curve = ConfigureCurve(new SecT113R2Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "01A57A6A7B26CA5EF52FCDB8164797"
+ + "00B3ADC94ED1FE674C06E695BABA1D"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect131r1
+ */
+ internal class SecT131R1Holder
+ : X9ECParametersHolder
+ {
+ private SecT131R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT131R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("4D696E676875615175985BD3ADBADA21B43A97E2");
+ ECCurve curve = ConfigureCurve(new SecT131R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "0081BAF91FDF9833C40F9C181343638399"
+ + "078C6E7EA38C001F73C8134B1B4EF9E150"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect131r2
+ */
+ internal class SecT131R2Holder
+ : X9ECParametersHolder
+ {
+ private SecT131R2Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT131R2Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("985BD3ADBAD4D696E676875615175A21B43A97E3");
+ ECCurve curve = ConfigureCurve(new SecT131R2Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "0356DCD8F2F95031AD652D23951BB366A8"
+ + "0648F06D867940A5366D9E265DE9EB240F"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect163k1
+ */
+ internal class SecT163K1Holder
+ : X9ECParametersHolder
+ {
+ private SecT163K1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT163K1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = null;
+ ECCurve curve = ConfigureCurve(new SecT163K1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8"
+ + "0289070FB05D38FF58321F2E800536D538CCDAA3D9"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect163r1
+ */
+ internal class SecT163R1Holder
+ : X9ECParametersHolder
+ {
+ private SecT163R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT163R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("24B7B137C8A14D696E6768756151756FD0DA2E5C");
+ ECCurve curve = ConfigureCurve(new SecT163R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "0369979697AB43897789566789567F787A7876A654"
+ + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect163r2
+ */
+ internal class SecT163R2Holder
+ : X9ECParametersHolder
+ {
+ private SecT163R2Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT163R2Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("85E25BFE5C86226CDB12016F7553F9D0E693A268");
+ ECCurve curve = ConfigureCurve(new SecT163R2Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "03F0EBA16286A2D57EA0991168D4994637E8343E36"
+ + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect193r1
+ */
+ internal class SecT193R1Holder
+ : X9ECParametersHolder
+ {
+ private SecT193R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT193R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("103FAEC74D696E676875615175777FC5B191EF30");
+ ECCurve curve = ConfigureCurve(new SecT193R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1"
+ + "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect193r2
+ */
+ internal class SecT193R2Holder
+ : X9ECParametersHolder
+ {
+ private SecT193R2Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT193R2Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("10B7B4D696E676875615175137C8A16FD0DA2211");
+ ECCurve curve = ConfigureCurve(new SecT193R2Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F"
+ + "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect233k1
+ */
+ internal class SecT233K1Holder
+ : X9ECParametersHolder
+ {
+ private SecT233K1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT233K1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = null;
+ ECCurve curve = ConfigureCurve(new SecT233K1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126"
+ + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect233r1
+ */
+ internal class SecT233R1Holder
+ : X9ECParametersHolder
+ {
+ private SecT233R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT233R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("74D59FF07F6B413D0EA14B344B20A2DB049B50C3");
+ ECCurve curve = ConfigureCurve(new SecT233R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"
+ + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect239k1
+ */
+ internal class SecT239K1Holder
+ : X9ECParametersHolder
+ {
+ private SecT239K1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT239K1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = null;
+ ECCurve curve = ConfigureCurve(new SecT239K1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC"
+ + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect283k1
+ */
+ internal class SecT283K1Holder
+ : X9ECParametersHolder
+ {
+ private SecT283K1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT283K1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = null;
+ ECCurve curve = ConfigureCurve(new SecT283K1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836"
+ + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect283r1
+ */
+ internal class SecT283R1Holder
+ : X9ECParametersHolder
+ {
+ private SecT283R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT283R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE");
+ ECCurve curve = ConfigureCurve(new SecT283R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053"
+ + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect409k1
+ */
+ internal class SecT409K1Holder
+ : X9ECParametersHolder
+ {
+ private SecT409K1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT409K1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = null;
+ ECCurve curve = ConfigureCurve(new SecT409K1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746"
+ + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect409r1
+ */
+ internal class SecT409R1Holder
+ : X9ECParametersHolder
+ {
+ private SecT409R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT409R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("4099B5A457F9D69F79213D094C4BCD4D4262210B");
+ ECCurve curve = ConfigureCurve(new SecT409R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7"
+ + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect571k1
+ */
+ internal class SecT571K1Holder
+ : X9ECParametersHolder
+ {
+ private SecT571K1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT571K1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = null;
+ ECCurve curve = ConfigureCurve(new SecT571K1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972"
+ + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sect571r1
+ */
+ internal class SecT571R1Holder
+ : X9ECParametersHolder
+ {
+ private SecT571R1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SecT571R1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = Hex.Decode("2AA058F73A0E33AB486B0F610410C53A7F132310");
+ ECCurve curve = ConfigureCurve(new SecT571R1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19"
+ + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ };
+
+ /*
+ * sm2p256v1
+ */
+ internal class SM2P256V1Holder
+ : X9ECParametersHolder
+ {
+ private SM2P256V1Holder() { }
+
+ internal static readonly X9ECParametersHolder Instance = new SM2P256V1Holder();
+
+ protected override X9ECParameters CreateParameters()
+ {
+ byte[] S = null;
+ ECCurve curve = ConfigureCurve(new SM2P256V1Curve());
+ X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
+ + "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7"
+ + "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"));
+ return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+ }
+ }
+
+
+ private static readonly IDictionary nameToCurve = Platform.CreateHashtable();
+ private static readonly IDictionary nameToOid = Platform.CreateHashtable();
+ private static readonly IDictionary oidToCurve = Platform.CreateHashtable();
+ private static readonly IDictionary oidToName = Platform.CreateHashtable();
+ private static readonly IList names = Platform.CreateArrayList();
+
+ private static void DefineCurve(string name, X9ECParametersHolder holder)
+ {
+ names.Add(name);
+ name = Platform.ToUpperInvariant(name);
+ nameToCurve.Add(name, holder);
+ }
+
+ private static void DefineCurveWithOid(string name, DerObjectIdentifier oid, X9ECParametersHolder holder)
+ {
+ names.Add(name);
+ oidToName.Add(oid, name);
+ oidToCurve.Add(oid, holder);
+ name = Platform.ToUpperInvariant(name);
+ nameToOid.Add(name, oid);
+ nameToCurve.Add(name, holder);
+ }
+
+ private static void DefineCurveAlias(string name, DerObjectIdentifier oid)
+ {
+ object curve = oidToCurve[oid];
+ if (curve == null)
+ throw new InvalidOperationException();
+
+ name = Platform.ToUpperInvariant(name);
+ nameToOid.Add(name, oid);
+ nameToCurve.Add(name, curve);
+ }
+
+ static CustomNamedCurves()
+ {
+ DefineCurve("curve25519", Curve25519Holder.Instance);
+
+ //DefineCurveWithOid("secp112r1", SecObjectIdentifiers.SecP112r1, SecP112R1Holder.Instance);
+ //DefineCurveWithOid("secp112r2", SecObjectIdentifiers.SecP112r2, SecP112R2Holder.Instance);
+ DefineCurveWithOid("secp128r1", SecObjectIdentifiers.SecP128r1, SecP128R1Holder.Instance);
+ //DefineCurveWithOid("secp128r2", SecObjectIdentifiers.SecP128r2, SecP128R2Holder.Instance);
+ DefineCurveWithOid("secp160k1", SecObjectIdentifiers.SecP160k1, SecP160K1Holder.Instance);
+ DefineCurveWithOid("secp160r1", SecObjectIdentifiers.SecP160r1, SecP160R1Holder.Instance);
+ DefineCurveWithOid("secp160r2", SecObjectIdentifiers.SecP160r2, SecP160R2Holder.Instance);
+ DefineCurveWithOid("secp192k1", SecObjectIdentifiers.SecP192k1, SecP192K1Holder.Instance);
+ DefineCurveWithOid("secp192r1", SecObjectIdentifiers.SecP192r1, SecP192R1Holder.Instance);
+ DefineCurveWithOid("secp224k1", SecObjectIdentifiers.SecP224k1, SecP224K1Holder.Instance);
+ DefineCurveWithOid("secp224r1", SecObjectIdentifiers.SecP224r1, SecP224R1Holder.Instance);
+ DefineCurveWithOid("secp256k1", SecObjectIdentifiers.SecP256k1, SecP256K1Holder.Instance);
+ DefineCurveWithOid("secp256r1", SecObjectIdentifiers.SecP256r1, SecP256R1Holder.Instance);
+ DefineCurveWithOid("secp384r1", SecObjectIdentifiers.SecP384r1, SecP384R1Holder.Instance);
+ DefineCurveWithOid("secp521r1", SecObjectIdentifiers.SecP521r1, SecP521R1Holder.Instance);
+
+ DefineCurveWithOid("sect113r1", SecObjectIdentifiers.SecT113r1, SecT113R1Holder.Instance);
+ DefineCurveWithOid("sect113r2", SecObjectIdentifiers.SecT113r2, SecT113R2Holder.Instance);
+ DefineCurveWithOid("sect131r1", SecObjectIdentifiers.SecT131r1, SecT131R1Holder.Instance);
+ DefineCurveWithOid("sect131r2", SecObjectIdentifiers.SecT131r2, SecT131R2Holder.Instance);
+ DefineCurveWithOid("sect163k1", SecObjectIdentifiers.SecT163k1, SecT163K1Holder.Instance);
+ DefineCurveWithOid("sect163r1", SecObjectIdentifiers.SecT163r1, SecT163R1Holder.Instance);
+ DefineCurveWithOid("sect163r2", SecObjectIdentifiers.SecT163r2, SecT163R2Holder.Instance);
+ DefineCurveWithOid("sect193r1", SecObjectIdentifiers.SecT193r1, SecT193R1Holder.Instance);
+ DefineCurveWithOid("sect193r2", SecObjectIdentifiers.SecT193r2, SecT193R2Holder.Instance);
+ DefineCurveWithOid("sect233k1", SecObjectIdentifiers.SecT233k1, SecT233K1Holder.Instance);
+ DefineCurveWithOid("sect233r1", SecObjectIdentifiers.SecT233r1, SecT233R1Holder.Instance);
+ DefineCurveWithOid("sect239k1", SecObjectIdentifiers.SecT239k1, SecT239K1Holder.Instance);
+ DefineCurveWithOid("sect283k1", SecObjectIdentifiers.SecT283k1, SecT283K1Holder.Instance);
+ DefineCurveWithOid("sect283r1", SecObjectIdentifiers.SecT283r1, SecT283R1Holder.Instance);
+ DefineCurveWithOid("sect409k1", SecObjectIdentifiers.SecT409k1, SecT409K1Holder.Instance);
+ DefineCurveWithOid("sect409r1", SecObjectIdentifiers.SecT409r1, SecT409R1Holder.Instance);
+ DefineCurveWithOid("sect571k1", SecObjectIdentifiers.SecT571k1, SecT571K1Holder.Instance);
+ DefineCurveWithOid("sect571r1", SecObjectIdentifiers.SecT571r1, SecT571R1Holder.Instance);
+
+ DefineCurveWithOid("sm2p256v1", GMObjectIdentifiers.sm2p256v1, SM2P256V1Holder.Instance);
+
+ DefineCurveAlias("B-163", SecObjectIdentifiers.SecT163r2);
+ DefineCurveAlias("B-233", SecObjectIdentifiers.SecT233r1);
+ DefineCurveAlias("B-283", SecObjectIdentifiers.SecT283r1);
+ DefineCurveAlias("B-409", SecObjectIdentifiers.SecT409r1);
+ DefineCurveAlias("B-571", SecObjectIdentifiers.SecT571r1);
+
+ DefineCurveAlias("K-163", SecObjectIdentifiers.SecT163k1);
+ DefineCurveAlias("K-233", SecObjectIdentifiers.SecT233k1);
+ DefineCurveAlias("K-283", SecObjectIdentifiers.SecT283k1);
+ DefineCurveAlias("K-409", SecObjectIdentifiers.SecT409k1);
+ DefineCurveAlias("K-571", SecObjectIdentifiers.SecT571k1);
+
+ DefineCurveAlias("P-192", SecObjectIdentifiers.SecP192r1);
+ DefineCurveAlias("P-224", SecObjectIdentifiers.SecP224r1);
+ DefineCurveAlias("P-256", SecObjectIdentifiers.SecP256r1);
+ DefineCurveAlias("P-384", SecObjectIdentifiers.SecP384r1);
+ DefineCurveAlias("P-521", SecObjectIdentifiers.SecP521r1);
+ }
+
+ public static X9ECParameters GetByName(string name)
+ {
+ X9ECParametersHolder holder = (X9ECParametersHolder)nameToCurve[Platform.ToUpperInvariant(name)];
+ return holder == null ? null : holder.Parameters;
+ }
+
+ /**
+ * return the X9ECParameters object for the named curve represented by
+ * the passed in object identifier. Null if the curve isn't present.
+ *
+ * @param oid an object identifier representing a named curve, if present.
+ */
+ public static X9ECParameters GetByOid(DerObjectIdentifier oid)
+ {
+ X9ECParametersHolder holder = (X9ECParametersHolder)oidToCurve[oid];
+ return holder == null ? null : holder.Parameters;
+ }
+
+ /**
+ * return the object identifier signified by the passed in name. Null
+ * if there is no object identifier associated with name.
+ *
+ * @return the object identifier associated with name, if present.
+ */
+ public static DerObjectIdentifier GetOid(string name)
+ {
+ return (DerObjectIdentifier)nameToOid[Platform.ToUpperInvariant(name)];
+ }
+
+ /**
+ * return the named curve name represented by the given object identifier.
+ */
+ public static string GetName(DerObjectIdentifier oid)
+ {
+ return (string)oidToName[oid];
+ }
+
+ /**
+ * returns an enumeration containing the name strings for curves
+ * contained in this structure.
+ */
+ public static IEnumerable Names
+ {
+ get { return new EnumerableProxy(names); }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/encodings/ISO9796d1Encoding.cs b/bc-sharp-crypto/src/crypto/encodings/ISO9796d1Encoding.cs
new file mode 100644
index 0000000000000000000000000000000000000000..30e98835669deb395730cf36034ca93dea33846f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/encodings/ISO9796d1Encoding.cs
@@ -0,0 +1,273 @@
+using System;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Encodings
+{
+ /**
+ * ISO 9796-1 padding. Note in the light of recent results you should
+ * only use this with RSA (rather than the "simpler" Rabin keys) and you
+ * should never use it with anything other than a hash (ie. even if the
+ * message is small don't sign the message, sign it's hash) or some "random"
+ * value. See your favorite search engine for details.
+ */
+ public class ISO9796d1Encoding
+ : IAsymmetricBlockCipher
+ {
+ private static readonly BigInteger Sixteen = BigInteger.ValueOf(16);
+ private static readonly BigInteger Six = BigInteger.ValueOf(6);
+
+ private static readonly byte[] shadows = { 0xe, 0x3, 0x5, 0x8, 0x9, 0x4, 0x2, 0xf,
+ 0x0, 0xd, 0xb, 0x6, 0x7, 0xa, 0xc, 0x1 };
+ private static readonly byte[] inverse = { 0x8, 0xf, 0x6, 0x1, 0x5, 0x2, 0xb, 0xc,
+ 0x3, 0x4, 0xd, 0xa, 0xe, 0x9, 0x0, 0x7 };
+
+ private readonly IAsymmetricBlockCipher engine;
+ private bool forEncryption;
+ private int bitSize;
+ private int padBits = 0;
+ private BigInteger modulus;
+
+ public ISO9796d1Encoding(
+ IAsymmetricBlockCipher cipher)
+ {
+ this.engine = cipher;
+ }
+
+ public string AlgorithmName
+ {
+ get { return engine.AlgorithmName + "/ISO9796-1Padding"; }
+ }
+
+ public IAsymmetricBlockCipher GetUnderlyingCipher()
+ {
+ return engine;
+ }
+
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ RsaKeyParameters kParam;
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+ kParam = (RsaKeyParameters)rParam.Parameters;
+ }
+ else
+ {
+ kParam = (RsaKeyParameters)parameters;
+ }
+
+ engine.Init(forEncryption, parameters);
+
+ modulus = kParam.Modulus;
+ bitSize = modulus.BitLength;
+
+ this.forEncryption = forEncryption;
+ }
+
+ /**
+ * return the input block size. The largest message we can process
+ * is (key_size_in_bits + 3)/16, which in our world comes to
+ * key_size_in_bytes / 2.
+ */
+ public int GetInputBlockSize()
+ {
+ int baseBlockSize = engine.GetInputBlockSize();
+
+ if (forEncryption)
+ {
+ return (baseBlockSize + 1) / 2;
+ }
+ else
+ {
+ return baseBlockSize;
+ }
+ }
+
+ /**
+ * return the maximum possible size for the output.
+ */
+ public int GetOutputBlockSize()
+ {
+ int baseBlockSize = engine.GetOutputBlockSize();
+
+ if (forEncryption)
+ {
+ return baseBlockSize;
+ }
+ else
+ {
+ return (baseBlockSize + 1) / 2;
+ }
+ }
+
+ /**
+ * set the number of bits in the next message to be treated as
+ * pad bits.
+ */
+ public void SetPadBits(
+ int padBits)
+ {
+ if (padBits > 7)
+ {
+ throw new ArgumentException("padBits > 7");
+ }
+
+ this.padBits = padBits;
+ }
+
+ /**
+ * retrieve the number of pad bits in the last decoded message.
+ */
+ public int GetPadBits()
+ {
+ return padBits;
+ }
+
+ public byte[] ProcessBlock(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (forEncryption)
+ {
+ return EncodeBlock(input, inOff, length);
+ }
+ else
+ {
+ return DecodeBlock(input, inOff, length);
+ }
+ }
+
+ private byte[] EncodeBlock(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ byte[] block = new byte[(bitSize + 7) / 8];
+ int r = padBits + 1;
+ int z = inLen;
+ int t = (bitSize + 13) / 16;
+
+ for (int i = 0; i < t; i += z)
+ {
+ if (i > t - z)
+ {
+ Array.Copy(input, inOff + inLen - (t - i),
+ block, block.Length - t, t - i);
+ }
+ else
+ {
+ Array.Copy(input, inOff, block, block.Length - (i + z), z);
+ }
+ }
+
+ for (int i = block.Length - 2 * t; i != block.Length; i += 2)
+ {
+ byte val = block[block.Length - t + i / 2];
+
+ block[i] = (byte)((shadows[(uint) (val & 0xff) >> 4] << 4)
+ | shadows[val & 0x0f]);
+ block[i + 1] = val;
+ }
+
+ block[block.Length - 2 * z] ^= (byte) r;
+ block[block.Length - 1] = (byte)((block[block.Length - 1] << 4) | 0x06);
+
+ int maxBit = (8 - (bitSize - 1) % 8);
+ int offSet = 0;
+
+ if (maxBit != 8)
+ {
+ block[0] &= (byte) ((ushort) 0xff >> maxBit);
+ block[0] |= (byte) ((ushort) 0x80 >> maxBit);
+ }
+ else
+ {
+ block[0] = 0x00;
+ block[1] |= 0x80;
+ offSet = 1;
+ }
+
+ return engine.ProcessBlock(block, offSet, block.Length - offSet);
+ }
+
+ /**
+ * @exception InvalidCipherTextException if the decrypted block is not a valid ISO 9796 bit string
+ */
+ private byte[] DecodeBlock(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ byte[] block = engine.ProcessBlock(input, inOff, inLen);
+ int r = 1;
+ int t = (bitSize + 13) / 16;
+
+ BigInteger iS = new BigInteger(1, block);
+ BigInteger iR;
+ if (iS.Mod(Sixteen).Equals(Six))
+ {
+ iR = iS;
+ }
+ else
+ {
+ iR = modulus.Subtract(iS);
+
+ if (!iR.Mod(Sixteen).Equals(Six))
+ throw new InvalidCipherTextException("resulting integer iS or (modulus - iS) is not congruent to 6 mod 16");
+ }
+
+ block = iR.ToByteArrayUnsigned();
+
+ if ((block[block.Length - 1] & 0x0f) != 0x6)
+ throw new InvalidCipherTextException("invalid forcing byte in block");
+
+ block[block.Length - 1] =
+ (byte)(((ushort)(block[block.Length - 1] & 0xff) >> 4)
+ | ((inverse[(block[block.Length - 2] & 0xff) >> 4]) << 4));
+
+ block[0] = (byte)((shadows[(uint) (block[1] & 0xff) >> 4] << 4)
+ | shadows[block[1] & 0x0f]);
+
+ bool boundaryFound = false;
+ int boundary = 0;
+
+ for (int i = block.Length - 1; i >= block.Length - 2 * t; i -= 2)
+ {
+ int val = ((shadows[(uint) (block[i] & 0xff) >> 4] << 4)
+ | shadows[block[i] & 0x0f]);
+
+ if (((block[i - 1] ^ val) & 0xff) != 0)
+ {
+ if (!boundaryFound)
+ {
+ boundaryFound = true;
+ r = (block[i - 1] ^ val) & 0xff;
+ boundary = i - 1;
+ }
+ else
+ {
+ throw new InvalidCipherTextException("invalid tsums in block");
+ }
+ }
+ }
+
+ block[boundary] = 0;
+
+ byte[] nblock = new byte[(block.Length - boundary) / 2];
+
+ for (int i = 0; i < nblock.Length; i++)
+ {
+ nblock[i] = block[2 * i + boundary + 1];
+ }
+
+ padBits = r - 1;
+
+ return nblock;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/encodings/OaepEncoding.cs b/bc-sharp-crypto/src/crypto/encodings/OaepEncoding.cs
new file mode 100644
index 0000000000000000000000000000000000000000..287876f12e879183e69fd9456d6584c64a01df5f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/encodings/OaepEncoding.cs
@@ -0,0 +1,345 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Encodings
+{
+ /**
+ * Optimal Asymmetric Encryption Padding (OAEP) - see PKCS 1 V 2.
+ */
+ public class OaepEncoding
+ : IAsymmetricBlockCipher
+ {
+ private byte[] defHash;
+ private IDigest mgf1Hash;
+
+ private IAsymmetricBlockCipher engine;
+ private SecureRandom random;
+ private bool forEncryption;
+
+ public OaepEncoding(
+ IAsymmetricBlockCipher cipher)
+ : this(cipher, new Sha1Digest(), null)
+ {
+ }
+
+ public OaepEncoding(
+ IAsymmetricBlockCipher cipher,
+ IDigest hash)
+ : this(cipher, hash, null)
+ {
+ }
+
+ public OaepEncoding(
+ IAsymmetricBlockCipher cipher,
+ IDigest hash,
+ byte[] encodingParams)
+ : this(cipher, hash, hash, encodingParams)
+ {
+ }
+
+ public OaepEncoding(
+ IAsymmetricBlockCipher cipher,
+ IDigest hash,
+ IDigest mgf1Hash,
+ byte[] encodingParams)
+ {
+ this.engine = cipher;
+ this.mgf1Hash = mgf1Hash;
+ this.defHash = new byte[hash.GetDigestSize()];
+
+ hash.Reset();
+
+ if (encodingParams != null)
+ {
+ hash.BlockUpdate(encodingParams, 0, encodingParams.Length);
+ }
+
+ hash.DoFinal(defHash, 0);
+ }
+
+ public IAsymmetricBlockCipher GetUnderlyingCipher()
+ {
+ return engine;
+ }
+
+ public string AlgorithmName
+ {
+ get { return engine.AlgorithmName + "/OAEPPadding"; }
+ }
+
+ public void Init(
+ bool forEncryption,
+ ICipherParameters param)
+ {
+ if (param is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+ this.random = rParam.Random;
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ }
+
+ engine.Init(forEncryption, param);
+
+ this.forEncryption = forEncryption;
+ }
+
+ public int GetInputBlockSize()
+ {
+ int baseBlockSize = engine.GetInputBlockSize();
+
+ if (forEncryption)
+ {
+ return baseBlockSize - 1 - 2 * defHash.Length;
+ }
+ else
+ {
+ return baseBlockSize;
+ }
+ }
+
+ public int GetOutputBlockSize()
+ {
+ int baseBlockSize = engine.GetOutputBlockSize();
+
+ if (forEncryption)
+ {
+ return baseBlockSize;
+ }
+ else
+ {
+ return baseBlockSize - 1 - 2 * defHash.Length;
+ }
+ }
+
+ public byte[] ProcessBlock(
+ byte[] inBytes,
+ int inOff,
+ int inLen)
+ {
+ if (forEncryption)
+ {
+ return EncodeBlock(inBytes, inOff, inLen);
+ }
+ else
+ {
+ return DecodeBlock(inBytes, inOff, inLen);
+ }
+ }
+
+ private byte[] EncodeBlock(
+ byte[] inBytes,
+ int inOff,
+ int inLen)
+ {
+ Check.DataLength(inLen > GetInputBlockSize(), "input data too long");
+
+ byte[] block = new byte[GetInputBlockSize() + 1 + 2 * defHash.Length];
+
+ //
+ // copy in the message
+ //
+ Array.Copy(inBytes, inOff, block, block.Length - inLen, inLen);
+
+ //
+ // add sentinel
+ //
+ block[block.Length - inLen - 1] = 0x01;
+
+ //
+ // as the block is already zeroed - there's no need to add PS (the >= 0 pad of 0)
+ //
+
+ //
+ // add the hash of the encoding params.
+ //
+ Array.Copy(defHash, 0, block, defHash.Length, defHash.Length);
+
+ //
+ // generate the seed.
+ //
+ byte[] seed = SecureRandom.GetNextBytes(random, defHash.Length);
+
+ //
+ // mask the message block.
+ //
+ byte[] mask = maskGeneratorFunction1(seed, 0, seed.Length, block.Length - defHash.Length);
+
+ for (int i = defHash.Length; i != block.Length; i++)
+ {
+ block[i] ^= mask[i - defHash.Length];
+ }
+
+ //
+ // add in the seed
+ //
+ Array.Copy(seed, 0, block, 0, defHash.Length);
+
+ //
+ // mask the seed.
+ //
+ mask = maskGeneratorFunction1(
+ block, defHash.Length, block.Length - defHash.Length, defHash.Length);
+
+ for (int i = 0; i != defHash.Length; i++)
+ {
+ block[i] ^= mask[i];
+ }
+
+ return engine.ProcessBlock(block, 0, block.Length);
+ }
+
+ /**
+ * @exception InvalidCipherTextException if the decrypted block turns out to
+ * be badly formatted.
+ */
+ private byte[] DecodeBlock(
+ byte[] inBytes,
+ int inOff,
+ int inLen)
+ {
+ byte[] data = engine.ProcessBlock(inBytes, inOff, inLen);
+ byte[] block = new byte[engine.GetOutputBlockSize()];
+
+ //
+ // as we may have zeros in our leading bytes for the block we produced
+ // on encryption, we need to make sure our decrypted block comes back
+ // the same size.
+ //
+
+ Array.Copy(data, 0, block, block.Length - data.Length, data.Length);
+
+ bool shortData = (block.Length < (2 * defHash.Length) + 1);
+
+ //
+ // unmask the seed.
+ //
+ byte[] mask = maskGeneratorFunction1(
+ block, defHash.Length, block.Length - defHash.Length, defHash.Length);
+
+ for (int i = 0; i != defHash.Length; i++)
+ {
+ block[i] ^= mask[i];
+ }
+
+ //
+ // unmask the message block.
+ //
+ mask = maskGeneratorFunction1(block, 0, defHash.Length, block.Length - defHash.Length);
+
+ for (int i = defHash.Length; i != block.Length; i++)
+ {
+ block[i] ^= mask[i - defHash.Length];
+ }
+
+ //
+ // check the hash of the encoding params.
+ // long check to try to avoid this been a source of a timing attack.
+ //
+ bool defHashWrong = false;
+
+ for (int i = 0; i != defHash.Length; i++)
+ {
+ if (defHash[i] != block[defHash.Length + i])
+ {
+ defHashWrong = true;
+ }
+ }
+
+ //
+ // find the data block
+ //
+ int start = block.Length;
+
+ for (int index = 2 * defHash.Length; index != block.Length; index++)
+ {
+ if (block[index] != 0 & start == block.Length)
+ {
+ start = index;
+ }
+ }
+
+ bool dataStartWrong = (start > (block.Length - 1) | block[start] != 1);
+
+ start++;
+
+ if (defHashWrong | shortData | dataStartWrong)
+ {
+ Arrays.Fill(block, 0);
+ throw new InvalidCipherTextException("data wrong");
+ }
+
+ //
+ // extract the data block
+ //
+ byte[] output = new byte[block.Length - start];
+
+ Array.Copy(block, start, output, 0, output.Length);
+
+ return output;
+ }
+
+ /**
+ * int to octet string.
+ */
+ private void ItoOSP(
+ int i,
+ byte[] sp)
+ {
+ sp[0] = (byte)((uint)i >> 24);
+ sp[1] = (byte)((uint)i >> 16);
+ sp[2] = (byte)((uint)i >> 8);
+ sp[3] = (byte)((uint)i >> 0);
+ }
+
+ /**
+ * mask generator function, as described in PKCS1v2.
+ */
+ private byte[] maskGeneratorFunction1(
+ byte[] Z,
+ int zOff,
+ int zLen,
+ int length)
+ {
+ byte[] mask = new byte[length];
+ byte[] hashBuf = new byte[mgf1Hash.GetDigestSize()];
+ byte[] C = new byte[4];
+ int counter = 0;
+
+ mgf1Hash.Reset();
+
+ while (counter < (length / hashBuf.Length))
+ {
+ ItoOSP(counter, C);
+
+ mgf1Hash.BlockUpdate(Z, zOff, zLen);
+ mgf1Hash.BlockUpdate(C, 0, C.Length);
+ mgf1Hash.DoFinal(hashBuf, 0);
+
+ Array.Copy(hashBuf, 0, mask, counter * hashBuf.Length, hashBuf.Length);
+
+ counter++;
+ }
+
+ if ((counter * hashBuf.Length) < length)
+ {
+ ItoOSP(counter, C);
+
+ mgf1Hash.BlockUpdate(Z, zOff, zLen);
+ mgf1Hash.BlockUpdate(C, 0, C.Length);
+ mgf1Hash.DoFinal(hashBuf, 0);
+
+ Array.Copy(hashBuf, 0, mask, counter * hashBuf.Length, mask.Length - (counter * hashBuf.Length));
+ }
+
+ return mask;
+ }
+ }
+}
+
diff --git a/bc-sharp-crypto/src/crypto/encodings/Pkcs1Encoding.cs b/bc-sharp-crypto/src/crypto/encodings/Pkcs1Encoding.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b2d60fe4ccbb99ffcb1e2da6c6626cf1eb779df6
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/encodings/Pkcs1Encoding.cs
@@ -0,0 +1,384 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Encodings
+{
+ /**
+ * this does your basic Pkcs 1 v1.5 padding - whether or not you should be using this
+ * depends on your application - see Pkcs1 Version 2 for details.
+ */
+ public class Pkcs1Encoding
+ : IAsymmetricBlockCipher
+ {
+ /**
+ * some providers fail to include the leading zero in PKCS1 encoded blocks. If you need to
+ * work with one of these set the system property Org.BouncyCastle.Pkcs1.Strict to false.
+ */
+ public const string StrictLengthEnabledProperty = "Org.BouncyCastle.Pkcs1.Strict";
+
+ private const int HeaderLength = 10;
+
+ /**
+ * The same effect can be achieved by setting the static property directly
+ *
+ * The static property is checked during construction of the encoding object, it is set to
+ * true by default.
+ *
+ */
+ public static bool StrictLengthEnabled
+ {
+ get { return strictLengthEnabled[0]; }
+ set { strictLengthEnabled[0] = value; }
+ }
+
+ private static readonly bool[] strictLengthEnabled;
+
+ static Pkcs1Encoding()
+ {
+ string strictProperty = Platform.GetEnvironmentVariable(StrictLengthEnabledProperty);
+
+ strictLengthEnabled = new bool[]{ strictProperty == null || strictProperty.Equals("true")};
+ }
+
+
+ private SecureRandom random;
+ private IAsymmetricBlockCipher engine;
+ private bool forEncryption;
+ private bool forPrivateKey;
+ private bool useStrictLength;
+ private int pLen = -1;
+ private byte[] fallback = null;
+ private byte[] blockBuffer = null;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher
+ */
+ public Pkcs1Encoding(
+ IAsymmetricBlockCipher cipher)
+ {
+ this.engine = cipher;
+ this.useStrictLength = StrictLengthEnabled;
+ }
+
+ /**
+ * Constructor for decryption with a fixed plaintext length.
+ *
+ * @param cipher The cipher to use for cryptographic operation.
+ * @param pLen Length of the expected plaintext.
+ */
+ public Pkcs1Encoding(IAsymmetricBlockCipher cipher, int pLen)
+ {
+ this.engine = cipher;
+ this.useStrictLength = StrictLengthEnabled;
+ this.pLen = pLen;
+ }
+
+ /**
+ * Constructor for decryption with a fixed plaintext length and a fallback
+ * value that is returned, if the padding is incorrect.
+ *
+ * @param cipher
+ * The cipher to use for cryptographic operation.
+ * @param fallback
+ * The fallback value, we don't to a arraycopy here.
+ */
+ public Pkcs1Encoding(IAsymmetricBlockCipher cipher, byte[] fallback)
+ {
+ this.engine = cipher;
+ this.useStrictLength = StrictLengthEnabled;
+ this.fallback = fallback;
+ this.pLen = fallback.Length;
+ }
+
+ public IAsymmetricBlockCipher GetUnderlyingCipher()
+ {
+ return engine;
+ }
+
+ public string AlgorithmName
+ {
+ get { return engine.AlgorithmName + "/PKCS1Padding"; }
+ }
+
+ public void Init(bool forEncryption, ICipherParameters parameters)
+ {
+ AsymmetricKeyParameter kParam;
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+
+ this.random = rParam.Random;
+ kParam = (AsymmetricKeyParameter)rParam.Parameters;
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ kParam = (AsymmetricKeyParameter)parameters;
+ }
+
+ engine.Init(forEncryption, parameters);
+
+ this.forPrivateKey = kParam.IsPrivate;
+ this.forEncryption = forEncryption;
+ this.blockBuffer = new byte[engine.GetOutputBlockSize()];
+
+ if (pLen > 0 && fallback == null && random == null)
+ throw new ArgumentException("encoder requires random");
+ }
+
+ public int GetInputBlockSize()
+ {
+ int baseBlockSize = engine.GetInputBlockSize();
+
+ return forEncryption
+ ? baseBlockSize - HeaderLength
+ : baseBlockSize;
+ }
+
+ public int GetOutputBlockSize()
+ {
+ int baseBlockSize = engine.GetOutputBlockSize();
+
+ return forEncryption
+ ? baseBlockSize
+ : baseBlockSize - HeaderLength;
+ }
+
+ public byte[] ProcessBlock(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ return forEncryption
+ ? EncodeBlock(input, inOff, length)
+ : DecodeBlock(input, inOff, length);
+ }
+
+ private byte[] EncodeBlock(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ if (inLen > GetInputBlockSize())
+ throw new ArgumentException("input data too large", "inLen");
+
+ byte[] block = new byte[engine.GetInputBlockSize()];
+
+ if (forPrivateKey)
+ {
+ block[0] = 0x01; // type code 1
+
+ for (int i = 1; i != block.Length - inLen - 1; i++)
+ {
+ block[i] = (byte)0xFF;
+ }
+ }
+ else
+ {
+ random.NextBytes(block); // random fill
+
+ block[0] = 0x02; // type code 2
+
+ //
+ // a zero byte marks the end of the padding, so all
+ // the pad bytes must be non-zero.
+ //
+ for (int i = 1; i != block.Length - inLen - 1; i++)
+ {
+ while (block[i] == 0)
+ {
+ block[i] = (byte)random.NextInt();
+ }
+ }
+ }
+
+ block[block.Length - inLen - 1] = 0x00; // mark the end of the padding
+ Array.Copy(input, inOff, block, block.Length - inLen, inLen);
+
+ return engine.ProcessBlock(block, 0, block.Length);
+ }
+
+ /**
+ * Checks if the argument is a correctly PKCS#1.5 encoded Plaintext
+ * for encryption.
+ *
+ * @param encoded The Plaintext.
+ * @param pLen Expected length of the plaintext.
+ * @return Either 0, if the encoding is correct, or -1, if it is incorrect.
+ */
+ private static int CheckPkcs1Encoding(byte[] encoded, int pLen)
+ {
+ int correct = 0;
+ /*
+ * Check if the first two bytes are 0 2
+ */
+ correct |= (encoded[0] ^ 2);
+
+ /*
+ * Now the padding check, check for no 0 byte in the padding
+ */
+ int plen = encoded.Length - (
+ pLen /* Lenght of the PMS */
+ + 1 /* Final 0-byte before PMS */
+ );
+
+ for (int i = 1; i < plen; i++)
+ {
+ int tmp = encoded[i];
+ tmp |= tmp >> 1;
+ tmp |= tmp >> 2;
+ tmp |= tmp >> 4;
+ correct |= (tmp & 1) - 1;
+ }
+
+ /*
+ * Make sure the padding ends with a 0 byte.
+ */
+ correct |= encoded[encoded.Length - (pLen + 1)];
+
+ /*
+ * Return 0 or 1, depending on the result.
+ */
+ correct |= correct >> 1;
+ correct |= correct >> 2;
+ correct |= correct >> 4;
+ return ~((correct & 1) - 1);
+ }
+
+ /**
+ * Decode PKCS#1.5 encoding, and return a random value if the padding is not correct.
+ *
+ * @param in The encrypted block.
+ * @param inOff Offset in the encrypted block.
+ * @param inLen Length of the encrypted block.
+ * @param pLen Length of the desired output.
+ * @return The plaintext without padding, or a random value if the padding was incorrect.
+ * @throws InvalidCipherTextException
+ */
+ private byte[] DecodeBlockOrRandom(byte[] input, int inOff, int inLen)
+ {
+ if (!forPrivateKey)
+ throw new InvalidCipherTextException("sorry, this method is only for decryption, not for signing");
+
+ byte[] block = engine.ProcessBlock(input, inOff, inLen);
+ byte[] random;
+ if (this.fallback == null)
+ {
+ random = new byte[this.pLen];
+ this.random.NextBytes(random);
+ }
+ else
+ {
+ random = fallback;
+ }
+
+ byte[] data = (useStrictLength & (block.Length != engine.GetOutputBlockSize())) ? blockBuffer : block;
+
+ /*
+ * Check the padding.
+ */
+ int correct = CheckPkcs1Encoding(data, this.pLen);
+
+ /*
+ * Now, to a constant time constant memory copy of the decrypted value
+ * or the random value, depending on the validity of the padding.
+ */
+ byte[] result = new byte[this.pLen];
+ for (int i = 0; i < this.pLen; i++)
+ {
+ result[i] = (byte)((data[i + (data.Length - pLen)] & (~correct)) | (random[i] & correct));
+ }
+
+ Arrays.Fill(data, 0);
+
+ return result;
+ }
+
+ /**
+ * @exception InvalidCipherTextException if the decrypted block is not in Pkcs1 format.
+ */
+ private byte[] DecodeBlock(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ /*
+ * If the length of the expected plaintext is known, we use a constant-time decryption.
+ * If the decryption fails, we return a random value.
+ */
+ if (this.pLen != -1)
+ {
+ return this.DecodeBlockOrRandom(input, inOff, inLen);
+ }
+
+ byte[] block = engine.ProcessBlock(input, inOff, inLen);
+ bool incorrectLength = (useStrictLength & (block.Length != engine.GetOutputBlockSize()));
+
+ byte[] data;
+ if (block.Length < GetOutputBlockSize())
+ {
+ data = blockBuffer;
+ }
+ else
+ {
+ data = block;
+ }
+
+ byte expectedType = (byte)(forPrivateKey ? 2 : 1);
+ byte type = data[0];
+
+ bool badType = (type != expectedType);
+
+ //
+ // find and extract the message block.
+ //
+ int start = FindStart(type, data);
+
+ start++; // data should start at the next byte
+
+ if (badType | (start < HeaderLength))
+ {
+ Arrays.Fill(data, 0);
+ throw new InvalidCipherTextException("block incorrect");
+ }
+
+ // if we get this far, it's likely to be a genuine encoding error
+ if (incorrectLength)
+ {
+ Arrays.Fill(data, 0);
+ throw new InvalidCipherTextException("block incorrect size");
+ }
+
+ byte[] result = new byte[data.Length - start];
+
+ Array.Copy(data, start, result, 0, result.Length);
+
+ return result;
+ }
+
+ private int FindStart(byte type, byte[] block)
+ {
+ int start = -1;
+ bool padErr = false;
+
+ for (int i = 1; i != block.Length; i++)
+ {
+ byte pad = block[i];
+
+ if (pad == 0 & start < 0)
+ {
+ start = i;
+ }
+ padErr |= ((type == 1) & (start < 0) & (pad != (byte)0xff));
+ }
+
+ return padErr ? -1 : start;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/AesEngine.cs b/bc-sharp-crypto/src/crypto/engines/AesEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..91bdf69ef730d2916499ff53d5f2f9d781bf438b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/AesEngine.cs
@@ -0,0 +1,610 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * an implementation of the AES (Rijndael), from FIPS-197.
+ *
+ * For further details see: http://csrc.nist.gov/encryption/aes/ .
+ *
+ * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
+ * http://fp.gladman.plus.com/cryptography_technology/rijndael/
+ *
+ * There are three levels of tradeoff of speed vs memory
+ * Because java has no preprocessor, they are written as three separate classes from which to choose
+ *
+ * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
+ * and 4 for decryption.
+ *
+ * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
+ * adding 12 rotate operations per round to compute the values contained in the other tables from
+ * the contents of the first.
+ *
+ * The slowest version uses no static tables at all and computes the values in each round.
+ *
+ *
+ * This file contains the middle performance version with 2Kbytes of static tables for round precomputation.
+ *
+ */
+ public class AesEngine
+ : IBlockCipher
+ {
+ // The S box
+ private static readonly byte[] S =
+ {
+ 99, 124, 119, 123, 242, 107, 111, 197,
+ 48, 1, 103, 43, 254, 215, 171, 118,
+ 202, 130, 201, 125, 250, 89, 71, 240,
+ 173, 212, 162, 175, 156, 164, 114, 192,
+ 183, 253, 147, 38, 54, 63, 247, 204,
+ 52, 165, 229, 241, 113, 216, 49, 21,
+ 4, 199, 35, 195, 24, 150, 5, 154,
+ 7, 18, 128, 226, 235, 39, 178, 117,
+ 9, 131, 44, 26, 27, 110, 90, 160,
+ 82, 59, 214, 179, 41, 227, 47, 132,
+ 83, 209, 0, 237, 32, 252, 177, 91,
+ 106, 203, 190, 57, 74, 76, 88, 207,
+ 208, 239, 170, 251, 67, 77, 51, 133,
+ 69, 249, 2, 127, 80, 60, 159, 168,
+ 81, 163, 64, 143, 146, 157, 56, 245,
+ 188, 182, 218, 33, 16, 255, 243, 210,
+ 205, 12, 19, 236, 95, 151, 68, 23,
+ 196, 167, 126, 61, 100, 93, 25, 115,
+ 96, 129, 79, 220, 34, 42, 144, 136,
+ 70, 238, 184, 20, 222, 94, 11, 219,
+ 224, 50, 58, 10, 73, 6, 36, 92,
+ 194, 211, 172, 98, 145, 149, 228, 121,
+ 231, 200, 55, 109, 141, 213, 78, 169,
+ 108, 86, 244, 234, 101, 122, 174, 8,
+ 186, 120, 37, 46, 28, 166, 180, 198,
+ 232, 221, 116, 31, 75, 189, 139, 138,
+ 112, 62, 181, 102, 72, 3, 246, 14,
+ 97, 53, 87, 185, 134, 193, 29, 158,
+ 225, 248, 152, 17, 105, 217, 142, 148,
+ 155, 30, 135, 233, 206, 85, 40, 223,
+ 140, 161, 137, 13, 191, 230, 66, 104,
+ 65, 153, 45, 15, 176, 84, 187, 22,
+ };
+
+ // The inverse S-box
+ private static readonly byte[] Si =
+ {
+ 82, 9, 106, 213, 48, 54, 165, 56,
+ 191, 64, 163, 158, 129, 243, 215, 251,
+ 124, 227, 57, 130, 155, 47, 255, 135,
+ 52, 142, 67, 68, 196, 222, 233, 203,
+ 84, 123, 148, 50, 166, 194, 35, 61,
+ 238, 76, 149, 11, 66, 250, 195, 78,
+ 8, 46, 161, 102, 40, 217, 36, 178,
+ 118, 91, 162, 73, 109, 139, 209, 37,
+ 114, 248, 246, 100, 134, 104, 152, 22,
+ 212, 164, 92, 204, 93, 101, 182, 146,
+ 108, 112, 72, 80, 253, 237, 185, 218,
+ 94, 21, 70, 87, 167, 141, 157, 132,
+ 144, 216, 171, 0, 140, 188, 211, 10,
+ 247, 228, 88, 5, 184, 179, 69, 6,
+ 208, 44, 30, 143, 202, 63, 15, 2,
+ 193, 175, 189, 3, 1, 19, 138, 107,
+ 58, 145, 17, 65, 79, 103, 220, 234,
+ 151, 242, 207, 206, 240, 180, 230, 115,
+ 150, 172, 116, 34, 231, 173, 53, 133,
+ 226, 249, 55, 232, 28, 117, 223, 110,
+ 71, 241, 26, 113, 29, 41, 197, 137,
+ 111, 183, 98, 14, 170, 24, 190, 27,
+ 252, 86, 62, 75, 198, 210, 121, 32,
+ 154, 219, 192, 254, 120, 205, 90, 244,
+ 31, 221, 168, 51, 136, 7, 199, 49,
+ 177, 18, 16, 89, 39, 128, 236, 95,
+ 96, 81, 127, 169, 25, 181, 74, 13,
+ 45, 229, 122, 159, 147, 201, 156, 239,
+ 160, 224, 59, 77, 174, 42, 245, 176,
+ 200, 235, 187, 60, 131, 83, 153, 97,
+ 23, 43, 4, 126, 186, 119, 214, 38,
+ 225, 105, 20, 99, 85, 33, 12, 125,
+ };
+
+ // vector used in calculating key schedule (powers of x in GF(256))
+ private static readonly byte[] 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
+ };
+
+ // precomputation tables of calculations for rounds
+ private static readonly uint[] T0 =
+ {
+ 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff,
+ 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102,
+ 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d,
+ 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa,
+ 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41,
+ 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453,
+ 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d,
+ 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83,
+ 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2,
+ 0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795,
+ 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a,
+ 0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,
+ 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912,
+ 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc,
+ 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7,
+ 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413,
+ 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040,
+ 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d,
+ 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0,
+ 0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed,
+ 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a,
+ 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78,
+ 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080,
+ 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
+ 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020,
+ 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18,
+ 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488,
+ 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a,
+ 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0,
+ 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54,
+ 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b,
+ 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad,
+ 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992,
+ 0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd,
+ 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3,
+ 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda,
+ 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8,
+ 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4,
+ 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a,
+ 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697,
+ 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96,
+ 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c,
+ 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7,
+ 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969,
+ 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9,
+ 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9,
+ 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715,
+ 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
+ 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65,
+ 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929,
+ 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d,
+ 0x3a16162c
+ };
+
+ private static readonly uint[] Tinv0 =
+ {
+ 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b,
+ 0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad,
+ 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526,
+ 0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d,
+ 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03,
+ 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458,
+ 0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899,
+ 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d,
+ 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1,
+ 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f,
+ 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3,
+ 0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3,
+ 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a,
+ 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506,
+ 0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05,
+ 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd,
+ 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491,
+ 0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6,
+ 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7,
+ 0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000,
+ 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd,
+ 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68,
+ 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, 0xd296eeb4,
+ 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c,
+ 0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e,
+ 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af,
+ 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644,
+ 0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8,
+ 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85,
+ 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc,
+ 0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411,
+ 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322,
+ 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6,
+ 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0x0d927850,
+ 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e,
+ 0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf,
+ 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd,
+ 0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa,
+ 0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea,
+ 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235,
+ 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1,
+ 0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43,
+ 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1,
+ 0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb,
+ 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a,
+ 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7,
+ 0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418,
+ 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478,
+ 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16,
+ 0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08,
+ 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48,
+ 0x4257b8d0
+ };
+
+ private static uint Shift(uint r, int shift)
+ {
+ return (r >> shift) | (r << (32 - shift));
+ }
+
+ /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+ private const uint m1 = 0x80808080;
+ private const uint m2 = 0x7f7f7f7f;
+ private const uint m3 = 0x0000001b;
+ private const uint m4 = 0xC0C0C0C0;
+ private const uint m5 = 0x3f3f3f3f;
+
+ private static uint FFmulX(uint x)
+ {
+ return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
+ }
+
+ private static uint FFmulX2(uint x)
+ {
+ uint t0 = (x & m5) << 2;
+ uint t1 = (x & m4);
+ t1 ^= (t1 >> 1);
+ return t0 ^ (t1 >> 2) ^ (t1 >> 5);
+ }
+
+ /*
+ The following defines provide alternative definitions of FFmulX that might
+ give improved performance if a fast 32-bit multiply is not available.
+
+ private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
+ private static final int m4 = 0x1b1b1b1b;
+ private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
+
+ */
+
+ private static uint Inv_Mcol(uint x)
+ {
+ uint t0, t1;
+ t0 = x;
+ t1 = t0 ^ Shift(t0, 8);
+ t0 ^= FFmulX(t1);
+ t1 ^= FFmulX2(t0);
+ t0 ^= t1 ^ Shift(t1, 16);
+ return t0;
+ }
+
+ private static uint SubWord(uint x)
+ {
+ return (uint)S[x&255]
+ | (((uint)S[(x>>8)&255]) << 8)
+ | (((uint)S[(x>>16)&255]) << 16)
+ | (((uint)S[(x>>24)&255]) << 24);
+ }
+
+ /**
+ * Calculate the necessary round keys
+ * The number of calculations depends on key size and block size
+ * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
+ * This code is written assuming those are the only possible values
+ */
+ private uint[][] GenerateWorkingKey(byte[] key, bool forEncryption)
+ {
+ int keyLen = key.Length;
+ if (keyLen < 16 || keyLen > 32 || (keyLen & 7) != 0)
+ throw new ArgumentException("Key length not 128/192/256 bits.");
+
+ int KC = keyLen >> 2;
+ this.ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
+
+ uint[][] W = new uint[ROUNDS + 1][]; // 4 words in a block
+ for (int i = 0; i <= ROUNDS; ++i)
+ {
+ W[i] = new uint[4];
+ }
+
+ switch (KC)
+ {
+ case 4:
+ {
+ uint t0 = Pack.LE_To_UInt32(key, 0); W[0][0] = t0;
+ uint t1 = Pack.LE_To_UInt32(key, 4); W[0][1] = t1;
+ uint t2 = Pack.LE_To_UInt32(key, 8); W[0][2] = t2;
+ uint t3 = Pack.LE_To_UInt32(key, 12); W[0][3] = t3;
+
+ for (int i = 1; i <= 10; ++i)
+ {
+ uint u = SubWord(Shift(t3, 8)) ^ rcon[i - 1];
+ t0 ^= u; W[i][0] = t0;
+ t1 ^= t0; W[i][1] = t1;
+ t2 ^= t1; W[i][2] = t2;
+ t3 ^= t2; W[i][3] = t3;
+ }
+
+ break;
+ }
+ case 6:
+ {
+ uint t0 = Pack.LE_To_UInt32(key, 0); W[0][0] = t0;
+ uint t1 = Pack.LE_To_UInt32(key, 4); W[0][1] = t1;
+ uint t2 = Pack.LE_To_UInt32(key, 8); W[0][2] = t2;
+ uint t3 = Pack.LE_To_UInt32(key, 12); W[0][3] = t3;
+ uint t4 = Pack.LE_To_UInt32(key, 16); W[1][0] = t4;
+ uint t5 = Pack.LE_To_UInt32(key, 20); W[1][1] = t5;
+
+ uint rcon = 1;
+ uint u = SubWord(Shift(t5, 8)) ^ rcon; rcon <<= 1;
+ t0 ^= u; W[1][2] = t0;
+ t1 ^= t0; W[1][3] = t1;
+ t2 ^= t1; W[2][0] = t2;
+ t3 ^= t2; W[2][1] = t3;
+ t4 ^= t3; W[2][2] = t4;
+ t5 ^= t4; W[2][3] = t5;
+
+ for (int i = 3; i < 12; i += 3)
+ {
+ u = SubWord(Shift(t5, 8)) ^ rcon; rcon <<= 1;
+ t0 ^= u; W[i ][0] = t0;
+ t1 ^= t0; W[i ][1] = t1;
+ t2 ^= t1; W[i ][2] = t2;
+ t3 ^= t2; W[i ][3] = t3;
+ t4 ^= t3; W[i + 1][0] = t4;
+ t5 ^= t4; W[i + 1][1] = t5;
+ u = SubWord(Shift(t5, 8)) ^ rcon; rcon <<= 1;
+ t0 ^= u; W[i + 1][2] = t0;
+ t1 ^= t0; W[i + 1][3] = t1;
+ t2 ^= t1; W[i + 2][0] = t2;
+ t3 ^= t2; W[i + 2][1] = t3;
+ t4 ^= t3; W[i + 2][2] = t4;
+ t5 ^= t4; W[i + 2][3] = t5;
+ }
+
+ u = SubWord(Shift(t5, 8)) ^ rcon;
+ t0 ^= u; W[12][0] = t0;
+ t1 ^= t0; W[12][1] = t1;
+ t2 ^= t1; W[12][2] = t2;
+ t3 ^= t2; W[12][3] = t3;
+
+ break;
+ }
+ case 8:
+ {
+ uint t0 = Pack.LE_To_UInt32(key, 0); W[0][0] = t0;
+ uint t1 = Pack.LE_To_UInt32(key, 4); W[0][1] = t1;
+ uint t2 = Pack.LE_To_UInt32(key, 8); W[0][2] = t2;
+ uint t3 = Pack.LE_To_UInt32(key, 12); W[0][3] = t3;
+ uint t4 = Pack.LE_To_UInt32(key, 16); W[1][0] = t4;
+ uint t5 = Pack.LE_To_UInt32(key, 20); W[1][1] = t5;
+ uint t6 = Pack.LE_To_UInt32(key, 24); W[1][2] = t6;
+ uint t7 = Pack.LE_To_UInt32(key, 28); W[1][3] = t7;
+
+ uint u, rcon = 1;
+
+ for (int i = 2; i < 14; i += 2)
+ {
+ u = SubWord(Shift(t7, 8)) ^ rcon; rcon <<= 1;
+ t0 ^= u; W[i ][0] = t0;
+ t1 ^= t0; W[i ][1] = t1;
+ t2 ^= t1; W[i ][2] = t2;
+ t3 ^= t2; W[i ][3] = t3;
+ u = SubWord(t3);
+ t4 ^= u; W[i + 1][0] = t4;
+ t5 ^= t4; W[i + 1][1] = t5;
+ t6 ^= t5; W[i + 1][2] = t6;
+ t7 ^= t6; W[i + 1][3] = t7;
+ }
+
+ u = SubWord(Shift(t7, 8)) ^ rcon;
+ t0 ^= u; W[14][0] = t0;
+ t1 ^= t0; W[14][1] = t1;
+ t2 ^= t1; W[14][2] = t2;
+ t3 ^= t2; W[14][3] = t3;
+
+ break;
+ }
+ default:
+ {
+ throw new InvalidOperationException("Should never get here");
+ }
+ }
+
+ if (!forEncryption)
+ {
+ for (int j = 1; j < ROUNDS; j++)
+ {
+ uint[] w = W[j];
+ for (int i = 0; i < 4; i++)
+ {
+ w[i] = Inv_Mcol(w[i]);
+ }
+ }
+ }
+
+ return W;
+ }
+
+ private int ROUNDS;
+ private uint[][] WorkingKey;
+ private uint C0, C1, C2, C3;
+ private bool forEncryption;
+
+ private byte[] s;
+
+ private const int BLOCK_SIZE = 16;
+
+ /**
+ * default constructor - 128 bit block size.
+ */
+ public AesEngine()
+ {
+ }
+
+ /**
+ * initialise an AES 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 virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ KeyParameter keyParameter = parameters as KeyParameter;
+
+ if (keyParameter == null)
+ throw new ArgumentException("invalid parameter passed to AES init - "
+ + Platform.GetTypeName(parameters));
+
+ WorkingKey = GenerateWorkingKey(keyParameter.GetKey(), forEncryption);
+
+ this.forEncryption = forEncryption;
+ this.s = Arrays.Clone(forEncryption ? S : Si);
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "AES"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (WorkingKey == null)
+ throw new InvalidOperationException("AES engine not initialised");
+
+ Check.DataLength(input, inOff, 16, "input buffer too short");
+ Check.OutputLength(output, outOff, 16, "output buffer too short");
+
+ UnPackBlock(input, inOff);
+
+ if (forEncryption)
+ {
+ EncryptBlock(WorkingKey);
+ }
+ else
+ {
+ DecryptBlock(WorkingKey);
+ }
+
+ PackBlock(output, outOff);
+
+ return BLOCK_SIZE;
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ private void UnPackBlock(
+ byte[] bytes,
+ int off)
+ {
+ C0 = Pack.LE_To_UInt32(bytes, off);
+ C1 = Pack.LE_To_UInt32(bytes, off + 4);
+ C2 = Pack.LE_To_UInt32(bytes, off + 8);
+ C3 = Pack.LE_To_UInt32(bytes, off + 12);
+ }
+
+ private void PackBlock(
+ byte[] bytes,
+ int off)
+ {
+ Pack.UInt32_To_LE(C0, bytes, off);
+ Pack.UInt32_To_LE(C1, bytes, off + 4);
+ Pack.UInt32_To_LE(C2, bytes, off + 8);
+ Pack.UInt32_To_LE(C3, bytes, off + 12);
+ }
+
+ private void EncryptBlock(uint[][] KW)
+ {
+ uint[] kw = KW[0];
+ uint t0 = this.C0 ^ kw[0];
+ uint t1 = this.C1 ^ kw[1];
+ uint t2 = this.C2 ^ kw[2];
+
+ uint r0, r1, r2, r3 = this.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];
+ this.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];
+ this.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];
+ this.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];
+ this.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];
+ }
+
+ private void DecryptBlock(uint[][] KW)
+ {
+ uint[] kw = KW[ROUNDS];
+ uint t0 = this.C0 ^ kw[0];
+ uint t1 = this.C1 ^ kw[1];
+ uint t2 = this.C2 ^ kw[2];
+
+ uint r0, r1, r2, r3 = this.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];
+ this.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];
+ this.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];
+ this.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];
+ this.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];
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/AesFastEngine.cs b/bc-sharp-crypto/src/crypto/engines/AesFastEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9d3a86fd2dad23bc69b2358321e9d060f8d90039
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/AesFastEngine.cs
@@ -0,0 +1,948 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * an implementation of the AES (Rijndael)), from FIPS-197.
+ *
+ * For further details see: http://csrc.nist.gov/encryption/aes/ .
+ *
+ * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
+ * http://fp.gladman.plus.com/cryptography_technology/rijndael/
+ *
+ * There are three levels of tradeoff of speed vs memory
+ * Because java has no preprocessor), they are written as three separate classes from which to choose
+ *
+ * The fastest uses 8Kbytes of static tables to precompute round calculations), 4 256 word tables for encryption
+ * and 4 for decryption.
+ *
+ * The middle performance version uses only one 256 word table for each), for a total of 2Kbytes),
+ * adding 12 rotate operations per round to compute the values contained in the other tables from
+ * the contents of the first
+ *
+ * The slowest version uses no static tables at all and computes the values in each round
+ *
+ *
+ * This file contains the fast version with 8Kbytes of static tables for round precomputation
+ *
+ */
+ ///
+ /// Unfortunately this class has a few side channel issues.
+ /// In an environment where encryption/decryption may be closely observed it should not be used.
+ ///
+ [Obsolete("Use AesEngine instead")]
+ public class AesFastEngine
+ : IBlockCipher
+ {
+ // The S box
+ private static readonly byte[] S =
+ {
+ 99, 124, 119, 123, 242, 107, 111, 197,
+ 48, 1, 103, 43, 254, 215, 171, 118,
+ 202, 130, 201, 125, 250, 89, 71, 240,
+ 173, 212, 162, 175, 156, 164, 114, 192,
+ 183, 253, 147, 38, 54, 63, 247, 204,
+ 52, 165, 229, 241, 113, 216, 49, 21,
+ 4, 199, 35, 195, 24, 150, 5, 154,
+ 7, 18, 128, 226, 235, 39, 178, 117,
+ 9, 131, 44, 26, 27, 110, 90, 160,
+ 82, 59, 214, 179, 41, 227, 47, 132,
+ 83, 209, 0, 237, 32, 252, 177, 91,
+ 106, 203, 190, 57, 74, 76, 88, 207,
+ 208, 239, 170, 251, 67, 77, 51, 133,
+ 69, 249, 2, 127, 80, 60, 159, 168,
+ 81, 163, 64, 143, 146, 157, 56, 245,
+ 188, 182, 218, 33, 16, 255, 243, 210,
+ 205, 12, 19, 236, 95, 151, 68, 23,
+ 196, 167, 126, 61, 100, 93, 25, 115,
+ 96, 129, 79, 220, 34, 42, 144, 136,
+ 70, 238, 184, 20, 222, 94, 11, 219,
+ 224, 50, 58, 10, 73, 6, 36, 92,
+ 194, 211, 172, 98, 145, 149, 228, 121,
+ 231, 200, 55, 109, 141, 213, 78, 169,
+ 108, 86, 244, 234, 101, 122, 174, 8,
+ 186, 120, 37, 46, 28, 166, 180, 198,
+ 232, 221, 116, 31, 75, 189, 139, 138,
+ 112, 62, 181, 102, 72, 3, 246, 14,
+ 97, 53, 87, 185, 134, 193, 29, 158,
+ 225, 248, 152, 17, 105, 217, 142, 148,
+ 155, 30, 135, 233, 206, 85, 40, 223,
+ 140, 161, 137, 13, 191, 230, 66, 104,
+ 65, 153, 45, 15, 176, 84, 187, 22,
+ };
+
+ // The inverse S-box
+ private static readonly byte[] Si =
+ {
+ 82, 9, 106, 213, 48, 54, 165, 56,
+ 191, 64, 163, 158, 129, 243, 215, 251,
+ 124, 227, 57, 130, 155, 47, 255, 135,
+ 52, 142, 67, 68, 196, 222, 233, 203,
+ 84, 123, 148, 50, 166, 194, 35, 61,
+ 238, 76, 149, 11, 66, 250, 195, 78,
+ 8, 46, 161, 102, 40, 217, 36, 178,
+ 118, 91, 162, 73, 109, 139, 209, 37,
+ 114, 248, 246, 100, 134, 104, 152, 22,
+ 212, 164, 92, 204, 93, 101, 182, 146,
+ 108, 112, 72, 80, 253, 237, 185, 218,
+ 94, 21, 70, 87, 167, 141, 157, 132,
+ 144, 216, 171, 0, 140, 188, 211, 10,
+ 247, 228, 88, 5, 184, 179, 69, 6,
+ 208, 44, 30, 143, 202, 63, 15, 2,
+ 193, 175, 189, 3, 1, 19, 138, 107,
+ 58, 145, 17, 65, 79, 103, 220, 234,
+ 151, 242, 207, 206, 240, 180, 230, 115,
+ 150, 172, 116, 34, 231, 173, 53, 133,
+ 226, 249, 55, 232, 28, 117, 223, 110,
+ 71, 241, 26, 113, 29, 41, 197, 137,
+ 111, 183, 98, 14, 170, 24, 190, 27,
+ 252, 86, 62, 75, 198, 210, 121, 32,
+ 154, 219, 192, 254, 120, 205, 90, 244,
+ 31, 221, 168, 51, 136, 7, 199, 49,
+ 177, 18, 16, 89, 39, 128, 236, 95,
+ 96, 81, 127, 169, 25, 181, 74, 13,
+ 45, 229, 122, 159, 147, 201, 156, 239,
+ 160, 224, 59, 77, 174, 42, 245, 176,
+ 200, 235, 187, 60, 131, 83, 153, 97,
+ 23, 43, 4, 126, 186, 119, 214, 38,
+ 225, 105, 20, 99, 85, 33, 12, 125,
+ };
+
+ // vector used in calculating key schedule (powers of x in GF(256))
+ private static readonly byte[] 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
+ };
+
+ // precomputation tables of calculations for rounds
+ private static readonly uint[] T0 =
+ {
+ 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff,
+ 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102,
+ 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d,
+ 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa,
+ 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41,
+ 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453,
+ 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d,
+ 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83,
+ 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2,
+ 0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795,
+ 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a,
+ 0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,
+ 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912,
+ 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc,
+ 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7,
+ 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413,
+ 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040,
+ 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d,
+ 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0,
+ 0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed,
+ 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a,
+ 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78,
+ 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080,
+ 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
+ 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020,
+ 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18,
+ 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488,
+ 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a,
+ 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0,
+ 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54,
+ 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b,
+ 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad,
+ 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992,
+ 0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd,
+ 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3,
+ 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda,
+ 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8,
+ 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4,
+ 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a,
+ 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697,
+ 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96,
+ 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c,
+ 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7,
+ 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969,
+ 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9,
+ 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9,
+ 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715,
+ 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
+ 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65,
+ 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929,
+ 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d,
+ 0x3a16162c
+ };
+
+ private static readonly uint[] T1 =
+ {
+ 0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d,
+ 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x01010203,
+ 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6,
+ 0x7676ec9a, 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87,
+ 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, 0xadad41ec,
+ 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7,
+ 0x7272e496, 0xc0c09b5b, 0xb7b775c2, 0xfdfde11c, 0x93933dae,
+ 0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f,
+ 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293,
+ 0xd8d8ab73, 0x31316253, 0x15152a3f, 0x0404080c, 0xc7c79552,
+ 0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x05050a0f,
+ 0x9a9a2fb5, 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d,
+ 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, 0x0909121b,
+ 0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2,
+ 0x5a5ab4ee, 0xa0a05bfb, 0x5252a4f6, 0x3b3b764d, 0xd6d6b761,
+ 0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397,
+ 0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, 0x20204060,
+ 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, 0x6a6ad4be, 0xcbcb8d46,
+ 0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8,
+ 0xcfcf854a, 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16,
+ 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, 0x45458acf,
+ 0xf9f9e910, 0x02020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844,
+ 0x9f9f25ba, 0xa8a84be3, 0x5151a2f3, 0xa3a35dfe, 0x404080c0,
+ 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104,
+ 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030,
+ 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, 0xcdcd814c, 0x0c0c1814,
+ 0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc,
+ 0x17172e39, 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47,
+ 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, 0x6060c0a0,
+ 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e,
+ 0x90903bab, 0x88880b83, 0x46468cca, 0xeeeec729, 0xb8b86bd3,
+ 0x1414283c, 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76,
+ 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, 0x494992db,
+ 0x06060c0a, 0x2424486c, 0x5c5cb8e4, 0xc2c29f5d, 0xd3d3bd6e,
+ 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337,
+ 0x7979f28b, 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7,
+ 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, 0x6c6cd8b4,
+ 0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e,
+ 0xaeae47e9, 0x08081018, 0xbaba6fd5, 0x7878f088, 0x25254a6f,
+ 0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751,
+ 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd,
+ 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, 0x7070e090, 0x3e3e7c42,
+ 0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x03030605, 0xf6f6f701,
+ 0x0e0e1c12, 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0,
+ 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, 0xe1e1d938,
+ 0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970,
+ 0x8e8e0789, 0x949433a7, 0x9b9b2db6, 0x1e1e3c22, 0x87871592,
+ 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a,
+ 0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da,
+ 0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3, 0x999929b0,
+ 0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6,
+ 0x16162c3a
+ };
+
+ private static readonly uint[] T2 =
+ {
+ 0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2,
+ 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x01020301,
+ 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab,
+ 0x76ec9a76, 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d,
+ 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, 0xad41ecad,
+ 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4,
+ 0x72e49672, 0xc09b5bc0, 0xb775c2b7, 0xfde11cfd, 0x933dae93,
+ 0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc,
+ 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371,
+ 0xd8ab73d8, 0x31625331, 0x152a3f15, 0x04080c04, 0xc79552c7,
+ 0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x050a0f05,
+ 0x9a2fb59a, 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2,
+ 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, 0x09121b09,
+ 0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e,
+ 0x5ab4ee5a, 0xa05bfba0, 0x52a4f652, 0x3b764d3b, 0xd6b761d6,
+ 0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784,
+ 0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, 0x20406020,
+ 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, 0x6ad4be6a, 0xcb8d46cb,
+ 0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858,
+ 0xcf854acf, 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb,
+ 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, 0x458acf45,
+ 0xf9e910f9, 0x02040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c,
+ 0x9f25ba9f, 0xa84be3a8, 0x51a2f351, 0xa35dfea3, 0x4080c040,
+ 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5,
+ 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010,
+ 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, 0xcd814ccd, 0x0c18140c,
+ 0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44,
+ 0x172e3917, 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d,
+ 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, 0x60c0a060,
+ 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a,
+ 0x903bab90, 0x880b8388, 0x468cca46, 0xeec729ee, 0xb86bd3b8,
+ 0x14283c14, 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db,
+ 0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, 0x4992db49,
+ 0x060c0a06, 0x24486c24, 0x5cb8e45c, 0xc29f5dc2, 0xd3bd6ed3,
+ 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4,
+ 0x79f28b79, 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d,
+ 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, 0x6cd8b46c,
+ 0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a,
+ 0xae47e9ae, 0x08101808, 0xba6fd5ba, 0x78f08878, 0x254a6f25,
+ 0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6,
+ 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b,
+ 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, 0x70e09070, 0x3e7c423e,
+ 0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x03060503, 0xf6f701f6,
+ 0x0e1c120e, 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9,
+ 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, 0xe1d938e1,
+ 0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9,
+ 0x8e07898e, 0x9433a794, 0x9b2db69b, 0x1e3c221e, 0x87159287,
+ 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf,
+ 0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf,
+ 0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341, 0x9929b099,
+ 0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb,
+ 0x162c3a16
+ };
+
+ private static readonly uint[] T3 =
+ {
+ 0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2,
+ 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x02030101,
+ 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab,
+ 0xec9a7676, 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d,
+ 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, 0x41ecadad,
+ 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4,
+ 0xe4967272, 0x9b5bc0c0, 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393,
+ 0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc,
+ 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171,
+ 0xab73d8d8, 0x62533131, 0x2a3f1515, 0x080c0404, 0x9552c7c7,
+ 0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0x0a0f0505,
+ 0x2fb59a9a, 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2,
+ 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, 0x121b0909,
+ 0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e,
+ 0xb4ee5a5a, 0x5bfba0a0, 0xa4f65252, 0x764d3b3b, 0xb761d6d6,
+ 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484,
+ 0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, 0x40602020,
+ 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, 0xd4be6a6a, 0x8d46cbcb,
+ 0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858,
+ 0x854acfcf, 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb,
+ 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, 0x8acf4545,
+ 0xe910f9f9, 0x04060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c,
+ 0x25ba9f9f, 0x4be3a8a8, 0xa2f35151, 0x5dfea3a3, 0x80c04040,
+ 0x058a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5,
+ 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010,
+ 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, 0x814ccdcd, 0x18140c0c,
+ 0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444,
+ 0x2e391717, 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d,
+ 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, 0xc0a06060,
+ 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a,
+ 0x3bab9090, 0x0b838888, 0x8cca4646, 0xc729eeee, 0x6bd3b8b8,
+ 0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb,
+ 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949,
+ 0x0c0a0606, 0x486c2424, 0xb8e45c5c, 0x9f5dc2c2, 0xbd6ed3d3,
+ 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4,
+ 0xf28b7979, 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d,
+ 0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, 0xd8b46c6c,
+ 0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a,
+ 0x47e9aeae, 0x10180808, 0x6fd5baba, 0xf0887878, 0x4a6f2525,
+ 0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6,
+ 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b,
+ 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, 0xe0907070, 0x7c423e3e,
+ 0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x06050303, 0xf701f6f6,
+ 0x1c120e0e, 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9,
+ 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, 0xd938e1e1,
+ 0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9,
+ 0x07898e8e, 0x33a79494, 0x2db69b9b, 0x3c221e1e, 0x15928787,
+ 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf,
+ 0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, 0x65dabfbf,
+ 0xd731e6e6, 0x84c64242, 0xd0b86868, 0x82c34141, 0x29b09999,
+ 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb,
+ 0x2c3a1616
+ };
+
+ private static readonly uint[] Tinv0 =
+ {
+ 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b,
+ 0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad,
+ 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526,
+ 0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d,
+ 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03,
+ 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458,
+ 0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899,
+ 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d,
+ 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1,
+ 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f,
+ 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3,
+ 0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3,
+ 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a,
+ 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506,
+ 0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05,
+ 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd,
+ 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491,
+ 0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6,
+ 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7,
+ 0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000,
+ 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd,
+ 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68,
+ 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, 0xd296eeb4,
+ 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c,
+ 0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e,
+ 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af,
+ 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644,
+ 0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8,
+ 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85,
+ 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc,
+ 0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411,
+ 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322,
+ 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6,
+ 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0x0d927850,
+ 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e,
+ 0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf,
+ 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd,
+ 0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa,
+ 0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea,
+ 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235,
+ 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1,
+ 0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43,
+ 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1,
+ 0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb,
+ 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a,
+ 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7,
+ 0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418,
+ 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478,
+ 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16,
+ 0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08,
+ 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48,
+ 0x4257b8d0
+ };
+
+ private static readonly uint[] Tinv1 =
+ {
+ 0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb,
+ 0x459d1ff1, 0x58faacab, 0x03e34b93, 0xfa302055, 0x6d76adf6,
+ 0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680,
+ 0xa362b58f, 0x5ab1de49, 0x1bba2567, 0x0eea4598, 0xc0fe5de1,
+ 0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, 0x5f8f03e7,
+ 0x9c921595, 0x7a6dbfeb, 0x595295da, 0x83bed42d, 0x217458d3,
+ 0x69e04929, 0xc8c98e44, 0x89c2756a, 0x798ef478, 0x3e58996b,
+ 0x71b927dd, 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4,
+ 0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245, 0x7764b1e0,
+ 0xae6bbb84, 0xa081fe1c, 0x2b08f994, 0x68487058, 0xfd458f19,
+ 0x6cde9487, 0xf87b52b7, 0xd373ab23, 0x024b72e2, 0x8f1fe357,
+ 0xab55662a, 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x0837d3a5,
+ 0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, 0x1ccf8a2b,
+ 0xb479a792, 0xf207f3f0, 0xe2694ea1, 0xf4da65cd, 0xbe0506d5,
+ 0x6234d11f, 0xfea6c48a, 0x532e349d, 0x55f3a2a0, 0xe18a0532,
+ 0xebf6a475, 0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51,
+ 0x8a213ef9, 0x06dd963d, 0x053eddae, 0xbde64d46, 0x8d5491b5,
+ 0x5dc47105, 0xd406046f, 0x155060ff, 0xfb981924, 0xe9bdd697,
+ 0x434089cc, 0x9ed96777, 0x42e8b0bd, 0x8b890788, 0x5b19e738,
+ 0xeec879db, 0x0a7ca147, 0x0f427ce9, 0x1e84f8c9, 0x00000000,
+ 0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, 0xff0efdfb,
+ 0x38850f56, 0xd5ae3d1e, 0x392d3627, 0xd90f0a64, 0xa65c6821,
+ 0x545b9bd1, 0x2e36243a, 0x670a0cb1, 0xe757930f, 0x96eeb4d2,
+ 0x919b1b9e, 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16,
+ 0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, 0x0d090e0b,
+ 0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, 0x19f15785, 0x0775af4c,
+ 0xdd99eebb, 0x607fa3fd, 0x2601f79f, 0xf5725cbc, 0x3b6644c5,
+ 0x7efb5b34, 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863,
+ 0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420, 0x244a857d,
+ 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, 0x2f9e1d4b, 0x30b2dcf3,
+ 0x52860dec, 0xe3c177d0, 0x16b32b6c, 0xb970a999, 0x489411fa,
+ 0x64e94722, 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef,
+ 0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0x0bd49836, 0x81f5a6cf,
+ 0xde7aa528, 0x8eb7da26, 0xbfad3fa4, 0x9d3a2ce4, 0x9278500d,
+ 0xcc5f6a9b, 0x467e5462, 0x138df6c2, 0xb8d890e8, 0xf7392e5e,
+ 0xafc382f5, 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3,
+ 0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, 0x7826cd09,
+ 0x18596ef4, 0xb79aec01, 0x9a4f83a8, 0x6e95e665, 0xe6ffaa7e,
+ 0xcfbc2108, 0xe815efe6, 0x9be7bad9, 0x366f4ace, 0x099fead4,
+ 0x7cb029d6, 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0,
+ 0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, 0x9804f14a,
+ 0xdaec41f7, 0x50cd7f0e, 0xf691172f, 0xd64d768d, 0xb0ef434d,
+ 0x4daacc54, 0x0496e4df, 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8,
+ 0x5165467f, 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e,
+ 0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13, 0x61d79a8c,
+ 0x0ca1377a, 0x14f8598e, 0x3c13eb89, 0x27a9ceee, 0xc961b735,
+ 0xe51ce1ed, 0xb1477a3c, 0xdfd29c59, 0x73f2553f, 0xce141879,
+ 0x37c773bf, 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886,
+ 0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672,
+ 0x25e2bc0c, 0x493c288b, 0x950dff41, 0x01a83971, 0xb30c08de,
+ 0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874,
+ 0x57b8d042
+ };
+
+ private static readonly uint[] Tinv2 =
+ {
+ 0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b,
+ 0x9d1ff145, 0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d,
+ 0xcc889176, 0x02f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044,
+ 0x62b58fa3, 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0,
+ 0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, 0x8f03e75f,
+ 0x9215959c, 0x6dbfeb7a, 0x5295da59, 0xbed42d83, 0x7458d321,
+ 0xe0492969, 0xc98e44c8, 0xc2756a89, 0x8ef47879, 0x58996b3e,
+ 0xb927dd71, 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a,
+ 0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f, 0x64b1e077,
+ 0x6bbb84ae, 0x81fe1ca0, 0x08f9942b, 0x48705868, 0x458f19fd,
+ 0xde94876c, 0x7b52b7f8, 0x73ab23d3, 0x4b72e202, 0x1fe3578f,
+ 0x55662aab, 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508,
+ 0x2830f287, 0xbf23b2a5, 0x0302ba6a, 0x16ed5c82, 0xcf8a2b1c,
+ 0x79a792b4, 0x07f3f0f2, 0x694ea1e2, 0xda65cdf4, 0x0506d5be,
+ 0x34d11f62, 0xa6c48afe, 0x2e349d53, 0xf3a2a055, 0x8a0532e1,
+ 0xf6a475eb, 0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110,
+ 0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, 0x5491b58d,
+ 0xc471055d, 0x06046fd4, 0x5060ff15, 0x981924fb, 0xbdd697e9,
+ 0x4089cc43, 0xd967779e, 0xe8b0bd42, 0x8907888b, 0x19e7385b,
+ 0xc879dbee, 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x00000000,
+ 0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, 0x0efdfbff,
+ 0x850f5638, 0xae3d1ed5, 0x2d362739, 0x0f0a64d9, 0x5c6821a6,
+ 0x5b9bd154, 0x36243a2e, 0x0a0cb167, 0x57930fe7, 0xeeb4d296,
+ 0x9b1b9e91, 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a,
+ 0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, 0x090e0b0d,
+ 0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, 0xf1578519, 0x75af4c07,
+ 0x99eebbdd, 0x7fa3fd60, 0x01f79f26, 0x725cbcf5, 0x6644c53b,
+ 0xfb5b347e, 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1,
+ 0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011, 0x4a857d24,
+ 0xbbd2f83d, 0xf9ae1132, 0x29c76da1, 0x9e1d4b2f, 0xb2dcf330,
+ 0x860dec52, 0xc177d0e3, 0xb32b6c16, 0x70a999b9, 0x9411fa48,
+ 0xe9472264, 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90,
+ 0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, 0xf5a6cf81,
+ 0x7aa528de, 0xb7da268e, 0xad3fa4bf, 0x3a2ce49d, 0x78500d92,
+ 0x5f6a9bcc, 0x7e546246, 0x8df6c213, 0xd890e8b8, 0x392e5ef7,
+ 0xc382f5af, 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312,
+ 0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, 0x26cd0978,
+ 0x596ef418, 0x9aec01b7, 0x4f83a89a, 0x95e6656e, 0xffaa7ee6,
+ 0xbc2108cf, 0x15efe6e8, 0xe7bad99b, 0x6f4ace36, 0x9fead409,
+ 0xb029d67c, 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066,
+ 0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, 0x04f14a98,
+ 0xec41f7da, 0xcd7f0e50, 0x91172ff6, 0x4d768dd6, 0xef434db0,
+ 0xaacc544d, 0x96e4df04, 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f,
+ 0x65467f51, 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0x0bfb2e41,
+ 0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347, 0xd79a8c61,
+ 0xa1377a0c, 0xf8598e14, 0x13eb893c, 0xa9ceee27, 0x61b735c9,
+ 0x1ce1ede5, 0x477a3cb1, 0xd29c59df, 0xf2553f73, 0x141879ce,
+ 0xc773bf37, 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db,
+ 0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3,
+ 0xe2bc0c25, 0x3c288b49, 0x0dff4195, 0xa8397101, 0x0c08deb3,
+ 0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c,
+ 0xb8d04257
+ };
+
+ private static readonly uint[] Tinv3 =
+ {
+ 0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab,
+ 0x1ff1459d, 0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76,
+ 0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435,
+ 0xb58fa362, 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe,
+ 0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, 0x03e75f8f,
+ 0x15959c92, 0xbfeb7a6d, 0x95da5952, 0xd42d83be, 0x58d32174,
+ 0x492969e0, 0x8e44c8c9, 0x756a89c2, 0xf478798e, 0x996b3e58,
+ 0x27dd71b9, 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace,
+ 0x63184adf, 0xe582311a, 0x97603351, 0x62457f53, 0xb1e07764,
+ 0xbb84ae6b, 0xfe1ca081, 0xf9942b08, 0x70586848, 0x8f19fd45,
+ 0x94876cde, 0x52b7f87b, 0xab23d373, 0x72e2024b, 0xe3578f1f,
+ 0x662aab55, 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837,
+ 0x30f28728, 0x23b2a5bf, 0x02ba6a03, 0xed5c8216, 0x8a2b1ccf,
+ 0xa792b479, 0xf3f0f207, 0x4ea1e269, 0x65cdf4da, 0x06d5be05,
+ 0xd11f6234, 0xc48afea6, 0x349d532e, 0xa2a055f3, 0x0532e18a,
+ 0xa475ebf6, 0x0b39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e,
+ 0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, 0x91b58d54,
+ 0x71055dc4, 0x046fd406, 0x60ff1550, 0x1924fb98, 0xd697e9bd,
+ 0x89cc4340, 0x67779ed9, 0xb0bd42e8, 0x07888b89, 0xe7385b19,
+ 0x79dbeec8, 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x00000000,
+ 0x09838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, 0xfdfbff0e,
+ 0x0f563885, 0x3d1ed5ae, 0x3627392d, 0x0a64d90f, 0x6821a65c,
+ 0x9bd1545b, 0x243a2e36, 0x0cb1670a, 0x930fe757, 0xb4d296ee,
+ 0x1b9e919b, 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12,
+ 0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, 0x0e0b0d09,
+ 0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, 0x578519f1, 0xaf4c0775,
+ 0xeebbdd99, 0xa3fd607f, 0xf79f2601, 0x5cbcf572, 0x44c53b66,
+ 0x5b347efb, 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4,
+ 0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6, 0x857d244a,
+ 0xd2f83dbb, 0xae1132f9, 0xc76da129, 0x1d4b2f9e, 0xdcf330b2,
+ 0x0dec5286, 0x77d0e3c1, 0x2b6c16b3, 0xa999b970, 0x11fa4894,
+ 0x472264e9, 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033,
+ 0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, 0xa6cf81f5,
+ 0xa528de7a, 0xda268eb7, 0x3fa4bfad, 0x2ce49d3a, 0x500d9278,
+ 0x6a9bcc5f, 0x5462467e, 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739,
+ 0x82f5afc3, 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225,
+ 0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, 0xcd097826,
+ 0x6ef41859, 0xec01b79a, 0x83a89a4f, 0xe6656e95, 0xaa7ee6ff,
+ 0x2108cfbc, 0xefe6e815, 0xbad99be7, 0x4ace366f, 0xead4099f,
+ 0x29d67cb0, 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2,
+ 0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, 0xf14a9804,
+ 0x41f7daec, 0x7f0e50cd, 0x172ff691, 0x768dd64d, 0x434db0ef,
+ 0xcc544daa, 0xe4df0496, 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c,
+ 0x467f5165, 0x9d04ea5e, 0x015d358c, 0xfa737487, 0xfb2e410b,
+ 0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6, 0x9a8c61d7,
+ 0x377a0ca1, 0x598e14f8, 0xeb893c13, 0xceee27a9, 0xb735c961,
+ 0xe1ede51c, 0x7a3cb147, 0x9c59dfd2, 0x553f73f2, 0x1879ce14,
+ 0x73bf37c7, 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44,
+ 0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, 0x1672c31d,
+ 0xbc0c25e2, 0x288b493c, 0xff41950d, 0x397101a8, 0x08deb30c,
+ 0xd89ce4b4, 0x6490c156, 0x7b6184cb, 0xd570b632, 0x48745c6c,
+ 0xd04257b8
+ };
+
+ private static uint Shift(uint r, int shift)
+ {
+ return (r >> shift) | (r << (32 - shift));
+ }
+
+ /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+ private const uint m1 = 0x80808080;
+ private const uint m2 = 0x7f7f7f7f;
+ private const uint m3 = 0x0000001b;
+ private const uint m4 = 0xC0C0C0C0;
+ private const uint m5 = 0x3f3f3f3f;
+
+ private static uint FFmulX(uint x)
+ {
+ return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
+ }
+
+ private static uint FFmulX2(uint x)
+ {
+ uint t0 = (x & m5) << 2;
+ uint t1 = (x & m4);
+ t1 ^= (t1 >> 1);
+ return t0 ^ (t1 >> 2) ^ (t1 >> 5);
+ }
+
+ /*
+ The following defines provide alternative definitions of FFmulX that might
+ give improved performance if a fast 32-bit multiply is not available.
+
+ private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
+ private static final int m4 = 0x1b1b1b1b;
+ private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
+
+ */
+
+ private static uint Inv_Mcol(uint x)
+ {
+ uint t0, t1;
+ t0 = x;
+ t1 = t0 ^ Shift(t0, 8);
+ t0 ^= FFmulX(t1);
+ t1 ^= FFmulX2(t0);
+ t0 ^= t1 ^ Shift(t1, 16);
+ return t0;
+ }
+
+ private static uint SubWord(uint x)
+ {
+ return (uint)S[x&255]
+ | (((uint)S[(x>>8)&255]) << 8)
+ | (((uint)S[(x>>16)&255]) << 16)
+ | (((uint)S[(x>>24)&255]) << 24);
+ }
+
+ /**
+ * Calculate the necessary round keys
+ * The number of calculations depends on key size and block size
+ * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
+ * This code is written assuming those are the only possible values
+ */
+ private uint[][] GenerateWorkingKey(byte[] key, bool forEncryption)
+ {
+ int keyLen = key.Length;
+ if (keyLen < 16 || keyLen > 32 || (keyLen & 7) != 0)
+ throw new ArgumentException("Key length not 128/192/256 bits.");
+
+ int KC = keyLen >> 2;
+ this.ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
+
+ uint[][] W = new uint[ROUNDS + 1][]; // 4 words in a block
+ for (int i = 0; i <= ROUNDS; ++i)
+ {
+ W[i] = new uint[4];
+ }
+
+ switch (KC)
+ {
+ case 4:
+ {
+ uint t0 = Pack.LE_To_UInt32(key, 0); W[0][0] = t0;
+ uint t1 = Pack.LE_To_UInt32(key, 4); W[0][1] = t1;
+ uint t2 = Pack.LE_To_UInt32(key, 8); W[0][2] = t2;
+ uint t3 = Pack.LE_To_UInt32(key, 12); W[0][3] = t3;
+
+ for (int i = 1; i <= 10; ++i)
+ {
+ uint u = SubWord(Shift(t3, 8)) ^ rcon[i - 1];
+ t0 ^= u; W[i][0] = t0;
+ t1 ^= t0; W[i][1] = t1;
+ t2 ^= t1; W[i][2] = t2;
+ t3 ^= t2; W[i][3] = t3;
+ }
+
+ break;
+ }
+ case 6:
+ {
+ uint t0 = Pack.LE_To_UInt32(key, 0); W[0][0] = t0;
+ uint t1 = Pack.LE_To_UInt32(key, 4); W[0][1] = t1;
+ uint t2 = Pack.LE_To_UInt32(key, 8); W[0][2] = t2;
+ uint t3 = Pack.LE_To_UInt32(key, 12); W[0][3] = t3;
+ uint t4 = Pack.LE_To_UInt32(key, 16); W[1][0] = t4;
+ uint t5 = Pack.LE_To_UInt32(key, 20); W[1][1] = t5;
+
+ uint rcon = 1;
+ uint u = SubWord(Shift(t5, 8)) ^ rcon; rcon <<= 1;
+ t0 ^= u; W[1][2] = t0;
+ t1 ^= t0; W[1][3] = t1;
+ t2 ^= t1; W[2][0] = t2;
+ t3 ^= t2; W[2][1] = t3;
+ t4 ^= t3; W[2][2] = t4;
+ t5 ^= t4; W[2][3] = t5;
+
+ for (int i = 3; i < 12; i += 3)
+ {
+ u = SubWord(Shift(t5, 8)) ^ rcon; rcon <<= 1;
+ t0 ^= u; W[i ][0] = t0;
+ t1 ^= t0; W[i ][1] = t1;
+ t2 ^= t1; W[i ][2] = t2;
+ t3 ^= t2; W[i ][3] = t3;
+ t4 ^= t3; W[i + 1][0] = t4;
+ t5 ^= t4; W[i + 1][1] = t5;
+ u = SubWord(Shift(t5, 8)) ^ rcon; rcon <<= 1;
+ t0 ^= u; W[i + 1][2] = t0;
+ t1 ^= t0; W[i + 1][3] = t1;
+ t2 ^= t1; W[i + 2][0] = t2;
+ t3 ^= t2; W[i + 2][1] = t3;
+ t4 ^= t3; W[i + 2][2] = t4;
+ t5 ^= t4; W[i + 2][3] = t5;
+ }
+
+ u = SubWord(Shift(t5, 8)) ^ rcon;
+ t0 ^= u; W[12][0] = t0;
+ t1 ^= t0; W[12][1] = t1;
+ t2 ^= t1; W[12][2] = t2;
+ t3 ^= t2; W[12][3] = t3;
+
+ break;
+ }
+ case 8:
+ {
+ uint t0 = Pack.LE_To_UInt32(key, 0); W[0][0] = t0;
+ uint t1 = Pack.LE_To_UInt32(key, 4); W[0][1] = t1;
+ uint t2 = Pack.LE_To_UInt32(key, 8); W[0][2] = t2;
+ uint t3 = Pack.LE_To_UInt32(key, 12); W[0][3] = t3;
+ uint t4 = Pack.LE_To_UInt32(key, 16); W[1][0] = t4;
+ uint t5 = Pack.LE_To_UInt32(key, 20); W[1][1] = t5;
+ uint t6 = Pack.LE_To_UInt32(key, 24); W[1][2] = t6;
+ uint t7 = Pack.LE_To_UInt32(key, 28); W[1][3] = t7;
+
+ uint u, rcon = 1;
+
+ for (int i = 2; i < 14; i += 2)
+ {
+ u = SubWord(Shift(t7, 8)) ^ rcon; rcon <<= 1;
+ t0 ^= u; W[i ][0] = t0;
+ t1 ^= t0; W[i ][1] = t1;
+ t2 ^= t1; W[i ][2] = t2;
+ t3 ^= t2; W[i ][3] = t3;
+ u = SubWord(t3);
+ t4 ^= u; W[i + 1][0] = t4;
+ t5 ^= t4; W[i + 1][1] = t5;
+ t6 ^= t5; W[i + 1][2] = t6;
+ t7 ^= t6; W[i + 1][3] = t7;
+ }
+
+ u = SubWord(Shift(t7, 8)) ^ rcon;
+ t0 ^= u; W[14][0] = t0;
+ t1 ^= t0; W[14][1] = t1;
+ t2 ^= t1; W[14][2] = t2;
+ t3 ^= t2; W[14][3] = t3;
+
+ break;
+ }
+ default:
+ {
+ throw new InvalidOperationException("Should never get here");
+ }
+ }
+
+ if (!forEncryption)
+ {
+ for (int j = 1; j < ROUNDS; j++)
+ {
+ uint[] w = W[j];
+ for (int i = 0; i < 4; i++)
+ {
+ w[i] = Inv_Mcol(w[i]);
+ }
+ }
+ }
+
+ return W;
+ }
+
+ private int ROUNDS;
+ private uint[][] WorkingKey;
+ private uint C0, C1, C2, C3;
+ private bool forEncryption;
+
+ private const int BLOCK_SIZE = 16;
+
+ /**
+ * default constructor - 128 bit block size.
+ */
+ public AesFastEngine()
+ {
+ }
+
+ /**
+ * initialise an AES 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 virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ KeyParameter keyParameter = parameters as KeyParameter;
+
+ if (keyParameter == null)
+ throw new ArgumentException("invalid parameter passed to AES init - "
+ + Platform.GetTypeName(parameters));
+
+ WorkingKey = GenerateWorkingKey(keyParameter.GetKey(), forEncryption);
+
+ this.forEncryption = forEncryption;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "AES"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (WorkingKey == null)
+ throw new InvalidOperationException("AES engine not initialised");
+
+ Check.DataLength(input, inOff, 16, "input buffer too short");
+ Check.OutputLength(output, outOff, 16, "output buffer too short");
+
+ UnPackBlock(input, inOff);
+
+ if (forEncryption)
+ {
+ EncryptBlock(WorkingKey);
+ }
+ else
+ {
+ DecryptBlock(WorkingKey);
+ }
+
+ PackBlock(output, outOff);
+
+ return BLOCK_SIZE;
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ private void UnPackBlock(
+ byte[] bytes,
+ int off)
+ {
+ C0 = Pack.LE_To_UInt32(bytes, off);
+ C1 = Pack.LE_To_UInt32(bytes, off + 4);
+ C2 = Pack.LE_To_UInt32(bytes, off + 8);
+ C3 = Pack.LE_To_UInt32(bytes, off + 12);
+ }
+
+ private void PackBlock(
+ byte[] bytes,
+ int off)
+ {
+ Pack.UInt32_To_LE(C0, bytes, off);
+ Pack.UInt32_To_LE(C1, bytes, off + 4);
+ Pack.UInt32_To_LE(C2, bytes, off + 8);
+ Pack.UInt32_To_LE(C3, bytes, off + 12);
+ }
+
+ private void EncryptBlock(uint[][] KW)
+ {
+ uint[] kw = KW[0];
+ uint t0 = this.C0 ^ kw[0];
+ uint t1 = this.C1 ^ kw[1];
+ uint t2 = this.C2 ^ kw[2];
+
+ uint r0, r1, r2, r3 = this.C3 ^ kw[3];
+ int r = 1;
+ while (r < ROUNDS - 1)
+ {
+ kw = KW[r++];
+ r0 = T0[t0 & 255] ^ T1[(t1 >> 8) & 255] ^ T2[(t2 >> 16) & 255] ^ T3[r3 >> 24] ^ kw[0];
+ r1 = T0[t1 & 255] ^ T1[(t2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[t0 >> 24] ^ kw[1];
+ r2 = T0[t2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(t0 >> 16) & 255] ^ T3[t1 >> 24] ^ kw[2];
+ r3 = T0[r3 & 255] ^ T1[(t0 >> 8) & 255] ^ T2[(t1 >> 16) & 255] ^ T3[t2 >> 24] ^ kw[3];
+ kw = KW[r++];
+ t0 = T0[r0 & 255] ^ T1[(r1 >> 8) & 255] ^ T2[(r2 >> 16) & 255] ^ T3[r3 >> 24] ^ kw[0];
+ t1 = T0[r1 & 255] ^ T1[(r2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[r0 >> 24] ^ kw[1];
+ t2 = T0[r2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(r0 >> 16) & 255] ^ T3[r1 >> 24] ^ kw[2];
+ r3 = T0[r3 & 255] ^ T1[(r0 >> 8) & 255] ^ T2[(r1 >> 16) & 255] ^ T3[r2 >> 24] ^ kw[3];
+ }
+
+ kw = KW[r++];
+ r0 = T0[t0 & 255] ^ T1[(t1 >> 8) & 255] ^ T2[(t2 >> 16) & 255] ^ T3[r3 >> 24] ^ kw[0];
+ r1 = T0[t1 & 255] ^ T1[(t2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[t0 >> 24] ^ kw[1];
+ r2 = T0[t2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(t0 >> 16) & 255] ^ T3[t1 >> 24] ^ kw[2];
+ r3 = T0[r3 & 255] ^ T1[(t0 >> 8) & 255] ^ T2[(t1 >> 16) & 255] ^ T3[t2 >> 24] ^ 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];
+ this.C0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[r3 >> 24]) << 24) ^ kw[0];
+ this.C1 = (uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[r0 >> 24]) << 24) ^ kw[1];
+ this.C2 = (uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[r1 >> 24]) << 24) ^ kw[2];
+ this.C3 = (uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[r2 >> 24]) << 24) ^ kw[3];
+ }
+
+ private void DecryptBlock(uint[][] KW)
+ {
+ uint[] kw = KW[ROUNDS];
+ uint t0 = this.C0 ^ kw[0];
+ uint t1 = this.C1 ^ kw[1];
+ uint t2 = this.C2 ^ kw[2];
+
+ uint r0, r1, r2, r3 = this.C3 ^ kw[3];
+ int r = ROUNDS - 1;
+ while (r > 1)
+ {
+ kw = KW[r--];
+ r0 = Tinv0[t0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(t2 >> 16) & 255] ^ Tinv3[t1 >> 24] ^ kw[0];
+ r1 = Tinv0[t1 & 255] ^ Tinv1[(t0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[t2 >> 24] ^ kw[1];
+ r2 = Tinv0[t2 & 255] ^ Tinv1[(t1 >> 8) & 255] ^ Tinv2[(t0 >> 16) & 255] ^ Tinv3[r3 >> 24] ^ kw[2];
+ r3 = Tinv0[r3 & 255] ^ Tinv1[(t2 >> 8) & 255] ^ Tinv2[(t1 >> 16) & 255] ^ Tinv3[t0 >> 24] ^ kw[3];
+ kw = KW[r--];
+ t0 = Tinv0[r0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(r2 >> 16) & 255] ^ Tinv3[r1 >> 24] ^ kw[0];
+ t1 = Tinv0[r1 & 255] ^ Tinv1[(r0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[r2 >> 24] ^ kw[1];
+ t2 = Tinv0[r2 & 255] ^ Tinv1[(r1 >> 8) & 255] ^ Tinv2[(r0 >> 16) & 255] ^ Tinv3[r3 >> 24] ^ kw[2];
+ r3 = Tinv0[r3 & 255] ^ Tinv1[(r2 >> 8) & 255] ^ Tinv2[(r1 >> 16) & 255] ^ Tinv3[r0 >> 24] ^ kw[3];
+ }
+
+ kw = KW[1];
+ r0 = Tinv0[t0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(t2 >> 16) & 255] ^ Tinv3[t1 >> 24] ^ kw[0];
+ r1 = Tinv0[t1 & 255] ^ Tinv1[(t0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[t2 >> 24] ^ kw[1];
+ r2 = Tinv0[t2 & 255] ^ Tinv1[(t1 >> 8) & 255] ^ Tinv2[(t0 >> 16) & 255] ^ Tinv3[r3 >> 24] ^ kw[2];
+ r3 = Tinv0[r3 & 255] ^ Tinv1[(t2 >> 8) & 255] ^ Tinv2[(t1 >> 16) & 255] ^ Tinv3[t0 >> 24] ^ 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];
+ this.C0 = (uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[r1 >> 24]) << 24) ^ kw[0];
+ this.C1 = (uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)Si[r2 >> 24]) << 24) ^ kw[1];
+ this.C2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[r3 >> 24]) << 24) ^ kw[2];
+ this.C3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[r0 >> 24]) << 24) ^ kw[3];
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/AesLightEngine.cs b/bc-sharp-crypto/src/crypto/engines/AesLightEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9cc9c34a0728d1b1f698999bb21fb0f0188ae813
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/AesLightEngine.cs
@@ -0,0 +1,504 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * an implementation of the AES (Rijndael), from FIPS-197.
+ *
+ * For further details see: http://csrc.nist.gov/encryption/aes/ .
+ *
+ * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
+ * http://fp.gladman.plus.com/cryptography_technology/rijndael/
+ *
+ * There are three levels of tradeoff of speed vs memory
+ * Because java has no preprocessor, they are written as three separate classes from which to choose
+ *
+ * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
+ * and 4 for decryption.
+ *
+ * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
+ * adding 12 rotate operations per round to compute the values contained in the other tables from
+ * the contents of the first
+ *
+ * The slowest version uses no static tables at all and computes the values
+ * in each round.
+ *
+ *
+ * This file contains the slowest performance version with no static tables
+ * for round precomputation, but it has the smallest foot print.
+ *
+ */
+ public class AesLightEngine
+ : IBlockCipher
+ {
+ // The S box
+ private static readonly byte[] S =
+ {
+ 99, 124, 119, 123, 242, 107, 111, 197,
+ 48, 1, 103, 43, 254, 215, 171, 118,
+ 202, 130, 201, 125, 250, 89, 71, 240,
+ 173, 212, 162, 175, 156, 164, 114, 192,
+ 183, 253, 147, 38, 54, 63, 247, 204,
+ 52, 165, 229, 241, 113, 216, 49, 21,
+ 4, 199, 35, 195, 24, 150, 5, 154,
+ 7, 18, 128, 226, 235, 39, 178, 117,
+ 9, 131, 44, 26, 27, 110, 90, 160,
+ 82, 59, 214, 179, 41, 227, 47, 132,
+ 83, 209, 0, 237, 32, 252, 177, 91,
+ 106, 203, 190, 57, 74, 76, 88, 207,
+ 208, 239, 170, 251, 67, 77, 51, 133,
+ 69, 249, 2, 127, 80, 60, 159, 168,
+ 81, 163, 64, 143, 146, 157, 56, 245,
+ 188, 182, 218, 33, 16, 255, 243, 210,
+ 205, 12, 19, 236, 95, 151, 68, 23,
+ 196, 167, 126, 61, 100, 93, 25, 115,
+ 96, 129, 79, 220, 34, 42, 144, 136,
+ 70, 238, 184, 20, 222, 94, 11, 219,
+ 224, 50, 58, 10, 73, 6, 36, 92,
+ 194, 211, 172, 98, 145, 149, 228, 121,
+ 231, 200, 55, 109, 141, 213, 78, 169,
+ 108, 86, 244, 234, 101, 122, 174, 8,
+ 186, 120, 37, 46, 28, 166, 180, 198,
+ 232, 221, 116, 31, 75, 189, 139, 138,
+ 112, 62, 181, 102, 72, 3, 246, 14,
+ 97, 53, 87, 185, 134, 193, 29, 158,
+ 225, 248, 152, 17, 105, 217, 142, 148,
+ 155, 30, 135, 233, 206, 85, 40, 223,
+ 140, 161, 137, 13, 191, 230, 66, 104,
+ 65, 153, 45, 15, 176, 84, 187, 22,
+ };
+
+ // The inverse S-box
+ private static readonly byte[] Si =
+ {
+ 82, 9, 106, 213, 48, 54, 165, 56,
+ 191, 64, 163, 158, 129, 243, 215, 251,
+ 124, 227, 57, 130, 155, 47, 255, 135,
+ 52, 142, 67, 68, 196, 222, 233, 203,
+ 84, 123, 148, 50, 166, 194, 35, 61,
+ 238, 76, 149, 11, 66, 250, 195, 78,
+ 8, 46, 161, 102, 40, 217, 36, 178,
+ 118, 91, 162, 73, 109, 139, 209, 37,
+ 114, 248, 246, 100, 134, 104, 152, 22,
+ 212, 164, 92, 204, 93, 101, 182, 146,
+ 108, 112, 72, 80, 253, 237, 185, 218,
+ 94, 21, 70, 87, 167, 141, 157, 132,
+ 144, 216, 171, 0, 140, 188, 211, 10,
+ 247, 228, 88, 5, 184, 179, 69, 6,
+ 208, 44, 30, 143, 202, 63, 15, 2,
+ 193, 175, 189, 3, 1, 19, 138, 107,
+ 58, 145, 17, 65, 79, 103, 220, 234,
+ 151, 242, 207, 206, 240, 180, 230, 115,
+ 150, 172, 116, 34, 231, 173, 53, 133,
+ 226, 249, 55, 232, 28, 117, 223, 110,
+ 71, 241, 26, 113, 29, 41, 197, 137,
+ 111, 183, 98, 14, 170, 24, 190, 27,
+ 252, 86, 62, 75, 198, 210, 121, 32,
+ 154, 219, 192, 254, 120, 205, 90, 244,
+ 31, 221, 168, 51, 136, 7, 199, 49,
+ 177, 18, 16, 89, 39, 128, 236, 95,
+ 96, 81, 127, 169, 25, 181, 74, 13,
+ 45, 229, 122, 159, 147, 201, 156, 239,
+ 160, 224, 59, 77, 174, 42, 245, 176,
+ 200, 235, 187, 60, 131, 83, 153, 97,
+ 23, 43, 4, 126, 186, 119, 214, 38,
+ 225, 105, 20, 99, 85, 33, 12, 125,
+ };
+
+ // vector used in calculating key schedule (powers of x in GF(256))
+ private static readonly byte[] 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
+ };
+
+ private static uint Shift(uint r, int shift)
+ {
+ return (r >> shift) | (r << (32 - shift));
+ }
+
+ /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+ private const uint m1 = 0x80808080;
+ private const uint m2 = 0x7f7f7f7f;
+ private const uint m3 = 0x0000001b;
+ private const uint m4 = 0xC0C0C0C0;
+ private const uint m5 = 0x3f3f3f3f;
+
+ private static uint FFmulX(uint x)
+ {
+ return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
+ }
+
+ private static uint FFmulX2(uint x)
+ {
+ uint t0 = (x & m5) << 2;
+ uint t1 = (x & m4);
+ t1 ^= (t1 >> 1);
+ return t0 ^ (t1 >> 2) ^ (t1 >> 5);
+ }
+
+ /*
+ The following defines provide alternative definitions of FFmulX that might
+ give improved performance if a fast 32-bit multiply is not available.
+
+ private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
+ private static final int m4 = 0x1b1b1b1b;
+ private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
+
+ */
+
+ private static uint Mcol(uint x)
+ {
+ uint t0, t1;
+ t0 = Shift(x, 8);
+ t1 = x ^ t0;
+ return Shift(t1, 16) ^ t0 ^ FFmulX(t1);
+ }
+
+ private static uint Inv_Mcol(uint x)
+ {
+ uint t0, t1;
+ t0 = x;
+ t1 = t0 ^ Shift(t0, 8);
+ t0 ^= FFmulX(t1);
+ t1 ^= FFmulX2(t0);
+ t0 ^= t1 ^ Shift(t1, 16);
+ return t0;
+ }
+
+ private static uint SubWord(uint x)
+ {
+ return (uint)S[x&255]
+ | (((uint)S[(x>>8)&255]) << 8)
+ | (((uint)S[(x>>16)&255]) << 16)
+ | (((uint)S[(x>>24)&255]) << 24);
+ }
+
+ /**
+ * Calculate the necessary round keys
+ * The number of calculations depends on key size and block size
+ * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
+ * This code is written assuming those are the only possible values
+ */
+ private uint[][] GenerateWorkingKey(byte[] key, bool forEncryption)
+ {
+ int keyLen = key.Length;
+ if (keyLen < 16 || keyLen > 32 || (keyLen & 7) != 0)
+ throw new ArgumentException("Key length not 128/192/256 bits.");
+
+ int KC = keyLen >> 2;
+ this.ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
+
+ uint[][] W = new uint[ROUNDS + 1][]; // 4 words in a block
+ for (int i = 0; i <= ROUNDS; ++i)
+ {
+ W[i] = new uint[4];
+ }
+
+ switch (KC)
+ {
+ case 4:
+ {
+ uint t0 = Pack.LE_To_UInt32(key, 0); W[0][0] = t0;
+ uint t1 = Pack.LE_To_UInt32(key, 4); W[0][1] = t1;
+ uint t2 = Pack.LE_To_UInt32(key, 8); W[0][2] = t2;
+ uint t3 = Pack.LE_To_UInt32(key, 12); W[0][3] = t3;
+
+ for (int i = 1; i <= 10; ++i)
+ {
+ uint u = SubWord(Shift(t3, 8)) ^ rcon[i - 1];
+ t0 ^= u; W[i][0] = t0;
+ t1 ^= t0; W[i][1] = t1;
+ t2 ^= t1; W[i][2] = t2;
+ t3 ^= t2; W[i][3] = t3;
+ }
+
+ break;
+ }
+ case 6:
+ {
+ uint t0 = Pack.LE_To_UInt32(key, 0); W[0][0] = t0;
+ uint t1 = Pack.LE_To_UInt32(key, 4); W[0][1] = t1;
+ uint t2 = Pack.LE_To_UInt32(key, 8); W[0][2] = t2;
+ uint t3 = Pack.LE_To_UInt32(key, 12); W[0][3] = t3;
+ uint t4 = Pack.LE_To_UInt32(key, 16); W[1][0] = t4;
+ uint t5 = Pack.LE_To_UInt32(key, 20); W[1][1] = t5;
+
+ uint rcon = 1;
+ uint u = SubWord(Shift(t5, 8)) ^ rcon; rcon <<= 1;
+ t0 ^= u; W[1][2] = t0;
+ t1 ^= t0; W[1][3] = t1;
+ t2 ^= t1; W[2][0] = t2;
+ t3 ^= t2; W[2][1] = t3;
+ t4 ^= t3; W[2][2] = t4;
+ t5 ^= t4; W[2][3] = t5;
+
+ for (int i = 3; i < 12; i += 3)
+ {
+ u = SubWord(Shift(t5, 8)) ^ rcon; rcon <<= 1;
+ t0 ^= u; W[i ][0] = t0;
+ t1 ^= t0; W[i ][1] = t1;
+ t2 ^= t1; W[i ][2] = t2;
+ t3 ^= t2; W[i ][3] = t3;
+ t4 ^= t3; W[i + 1][0] = t4;
+ t5 ^= t4; W[i + 1][1] = t5;
+ u = SubWord(Shift(t5, 8)) ^ rcon; rcon <<= 1;
+ t0 ^= u; W[i + 1][2] = t0;
+ t1 ^= t0; W[i + 1][3] = t1;
+ t2 ^= t1; W[i + 2][0] = t2;
+ t3 ^= t2; W[i + 2][1] = t3;
+ t4 ^= t3; W[i + 2][2] = t4;
+ t5 ^= t4; W[i + 2][3] = t5;
+ }
+
+ u = SubWord(Shift(t5, 8)) ^ rcon;
+ t0 ^= u; W[12][0] = t0;
+ t1 ^= t0; W[12][1] = t1;
+ t2 ^= t1; W[12][2] = t2;
+ t3 ^= t2; W[12][3] = t3;
+
+ break;
+ }
+ case 8:
+ {
+ uint t0 = Pack.LE_To_UInt32(key, 0); W[0][0] = t0;
+ uint t1 = Pack.LE_To_UInt32(key, 4); W[0][1] = t1;
+ uint t2 = Pack.LE_To_UInt32(key, 8); W[0][2] = t2;
+ uint t3 = Pack.LE_To_UInt32(key, 12); W[0][3] = t3;
+ uint t4 = Pack.LE_To_UInt32(key, 16); W[1][0] = t4;
+ uint t5 = Pack.LE_To_UInt32(key, 20); W[1][1] = t5;
+ uint t6 = Pack.LE_To_UInt32(key, 24); W[1][2] = t6;
+ uint t7 = Pack.LE_To_UInt32(key, 28); W[1][3] = t7;
+
+ uint u, rcon = 1;
+
+ for (int i = 2; i < 14; i += 2)
+ {
+ u = SubWord(Shift(t7, 8)) ^ rcon; rcon <<= 1;
+ t0 ^= u; W[i ][0] = t0;
+ t1 ^= t0; W[i ][1] = t1;
+ t2 ^= t1; W[i ][2] = t2;
+ t3 ^= t2; W[i ][3] = t3;
+ u = SubWord(t3);
+ t4 ^= u; W[i + 1][0] = t4;
+ t5 ^= t4; W[i + 1][1] = t5;
+ t6 ^= t5; W[i + 1][2] = t6;
+ t7 ^= t6; W[i + 1][3] = t7;
+ }
+
+ u = SubWord(Shift(t7, 8)) ^ rcon;
+ t0 ^= u; W[14][0] = t0;
+ t1 ^= t0; W[14][1] = t1;
+ t2 ^= t1; W[14][2] = t2;
+ t3 ^= t2; W[14][3] = t3;
+
+ break;
+ }
+ default:
+ {
+ throw new InvalidOperationException("Should never get here");
+ }
+ }
+
+ if (!forEncryption)
+ {
+ for (int j = 1; j < ROUNDS; j++)
+ {
+ uint[] w = W[j];
+ for (int i = 0; i < 4; i++)
+ {
+ w[i] = Inv_Mcol(w[i]);
+ }
+ }
+ }
+
+ return W;
+ }
+
+ private int ROUNDS;
+ private uint[][] WorkingKey;
+ private uint C0, C1, C2, C3;
+ private bool forEncryption;
+
+ private const int BLOCK_SIZE = 16;
+
+ /**
+ * default constructor - 128 bit block size.
+ */
+ public AesLightEngine()
+ {
+ }
+
+ /**
+ * initialise an AES 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 virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ KeyParameter keyParameter = parameters as KeyParameter;
+
+ if (keyParameter == null)
+ throw new ArgumentException("invalid parameter passed to AES init - "
+ + Platform.GetTypeName(parameters));
+
+ WorkingKey = GenerateWorkingKey(keyParameter.GetKey(), forEncryption);
+
+ this.forEncryption = forEncryption;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "AES"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (WorkingKey == null)
+ throw new InvalidOperationException("AES engine not initialised");
+
+ Check.DataLength(input, inOff, 16, "input buffer too short");
+ Check.OutputLength(output, outOff, 16, "output buffer too short");
+
+ UnPackBlock(input, inOff);
+
+ if (forEncryption)
+ {
+ EncryptBlock(WorkingKey);
+ }
+ else
+ {
+ DecryptBlock(WorkingKey);
+ }
+
+ PackBlock(output, outOff);
+
+ return BLOCK_SIZE;
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ private void UnPackBlock(
+ byte[] bytes,
+ int off)
+ {
+ C0 = Pack.LE_To_UInt32(bytes, off);
+ C1 = Pack.LE_To_UInt32(bytes, off + 4);
+ C2 = Pack.LE_To_UInt32(bytes, off + 8);
+ C3 = Pack.LE_To_UInt32(bytes, off + 12);
+ }
+
+ private void PackBlock(
+ byte[] bytes,
+ int off)
+ {
+ Pack.UInt32_To_LE(C0, bytes, off);
+ Pack.UInt32_To_LE(C1, bytes, off + 4);
+ Pack.UInt32_To_LE(C2, bytes, off + 8);
+ Pack.UInt32_To_LE(C3, bytes, off + 12);
+ }
+
+ private void EncryptBlock(uint[][] KW)
+ {
+ uint[] kw = KW[0];
+ uint t0 = this.C0 ^ kw[0];
+ uint t1 = this.C1 ^ kw[1];
+ uint t2 = this.C2 ^ kw[2];
+
+ uint r0, r1, r2, r3 = this.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];
+ this.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];
+ this.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];
+ this.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];
+ this.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];
+ }
+
+ private void DecryptBlock(uint[][] KW)
+ {
+ uint[] kw = KW[ROUNDS];
+ uint t0 = this.C0 ^ kw[0];
+ uint t1 = this.C1 ^ kw[1];
+ uint t2 = this.C2 ^ kw[2];
+
+ uint r0, r1, r2, r3 = this.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];
+ this.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];
+ this.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];
+ this.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];
+ this.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];
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/AesWrapEngine.cs b/bc-sharp-crypto/src/crypto/engines/AesWrapEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1ce01542b6fd2d7bf497039f0398d0427f730b2a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/AesWrapEngine.cs
@@ -0,0 +1,16 @@
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ ///
+ /// An implementation of the AES Key Wrapper from the NIST Key Wrap Specification.
+ ///
+ /// For further details see: http://csrc.nist.gov/encryption/kms/key-wrap.pdf .
+ ///
+ public class AesWrapEngine
+ : Rfc3394WrapEngine
+ {
+ public AesWrapEngine()
+ : base(new AesEngine())
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/BlowfishEngine.cs b/bc-sharp-crypto/src/crypto/engines/BlowfishEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e38f4e8f6c2571b437212ec24652c3cae4fd03d8
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/BlowfishEngine.cs
@@ -0,0 +1,553 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * A class that provides Blowfish key encryption operations,
+ * such as encoding data and generating keys.
+ * All the algorithms herein are from Applied Cryptography
+ * and implement a simplified cryptography interface.
+ */
+ public sealed class BlowfishEngine
+ : IBlockCipher
+ {
+ private readonly static uint[] KP =
+ {
+ 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344,
+ 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89,
+ 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C,
+ 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917,
+ 0x9216D5D9, 0x8979FB1B
+ },
+ KS0 =
+ {
+ 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7,
+ 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99,
+ 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16,
+ 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E,
+ 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE,
+ 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013,
+ 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF,
+ 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E,
+ 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60,
+ 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440,
+ 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE,
+ 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A,
+ 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E,
+ 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677,
+ 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193,
+ 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032,
+ 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88,
+ 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239,
+ 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E,
+ 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0,
+ 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3,
+ 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98,
+ 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88,
+ 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE,
+ 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6,
+ 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D,
+ 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B,
+ 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7,
+ 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA,
+ 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463,
+ 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F,
+ 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09,
+ 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3,
+ 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB,
+ 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279,
+ 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8,
+ 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB,
+ 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82,
+ 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB,
+ 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573,
+ 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0,
+ 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B,
+ 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790,
+ 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8,
+ 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4,
+ 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0,
+ 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7,
+ 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C,
+ 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD,
+ 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1,
+ 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299,
+ 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9,
+ 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477,
+ 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF,
+ 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49,
+ 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF,
+ 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA,
+ 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5,
+ 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41,
+ 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915,
+ 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400,
+ 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915,
+ 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664,
+ 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A
+ },
+ KS1 =
+ {
+ 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623,
+ 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266,
+ 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1,
+ 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E,
+ 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6,
+ 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1,
+ 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E,
+ 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1,
+ 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737,
+ 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8,
+ 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF,
+ 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD,
+ 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701,
+ 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7,
+ 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41,
+ 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331,
+ 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF,
+ 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF,
+ 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E,
+ 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87,
+ 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C,
+ 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2,
+ 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16,
+ 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD,
+ 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B,
+ 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509,
+ 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E,
+ 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3,
+ 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F,
+ 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A,
+ 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4,
+ 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960,
+ 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66,
+ 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28,
+ 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802,
+ 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84,
+ 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510,
+ 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF,
+ 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14,
+ 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E,
+ 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50,
+ 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7,
+ 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8,
+ 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281,
+ 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99,
+ 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696,
+ 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128,
+ 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73,
+ 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0,
+ 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0,
+ 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105,
+ 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250,
+ 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3,
+ 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285,
+ 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00,
+ 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061,
+ 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB,
+ 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E,
+ 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735,
+ 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC,
+ 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9,
+ 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340,
+ 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20,
+ 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7
+ },
+ KS2 =
+ {
+ 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934,
+ 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068,
+ 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF,
+ 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840,
+ 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45,
+ 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504,
+ 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A,
+ 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB,
+ 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE,
+ 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6,
+ 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42,
+ 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B,
+ 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2,
+ 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB,
+ 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527,
+ 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B,
+ 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33,
+ 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C,
+ 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3,
+ 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC,
+ 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17,
+ 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564,
+ 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B,
+ 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115,
+ 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922,
+ 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728,
+ 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0,
+ 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E,
+ 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37,
+ 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D,
+ 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804,
+ 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B,
+ 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3,
+ 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB,
+ 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D,
+ 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C,
+ 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350,
+ 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9,
+ 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A,
+ 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE,
+ 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D,
+ 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC,
+ 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F,
+ 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61,
+ 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2,
+ 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9,
+ 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2,
+ 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C,
+ 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E,
+ 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633,
+ 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10,
+ 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169,
+ 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52,
+ 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027,
+ 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5,
+ 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62,
+ 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634,
+ 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76,
+ 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24,
+ 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC,
+ 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4,
+ 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C,
+ 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837,
+ 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0
+ },
+ KS3 =
+ {
+ 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B,
+ 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE,
+ 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B,
+ 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4,
+ 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8,
+ 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6,
+ 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304,
+ 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22,
+ 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4,
+ 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6,
+ 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9,
+ 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59,
+ 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593,
+ 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51,
+ 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28,
+ 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C,
+ 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B,
+ 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28,
+ 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C,
+ 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD,
+ 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A,
+ 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319,
+ 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB,
+ 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F,
+ 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991,
+ 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32,
+ 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680,
+ 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166,
+ 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE,
+ 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB,
+ 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5,
+ 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47,
+ 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370,
+ 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D,
+ 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84,
+ 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048,
+ 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8,
+ 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD,
+ 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9,
+ 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7,
+ 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38,
+ 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F,
+ 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C,
+ 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525,
+ 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1,
+ 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442,
+ 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964,
+ 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E,
+ 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8,
+ 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D,
+ 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F,
+ 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299,
+ 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02,
+ 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC,
+ 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614,
+ 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A,
+ 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6,
+ 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B,
+ 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0,
+ 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060,
+ 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E,
+ 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9,
+ 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F,
+ 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6
+ };
+
+ //====================================
+ // Useful constants
+ //====================================
+
+ private static readonly int ROUNDS = 16;
+ private const int BLOCK_SIZE = 8; // bytes = 64 bits
+ private static readonly int SBOX_SK = 256;
+ private static readonly int P_SZ = ROUNDS+2;
+
+ private readonly uint[] S0, S1, S2, S3; // the s-boxes
+ private readonly uint[] P; // the p-array
+
+ private bool encrypting;
+
+ private byte[] workingKey;
+
+ public BlowfishEngine()
+ {
+ S0 = new uint[SBOX_SK];
+ S1 = new uint[SBOX_SK];
+ S2 = new uint[SBOX_SK];
+ S3 = new uint[SBOX_SK];
+ P = new uint[P_SZ];
+ }
+
+ /**
+ * initialise a Blowfish 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 (!(parameters is KeyParameter))
+ throw new ArgumentException("invalid parameter passed to Blowfish init - " + Platform.GetTypeName(parameters));
+
+ this.encrypting = forEncryption;
+ this.workingKey = ((KeyParameter)parameters).GetKey();
+ SetKey(this.workingKey);
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Blowfish"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (workingKey == null)
+ throw new InvalidOperationException("Blowfish not initialised");
+
+ Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+ if (encrypting)
+ {
+ EncryptBlock(input, inOff, output, outOff);
+ }
+ else
+ {
+ DecryptBlock(input, inOff, output, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ public void Reset()
+ {
+ }
+
+ public int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ //==================================
+ // Private Implementation
+ //==================================
+
+ private uint F(uint x)
+ {
+ return (((S0[x >> 24] + S1[(x >> 16) & 0xff]) ^ S2[(x >> 8) & 0xff]) + S3[x & 0xff]);
+ }
+
+ /**
+ * apply the encryption cycle to each value pair in the table.
+ */
+ private void ProcessTable(
+ uint xl,
+ uint xr,
+ uint[] table)
+ {
+ int size = table.Length;
+
+ for (int s = 0; s < size; s += 2)
+ {
+ 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];
+
+ table[s] = xr;
+ table[s + 1] = xl;
+
+ xr = xl; // end of cycle swap
+ xl = table[s];
+ }
+ }
+
+ private void SetKey(byte[] key)
+ {
+ /*
+ * - comments are from _Applied Crypto_, Schneier, p338
+ * please be careful comparing the two, AC numbers the
+ * arrays from 1, the enclosed code from 0.
+ *
+ * (1)
+ * Initialise the S-boxes and the P-array, with a fixed string
+ * This string contains the hexadecimal digits of pi (3.141...)
+ */
+ Array.Copy(KS0, 0, S0, 0, SBOX_SK);
+ Array.Copy(KS1, 0, S1, 0, SBOX_SK);
+ Array.Copy(KS2, 0, S2, 0, SBOX_SK);
+ Array.Copy(KS3, 0, S3, 0, SBOX_SK);
+
+ Array.Copy(KP, 0, P, 0, P_SZ);
+
+ /*
+ * (2)
+ * Now, XOR P[0] with the first 32 bits of the key, XOR P[1] with the
+ * second 32-bits of the key, and so on for all bits of the key
+ * (up to P[17]). Repeatedly cycle through the key bits until the
+ * entire P-array has been XOR-ed with the key bits
+ */
+ int keyLength = key.Length;
+ int keyIndex = 0;
+
+ for (int i=0; i < P_SZ; i++)
+ {
+ // Get the 32 bits of the key, in 4 * 8 bit chunks
+ uint data = 0x0000000;
+ for (int j=0; j < 4; j++)
+ {
+ // create a 32 bit block
+ data = (data << 8) | (uint)key[keyIndex++];
+
+ // wrap when we get to the end of the key
+ if (keyIndex >= keyLength)
+ {
+ keyIndex = 0;
+ }
+ }
+ // XOR the newly created 32 bit chunk onto the P-array
+ P[i] ^= data;
+ }
+
+ /*
+ * (3)
+ * Encrypt the all-zero string with the Blowfish algorithm, using
+ * the subkeys described in (1) and (2)
+ *
+ * (4)
+ * Replace P1 and P2 with the output of step (3)
+ *
+ * (5)
+ * Encrypt the output of step(3) using the Blowfish algorithm,
+ * with the modified subkeys.
+ *
+ * (6)
+ * Replace P3 and P4 with the output of step (5)
+ *
+ * (7)
+ * Continue the process, replacing all elements of the P-array
+ * and then all four S-boxes in order, with the output of the
+ * continuously changing Blowfish algorithm
+ */
+
+ ProcessTable(0, 0, P);
+ ProcessTable(P[P_SZ - 2], P[P_SZ - 1], S0);
+ ProcessTable(S0[SBOX_SK - 2], S0[SBOX_SK - 1], S1);
+ ProcessTable(S1[SBOX_SK - 2], S1[SBOX_SK - 1], S2);
+ 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)
+ {
+ uint xl = Pack.BE_To_UInt32(src, srcIndex);
+ uint xr = Pack.BE_To_UInt32(src, srcIndex+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, dst, dstIndex);
+ 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)
+ {
+ uint xl = Pack.BE_To_UInt32(src, srcIndex);
+ uint xr = Pack.BE_To_UInt32(src, srcIndex + 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, dst, dstIndex);
+ Pack.UInt32_To_BE(xl, dst, dstIndex + 4);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/CamelliaEngine.cs b/bc-sharp-crypto/src/crypto/engines/CamelliaEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..71bd1b0dcc2c4089d9b88f2e7ffa04f257403e34
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/CamelliaEngine.cs
@@ -0,0 +1,668 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * Camellia - based on RFC 3713.
+ */
+ public class CamelliaEngine
+ : IBlockCipher
+ {
+ private bool initialised = false;
+ private bool _keyIs128;
+
+ private const int BLOCK_SIZE = 16;
+
+ private uint[] subkey = new uint[24 * 4];
+ private uint[] kw = new uint[4 * 2]; // for whitening
+ private uint[] ke = new uint[6 * 2]; // for FL and FL^(-1)
+ private uint[] state = new uint[4]; // for encryption and decryption
+
+ private static readonly uint[] SIGMA = new uint[]{
+ 0xa09e667f, 0x3bcc908b,
+ 0xb67ae858, 0x4caa73b2,
+ 0xc6ef372f, 0xe94f82be,
+ 0x54ff53a5, 0xf1d36f1c,
+ 0x10e527fa, 0xde682d1d,
+ 0xb05688c2, 0xb3e6c1fd
+ };
+
+ /*
+ *
+ * S-box data
+ *
+ */
+ private static readonly uint[] SBOX1_1110 = new uint[]{
+ 0x70707000, 0x82828200, 0x2c2c2c00, 0xececec00, 0xb3b3b300, 0x27272700,
+ 0xc0c0c000, 0xe5e5e500, 0xe4e4e400, 0x85858500, 0x57575700, 0x35353500,
+ 0xeaeaea00, 0x0c0c0c00, 0xaeaeae00, 0x41414100, 0x23232300, 0xefefef00,
+ 0x6b6b6b00, 0x93939300, 0x45454500, 0x19191900, 0xa5a5a500, 0x21212100,
+ 0xededed00, 0x0e0e0e00, 0x4f4f4f00, 0x4e4e4e00, 0x1d1d1d00, 0x65656500,
+ 0x92929200, 0xbdbdbd00, 0x86868600, 0xb8b8b800, 0xafafaf00, 0x8f8f8f00,
+ 0x7c7c7c00, 0xebebeb00, 0x1f1f1f00, 0xcecece00, 0x3e3e3e00, 0x30303000,
+ 0xdcdcdc00, 0x5f5f5f00, 0x5e5e5e00, 0xc5c5c500, 0x0b0b0b00, 0x1a1a1a00,
+ 0xa6a6a600, 0xe1e1e100, 0x39393900, 0xcacaca00, 0xd5d5d500, 0x47474700,
+ 0x5d5d5d00, 0x3d3d3d00, 0xd9d9d900, 0x01010100, 0x5a5a5a00, 0xd6d6d600,
+ 0x51515100, 0x56565600, 0x6c6c6c00, 0x4d4d4d00, 0x8b8b8b00, 0x0d0d0d00,
+ 0x9a9a9a00, 0x66666600, 0xfbfbfb00, 0xcccccc00, 0xb0b0b000, 0x2d2d2d00,
+ 0x74747400, 0x12121200, 0x2b2b2b00, 0x20202000, 0xf0f0f000, 0xb1b1b100,
+ 0x84848400, 0x99999900, 0xdfdfdf00, 0x4c4c4c00, 0xcbcbcb00, 0xc2c2c200,
+ 0x34343400, 0x7e7e7e00, 0x76767600, 0x05050500, 0x6d6d6d00, 0xb7b7b700,
+ 0xa9a9a900, 0x31313100, 0xd1d1d100, 0x17171700, 0x04040400, 0xd7d7d700,
+ 0x14141400, 0x58585800, 0x3a3a3a00, 0x61616100, 0xdedede00, 0x1b1b1b00,
+ 0x11111100, 0x1c1c1c00, 0x32323200, 0x0f0f0f00, 0x9c9c9c00, 0x16161600,
+ 0x53535300, 0x18181800, 0xf2f2f200, 0x22222200, 0xfefefe00, 0x44444400,
+ 0xcfcfcf00, 0xb2b2b200, 0xc3c3c300, 0xb5b5b500, 0x7a7a7a00, 0x91919100,
+ 0x24242400, 0x08080800, 0xe8e8e800, 0xa8a8a800, 0x60606000, 0xfcfcfc00,
+ 0x69696900, 0x50505000, 0xaaaaaa00, 0xd0d0d000, 0xa0a0a000, 0x7d7d7d00,
+ 0xa1a1a100, 0x89898900, 0x62626200, 0x97979700, 0x54545400, 0x5b5b5b00,
+ 0x1e1e1e00, 0x95959500, 0xe0e0e000, 0xffffff00, 0x64646400, 0xd2d2d200,
+ 0x10101000, 0xc4c4c400, 0x00000000, 0x48484800, 0xa3a3a300, 0xf7f7f700,
+ 0x75757500, 0xdbdbdb00, 0x8a8a8a00, 0x03030300, 0xe6e6e600, 0xdadada00,
+ 0x09090900, 0x3f3f3f00, 0xdddddd00, 0x94949400, 0x87878700, 0x5c5c5c00,
+ 0x83838300, 0x02020200, 0xcdcdcd00, 0x4a4a4a00, 0x90909000, 0x33333300,
+ 0x73737300, 0x67676700, 0xf6f6f600, 0xf3f3f300, 0x9d9d9d00, 0x7f7f7f00,
+ 0xbfbfbf00, 0xe2e2e200, 0x52525200, 0x9b9b9b00, 0xd8d8d800, 0x26262600,
+ 0xc8c8c800, 0x37373700, 0xc6c6c600, 0x3b3b3b00, 0x81818100, 0x96969600,
+ 0x6f6f6f00, 0x4b4b4b00, 0x13131300, 0xbebebe00, 0x63636300, 0x2e2e2e00,
+ 0xe9e9e900, 0x79797900, 0xa7a7a700, 0x8c8c8c00, 0x9f9f9f00, 0x6e6e6e00,
+ 0xbcbcbc00, 0x8e8e8e00, 0x29292900, 0xf5f5f500, 0xf9f9f900, 0xb6b6b600,
+ 0x2f2f2f00, 0xfdfdfd00, 0xb4b4b400, 0x59595900, 0x78787800, 0x98989800,
+ 0x06060600, 0x6a6a6a00, 0xe7e7e700, 0x46464600, 0x71717100, 0xbababa00,
+ 0xd4d4d400, 0x25252500, 0xababab00, 0x42424200, 0x88888800, 0xa2a2a200,
+ 0x8d8d8d00, 0xfafafa00, 0x72727200, 0x07070700, 0xb9b9b900, 0x55555500,
+ 0xf8f8f800, 0xeeeeee00, 0xacacac00, 0x0a0a0a00, 0x36363600, 0x49494900,
+ 0x2a2a2a00, 0x68686800, 0x3c3c3c00, 0x38383800, 0xf1f1f100, 0xa4a4a400,
+ 0x40404000, 0x28282800, 0xd3d3d300, 0x7b7b7b00, 0xbbbbbb00, 0xc9c9c900,
+ 0x43434300, 0xc1c1c100, 0x15151500, 0xe3e3e300, 0xadadad00, 0xf4f4f400,
+ 0x77777700, 0xc7c7c700, 0x80808000, 0x9e9e9e00
+ };
+
+ private static readonly uint[] SBOX4_4404 = new uint[]{
+ 0x70700070, 0x2c2c002c, 0xb3b300b3, 0xc0c000c0, 0xe4e400e4, 0x57570057,
+ 0xeaea00ea, 0xaeae00ae, 0x23230023, 0x6b6b006b, 0x45450045, 0xa5a500a5,
+ 0xeded00ed, 0x4f4f004f, 0x1d1d001d, 0x92920092, 0x86860086, 0xafaf00af,
+ 0x7c7c007c, 0x1f1f001f, 0x3e3e003e, 0xdcdc00dc, 0x5e5e005e, 0x0b0b000b,
+ 0xa6a600a6, 0x39390039, 0xd5d500d5, 0x5d5d005d, 0xd9d900d9, 0x5a5a005a,
+ 0x51510051, 0x6c6c006c, 0x8b8b008b, 0x9a9a009a, 0xfbfb00fb, 0xb0b000b0,
+ 0x74740074, 0x2b2b002b, 0xf0f000f0, 0x84840084, 0xdfdf00df, 0xcbcb00cb,
+ 0x34340034, 0x76760076, 0x6d6d006d, 0xa9a900a9, 0xd1d100d1, 0x04040004,
+ 0x14140014, 0x3a3a003a, 0xdede00de, 0x11110011, 0x32320032, 0x9c9c009c,
+ 0x53530053, 0xf2f200f2, 0xfefe00fe, 0xcfcf00cf, 0xc3c300c3, 0x7a7a007a,
+ 0x24240024, 0xe8e800e8, 0x60600060, 0x69690069, 0xaaaa00aa, 0xa0a000a0,
+ 0xa1a100a1, 0x62620062, 0x54540054, 0x1e1e001e, 0xe0e000e0, 0x64640064,
+ 0x10100010, 0x00000000, 0xa3a300a3, 0x75750075, 0x8a8a008a, 0xe6e600e6,
+ 0x09090009, 0xdddd00dd, 0x87870087, 0x83830083, 0xcdcd00cd, 0x90900090,
+ 0x73730073, 0xf6f600f6, 0x9d9d009d, 0xbfbf00bf, 0x52520052, 0xd8d800d8,
+ 0xc8c800c8, 0xc6c600c6, 0x81810081, 0x6f6f006f, 0x13130013, 0x63630063,
+ 0xe9e900e9, 0xa7a700a7, 0x9f9f009f, 0xbcbc00bc, 0x29290029, 0xf9f900f9,
+ 0x2f2f002f, 0xb4b400b4, 0x78780078, 0x06060006, 0xe7e700e7, 0x71710071,
+ 0xd4d400d4, 0xabab00ab, 0x88880088, 0x8d8d008d, 0x72720072, 0xb9b900b9,
+ 0xf8f800f8, 0xacac00ac, 0x36360036, 0x2a2a002a, 0x3c3c003c, 0xf1f100f1,
+ 0x40400040, 0xd3d300d3, 0xbbbb00bb, 0x43430043, 0x15150015, 0xadad00ad,
+ 0x77770077, 0x80800080, 0x82820082, 0xecec00ec, 0x27270027, 0xe5e500e5,
+ 0x85850085, 0x35350035, 0x0c0c000c, 0x41410041, 0xefef00ef, 0x93930093,
+ 0x19190019, 0x21210021, 0x0e0e000e, 0x4e4e004e, 0x65650065, 0xbdbd00bd,
+ 0xb8b800b8, 0x8f8f008f, 0xebeb00eb, 0xcece00ce, 0x30300030, 0x5f5f005f,
+ 0xc5c500c5, 0x1a1a001a, 0xe1e100e1, 0xcaca00ca, 0x47470047, 0x3d3d003d,
+ 0x01010001, 0xd6d600d6, 0x56560056, 0x4d4d004d, 0x0d0d000d, 0x66660066,
+ 0xcccc00cc, 0x2d2d002d, 0x12120012, 0x20200020, 0xb1b100b1, 0x99990099,
+ 0x4c4c004c, 0xc2c200c2, 0x7e7e007e, 0x05050005, 0xb7b700b7, 0x31310031,
+ 0x17170017, 0xd7d700d7, 0x58580058, 0x61610061, 0x1b1b001b, 0x1c1c001c,
+ 0x0f0f000f, 0x16160016, 0x18180018, 0x22220022, 0x44440044, 0xb2b200b2,
+ 0xb5b500b5, 0x91910091, 0x08080008, 0xa8a800a8, 0xfcfc00fc, 0x50500050,
+ 0xd0d000d0, 0x7d7d007d, 0x89890089, 0x97970097, 0x5b5b005b, 0x95950095,
+ 0xffff00ff, 0xd2d200d2, 0xc4c400c4, 0x48480048, 0xf7f700f7, 0xdbdb00db,
+ 0x03030003, 0xdada00da, 0x3f3f003f, 0x94940094, 0x5c5c005c, 0x02020002,
+ 0x4a4a004a, 0x33330033, 0x67670067, 0xf3f300f3, 0x7f7f007f, 0xe2e200e2,
+ 0x9b9b009b, 0x26260026, 0x37370037, 0x3b3b003b, 0x96960096, 0x4b4b004b,
+ 0xbebe00be, 0x2e2e002e, 0x79790079, 0x8c8c008c, 0x6e6e006e, 0x8e8e008e,
+ 0xf5f500f5, 0xb6b600b6, 0xfdfd00fd, 0x59590059, 0x98980098, 0x6a6a006a,
+ 0x46460046, 0xbaba00ba, 0x25250025, 0x42420042, 0xa2a200a2, 0xfafa00fa,
+ 0x07070007, 0x55550055, 0xeeee00ee, 0x0a0a000a, 0x49490049, 0x68680068,
+ 0x38380038, 0xa4a400a4, 0x28280028, 0x7b7b007b, 0xc9c900c9, 0xc1c100c1,
+ 0xe3e300e3, 0xf4f400f4, 0xc7c700c7, 0x9e9e009e
+ };
+
+ private static readonly uint[] SBOX2_0222 = new uint[]{
+ 0x00e0e0e0, 0x00050505, 0x00585858, 0x00d9d9d9, 0x00676767, 0x004e4e4e,
+ 0x00818181, 0x00cbcbcb, 0x00c9c9c9, 0x000b0b0b, 0x00aeaeae, 0x006a6a6a,
+ 0x00d5d5d5, 0x00181818, 0x005d5d5d, 0x00828282, 0x00464646, 0x00dfdfdf,
+ 0x00d6d6d6, 0x00272727, 0x008a8a8a, 0x00323232, 0x004b4b4b, 0x00424242,
+ 0x00dbdbdb, 0x001c1c1c, 0x009e9e9e, 0x009c9c9c, 0x003a3a3a, 0x00cacaca,
+ 0x00252525, 0x007b7b7b, 0x000d0d0d, 0x00717171, 0x005f5f5f, 0x001f1f1f,
+ 0x00f8f8f8, 0x00d7d7d7, 0x003e3e3e, 0x009d9d9d, 0x007c7c7c, 0x00606060,
+ 0x00b9b9b9, 0x00bebebe, 0x00bcbcbc, 0x008b8b8b, 0x00161616, 0x00343434,
+ 0x004d4d4d, 0x00c3c3c3, 0x00727272, 0x00959595, 0x00ababab, 0x008e8e8e,
+ 0x00bababa, 0x007a7a7a, 0x00b3b3b3, 0x00020202, 0x00b4b4b4, 0x00adadad,
+ 0x00a2a2a2, 0x00acacac, 0x00d8d8d8, 0x009a9a9a, 0x00171717, 0x001a1a1a,
+ 0x00353535, 0x00cccccc, 0x00f7f7f7, 0x00999999, 0x00616161, 0x005a5a5a,
+ 0x00e8e8e8, 0x00242424, 0x00565656, 0x00404040, 0x00e1e1e1, 0x00636363,
+ 0x00090909, 0x00333333, 0x00bfbfbf, 0x00989898, 0x00979797, 0x00858585,
+ 0x00686868, 0x00fcfcfc, 0x00ececec, 0x000a0a0a, 0x00dadada, 0x006f6f6f,
+ 0x00535353, 0x00626262, 0x00a3a3a3, 0x002e2e2e, 0x00080808, 0x00afafaf,
+ 0x00282828, 0x00b0b0b0, 0x00747474, 0x00c2c2c2, 0x00bdbdbd, 0x00363636,
+ 0x00222222, 0x00383838, 0x00646464, 0x001e1e1e, 0x00393939, 0x002c2c2c,
+ 0x00a6a6a6, 0x00303030, 0x00e5e5e5, 0x00444444, 0x00fdfdfd, 0x00888888,
+ 0x009f9f9f, 0x00656565, 0x00878787, 0x006b6b6b, 0x00f4f4f4, 0x00232323,
+ 0x00484848, 0x00101010, 0x00d1d1d1, 0x00515151, 0x00c0c0c0, 0x00f9f9f9,
+ 0x00d2d2d2, 0x00a0a0a0, 0x00555555, 0x00a1a1a1, 0x00414141, 0x00fafafa,
+ 0x00434343, 0x00131313, 0x00c4c4c4, 0x002f2f2f, 0x00a8a8a8, 0x00b6b6b6,
+ 0x003c3c3c, 0x002b2b2b, 0x00c1c1c1, 0x00ffffff, 0x00c8c8c8, 0x00a5a5a5,
+ 0x00202020, 0x00898989, 0x00000000, 0x00909090, 0x00474747, 0x00efefef,
+ 0x00eaeaea, 0x00b7b7b7, 0x00151515, 0x00060606, 0x00cdcdcd, 0x00b5b5b5,
+ 0x00121212, 0x007e7e7e, 0x00bbbbbb, 0x00292929, 0x000f0f0f, 0x00b8b8b8,
+ 0x00070707, 0x00040404, 0x009b9b9b, 0x00949494, 0x00212121, 0x00666666,
+ 0x00e6e6e6, 0x00cecece, 0x00ededed, 0x00e7e7e7, 0x003b3b3b, 0x00fefefe,
+ 0x007f7f7f, 0x00c5c5c5, 0x00a4a4a4, 0x00373737, 0x00b1b1b1, 0x004c4c4c,
+ 0x00919191, 0x006e6e6e, 0x008d8d8d, 0x00767676, 0x00030303, 0x002d2d2d,
+ 0x00dedede, 0x00969696, 0x00262626, 0x007d7d7d, 0x00c6c6c6, 0x005c5c5c,
+ 0x00d3d3d3, 0x00f2f2f2, 0x004f4f4f, 0x00191919, 0x003f3f3f, 0x00dcdcdc,
+ 0x00797979, 0x001d1d1d, 0x00525252, 0x00ebebeb, 0x00f3f3f3, 0x006d6d6d,
+ 0x005e5e5e, 0x00fbfbfb, 0x00696969, 0x00b2b2b2, 0x00f0f0f0, 0x00313131,
+ 0x000c0c0c, 0x00d4d4d4, 0x00cfcfcf, 0x008c8c8c, 0x00e2e2e2, 0x00757575,
+ 0x00a9a9a9, 0x004a4a4a, 0x00575757, 0x00848484, 0x00111111, 0x00454545,
+ 0x001b1b1b, 0x00f5f5f5, 0x00e4e4e4, 0x000e0e0e, 0x00737373, 0x00aaaaaa,
+ 0x00f1f1f1, 0x00dddddd, 0x00595959, 0x00141414, 0x006c6c6c, 0x00929292,
+ 0x00545454, 0x00d0d0d0, 0x00787878, 0x00707070, 0x00e3e3e3, 0x00494949,
+ 0x00808080, 0x00505050, 0x00a7a7a7, 0x00f6f6f6, 0x00777777, 0x00939393,
+ 0x00868686, 0x00838383, 0x002a2a2a, 0x00c7c7c7, 0x005b5b5b, 0x00e9e9e9,
+ 0x00eeeeee, 0x008f8f8f, 0x00010101, 0x003d3d3d
+ };
+
+ private static readonly uint[] SBOX3_3033 = new uint[]{
+ 0x38003838, 0x41004141, 0x16001616, 0x76007676, 0xd900d9d9, 0x93009393,
+ 0x60006060, 0xf200f2f2, 0x72007272, 0xc200c2c2, 0xab00abab, 0x9a009a9a,
+ 0x75007575, 0x06000606, 0x57005757, 0xa000a0a0, 0x91009191, 0xf700f7f7,
+ 0xb500b5b5, 0xc900c9c9, 0xa200a2a2, 0x8c008c8c, 0xd200d2d2, 0x90009090,
+ 0xf600f6f6, 0x07000707, 0xa700a7a7, 0x27002727, 0x8e008e8e, 0xb200b2b2,
+ 0x49004949, 0xde00dede, 0x43004343, 0x5c005c5c, 0xd700d7d7, 0xc700c7c7,
+ 0x3e003e3e, 0xf500f5f5, 0x8f008f8f, 0x67006767, 0x1f001f1f, 0x18001818,
+ 0x6e006e6e, 0xaf00afaf, 0x2f002f2f, 0xe200e2e2, 0x85008585, 0x0d000d0d,
+ 0x53005353, 0xf000f0f0, 0x9c009c9c, 0x65006565, 0xea00eaea, 0xa300a3a3,
+ 0xae00aeae, 0x9e009e9e, 0xec00ecec, 0x80008080, 0x2d002d2d, 0x6b006b6b,
+ 0xa800a8a8, 0x2b002b2b, 0x36003636, 0xa600a6a6, 0xc500c5c5, 0x86008686,
+ 0x4d004d4d, 0x33003333, 0xfd00fdfd, 0x66006666, 0x58005858, 0x96009696,
+ 0x3a003a3a, 0x09000909, 0x95009595, 0x10001010, 0x78007878, 0xd800d8d8,
+ 0x42004242, 0xcc00cccc, 0xef00efef, 0x26002626, 0xe500e5e5, 0x61006161,
+ 0x1a001a1a, 0x3f003f3f, 0x3b003b3b, 0x82008282, 0xb600b6b6, 0xdb00dbdb,
+ 0xd400d4d4, 0x98009898, 0xe800e8e8, 0x8b008b8b, 0x02000202, 0xeb00ebeb,
+ 0x0a000a0a, 0x2c002c2c, 0x1d001d1d, 0xb000b0b0, 0x6f006f6f, 0x8d008d8d,
+ 0x88008888, 0x0e000e0e, 0x19001919, 0x87008787, 0x4e004e4e, 0x0b000b0b,
+ 0xa900a9a9, 0x0c000c0c, 0x79007979, 0x11001111, 0x7f007f7f, 0x22002222,
+ 0xe700e7e7, 0x59005959, 0xe100e1e1, 0xda00dada, 0x3d003d3d, 0xc800c8c8,
+ 0x12001212, 0x04000404, 0x74007474, 0x54005454, 0x30003030, 0x7e007e7e,
+ 0xb400b4b4, 0x28002828, 0x55005555, 0x68006868, 0x50005050, 0xbe00bebe,
+ 0xd000d0d0, 0xc400c4c4, 0x31003131, 0xcb00cbcb, 0x2a002a2a, 0xad00adad,
+ 0x0f000f0f, 0xca00caca, 0x70007070, 0xff00ffff, 0x32003232, 0x69006969,
+ 0x08000808, 0x62006262, 0x00000000, 0x24002424, 0xd100d1d1, 0xfb00fbfb,
+ 0xba00baba, 0xed00eded, 0x45004545, 0x81008181, 0x73007373, 0x6d006d6d,
+ 0x84008484, 0x9f009f9f, 0xee00eeee, 0x4a004a4a, 0xc300c3c3, 0x2e002e2e,
+ 0xc100c1c1, 0x01000101, 0xe600e6e6, 0x25002525, 0x48004848, 0x99009999,
+ 0xb900b9b9, 0xb300b3b3, 0x7b007b7b, 0xf900f9f9, 0xce00cece, 0xbf00bfbf,
+ 0xdf00dfdf, 0x71007171, 0x29002929, 0xcd00cdcd, 0x6c006c6c, 0x13001313,
+ 0x64006464, 0x9b009b9b, 0x63006363, 0x9d009d9d, 0xc000c0c0, 0x4b004b4b,
+ 0xb700b7b7, 0xa500a5a5, 0x89008989, 0x5f005f5f, 0xb100b1b1, 0x17001717,
+ 0xf400f4f4, 0xbc00bcbc, 0xd300d3d3, 0x46004646, 0xcf00cfcf, 0x37003737,
+ 0x5e005e5e, 0x47004747, 0x94009494, 0xfa00fafa, 0xfc00fcfc, 0x5b005b5b,
+ 0x97009797, 0xfe00fefe, 0x5a005a5a, 0xac00acac, 0x3c003c3c, 0x4c004c4c,
+ 0x03000303, 0x35003535, 0xf300f3f3, 0x23002323, 0xb800b8b8, 0x5d005d5d,
+ 0x6a006a6a, 0x92009292, 0xd500d5d5, 0x21002121, 0x44004444, 0x51005151,
+ 0xc600c6c6, 0x7d007d7d, 0x39003939, 0x83008383, 0xdc00dcdc, 0xaa00aaaa,
+ 0x7c007c7c, 0x77007777, 0x56005656, 0x05000505, 0x1b001b1b, 0xa400a4a4,
+ 0x15001515, 0x34003434, 0x1e001e1e, 0x1c001c1c, 0xf800f8f8, 0x52005252,
+ 0x20002020, 0x14001414, 0xe900e9e9, 0xbd00bdbd, 0xdd00dddd, 0xe400e4e4,
+ 0xa100a1a1, 0xe000e0e0, 0x8a008a8a, 0xf100f1f1, 0xd600d6d6, 0x7a007a7a,
+ 0xbb00bbbb, 0xe300e3e3, 0x40004040, 0x4f004f4f
+ };
+
+ private static uint rightRotate(uint x, int s)
+ {
+ return ((x >> s) + (x << (32 - s)));
+ }
+
+ private static uint leftRotate(uint x, int s)
+ {
+ return (x << s) + (x >> (32 - s));
+ }
+
+ private static void roldq(int rot, uint[] ki, int ioff, uint[] ko, int ooff)
+ {
+ ko[0 + ooff] = (ki[0 + ioff] << rot) | (ki[1 + ioff] >> (32 - rot));
+ ko[1 + ooff] = (ki[1 + ioff] << rot) | (ki[2 + ioff] >> (32 - rot));
+ ko[2 + ooff] = (ki[2 + ioff] << rot) | (ki[3 + ioff] >> (32 - rot));
+ ko[3 + ooff] = (ki[3 + ioff] << rot) | (ki[0 + ioff] >> (32 - rot));
+ ki[0 + ioff] = ko[0 + ooff];
+ ki[1 + ioff] = ko[1 + ooff];
+ ki[2 + ioff] = ko[2 + ooff];
+ ki[3 + ioff] = ko[3 + ooff];
+ }
+
+ private static void decroldq(int rot, uint[] ki, int ioff, uint[] ko, int ooff)
+ {
+ ko[2 + ooff] = (ki[0 + ioff] << rot) | (ki[1 + ioff] >> (32 - rot));
+ ko[3 + ooff] = (ki[1 + ioff] << rot) | (ki[2 + ioff] >> (32 - rot));
+ ko[0 + ooff] = (ki[2 + ioff] << rot) | (ki[3 + ioff] >> (32 - rot));
+ ko[1 + ooff] = (ki[3 + ioff] << rot) | (ki[0 + ioff] >> (32 - rot));
+ ki[0 + ioff] = ko[2 + ooff];
+ ki[1 + ioff] = ko[3 + ooff];
+ ki[2 + ioff] = ko[0 + ooff];
+ ki[3 + ioff] = ko[1 + ooff];
+ }
+
+ private static void roldqo32(int rot, uint[] ki, int ioff, uint[] ko, int ooff)
+ {
+ ko[0 + ooff] = (ki[1 + ioff] << (rot - 32)) | (ki[2 + ioff] >> (64 - rot));
+ ko[1 + ooff] = (ki[2 + ioff] << (rot - 32)) | (ki[3 + ioff] >> (64 - rot));
+ ko[2 + ooff] = (ki[3 + ioff] << (rot - 32)) | (ki[0 + ioff] >> (64 - rot));
+ ko[3 + ooff] = (ki[0 + ioff] << (rot - 32)) | (ki[1 + ioff] >> (64 - rot));
+ ki[0 + ioff] = ko[0 + ooff];
+ ki[1 + ioff] = ko[1 + ooff];
+ ki[2 + ioff] = ko[2 + ooff];
+ ki[3 + ioff] = ko[3 + ooff];
+ }
+
+ private static void decroldqo32(int rot, uint[] ki, int ioff, uint[] ko, int ooff)
+ {
+ ko[2 + ooff] = (ki[1 + ioff] << (rot - 32)) | (ki[2 + ioff] >> (64 - rot));
+ ko[3 + ooff] = (ki[2 + ioff] << (rot - 32)) | (ki[3 + ioff] >> (64 - rot));
+ ko[0 + ooff] = (ki[3 + ioff] << (rot - 32)) | (ki[0 + ioff] >> (64 - rot));
+ ko[1 + ooff] = (ki[0 + ioff] << (rot - 32)) | (ki[1 + ioff] >> (64 - rot));
+ ki[0 + ioff] = ko[2 + ooff];
+ ki[1 + ioff] = ko[3 + ooff];
+ ki[2 + ioff] = ko[0 + ooff];
+ 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;
+
+ t1 = s[0] ^ skey[0 + keyoff];
+ u = SBOX4_4404[(byte)t1];
+ u ^= SBOX3_3033[(byte)(t1 >> 8)];
+ u ^= SBOX2_0222[(byte)(t1 >> 16)];
+ u ^= SBOX1_1110[(byte)(t1 >> 24)];
+ t2 = s[1] ^ skey[1 + keyoff];
+ v = SBOX1_1110[(byte)t2];
+ v ^= SBOX4_4404[(byte)(t2 >> 8)];
+ v ^= SBOX3_3033[(byte)(t2 >> 16)];
+ v ^= SBOX2_0222[(byte)(t2 >> 24)];
+
+ s[2] ^= u ^ v;
+ s[3] ^= u ^ v ^ rightRotate(u, 8);
+
+ t1 = s[2] ^ skey[2 + keyoff];
+ u = SBOX4_4404[(byte)t1];
+ u ^= SBOX3_3033[(byte)(t1 >> 8)];
+ u ^= SBOX2_0222[(byte)(t1 >> 16)];
+ u ^= SBOX1_1110[(byte)(t1 >> 24)];
+ t2 = s[3] ^ skey[3 + keyoff];
+ v = SBOX1_1110[(byte)t2];
+ v ^= SBOX4_4404[(byte)(t2 >> 8)];
+ v ^= SBOX3_3033[(byte)(t2 >> 16)];
+ v ^= SBOX2_0222[(byte)(t2 >> 24)];
+
+ s[0] ^= u ^ v;
+ s[1] ^= u ^ v ^ rightRotate(u, 8);
+ }
+
+ private static void camelliaFLs(uint[] s, uint[] fkey, int keyoff)
+ {
+
+ s[1] ^= leftRotate(s[0] & fkey[0 + keyoff], 1);
+ s[0] ^= fkey[1 + keyoff] | s[1];
+
+ s[2] ^= fkey[3 + keyoff] | s[3];
+ s[3] ^= leftRotate(fkey[2 + keyoff] & s[2], 1);
+ }
+
+ private void setKey(bool forEncryption, byte[] key)
+ {
+ uint[] k = new uint[8];
+ uint[] ka = new uint[4];
+ uint[] kb = new uint[4];
+ uint[] t = new uint[4];
+
+ 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.");
+ }
+
+ for (int i = 0; i < 4; i++)
+ {
+ ka[i] = k[i] ^ k[i + 4];
+ }
+ /* compute KA */
+ camelliaF2(ka, SIGMA, 0);
+ for (int i = 0; i < 4; i++)
+ {
+ ka[i] ^= k[i];
+ }
+ camelliaF2(ka, SIGMA, 4);
+
+ if (_keyIs128)
+ {
+ if (forEncryption)
+ {
+ /* KL dependant keys */
+ kw[0] = k[0];
+ kw[1] = k[1];
+ kw[2] = k[2];
+ kw[3] = k[3];
+ roldq(15, k, 0, subkey, 4);
+ roldq(30, k, 0, subkey, 12);
+ roldq(15, k, 0, t, 0);
+ subkey[18] = t[2];
+ subkey[19] = t[3];
+ roldq(17, k, 0, ke, 4);
+ roldq(17, k, 0, subkey, 24);
+ roldq(17, k, 0, subkey, 32);
+ /* KA dependant keys */
+ subkey[0] = ka[0];
+ subkey[1] = ka[1];
+ subkey[2] = ka[2];
+ subkey[3] = ka[3];
+ roldq(15, ka, 0, subkey, 8);
+ roldq(15, ka, 0, ke, 0);
+ roldq(15, ka, 0, t, 0);
+ subkey[16] = t[0];
+ subkey[17] = t[1];
+ roldq(15, ka, 0, subkey, 20);
+ roldqo32(34, ka, 0, subkey, 28);
+ roldq(17, ka, 0, kw, 4);
+
+ }
+ else
+ { // decryption
+ /* KL dependant keys */
+ kw[4] = k[0];
+ kw[5] = k[1];
+ kw[6] = k[2];
+ kw[7] = k[3];
+ decroldq(15, k, 0, subkey, 28);
+ decroldq(30, k, 0, subkey, 20);
+ decroldq(15, k, 0, t, 0);
+ subkey[16] = t[0];
+ subkey[17] = t[1];
+ decroldq(17, k, 0, ke, 0);
+ decroldq(17, k, 0, subkey, 8);
+ decroldq(17, k, 0, subkey, 0);
+ /* KA dependant keys */
+ subkey[34] = ka[0];
+ subkey[35] = ka[1];
+ subkey[32] = ka[2];
+ subkey[33] = ka[3];
+ decroldq(15, ka, 0, subkey, 24);
+ decroldq(15, ka, 0, ke, 4);
+ decroldq(15, ka, 0, t, 0);
+ subkey[18] = t[2];
+ subkey[19] = t[3];
+ decroldq(15, ka, 0, subkey, 12);
+ decroldqo32(34, ka, 0, subkey, 4);
+ roldq(17, ka, 0, kw, 0);
+ }
+ }
+ else
+ { // 192bit or 256bit
+ /* compute KB */
+ for (int i = 0; i < 4; i++)
+ {
+ kb[i] = ka[i] ^ k[i + 4];
+ }
+ camelliaF2(kb, SIGMA, 8);
+
+ if (forEncryption)
+ {
+ /* KL dependant keys */
+ kw[0] = k[0];
+ kw[1] = k[1];
+ kw[2] = k[2];
+ kw[3] = k[3];
+ roldqo32(45, k, 0, subkey, 16);
+ roldq(15, k, 0, ke, 4);
+ roldq(17, k, 0, subkey, 32);
+ roldqo32(34, k, 0, subkey, 44);
+ /* KR dependant keys */
+ roldq(15, k, 4, subkey, 4);
+ roldq(15, k, 4, ke, 0);
+ roldq(30, k, 4, subkey, 24);
+ roldqo32(34, k, 4, subkey, 36);
+ /* KA dependant keys */
+ roldq(15, ka, 0, subkey, 8);
+ roldq(30, ka, 0, subkey, 20);
+ /* 32bit rotation */
+ ke[8] = ka[1];
+ ke[9] = ka[2];
+ ke[10] = ka[3];
+ ke[11] = ka[0];
+ roldqo32(49, ka, 0, subkey, 40);
+
+ /* KB dependant keys */
+ subkey[0] = kb[0];
+ subkey[1] = kb[1];
+ subkey[2] = kb[2];
+ subkey[3] = kb[3];
+ roldq(30, kb, 0, subkey, 12);
+ roldq(30, kb, 0, subkey, 28);
+ roldqo32(51, kb, 0, kw, 4);
+
+ }
+ else
+ { // decryption
+ /* KL dependant keys */
+ kw[4] = k[0];
+ kw[5] = k[1];
+ kw[6] = k[2];
+ kw[7] = k[3];
+ decroldqo32(45, k, 0, subkey, 28);
+ decroldq(15, k, 0, ke, 4);
+ decroldq(17, k, 0, subkey, 12);
+ decroldqo32(34, k, 0, subkey, 0);
+ /* KR dependant keys */
+ decroldq(15, k, 4, subkey, 40);
+ decroldq(15, k, 4, ke, 8);
+ decroldq(30, k, 4, subkey, 20);
+ decroldqo32(34, k, 4, subkey, 8);
+ /* KA dependant keys */
+ decroldq(15, ka, 0, subkey, 36);
+ decroldq(30, ka, 0, subkey, 24);
+ /* 32bit rotation */
+ ke[2] = ka[1];
+ ke[3] = ka[2];
+ ke[0] = ka[3];
+ ke[1] = ka[0];
+ decroldqo32(49, ka, 0, subkey, 4);
+
+ /* KB dependant keys */
+ subkey[46] = kb[0];
+ subkey[47] = kb[1];
+ subkey[44] = kb[2];
+ subkey[45] = kb[3];
+ decroldq(30, kb, 0, subkey, 32);
+ decroldq(30, kb, 0, subkey, 16);
+ roldqo32(51, kb, 0, kw, 0);
+ }
+ }
+ }
+
+ private int processBlock128(byte[] input, int inOff, byte[] output, int outOff)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ state[i] = bytes2uint(input, inOff + (i * 4));
+ state[i] ^= kw[i];
+ }
+
+ 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);
+
+ 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);
+
+ return BLOCK_SIZE;
+ }
+
+ private int processBlock192or256(byte[] input, int inOff, byte[] output, int outOff)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ state[i] = bytes2uint(input, inOff + (i * 4));
+ state[i] ^= kw[i];
+ }
+
+ 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);
+
+ 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);
+ return BLOCK_SIZE;
+ }
+
+ public CamelliaEngine()
+ {
+ }
+
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("only simple KeyParameter expected.");
+
+ setKey(forEncryption, ((KeyParameter)parameters).GetKey());
+
+ initialised = true;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Camellia"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (!initialised)
+ throw new InvalidOperationException("Camellia engine not initialised");
+
+ Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+ if (_keyIs128)
+ {
+ return processBlock128(input, inOff, output, outOff);
+ }
+ else
+ {
+ return processBlock192or256(input, inOff, output, outOff);
+ }
+ }
+
+ public virtual void Reset()
+ {
+ // nothing
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/CamelliaLightEngine.cs b/bc-sharp-crypto/src/crypto/engines/CamelliaLightEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a132227c57bcd8bc5ab22ff3c2ab7747f85fb0c9
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/CamelliaLightEngine.cs
@@ -0,0 +1,580 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * Camellia - based on RFC 3713, smaller implementation, about half the size of CamelliaEngine.
+ */
+ public class CamelliaLightEngine
+ : IBlockCipher
+ {
+ private const int BLOCK_SIZE = 16;
+// private const int MASK8 = 0xff;
+ private bool initialised;
+ private bool _keyis128;
+
+ private uint[] subkey = new uint[24 * 4];
+ private uint[] kw = new uint[4 * 2]; // for whitening
+ private uint[] ke = new uint[6 * 2]; // for FL and FL^(-1)
+ private uint[] state = new uint[4]; // for encryption and decryption
+
+ private static readonly uint[] SIGMA = {
+ 0xa09e667f, 0x3bcc908b,
+ 0xb67ae858, 0x4caa73b2,
+ 0xc6ef372f, 0xe94f82be,
+ 0x54ff53a5, 0xf1d36f1c,
+ 0x10e527fa, 0xde682d1d,
+ 0xb05688c2, 0xb3e6c1fd
+ };
+
+ /*
+ *
+ * S-box data
+ *
+ */
+ private static readonly byte[] SBOX1 = {
+ (byte)112, (byte)130, (byte)44, (byte)236,
+ (byte)179, (byte)39, (byte)192, (byte)229,
+ (byte)228, (byte)133, (byte)87, (byte)53,
+ (byte)234, (byte)12, (byte)174, (byte)65,
+ (byte)35, (byte)239, (byte)107, (byte)147,
+ (byte)69, (byte)25, (byte)165, (byte)33,
+ (byte)237, (byte)14, (byte)79, (byte)78,
+ (byte)29, (byte)101, (byte)146, (byte)189,
+ (byte)134, (byte)184, (byte)175, (byte)143,
+ (byte)124, (byte)235, (byte)31, (byte)206,
+ (byte)62, (byte)48, (byte)220, (byte)95,
+ (byte)94, (byte)197, (byte)11, (byte)26,
+ (byte)166, (byte)225, (byte)57, (byte)202,
+ (byte)213, (byte)71, (byte)93, (byte)61,
+ (byte)217, (byte)1, (byte)90, (byte)214,
+ (byte)81, (byte)86, (byte)108, (byte)77,
+ (byte)139, (byte)13, (byte)154, (byte)102,
+ (byte)251, (byte)204, (byte)176, (byte)45,
+ (byte)116, (byte)18, (byte)43, (byte)32,
+ (byte)240, (byte)177, (byte)132, (byte)153,
+ (byte)223, (byte)76, (byte)203, (byte)194,
+ (byte)52, (byte)126, (byte)118, (byte)5,
+ (byte)109, (byte)183, (byte)169, (byte)49,
+ (byte)209, (byte)23, (byte)4, (byte)215,
+ (byte)20, (byte)88, (byte)58, (byte)97,
+ (byte)222, (byte)27, (byte)17, (byte)28,
+ (byte)50, (byte)15, (byte)156, (byte)22,
+ (byte)83, (byte)24, (byte)242, (byte)34,
+ (byte)254, (byte)68, (byte)207, (byte)178,
+ (byte)195, (byte)181, (byte)122, (byte)145,
+ (byte)36, (byte)8, (byte)232, (byte)168,
+ (byte)96, (byte)252, (byte)105, (byte)80,
+ (byte)170, (byte)208, (byte)160, (byte)125,
+ (byte)161, (byte)137, (byte)98, (byte)151,
+ (byte)84, (byte)91, (byte)30, (byte)149,
+ (byte)224, (byte)255, (byte)100, (byte)210,
+ (byte)16, (byte)196, (byte)0, (byte)72,
+ (byte)163, (byte)247, (byte)117, (byte)219,
+ (byte)138, (byte)3, (byte)230, (byte)218,
+ (byte)9, (byte)63, (byte)221, (byte)148,
+ (byte)135, (byte)92, (byte)131, (byte)2,
+ (byte)205, (byte)74, (byte)144, (byte)51,
+ (byte)115, (byte)103, (byte)246, (byte)243,
+ (byte)157, (byte)127, (byte)191, (byte)226,
+ (byte)82, (byte)155, (byte)216, (byte)38,
+ (byte)200, (byte)55, (byte)198, (byte)59,
+ (byte)129, (byte)150, (byte)111, (byte)75,
+ (byte)19, (byte)190, (byte)99, (byte)46,
+ (byte)233, (byte)121, (byte)167, (byte)140,
+ (byte)159, (byte)110, (byte)188, (byte)142,
+ (byte)41, (byte)245, (byte)249, (byte)182,
+ (byte)47, (byte)253, (byte)180, (byte)89,
+ (byte)120, (byte)152, (byte)6, (byte)106,
+ (byte)231, (byte)70, (byte)113, (byte)186,
+ (byte)212, (byte)37, (byte)171, (byte)66,
+ (byte)136, (byte)162, (byte)141, (byte)250,
+ (byte)114, (byte)7, (byte)185, (byte)85,
+ (byte)248, (byte)238, (byte)172, (byte)10,
+ (byte)54, (byte)73, (byte)42, (byte)104,
+ (byte)60, (byte)56, (byte)241, (byte)164,
+ (byte)64, (byte)40, (byte)211, (byte)123,
+ (byte)187, (byte)201, (byte)67, (byte)193,
+ (byte)21, (byte)227, (byte)173, (byte)244,
+ (byte)119, (byte)199, (byte)128, (byte)158
+ };
+
+ private static uint rightRotate(uint x, int s)
+ {
+ return ((x >> s) + (x << (32 - s)));
+ }
+
+ private static uint leftRotate(uint x, int s)
+ {
+ return (x << s) + (x >> (32 - s));
+ }
+
+ private static void roldq(int rot, uint[] ki, int ioff, uint[] ko, int ooff)
+ {
+ ko[0 + ooff] = (ki[0 + ioff] << rot) | (ki[1 + ioff] >> (32 - rot));
+ ko[1 + ooff] = (ki[1 + ioff] << rot) | (ki[2 + ioff] >> (32 - rot));
+ ko[2 + ooff] = (ki[2 + ioff] << rot) | (ki[3 + ioff] >> (32 - rot));
+ ko[3 + ooff] = (ki[3 + ioff] << rot) | (ki[0 + ioff] >> (32 - rot));
+ ki[0 + ioff] = ko[0 + ooff];
+ ki[1 + ioff] = ko[1 + ooff];
+ ki[2 + ioff] = ko[2 + ooff];
+ ki[3 + ioff] = ko[3 + ooff];
+ }
+
+ private static void decroldq(int rot, uint[] ki, int ioff, uint[] ko, int ooff)
+ {
+ ko[2 + ooff] = (ki[0 + ioff] << rot) | (ki[1 + ioff] >> (32 - rot));
+ ko[3 + ooff] = (ki[1 + ioff] << rot) | (ki[2 + ioff] >> (32 - rot));
+ ko[0 + ooff] = (ki[2 + ioff] << rot) | (ki[3 + ioff] >> (32 - rot));
+ ko[1 + ooff] = (ki[3 + ioff] << rot) | (ki[0 + ioff] >> (32 - rot));
+ ki[0 + ioff] = ko[2 + ooff];
+ ki[1 + ioff] = ko[3 + ooff];
+ ki[2 + ioff] = ko[0 + ooff];
+ ki[3 + ioff] = ko[1 + ooff];
+ }
+
+ private static void roldqo32(int rot, uint[] ki, int ioff, uint[] ko, int ooff)
+ {
+ ko[0 + ooff] = (ki[1 + ioff] << (rot - 32)) | (ki[2 + ioff] >> (64 - rot));
+ ko[1 + ooff] = (ki[2 + ioff] << (rot - 32)) | (ki[3 + ioff] >> (64 - rot));
+ ko[2 + ooff] = (ki[3 + ioff] << (rot - 32)) | (ki[0 + ioff] >> (64 - rot));
+ ko[3 + ooff] = (ki[0 + ioff] << (rot - 32)) | (ki[1 + ioff] >> (64 - rot));
+ ki[0 + ioff] = ko[0 + ooff];
+ ki[1 + ioff] = ko[1 + ooff];
+ ki[2 + ioff] = ko[2 + ooff];
+ ki[3 + ioff] = ko[3 + ooff];
+ }
+
+ private static void decroldqo32(int rot, uint[] ki, int ioff, uint[] ko, int ooff)
+ {
+ ko[2 + ooff] = (ki[1 + ioff] << (rot - 32)) | (ki[2 + ioff] >> (64 - rot));
+ ko[3 + ooff] = (ki[2 + ioff] << (rot - 32)) | (ki[3 + ioff] >> (64 - rot));
+ ko[0 + ooff] = (ki[3 + ioff] << (rot - 32)) | (ki[0 + ioff] >> (64 - rot));
+ ko[1 + ooff] = (ki[0 + ioff] << (rot - 32)) | (ki[1 + ioff] >> (64 - rot));
+ ki[0 + ioff] = ko[2 + ooff];
+ ki[1 + ioff] = ko[3 + ooff];
+ ki[2 + ioff] = ko[0 + ooff];
+ 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)));
+ }
+
+ private uint sbox2(int x)
+ {
+ return (uint)lRot8(SBOX1[x], 1);
+ }
+
+ private uint sbox3(int x)
+ {
+ return (uint)lRot8(SBOX1[x], 7);
+ }
+
+ private uint sbox4(int x)
+ {
+ return (uint)SBOX1[lRot8((byte)x, 1)];
+ }
+
+ private void camelliaF2(uint[] s, uint[] skey, int keyoff)
+ {
+ uint t1, t2, u, v;
+
+ t1 = s[0] ^ skey[0 + keyoff];
+ u = sbox4((byte)t1);
+ u |= (sbox3((byte)(t1 >> 8)) << 8);
+ u |= (sbox2((byte)(t1 >> 16)) << 16);
+ u |= ((uint)(SBOX1[(byte)(t1 >> 24)]) << 24);
+
+ t2 = s[1] ^ skey[1 + keyoff];
+ v = (uint)SBOX1[(byte)t2];
+ v |= (sbox4((byte)(t2 >> 8)) << 8);
+ v |= (sbox3((byte)(t2 >> 16)) << 16);
+ v |= (sbox2((byte)(t2 >> 24)) << 24);
+
+ v = leftRotate(v, 8);
+ u ^= v;
+ v = leftRotate(v, 8) ^ u;
+ u = rightRotate(u, 8) ^ v;
+ s[2] ^= leftRotate(v, 16) ^ u;
+ s[3] ^= leftRotate(u, 8);
+
+ t1 = s[2] ^ skey[2 + keyoff];
+ u = sbox4((byte)t1);
+ u |= sbox3((byte)(t1 >> 8)) << 8;
+ u |= sbox2((byte)(t1 >> 16)) << 16;
+ u |= ((uint)SBOX1[(byte)(t1 >> 24)]) << 24;
+
+ t2 = s[3] ^ skey[3 + keyoff];
+ v = (uint)SBOX1[(byte)t2];
+ v |= sbox4((byte)(t2 >> 8)) << 8;
+ v |= sbox3((byte)(t2 >> 16)) << 16;
+ v |= sbox2((byte)(t2 >> 24)) << 24;
+
+ v = leftRotate(v, 8);
+ u ^= v;
+ v = leftRotate(v, 8) ^ u;
+ u = rightRotate(u, 8) ^ v;
+ s[0] ^= leftRotate(v, 16) ^ u;
+ s[1] ^= leftRotate(u, 8);
+ }
+
+ private void camelliaFLs(uint[] s, uint[] fkey, int keyoff)
+ {
+ s[1] ^= leftRotate(s[0] & fkey[0 + keyoff], 1);
+ s[0] ^= fkey[1 + keyoff] | s[1];
+
+ s[2] ^= fkey[3 + keyoff] | s[3];
+ s[3] ^= leftRotate(fkey[2 + keyoff] & s[2], 1);
+ }
+
+ private void setKey(bool forEncryption, byte[] key)
+ {
+ uint[] k = new uint[8];
+ uint[] ka = new uint[4];
+ uint[] kb = new uint[4];
+ uint[] t = new uint[4];
+
+ 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.");
+ }
+
+ for (int i = 0; i < 4; i++)
+ {
+ ka[i] = k[i] ^ k[i + 4];
+ }
+ /* compute KA */
+ camelliaF2(ka, SIGMA, 0);
+ for (int i = 0; i < 4; i++)
+ {
+ ka[i] ^= k[i];
+ }
+ camelliaF2(ka, SIGMA, 4);
+
+ if (_keyis128)
+ {
+ if (forEncryption)
+ {
+ /* KL dependant keys */
+ kw[0] = k[0];
+ kw[1] = k[1];
+ kw[2] = k[2];
+ kw[3] = k[3];
+ roldq(15, k, 0, subkey, 4);
+ roldq(30, k, 0, subkey, 12);
+ roldq(15, k, 0, t, 0);
+ subkey[18] = t[2];
+ subkey[19] = t[3];
+ roldq(17, k, 0, ke, 4);
+ roldq(17, k, 0, subkey, 24);
+ roldq(17, k, 0, subkey, 32);
+ /* KA dependant keys */
+ subkey[0] = ka[0];
+ subkey[1] = ka[1];
+ subkey[2] = ka[2];
+ subkey[3] = ka[3];
+ roldq(15, ka, 0, subkey, 8);
+ roldq(15, ka, 0, ke, 0);
+ roldq(15, ka, 0, t, 0);
+ subkey[16] = t[0];
+ subkey[17] = t[1];
+ roldq(15, ka, 0, subkey, 20);
+ roldqo32(34, ka, 0, subkey, 28);
+ roldq(17, ka, 0, kw, 4);
+
+ }
+ else
+ { // decryption
+ /* KL dependant keys */
+ kw[4] = k[0];
+ kw[5] = k[1];
+ kw[6] = k[2];
+ kw[7] = k[3];
+ decroldq(15, k, 0, subkey, 28);
+ decroldq(30, k, 0, subkey, 20);
+ decroldq(15, k, 0, t, 0);
+ subkey[16] = t[0];
+ subkey[17] = t[1];
+ decroldq(17, k, 0, ke, 0);
+ decroldq(17, k, 0, subkey, 8);
+ decroldq(17, k, 0, subkey, 0);
+ /* KA dependant keys */
+ subkey[34] = ka[0];
+ subkey[35] = ka[1];
+ subkey[32] = ka[2];
+ subkey[33] = ka[3];
+ decroldq(15, ka, 0, subkey, 24);
+ decroldq(15, ka, 0, ke, 4);
+ decroldq(15, ka, 0, t, 0);
+ subkey[18] = t[2];
+ subkey[19] = t[3];
+ decroldq(15, ka, 0, subkey, 12);
+ decroldqo32(34, ka, 0, subkey, 4);
+ roldq(17, ka, 0, kw, 0);
+ }
+ }
+ else
+ { // 192bit or 256bit
+ /* compute KB */
+ for (int i = 0; i < 4; i++)
+ {
+ kb[i] = ka[i] ^ k[i + 4];
+ }
+ camelliaF2(kb, SIGMA, 8);
+
+ if (forEncryption)
+ {
+ /* KL dependant keys */
+ kw[0] = k[0];
+ kw[1] = k[1];
+ kw[2] = k[2];
+ kw[3] = k[3];
+ roldqo32(45, k, 0, subkey, 16);
+ roldq(15, k, 0, ke, 4);
+ roldq(17, k, 0, subkey, 32);
+ roldqo32(34, k, 0, subkey, 44);
+ /* KR dependant keys */
+ roldq(15, k, 4, subkey, 4);
+ roldq(15, k, 4, ke, 0);
+ roldq(30, k, 4, subkey, 24);
+ roldqo32(34, k, 4, subkey, 36);
+ /* KA dependant keys */
+ roldq(15, ka, 0, subkey, 8);
+ roldq(30, ka, 0, subkey, 20);
+ /* 32bit rotation */
+ ke[8] = ka[1];
+ ke[9] = ka[2];
+ ke[10] = ka[3];
+ ke[11] = ka[0];
+ roldqo32(49, ka, 0, subkey, 40);
+
+ /* KB dependant keys */
+ subkey[0] = kb[0];
+ subkey[1] = kb[1];
+ subkey[2] = kb[2];
+ subkey[3] = kb[3];
+ roldq(30, kb, 0, subkey, 12);
+ roldq(30, kb, 0, subkey, 28);
+ roldqo32(51, kb, 0, kw, 4);
+
+ }
+ else
+ { // decryption
+ /* KL dependant keys */
+ kw[4] = k[0];
+ kw[5] = k[1];
+ kw[6] = k[2];
+ kw[7] = k[3];
+ decroldqo32(45, k, 0, subkey, 28);
+ decroldq(15, k, 0, ke, 4);
+ decroldq(17, k, 0, subkey, 12);
+ decroldqo32(34, k, 0, subkey, 0);
+ /* KR dependant keys */
+ decroldq(15, k, 4, subkey, 40);
+ decroldq(15, k, 4, ke, 8);
+ decroldq(30, k, 4, subkey, 20);
+ decroldqo32(34, k, 4, subkey, 8);
+ /* KA dependant keys */
+ decroldq(15, ka, 0, subkey, 36);
+ decroldq(30, ka, 0, subkey, 24);
+ /* 32bit rotation */
+ ke[2] = ka[1];
+ ke[3] = ka[2];
+ ke[0] = ka[3];
+ ke[1] = ka[0];
+ decroldqo32(49, ka, 0, subkey, 4);
+
+ /* KB dependant keys */
+ subkey[46] = kb[0];
+ subkey[47] = kb[1];
+ subkey[44] = kb[2];
+ subkey[45] = kb[3];
+ decroldq(30, kb, 0, subkey, 32);
+ decroldq(30, kb, 0, subkey, 16);
+ roldqo32(51, kb, 0, kw, 0);
+ }
+ }
+ }
+
+ private int processBlock128(byte[] input, int inOff, byte[] output, int outOff)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ state[i] = bytes2uint(input, inOff + (i * 4));
+ state[i] ^= kw[i];
+ }
+
+ 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);
+
+ 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);
+
+ return BLOCK_SIZE;
+ }
+
+ private int processBlock192or256(byte[] input, int inOff, byte[] output, int outOff)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ state[i] = bytes2uint(input, inOff + (i * 4));
+ state[i] ^= kw[i];
+ }
+
+ 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);
+
+ 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);
+ return BLOCK_SIZE;
+ }
+
+ public CamelliaLightEngine()
+ {
+ initialised = false;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Camellia"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("only simple KeyParameter expected.");
+
+ setKey(forEncryption, ((KeyParameter)parameters).GetKey());
+
+ initialised = true;
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (!initialised)
+ throw new InvalidOperationException("Camellia engine not initialised");
+
+ Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+ if (_keyis128)
+ {
+ return processBlock128(input, inOff, output, outOff);
+ }
+ else
+ {
+ return processBlock192or256(input, inOff, output, outOff);
+ }
+ }
+
+ public virtual void Reset()
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/CamelliaWrapEngine.cs b/bc-sharp-crypto/src/crypto/engines/CamelliaWrapEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..49dc833e63829e38724ac739655b7cc414d8a932
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/CamelliaWrapEngine.cs
@@ -0,0 +1,16 @@
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ ///
+ /// An implementation of the Camellia key wrapper based on RFC 3657/RFC 3394.
+ ///
+ /// For further details see: http://www.ietf.org/rfc/rfc3657.txt .
+ ///
+ public class CamelliaWrapEngine
+ : Rfc3394WrapEngine
+ {
+ public CamelliaWrapEngine()
+ : base(new CamelliaEngine())
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/Cast5Engine.cs b/bc-sharp-crypto/src/crypto/engines/Cast5Engine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..53836db026489aab41e5bbdb00a57ae12fd9d8dc
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/Cast5Engine.cs
@@ -0,0 +1,802 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * A class that provides CAST key encryption operations,
+ * such as encoding data and generating keys.
+ *
+ * All the algorithms herein are from the Internet RFC's
+ *
+ * RFC2144 - Cast5 (64bit block, 40-128bit key)
+ * RFC2612 - CAST6 (128bit block, 128-256bit key)
+ *
+ * and implement a simplified cryptography interface.
+ */
+ public class Cast5Engine
+ : IBlockCipher
+ {
+ internal static readonly uint[] S1 =
+ {
+ 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
+ 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
+ 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
+ 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
+ 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
+ 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
+ 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
+ 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
+ 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
+ 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
+ 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
+ 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
+ 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
+ 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
+ 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
+ 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
+ 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
+ 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
+ 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
+ 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
+ 0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
+ 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
+ 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
+ 0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
+ 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
+ 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
+ 0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
+ 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
+ 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
+ 0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
+ 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
+ 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf
+ },
+ S2 =
+ {
+ 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
+ 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
+ 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
+ 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
+ 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
+ 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
+ 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
+ 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
+ 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
+ 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
+ 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
+ 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
+ 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
+ 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
+ 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
+ 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
+ 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
+ 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
+ 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
+ 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
+ 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
+ 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
+ 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
+ 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
+ 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
+ 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
+ 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
+ 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
+ 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
+ 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
+ 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
+ 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1
+ },
+ S3 =
+ {
+ 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
+ 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
+ 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
+ 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
+ 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
+ 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
+ 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
+ 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
+ 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
+ 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
+ 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
+ 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
+ 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
+ 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
+ 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
+ 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
+ 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
+ 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
+ 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
+ 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
+ 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
+ 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
+ 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
+ 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
+ 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
+ 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
+ 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
+ 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
+ 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
+ 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
+ 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
+ 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783
+ },
+ S4 =
+ {
+ 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
+ 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
+ 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
+ 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
+ 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
+ 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
+ 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
+ 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
+ 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
+ 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
+ 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
+ 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
+ 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
+ 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
+ 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
+ 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
+ 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
+ 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
+ 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
+ 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
+ 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
+ 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
+ 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
+ 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
+ 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
+ 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
+ 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
+ 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
+ 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
+ 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
+ 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
+ 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2
+ },
+ S5 =
+ {
+ 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
+ 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
+ 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
+ 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
+ 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
+ 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
+ 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
+ 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
+ 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
+ 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
+ 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
+ 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
+ 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
+ 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
+ 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
+ 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
+ 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
+ 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
+ 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
+ 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
+ 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
+ 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
+ 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
+ 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
+ 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
+ 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
+ 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
+ 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
+ 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
+ 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
+ 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
+ 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4
+ },
+ S6 =
+ {
+ 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
+ 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
+ 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
+ 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
+ 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
+ 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
+ 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
+ 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
+ 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
+ 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
+ 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
+ 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
+ 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
+ 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
+ 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
+ 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
+ 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
+ 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
+ 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
+ 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
+ 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
+ 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
+ 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
+ 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
+ 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
+ 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
+ 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
+ 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
+ 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
+ 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
+ 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
+ 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f
+ },
+ S7 =
+ {
+ 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
+ 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
+ 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
+ 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
+ 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
+ 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
+ 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
+ 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
+ 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
+ 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
+ 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
+ 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
+ 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
+ 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
+ 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
+ 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
+ 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
+ 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
+ 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
+ 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
+ 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
+ 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
+ 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
+ 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
+ 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
+ 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
+ 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
+ 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
+ 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
+ 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
+ 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
+ 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3
+ },
+ S8 =
+ {
+ 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
+ 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
+ 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
+ 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
+ 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
+ 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
+ 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
+ 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
+ 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
+ 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
+ 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
+ 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
+ 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
+ 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
+ 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
+ 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
+ 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
+ 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
+ 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
+ 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
+ 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
+ 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
+ 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
+ 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
+ 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
+ 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
+ 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
+ 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
+ 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
+ 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
+ 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
+ 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e
+ };
+
+ //====================================
+ // Useful constants
+ //====================================
+
+ internal static readonly int MAX_ROUNDS = 16;
+ internal static readonly int RED_ROUNDS = 12;
+
+ private const int BLOCK_SIZE = 8; // bytes = 64 bits
+
+ private int[] _Kr = new int[17]; // the rotating round key
+ private uint[] _Km = new uint[17]; // the masking round key
+
+ private bool _encrypting;
+
+ private byte[] _workingKey;
+ private int _rounds = MAX_ROUNDS;
+
+ public Cast5Engine()
+ {
+ }
+
+ /**
+ * initialise a CAST 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 virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("Invalid parameter passed to "+ AlgorithmName +" init - " + Platform.GetTypeName(parameters));
+
+ _encrypting = forEncryption;
+ _workingKey = ((KeyParameter)parameters).GetKey();
+ SetKey(_workingKey);
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "CAST5"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ int blockSize = GetBlockSize();
+ if (_workingKey == null)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ Check.DataLength(input, inOff, blockSize, "input buffer too short");
+ Check.OutputLength(output, outOff, blockSize, "output buffer too short");
+
+ if (_encrypting)
+ {
+ return EncryptBlock(input, inOff, output, outOff);
+ }
+ else
+ {
+ return DecryptBlock(input, inOff, output, outOff);
+ }
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ //==================================
+ // Private Implementation
+ //==================================
+
+ /*
+ * Creates the subkeys using the same nomenclature
+ * as described in RFC2144.
+ *
+ * See section 2.4
+ */
+ internal virtual void SetKey(byte[] key)
+ {
+ /*
+ * Determine the key size here, if required
+ *
+ * if keysize <= 80bits, use 12 rounds instead of 16
+ * if keysize < 128bits, pad with 0
+ *
+ * Typical key sizes => 40, 64, 80, 128
+ */
+
+ if (key.Length < 11)
+ {
+ _rounds = RED_ROUNDS;
+ }
+
+ int [] z = new int[16];
+ int [] x = new int[16];
+
+ uint z03, z47, z8B, zCF;
+ uint x03, x47, x8B, xCF;
+
+ /* copy the key into x */
+ for (int i=0; i< key.Length; i++)
+ {
+ x[i] = (int)(key[i] & 0xff);
+ }
+
+ /*
+ * This will look different because the selection of
+ * bytes from the input key I've already chosen the
+ * correct int.
+ */
+ x03 = IntsTo32bits(x, 0x0);
+ x47 = IntsTo32bits(x, 0x4);
+ x8B = IntsTo32bits(x, 0x8);
+ xCF = IntsTo32bits(x, 0xC);
+
+ z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
+
+ Bits32ToInts(z03, z, 0x0);
+ z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
+ Bits32ToInts(z47, z, 0x4);
+ z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
+ Bits32ToInts(z8B, z, 0x8);
+ zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
+ Bits32ToInts(zCF, z, 0xC);
+ _Km[ 1]= S5[z[0x8]] ^ S6[z[0x9]] ^ S7[z[0x7]] ^ S8[z[0x6]] ^ S5[z[0x2]];
+ _Km[ 2]= S5[z[0xA]] ^ S6[z[0xB]] ^ S7[z[0x5]] ^ S8[z[0x4]] ^ S6[z[0x6]];
+ _Km[ 3]= S5[z[0xC]] ^ S6[z[0xD]] ^ S7[z[0x3]] ^ S8[z[0x2]] ^ S7[z[0x9]];
+ _Km[ 4]= S5[z[0xE]] ^ S6[z[0xF]] ^ S7[z[0x1]] ^ S8[z[0x0]] ^ S8[z[0xC]];
+
+ z03 = IntsTo32bits(z, 0x0);
+ z47 = IntsTo32bits(z, 0x4);
+ z8B = IntsTo32bits(z, 0x8);
+ zCF = IntsTo32bits(z, 0xC);
+ x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
+ Bits32ToInts(x03, x, 0x0);
+ x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
+ Bits32ToInts(x47, x, 0x4);
+ x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
+ Bits32ToInts(x8B, x, 0x8);
+ xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
+ Bits32ToInts(xCF, x, 0xC);
+ _Km[ 5]= S5[x[0x3]] ^ S6[x[0x2]] ^ S7[x[0xC]] ^ S8[x[0xD]] ^ S5[x[0x8]];
+ _Km[ 6]= S5[x[0x1]] ^ S6[x[0x0]] ^ S7[x[0xE]] ^ S8[x[0xF]] ^ S6[x[0xD]];
+ _Km[ 7]= S5[x[0x7]] ^ S6[x[0x6]] ^ S7[x[0x8]] ^ S8[x[0x9]] ^ S7[x[0x3]];
+ _Km[ 8]= S5[x[0x5]] ^ S6[x[0x4]] ^ S7[x[0xA]] ^ S8[x[0xB]] ^ S8[x[0x7]];
+
+ x03 = IntsTo32bits(x, 0x0);
+ x47 = IntsTo32bits(x, 0x4);
+ x8B = IntsTo32bits(x, 0x8);
+ xCF = IntsTo32bits(x, 0xC);
+ z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
+ Bits32ToInts(z03, z, 0x0);
+ z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
+ Bits32ToInts(z47, z, 0x4);
+ z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
+ Bits32ToInts(z8B, z, 0x8);
+ zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
+ Bits32ToInts(zCF, z, 0xC);
+ _Km[ 9]= S5[z[0x3]] ^ S6[z[0x2]] ^ S7[z[0xC]] ^ S8[z[0xD]] ^ S5[z[0x9]];
+ _Km[10]= S5[z[0x1]] ^ S6[z[0x0]] ^ S7[z[0xE]] ^ S8[z[0xF]] ^ S6[z[0xc]];
+ _Km[11]= S5[z[0x7]] ^ S6[z[0x6]] ^ S7[z[0x8]] ^ S8[z[0x9]] ^ S7[z[0x2]];
+ _Km[12]= S5[z[0x5]] ^ S6[z[0x4]] ^ S7[z[0xA]] ^ S8[z[0xB]] ^ S8[z[0x6]];
+
+ z03 = IntsTo32bits(z, 0x0);
+ z47 = IntsTo32bits(z, 0x4);
+ z8B = IntsTo32bits(z, 0x8);
+ zCF = IntsTo32bits(z, 0xC);
+ x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
+ Bits32ToInts(x03, x, 0x0);
+ x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
+ Bits32ToInts(x47, x, 0x4);
+ x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
+ Bits32ToInts(x8B, x, 0x8);
+ xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
+ Bits32ToInts(xCF, x, 0xC);
+ _Km[13]= S5[x[0x8]] ^ S6[x[0x9]] ^ S7[x[0x7]] ^ S8[x[0x6]] ^ S5[x[0x3]];
+ _Km[14]= S5[x[0xA]] ^ S6[x[0xB]] ^ S7[x[0x5]] ^ S8[x[0x4]] ^ S6[x[0x7]];
+ _Km[15]= S5[x[0xC]] ^ S6[x[0xD]] ^ S7[x[0x3]] ^ S8[x[0x2]] ^ S7[x[0x8]];
+ _Km[16]= S5[x[0xE]] ^ S6[x[0xF]] ^ S7[x[0x1]] ^ S8[x[0x0]] ^ S8[x[0xD]];
+
+ x03 = IntsTo32bits(x, 0x0);
+ x47 = IntsTo32bits(x, 0x4);
+ x8B = IntsTo32bits(x, 0x8);
+ xCF = IntsTo32bits(x, 0xC);
+ z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
+ Bits32ToInts(z03, z, 0x0);
+ z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
+ Bits32ToInts(z47, z, 0x4);
+ z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
+ Bits32ToInts(z8B, z, 0x8);
+ zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
+ Bits32ToInts(zCF, z, 0xC);
+ _Kr[ 1]=(int)((S5[z[0x8]]^S6[z[0x9]]^S7[z[0x7]]^S8[z[0x6]] ^ S5[z[0x2]])&0x1f);
+ _Kr[ 2]=(int)((S5[z[0xA]]^S6[z[0xB]]^S7[z[0x5]]^S8[z[0x4]] ^ S6[z[0x6]])&0x1f);
+ _Kr[ 3]=(int)((S5[z[0xC]]^S6[z[0xD]]^S7[z[0x3]]^S8[z[0x2]] ^ S7[z[0x9]])&0x1f);
+ _Kr[ 4]=(int)((S5[z[0xE]]^S6[z[0xF]]^S7[z[0x1]]^S8[z[0x0]] ^ S8[z[0xC]])&0x1f);
+
+ z03 = IntsTo32bits(z, 0x0);
+ z47 = IntsTo32bits(z, 0x4);
+ z8B = IntsTo32bits(z, 0x8);
+ zCF = IntsTo32bits(z, 0xC);
+ x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
+ Bits32ToInts(x03, x, 0x0);
+ x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
+ Bits32ToInts(x47, x, 0x4);
+ x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
+ Bits32ToInts(x8B, x, 0x8);
+ xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
+ Bits32ToInts(xCF, x, 0xC);
+ _Kr[ 5]=(int)((S5[x[0x3]]^S6[x[0x2]]^S7[x[0xC]]^S8[x[0xD]]^S5[x[0x8]])&0x1f);
+ _Kr[ 6]=(int)((S5[x[0x1]]^S6[x[0x0]]^S7[x[0xE]]^S8[x[0xF]]^S6[x[0xD]])&0x1f);
+ _Kr[ 7]=(int)((S5[x[0x7]]^S6[x[0x6]]^S7[x[0x8]]^S8[x[0x9]]^S7[x[0x3]])&0x1f);
+ _Kr[ 8]=(int)((S5[x[0x5]]^S6[x[0x4]]^S7[x[0xA]]^S8[x[0xB]]^S8[x[0x7]])&0x1f);
+
+ x03 = IntsTo32bits(x, 0x0);
+ x47 = IntsTo32bits(x, 0x4);
+ x8B = IntsTo32bits(x, 0x8);
+ xCF = IntsTo32bits(x, 0xC);
+ z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
+ Bits32ToInts(z03, z, 0x0);
+ z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
+ Bits32ToInts(z47, z, 0x4);
+ z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
+ Bits32ToInts(z8B, z, 0x8);
+ zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
+ Bits32ToInts(zCF, z, 0xC);
+ _Kr[ 9]=(int)((S5[z[0x3]]^S6[z[0x2]]^S7[z[0xC]]^S8[z[0xD]]^S5[z[0x9]])&0x1f);
+ _Kr[10]=(int)((S5[z[0x1]]^S6[z[0x0]]^S7[z[0xE]]^S8[z[0xF]]^S6[z[0xc]])&0x1f);
+ _Kr[11]=(int)((S5[z[0x7]]^S6[z[0x6]]^S7[z[0x8]]^S8[z[0x9]]^S7[z[0x2]])&0x1f);
+ _Kr[12]=(int)((S5[z[0x5]]^S6[z[0x4]]^S7[z[0xA]]^S8[z[0xB]]^S8[z[0x6]])&0x1f);
+
+ z03 = IntsTo32bits(z, 0x0);
+ z47 = IntsTo32bits(z, 0x4);
+ z8B = IntsTo32bits(z, 0x8);
+ zCF = IntsTo32bits(z, 0xC);
+ x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
+ Bits32ToInts(x03, x, 0x0);
+ x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
+ Bits32ToInts(x47, x, 0x4);
+ x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
+ Bits32ToInts(x8B, x, 0x8);
+ xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
+ Bits32ToInts(xCF, x, 0xC);
+ _Kr[13]=(int)((S5[x[0x8]]^S6[x[0x9]]^S7[x[0x7]]^S8[x[0x6]]^S5[x[0x3]])&0x1f);
+ _Kr[14]=(int)((S5[x[0xA]]^S6[x[0xB]]^S7[x[0x5]]^S8[x[0x4]]^S6[x[0x7]])&0x1f);
+ _Kr[15]=(int)((S5[x[0xC]]^S6[x[0xD]]^S7[x[0x3]]^S8[x[0x2]]^S7[x[0x8]])&0x1f);
+ _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)
+ {
+ // 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(src, srcIndex);
+ uint R0 = Pack.BE_To_UInt32(src, srcIndex + 4);
+
+ uint[] result = new uint[2];
+ CAST_Encipher(L0, R0, result);
+
+ // now stuff them into the destination block
+ Pack.UInt32_To_BE(result[0], dst, dstIndex);
+ Pack.UInt32_To_BE(result[1], dst, dstIndex + 4);
+
+ 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)
+ {
+ // 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(src, srcIndex);
+ uint R16 = Pack.BE_To_UInt32(src, srcIndex + 4);
+
+ uint[] result = new uint[2];
+ CAST_Decipher(L16, R16, result);
+
+ // now stuff them into the destination block
+ Pack.UInt32_To_BE(result[0], dst, dstIndex);
+ Pack.UInt32_To_BE(result[1], dst, dstIndex + 4);
+
+ return BLOCK_SIZE;
+ }
+
+ /**
+ * The first of the three processing functions for the
+ * encryption and decryption.
+ *
+ * @param D the input to be processed
+ * @param Kmi the mask to be used from Km[n]
+ * @param Kri the rotation value to be used
+ *
+ */
+ internal static uint F1(uint D, uint Kmi, int Kri)
+ {
+ uint I = Kmi + D;
+ I = I << Kri | (I >> (32-Kri));
+ return ((S1[(I>>24)&0xff]^S2[(I>>16)&0xff])-S3[(I>>8)&0xff])+S4[I&0xff];
+ }
+
+ /**
+ * The second of the three processing functions for the
+ * encryption and decryption.
+ *
+ * @param D the input to be processed
+ * @param Kmi the mask to be used from Km[n]
+ * @param Kri the rotation value to be used
+ *
+ */
+ internal static uint F2(uint D, uint Kmi, int Kri)
+ {
+ uint I = Kmi ^ D;
+ I = I << Kri | (I >> (32-Kri));
+ return ((S1[(I>>24)&0xff]-S2[(I>>16)&0xff])+S3[(I>>8)&0xff])^S4[I&0xff];
+ }
+
+ /**
+ * The third of the three processing functions for the
+ * encryption and decryption.
+ *
+ * @param D the input to be processed
+ * @param Kmi the mask to be used from Km[n]
+ * @param Kri the rotation value to be used
+ *
+ */
+ internal static uint F3(uint D, uint Kmi, int Kri)
+ {
+ uint I = Kmi - D;
+ I = I << Kri | (I >> (32-Kri));
+ return ((S1[(I>>24)&0xff]+S2[(I>>16)&0xff])^S3[(I>>8)&0xff])-S4[I&0xff];
+ }
+
+ /**
+ * Does the 16 rounds to encrypt the block.
+ *
+ * @param L0 the LH-32bits of the plaintext block
+ * @param R0 the RH-32bits of the plaintext block
+ */
+ internal void CAST_Encipher(uint L0, uint R0, uint[] result)
+ {
+ uint Lp = L0; // the previous value, equiv to L[i-1]
+ uint Rp = R0; // equivalent to R[i-1]
+
+ /*
+ * numbering consistent with paper to make
+ * checking and validating easier
+ */
+ uint Li = L0, Ri = R0;
+
+ for (int i = 1; i<=_rounds ; i++)
+ {
+ Lp = Li;
+ Rp = Ri;
+
+ 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;
+ }
+ }
+
+ result[0] = Ri;
+ result[1] = Li;
+
+ return;
+ }
+
+ internal void CAST_Decipher(uint L16, uint R16, uint[] result)
+ {
+ uint Lp = L16; // the previous value, equiv to L[i-1]
+ uint Rp = R16; // equivalent to R[i-1]
+
+ /*
+ * numbering consistent with paper to make
+ * checking and validating easier
+ */
+ uint Li = L16, Ri = R16;
+
+ for (int i = _rounds; i > 0; i--)
+ {
+ Lp = Li;
+ Rp = Ri;
+
+ 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;
+ }
+ }
+
+ result[0] = Ri;
+ result[1] = Li;
+
+ return;
+ }
+
+ internal static void Bits32ToInts(uint inData, int[] b, int offset)
+ {
+ b[offset + 3] = (int) (inData & 0xff);
+ b[offset + 2] = (int) ((inData >> 8) & 0xff);
+ b[offset + 1] = (int) ((inData >> 16) & 0xff);
+ b[offset] = (int) ((inData >> 24) & 0xff);
+ }
+
+ internal static uint IntsTo32bits(int[] b, int i)
+ {
+ return (uint)(((b[i] & 0xff) << 24) |
+ ((b[i+1] & 0xff) << 16) |
+ ((b[i+2] & 0xff) << 8) |
+ ((b[i+3] & 0xff)));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/Cast6Engine.cs b/bc-sharp-crypto/src/crypto/engines/Cast6Engine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c5c419b7859a9f7444c5c8025c0487b482f63975
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/Cast6Engine.cs
@@ -0,0 +1,279 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * A class that provides CAST6 key encryption operations,
+ * such as encoding data and generating keys.
+ *
+ * All the algorithms herein are from the Internet RFC
+ *
+ * RFC2612 - CAST6 (128bit block, 128-256bit key)
+ *
+ * and implement a simplified cryptography interface.
+ */
+ public sealed class Cast6Engine
+ : Cast5Engine
+ {
+ //====================================
+ // Useful constants
+ //====================================
+ private const int ROUNDS = 12;
+ private const int BLOCK_SIZE = 16; // bytes = 128 bits
+
+ /*
+ * Put the round and mask keys into an array.
+ * Kr0[i] => _Kr[i*4 + 0]
+ */
+ private int []_Kr = new int[ROUNDS*4]; // the rotating round key(s)
+ private uint []_Km = new uint[ROUNDS*4]; // the masking round key(s)
+
+ /*
+ * Key setup
+ */
+ private int []_Tr = new int[24 * 8];
+ private uint []_Tm = new uint[24 * 8];
+ private uint[] _workingKey = new uint[8];
+
+ public Cast6Engine()
+ {
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "CAST6"; }
+ }
+
+ public override void Reset()
+ {
+ }
+
+ public override int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ //==================================
+ // Private Implementation
+ //==================================
+ /*
+ * Creates the subkeys using the same nomenclature
+ * as described in RFC2612.
+ *
+ * See section 2.4
+ */
+ internal override void SetKey(
+ byte[] key)
+ {
+ uint Cm = 0x5a827999;
+ uint Mm = 0x6ed9eba1;
+ int Cr = 19;
+ int Mr = 17;
+ /*
+ * Determine the key size here, if required
+ *
+ * if keysize < 256 bytes, pad with 0
+ *
+ * Typical key sizes => 128, 160, 192, 224, 256
+ */
+ for (int i=0; i< 24; i++)
+ {
+ for (int j=0; j< 8; j++)
+ {
+ _Tm[i*8 + j] = Cm;
+ Cm += Mm; //mod 2^32;
+ _Tr[i*8 + j] = Cr;
+ Cr = (Cr + Mr) & 0x1f; // mod 32
+ }
+ }
+
+ byte[] tmpKey = new byte[64];
+ key.CopyTo(tmpKey, 0);
+
+ // now create ABCDEFGH
+ for (int i = 0; i < 8; i++)
+ {
+ _workingKey[i] = Pack.BE_To_UInt32(tmpKey, i*4);
+ }
+
+ // Generate the key schedule
+ for (int i = 0; i < 12; i++)
+ {
+ // KAPPA <- W2i(KAPPA)
+ int i2 = i*2 *8;
+ _workingKey[6] ^= F1(_workingKey[7], _Tm[i2], _Tr[i2]);
+ _workingKey[5] ^= F2(_workingKey[6], _Tm[i2+1], _Tr[i2+1]);
+ _workingKey[4] ^= F3(_workingKey[5], _Tm[i2+2], _Tr[i2+2]);
+ _workingKey[3] ^= F1(_workingKey[4], _Tm[i2+3], _Tr[i2+3]);
+ _workingKey[2] ^= F2(_workingKey[3], _Tm[i2+4], _Tr[i2+4]);
+ _workingKey[1] ^= F3(_workingKey[2], _Tm[i2+5], _Tr[i2+5]);
+ _workingKey[0] ^= F1(_workingKey[1], _Tm[i2+6], _Tr[i2+6]);
+ _workingKey[7] ^= F2(_workingKey[0], _Tm[i2+7], _Tr[i2+7]);
+ // KAPPA <- W2i+1(KAPPA)
+ i2 = (i*2 + 1)*8;
+ _workingKey[6] ^= F1(_workingKey[7], _Tm[i2], _Tr[i2]);
+ _workingKey[5] ^= F2(_workingKey[6], _Tm[i2+1], _Tr[i2+1]);
+ _workingKey[4] ^= F3(_workingKey[5], _Tm[i2+2], _Tr[i2+2]);
+ _workingKey[3] ^= F1(_workingKey[4], _Tm[i2+3], _Tr[i2+3]);
+ _workingKey[2] ^= F2(_workingKey[3], _Tm[i2+4], _Tr[i2+4]);
+ _workingKey[1] ^= F3(_workingKey[2], _Tm[i2+5], _Tr[i2+5]);
+ _workingKey[0] ^= F1(_workingKey[1], _Tm[i2+6], _Tr[i2+6]);
+ _workingKey[7] ^= F2(_workingKey[0], _Tm[i2+7], _Tr[i2+7]);
+ // Kr_(i) <- KAPPA
+ _Kr[i*4] = (int)(_workingKey[0] & 0x1f);
+ _Kr[i*4 + 1] = (int)(_workingKey[2] & 0x1f);
+ _Kr[i*4 + 2] = (int)(_workingKey[4] & 0x1f);
+ _Kr[i*4 + 3] = (int)(_workingKey[6] & 0x1f);
+ // Km_(i) <- KAPPA
+ _Km[i*4] = _workingKey[7];
+ _Km[i*4 + 1] = _workingKey[5];
+ _Km[i*4 + 2] = _workingKey[3];
+ _Km[i*4 + 3] = _workingKey[1];
+ }
+ }
+
+ /**
+ * 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)
+ {
+ // process the input block
+ // batch the units up into 4x32 bit chunks and go for it
+ uint A = Pack.BE_To_UInt32(src, srcIndex);
+ uint B = Pack.BE_To_UInt32(src, srcIndex + 4);
+ uint C = Pack.BE_To_UInt32(src, srcIndex + 8);
+ uint D = Pack.BE_To_UInt32(src, srcIndex + 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], dst, dstIndex);
+ Pack.UInt32_To_BE(result[1], dst, dstIndex + 4);
+ Pack.UInt32_To_BE(result[2], dst, dstIndex + 8);
+ Pack.UInt32_To_BE(result[3], dst, dstIndex + 12);
+ 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)
+ {
+ // process the input block
+ // batch the units up into 4x32 bit chunks and go for it
+ uint A = Pack.BE_To_UInt32(src, srcIndex);
+ uint B = Pack.BE_To_UInt32(src, srcIndex + 4);
+ uint C = Pack.BE_To_UInt32(src, srcIndex + 8);
+ uint D = Pack.BE_To_UInt32(src, srcIndex + 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], dst, dstIndex);
+ Pack.UInt32_To_BE(result[1], dst, dstIndex + 4);
+ Pack.UInt32_To_BE(result[2], dst, dstIndex + 8);
+ Pack.UInt32_To_BE(result[3], dst, dstIndex + 12);
+ return BLOCK_SIZE;
+ }
+
+ /**
+ * Does the 12 quad rounds rounds to encrypt the block.
+ *
+ * @param A the 00-31 bits of the plaintext block
+ * @param B the 32-63 bits of the plaintext block
+ * @param C the 64-95 bits of the plaintext block
+ * @param D the 96-127 bits of the plaintext block
+ * @param result the resulting ciphertext
+ */
+ private void CAST_Encipher(
+ uint A,
+ uint B,
+ uint C,
+ uint D,
+ uint[] result)
+ {
+ for (int i = 0; i < 6; i++)
+ {
+ int x = i*4;
+ // BETA <- Qi(BETA)
+ C ^= F1(D, _Km[x], _Kr[x]);
+ B ^= F2(C, _Km[x + 1], _Kr[x + 1]);
+ A ^= F3(B, _Km[x + 2], _Kr[x + 2]);
+ D ^= F1(A, _Km[x + 3], _Kr[x + 3]);
+ }
+ for (int i = 6; i < 12; i++)
+ {
+ int x = i*4;
+ // BETA <- QBARi(BETA)
+ D ^= F1(A, _Km[x + 3], _Kr[x + 3]);
+ A ^= F3(B, _Km[x + 2], _Kr[x + 2]);
+ B ^= F2(C, _Km[x + 1], _Kr[x + 1]);
+ C ^= F1(D, _Km[x], _Kr[x]);
+ }
+ result[0] = A;
+ result[1] = B;
+ result[2] = C;
+ result[3] = D;
+ }
+
+ /**
+ * Does the 12 quad rounds rounds to decrypt the block.
+ *
+ * @param A the 00-31 bits of the ciphertext block
+ * @param B the 32-63 bits of the ciphertext block
+ * @param C the 64-95 bits of the ciphertext block
+ * @param D the 96-127 bits of the ciphertext block
+ * @param result the resulting plaintext
+ */
+ private void CAST_Decipher(
+ uint A,
+ uint B,
+ uint C,
+ uint D,
+ uint[] result)
+ {
+ for (int i = 0; i < 6; i++)
+ {
+ int x = (11-i)*4;
+ // BETA <- Qi(BETA)
+ C ^= F1(D, _Km[x], _Kr[x]);
+ B ^= F2(C, _Km[x + 1], _Kr[x + 1]);
+ A ^= F3(B, _Km[x + 2], _Kr[x + 2]);
+ D ^= F1(A, _Km[x + 3], _Kr[x + 3]);
+ }
+ for (int i=6; i<12; i++)
+ {
+ int x = (11-i)*4;
+ // BETA <- QBARi(BETA)
+ D ^= F1(A, _Km[x + 3], _Kr[x + 3]);
+ A ^= F3(B, _Km[x + 2], _Kr[x + 2]);
+ B ^= F2(C, _Km[x + 1], _Kr[x + 1]);
+ C ^= F1(D, _Km[x], _Kr[x]);
+ }
+ result[0] = A;
+ result[1] = B;
+ result[2] = C;
+ result[3] = D;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/ChaCha7539Engine.cs b/bc-sharp-crypto/src/crypto/engines/ChaCha7539Engine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..af4163a026846644701328843c06adea8b382a62
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/ChaCha7539Engine.cs
@@ -0,0 +1,65 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ ///
+ /// Implementation of Daniel J. Bernstein's ChaCha stream cipher.
+ ///
+ public class ChaCha7539Engine
+ : Salsa20Engine
+ {
+ ///
+ /// Creates a 20 rounds ChaCha engine.
+ ///
+ public ChaCha7539Engine()
+ {
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "ChaCha7539" + rounds; }
+ }
+
+ protected override int NonceSize
+ {
+ get { return 12; }
+ }
+
+ protected override void AdvanceCounter()
+ {
+ if (++engineState[12] == 0)
+ throw new InvalidOperationException("attempt to increase counter past 2^32.");
+ }
+
+ protected override void ResetCounter()
+ {
+ engineState[12] = 0;
+ }
+
+ protected override void SetKey(byte[] keyBytes, byte[] ivBytes)
+ {
+ if (keyBytes != null)
+ {
+ if (keyBytes.Length != 32)
+ throw new ArgumentException(AlgorithmName + " requires 256 bit key");
+
+ PackTauOrSigma(keyBytes.Length, engineState, 0);
+
+ // Key
+ Pack.LE_To_UInt32(keyBytes, 0, engineState, 4, 8);
+ }
+
+ // IV
+ Pack.LE_To_UInt32(ivBytes, 0, engineState, 13, 3);
+ }
+
+ protected override void GenerateKeyStream(byte[] output)
+ {
+ ChaChaEngine.ChachaCore(rounds, engineState, x);
+ Pack.UInt32_To_LE(x, output, 0);
+ }
+ }
+}
+
diff --git a/bc-sharp-crypto/src/crypto/engines/ChaChaEngine.cs b/bc-sharp-crypto/src/crypto/engines/ChaChaEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8720504cd7309ddaca0595e565ac463cd52565b7
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/ChaChaEngine.cs
@@ -0,0 +1,157 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ ///
+ /// Implementation of Daniel J. Bernstein's ChaCha stream cipher.
+ ///
+ public class ChaChaEngine
+ : Salsa20Engine
+ {
+ ///
+ /// Creates a 20 rounds ChaCha engine.
+ ///
+ public ChaChaEngine()
+ {
+ }
+
+ ///
+ /// Creates a ChaCha engine with a specific number of rounds.
+ ///
+ /// the number of rounds (must be an even number).
+ public ChaChaEngine(int rounds)
+ : base(rounds)
+ {
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "ChaCha" + rounds; }
+ }
+
+ protected override void AdvanceCounter()
+ {
+ if (++engineState[12] == 0)
+ {
+ ++engineState[13];
+ }
+ }
+
+ protected override void ResetCounter()
+ {
+ engineState[12] = engineState[13] = 0;
+ }
+
+ protected override void SetKey(byte[] keyBytes, byte[] ivBytes)
+ {
+ if (keyBytes != null)
+ {
+ if ((keyBytes.Length != 16) && (keyBytes.Length != 32))
+ throw new ArgumentException(AlgorithmName + " requires 128 bit or 256 bit key");
+
+ PackTauOrSigma(keyBytes.Length, engineState, 0);
+
+ // Key
+ Pack.LE_To_UInt32(keyBytes, 0, engineState, 4, 4);
+ Pack.LE_To_UInt32(keyBytes, keyBytes.Length - 16, engineState, 8, 4);
+ }
+
+ // IV
+ Pack.LE_To_UInt32(ivBytes, 0, engineState, 14, 2);
+ }
+
+ protected override void GenerateKeyStream(byte[] output)
+ {
+ ChachaCore(rounds, engineState, x);
+ Pack.UInt32_To_LE(x, output, 0);
+ }
+
+ ///
+ /// ChaCha function.
+ ///
+ /// The number of ChaCha rounds to execute
+ /// The input words.
+ /// The ChaCha state to modify.
+ internal static void ChachaCore(int rounds, uint[] input, uint[] x)
+ {
+ if (input.Length != 16)
+ throw new ArgumentException();
+ if (x.Length != 16)
+ throw new ArgumentException();
+ if (rounds % 2 != 0)
+ throw new ArgumentException("Number of rounds must be even");
+
+ uint x00 = input[ 0];
+ uint x01 = input[ 1];
+ uint x02 = input[ 2];
+ uint x03 = input[ 3];
+ uint x04 = input[ 4];
+ uint x05 = input[ 5];
+ uint x06 = input[ 6];
+ uint x07 = input[ 7];
+ uint x08 = input[ 8];
+ uint x09 = input[ 9];
+ uint x10 = input[10];
+ uint x11 = input[11];
+ uint x12 = input[12];
+ uint x13 = input[13];
+ uint x14 = input[14];
+ uint x15 = input[15];
+
+ for (int i = rounds; i > 0; i -= 2)
+ {
+ x00 += x04; x12 = R(x12 ^ x00, 16);
+ x08 += x12; x04 = R(x04 ^ x08, 12);
+ x00 += x04; x12 = R(x12 ^ x00, 8);
+ x08 += x12; x04 = R(x04 ^ x08, 7);
+ x01 += x05; x13 = R(x13 ^ x01, 16);
+ x09 += x13; x05 = R(x05 ^ x09, 12);
+ x01 += x05; x13 = R(x13 ^ x01, 8);
+ x09 += x13; x05 = R(x05 ^ x09, 7);
+ x02 += x06; x14 = R(x14 ^ x02, 16);
+ x10 += x14; x06 = R(x06 ^ x10, 12);
+ x02 += x06; x14 = R(x14 ^ x02, 8);
+ x10 += x14; x06 = R(x06 ^ x10, 7);
+ x03 += x07; x15 = R(x15 ^ x03, 16);
+ x11 += x15; x07 = R(x07 ^ x11, 12);
+ x03 += x07; x15 = R(x15 ^ x03, 8);
+ x11 += x15; x07 = R(x07 ^ x11, 7);
+ x00 += x05; x15 = R(x15 ^ x00, 16);
+ x10 += x15; x05 = R(x05 ^ x10, 12);
+ x00 += x05; x15 = R(x15 ^ x00, 8);
+ x10 += x15; x05 = R(x05 ^ x10, 7);
+ x01 += x06; x12 = R(x12 ^ x01, 16);
+ x11 += x12; x06 = R(x06 ^ x11, 12);
+ x01 += x06; x12 = R(x12 ^ x01, 8);
+ x11 += x12; x06 = R(x06 ^ x11, 7);
+ x02 += x07; x13 = R(x13 ^ x02, 16);
+ x08 += x13; x07 = R(x07 ^ x08, 12);
+ x02 += x07; x13 = R(x13 ^ x02, 8);
+ x08 += x13; x07 = R(x07 ^ x08, 7);
+ x03 += x04; x14 = R(x14 ^ x03, 16);
+ x09 += x14; x04 = R(x04 ^ x09, 12);
+ x03 += x04; x14 = R(x14 ^ x03, 8);
+ x09 += x14; x04 = R(x04 ^ x09, 7);
+ }
+
+ x[ 0] = x00 + input[ 0];
+ x[ 1] = x01 + input[ 1];
+ x[ 2] = x02 + input[ 2];
+ x[ 3] = x03 + input[ 3];
+ x[ 4] = x04 + input[ 4];
+ x[ 5] = x05 + input[ 5];
+ x[ 6] = x06 + input[ 6];
+ x[ 7] = x07 + input[ 7];
+ x[ 8] = x08 + input[ 8];
+ x[ 9] = x09 + input[ 9];
+ x[10] = x10 + input[10];
+ x[11] = x11 + input[11];
+ x[12] = x12 + input[12];
+ x[13] = x13 + input[13];
+ x[14] = x14 + input[14];
+ x[15] = x15 + input[15];
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/DesEdeEngine.cs b/bc-sharp-crypto/src/crypto/engines/DesEdeEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2fac24ac026a0d9e412790664d6b86b7817de84b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/DesEdeEngine.cs
@@ -0,0 +1,100 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /// A class that provides a basic DESede (or Triple DES) engine.
+ public class DesEdeEngine
+ : DesEngine
+ {
+ private int[] workingKey1, workingKey2, workingKey3;
+ private bool forEncryption;
+
+ /**
+ * initialise a DESede 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 override void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("invalid parameter passed to DESede init - " + Platform.GetTypeName(parameters));
+
+ byte[] keyMaster = ((KeyParameter)parameters).GetKey();
+ if (keyMaster.Length != 24 && keyMaster.Length != 16)
+ throw new ArgumentException("key size must be 16 or 24 bytes.");
+
+ this.forEncryption = forEncryption;
+
+ byte[] key1 = new byte[8];
+ Array.Copy(keyMaster, 0, key1, 0, key1.Length);
+ workingKey1 = GenerateWorkingKey(forEncryption, key1);
+
+ byte[] key2 = new byte[8];
+ Array.Copy(keyMaster, 8, key2, 0, key2.Length);
+ workingKey2 = GenerateWorkingKey(!forEncryption, key2);
+
+ if (keyMaster.Length == 24)
+ {
+ byte[] key3 = new byte[8];
+ Array.Copy(keyMaster, 16, key3, 0, key3.Length);
+ workingKey3 = GenerateWorkingKey(forEncryption, key3);
+ }
+ else // 16 byte key
+ {
+ workingKey3 = workingKey1;
+ }
+ }
+
+ public override string AlgorithmName
+ {
+ get { return "DESede"; }
+ }
+
+ public override int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public override int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (workingKey1 == null)
+ throw new InvalidOperationException("DESede engine not initialised");
+
+ 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];
+
+ if (forEncryption)
+ {
+ DesFunc(workingKey1, input, inOff, temp, 0);
+ DesFunc(workingKey2, temp, 0, temp, 0);
+ DesFunc(workingKey3, temp, 0, output, outOff);
+ }
+ else
+ {
+ DesFunc(workingKey3, input, inOff, temp, 0);
+ DesFunc(workingKey2, temp, 0, temp, 0);
+ DesFunc(workingKey1, temp, 0, output, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ public override void Reset()
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/DesEdeWrapEngine.cs b/bc-sharp-crypto/src/crypto/engines/DesEdeWrapEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..43100a9bdb86c473379b05aff84d978d517786da
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/DesEdeWrapEngine.cs
@@ -0,0 +1,322 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * Wrap keys according to
+ *
+ * draft-ietf-smime-key-wrap-01.txt .
+ *
+ * Note:
+ *
+ * this is based on a draft, and as such is subject to change - don't use this class for anything requiring long term storage.
+ * if you are using this to wrap triple-des keys you need to set the
+ * parity bits on the key and, if it's a two-key triple-des key, pad it
+ * yourself.
+ *
+ *
+ */
+ public class DesEdeWrapEngine
+ : IWrapper
+ {
+ /** Field engine */
+ private CbcBlockCipher engine;
+ /** Field param */
+ private KeyParameter param;
+ /** Field paramPlusIV */
+ private ParametersWithIV paramPlusIV;
+ /** Field iv */
+ private byte[] iv;
+ /** Field forWrapping */
+ private bool forWrapping;
+ /** Field IV2 */
+ private static readonly byte[] IV2 = { (byte) 0x4a, (byte) 0xdd, (byte) 0xa2,
+ (byte) 0x2c, (byte) 0x79, (byte) 0xe8,
+ (byte) 0x21, (byte) 0x05 };
+
+ //
+ // checksum digest
+ //
+ private readonly IDigest sha1 = new Sha1Digest();
+ private readonly byte[] digest = new byte[20];
+
+ /**
+ * Method init
+ *
+ * @param forWrapping
+ * @param param
+ */
+ public virtual void Init(
+ bool forWrapping,
+ ICipherParameters parameters)
+ {
+ this.forWrapping = forWrapping;
+ this.engine = new CbcBlockCipher(new DesEdeEngine());
+
+ SecureRandom sr;
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom pr = (ParametersWithRandom) parameters;
+ parameters = pr.Parameters;
+ sr = pr.Random;
+ }
+ else
+ {
+ sr = new SecureRandom();
+ }
+
+ if (parameters is KeyParameter)
+ {
+ this.param = (KeyParameter) parameters;
+ if (this.forWrapping)
+ {
+ // Hm, we have no IV but we want to wrap ?!?
+ // well, then we have to create our own IV.
+ this.iv = new byte[8];
+ sr.NextBytes(iv);
+
+ this.paramPlusIV = new ParametersWithIV(this.param, this.iv);
+ }
+ }
+ else if (parameters is ParametersWithIV)
+ {
+ if (!forWrapping)
+ throw new ArgumentException("You should not supply an IV for unwrapping");
+
+ this.paramPlusIV = (ParametersWithIV) parameters;
+ this.iv = this.paramPlusIV.GetIV();
+ this.param = (KeyParameter) this.paramPlusIV.Parameters;
+
+ if (this.iv.Length != 8)
+ throw new ArgumentException("IV is not 8 octets", "parameters");
+ }
+ }
+
+ /**
+ * Method GetAlgorithmName
+ *
+ * @return
+ */
+ public virtual string AlgorithmName
+ {
+ get { return "DESede"; }
+ }
+
+ /**
+ * Method wrap
+ *
+ * @param in
+ * @param inOff
+ * @param inLen
+ * @return
+ */
+ public virtual byte[] Wrap(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (!forWrapping)
+ {
+ throw new InvalidOperationException("Not initialized for wrapping");
+ }
+
+ byte[] keyToBeWrapped = new byte[length];
+ Array.Copy(input, inOff, keyToBeWrapped, 0, length);
+
+ // Compute the CMS Key Checksum, (section 5.6.1), call this CKS.
+ byte[] CKS = CalculateCmsKeyChecksum(keyToBeWrapped);
+
+ // Let WKCKS = WK || CKS where || is concatenation.
+ byte[] WKCKS = new byte[keyToBeWrapped.Length + CKS.Length];
+ Array.Copy(keyToBeWrapped, 0, WKCKS, 0, keyToBeWrapped.Length);
+ Array.Copy(CKS, 0, WKCKS, keyToBeWrapped.Length, CKS.Length);
+
+ // Encrypt WKCKS in CBC mode using KEK as the key and IV as the
+ // initialization vector. Call the results TEMP1.
+
+ int blockSize = engine.GetBlockSize();
+
+ if (WKCKS.Length % blockSize != 0)
+ throw new InvalidOperationException("Not multiple of block length");
+
+ engine.Init(true, paramPlusIV);
+
+ byte [] TEMP1 = new byte[WKCKS.Length];
+
+ for (int currentBytePos = 0; currentBytePos != WKCKS.Length; currentBytePos += blockSize)
+ {
+ engine.ProcessBlock(WKCKS, currentBytePos, TEMP1, currentBytePos);
+ }
+
+ // Let TEMP2 = IV || TEMP1.
+ byte[] TEMP2 = new byte[this.iv.Length + TEMP1.Length];
+ Array.Copy(this.iv, 0, TEMP2, 0, this.iv.Length);
+ Array.Copy(TEMP1, 0, TEMP2, this.iv.Length, TEMP1.Length);
+
+ // Reverse the order of the octets in TEMP2 and call the result TEMP3.
+ byte[] TEMP3 = reverse(TEMP2);
+
+ // Encrypt TEMP3 in CBC mode using the KEK and an initialization vector
+ // of 0x 4a dd a2 2c 79 e8 21 05. The resulting cipher text is the desired
+ // result. It is 40 octets long if a 168 bit key is being wrapped.
+ ParametersWithIV param2 = new ParametersWithIV(this.param, IV2);
+ this.engine.Init(true, param2);
+
+ for (int currentBytePos = 0; currentBytePos != TEMP3.Length; currentBytePos += blockSize)
+ {
+ engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
+ }
+
+ return TEMP3;
+ }
+
+ /**
+ * Method unwrap
+ *
+ * @param in
+ * @param inOff
+ * @param inLen
+ * @return
+ * @throws InvalidCipherTextException
+ */
+ public virtual byte[] Unwrap(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (forWrapping)
+ {
+ throw new InvalidOperationException("Not set for unwrapping");
+ }
+ if (input == null)
+ {
+ throw new InvalidCipherTextException("Null pointer as ciphertext");
+ }
+
+ int blockSize = engine.GetBlockSize();
+
+ if (length % blockSize != 0)
+ {
+ throw new InvalidCipherTextException("Ciphertext not multiple of " + blockSize);
+ }
+
+ /*
+ // Check if the length of the cipher text is reasonable given the key
+ // type. It must be 40 bytes for a 168 bit key and either 32, 40, or
+ // 48 bytes for a 128, 192, or 256 bit key. If the length is not supported
+ // or inconsistent with the algorithm for which the key is intended,
+ // return error.
+ //
+ // we do not accept 168 bit keys. it has to be 192 bit.
+ int lengthA = (estimatedKeyLengthInBit / 8) + 16;
+ int lengthB = estimatedKeyLengthInBit % 8;
+ if ((lengthA != keyToBeUnwrapped.Length) || (lengthB != 0)) {
+ throw new XMLSecurityException("empty");
+ }
+ */
+
+ // Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK
+ // and an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP3.
+ ParametersWithIV param2 = new ParametersWithIV(this.param, IV2);
+ this.engine.Init(false, param2);
+
+ byte [] TEMP3 = new byte[length];
+
+ for (int currentBytePos = 0; currentBytePos != TEMP3.Length; currentBytePos += blockSize)
+ {
+ engine.ProcessBlock(input, inOff + currentBytePos, TEMP3, currentBytePos);
+ }
+
+ // Reverse the order of the octets in TEMP3 and call the result TEMP2.
+ byte[] TEMP2 = reverse(TEMP3);
+
+ // Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining octets.
+ this.iv = new byte[8];
+ byte[] TEMP1 = new byte[TEMP2.Length - 8];
+ Array.Copy(TEMP2, 0, this.iv, 0, 8);
+ Array.Copy(TEMP2, 8, TEMP1, 0, TEMP2.Length - 8);
+
+ // Decrypt TEMP1 using TRIPLedeS in CBC mode using the KEK and the IV
+ // found in the previous step. Call the result WKCKS.
+ this.paramPlusIV = new ParametersWithIV(this.param, this.iv);
+ this.engine.Init(false, this.paramPlusIV);
+
+ byte[] WKCKS = new byte[TEMP1.Length];
+
+ for (int currentBytePos = 0; currentBytePos != WKCKS.Length; currentBytePos += blockSize)
+ {
+ engine.ProcessBlock(TEMP1, currentBytePos, WKCKS, currentBytePos);
+ }
+
+ // Decompose WKCKS. CKS is the last 8 octets and WK, the wrapped key, are
+ // those octets before the CKS.
+ byte[] result = new byte[WKCKS.Length - 8];
+ byte[] CKStoBeVerified = new byte[8];
+ Array.Copy(WKCKS, 0, result, 0, WKCKS.Length - 8);
+ Array.Copy(WKCKS, WKCKS.Length - 8, CKStoBeVerified, 0, 8);
+
+ // Calculate a CMS Key Checksum, (section 5.6.1), over the WK and compare
+ // with the CKS extracted in the above step. If they are not equal, return error.
+ if (!CheckCmsKeyChecksum(result, CKStoBeVerified)) {
+ throw new InvalidCipherTextException(
+ "Checksum inside ciphertext is corrupted");
+ }
+
+ // WK is the wrapped key, now extracted for use in data decryption.
+ return result;
+ }
+
+ /**
+ * Some key wrap algorithms make use of the Key Checksum defined
+ * in CMS [CMS-Algorithms]. This is used to provide an integrity
+ * check value for the key being wrapped. The algorithm is
+ *
+ * - Compute the 20 octet SHA-1 hash on the key being wrapped.
+ * - Use the first 8 octets of this hash as the checksum value.
+ *
+ * @param key
+ * @return
+ * @throws Exception
+ * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+ */
+ private byte[] CalculateCmsKeyChecksum(
+ byte[] key)
+ {
+ sha1.BlockUpdate(key, 0, key.Length);
+ sha1.DoFinal(digest, 0);
+
+ byte[] result = new byte[8];
+ Array.Copy(digest, 0, result, 0, 8);
+ return result;
+ }
+
+ /**
+ * @param key
+ * @param checksum
+ * @return
+ * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+ */
+ private bool CheckCmsKeyChecksum(
+ byte[] key,
+ byte[] checksum)
+ {
+ return Arrays.ConstantTimeAreEqual(CalculateCmsKeyChecksum(key), checksum);
+ }
+
+ private static byte[] reverse(byte[] bs)
+ {
+ byte[] result = new byte[bs.Length];
+ for (int i = 0; i < bs.Length; i++)
+ {
+ result[i] = bs[bs.Length - (i + 1)];
+ }
+ return result;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/DesEngine.cs b/bc-sharp-crypto/src/crypto/engines/DesEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cfd50681eb2548a6a69e6f1efcf4bb4cbba57264
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/DesEngine.cs
@@ -0,0 +1,475 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /// A class that provides a basic DES engine.
+ public class DesEngine
+ : IBlockCipher
+ {
+ internal const int BLOCK_SIZE = 8;
+
+ private int[] workingKey;
+
+ public virtual int[] GetWorkingKey()
+ {
+ return workingKey;
+ }
+
+ /**
+ * initialise a DES 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 virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("invalid parameter passed to DES init - " + Platform.GetTypeName(parameters));
+
+ workingKey = GenerateWorkingKey(forEncryption, ((KeyParameter)parameters).GetKey());
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "DES"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (workingKey == null)
+ throw new InvalidOperationException("DES engine not initialised");
+
+ 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);
+
+ return BLOCK_SIZE;
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ /**
+ * what follows is mainly taken from "Applied Cryptography", by
+ * Bruce Schneier, however it also bears great resemblance to Richard
+ * Outerbridge's D3DES...
+ */
+
+// private static readonly short[] Df_Key =
+// {
+// 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
+// 0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,
+// 0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67
+// };
+
+ private static readonly short[] bytebit =
+ {
+ 128, 64, 32, 16, 8, 4, 2, 1
+ };
+
+ private static readonly int[] bigbyte =
+ {
+ 0x800000, 0x400000, 0x200000, 0x100000,
+ 0x80000, 0x40000, 0x20000, 0x10000,
+ 0x8000, 0x4000, 0x2000, 0x1000,
+ 0x800, 0x400, 0x200, 0x100,
+ 0x80, 0x40, 0x20, 0x10,
+ 0x8, 0x4, 0x2, 0x1
+ };
+
+ /*
+ * Use the key schedule specified in the Standard (ANSI X3.92-1981).
+ */
+ private static readonly byte[] pc1 =
+ {
+ 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
+ 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
+ 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
+ 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3
+ };
+
+ private static readonly byte[] totrot =
+ {
+ 1, 2, 4, 6, 8, 10, 12, 14,
+ 15, 17, 19, 21, 23, 25, 27, 28
+ };
+
+ private static readonly byte[] pc2 =
+ {
+ 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
+ 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
+ 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
+ 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31
+ };
+
+ private static readonly uint[] SP1 =
+ {
+ 0x01010400, 0x00000000, 0x00010000, 0x01010404,
+ 0x01010004, 0x00010404, 0x00000004, 0x00010000,
+ 0x00000400, 0x01010400, 0x01010404, 0x00000400,
+ 0x01000404, 0x01010004, 0x01000000, 0x00000004,
+ 0x00000404, 0x01000400, 0x01000400, 0x00010400,
+ 0x00010400, 0x01010000, 0x01010000, 0x01000404,
+ 0x00010004, 0x01000004, 0x01000004, 0x00010004,
+ 0x00000000, 0x00000404, 0x00010404, 0x01000000,
+ 0x00010000, 0x01010404, 0x00000004, 0x01010000,
+ 0x01010400, 0x01000000, 0x01000000, 0x00000400,
+ 0x01010004, 0x00010000, 0x00010400, 0x01000004,
+ 0x00000400, 0x00000004, 0x01000404, 0x00010404,
+ 0x01010404, 0x00010004, 0x01010000, 0x01000404,
+ 0x01000004, 0x00000404, 0x00010404, 0x01010400,
+ 0x00000404, 0x01000400, 0x01000400, 0x00000000,
+ 0x00010004, 0x00010400, 0x00000000, 0x01010004
+ };
+
+ private static readonly uint[] SP2 =
+ {
+ 0x80108020, 0x80008000, 0x00008000, 0x00108020,
+ 0x00100000, 0x00000020, 0x80100020, 0x80008020,
+ 0x80000020, 0x80108020, 0x80108000, 0x80000000,
+ 0x80008000, 0x00100000, 0x00000020, 0x80100020,
+ 0x00108000, 0x00100020, 0x80008020, 0x00000000,
+ 0x80000000, 0x00008000, 0x00108020, 0x80100000,
+ 0x00100020, 0x80000020, 0x00000000, 0x00108000,
+ 0x00008020, 0x80108000, 0x80100000, 0x00008020,
+ 0x00000000, 0x00108020, 0x80100020, 0x00100000,
+ 0x80008020, 0x80100000, 0x80108000, 0x00008000,
+ 0x80100000, 0x80008000, 0x00000020, 0x80108020,
+ 0x00108020, 0x00000020, 0x00008000, 0x80000000,
+ 0x00008020, 0x80108000, 0x00100000, 0x80000020,
+ 0x00100020, 0x80008020, 0x80000020, 0x00100020,
+ 0x00108000, 0x00000000, 0x80008000, 0x00008020,
+ 0x80000000, 0x80100020, 0x80108020, 0x00108000
+ };
+
+ private static readonly uint[] SP3 =
+ {
+ 0x00000208, 0x08020200, 0x00000000, 0x08020008,
+ 0x08000200, 0x00000000, 0x00020208, 0x08000200,
+ 0x00020008, 0x08000008, 0x08000008, 0x00020000,
+ 0x08020208, 0x00020008, 0x08020000, 0x00000208,
+ 0x08000000, 0x00000008, 0x08020200, 0x00000200,
+ 0x00020200, 0x08020000, 0x08020008, 0x00020208,
+ 0x08000208, 0x00020200, 0x00020000, 0x08000208,
+ 0x00000008, 0x08020208, 0x00000200, 0x08000000,
+ 0x08020200, 0x08000000, 0x00020008, 0x00000208,
+ 0x00020000, 0x08020200, 0x08000200, 0x00000000,
+ 0x00000200, 0x00020008, 0x08020208, 0x08000200,
+ 0x08000008, 0x00000200, 0x00000000, 0x08020008,
+ 0x08000208, 0x00020000, 0x08000000, 0x08020208,
+ 0x00000008, 0x00020208, 0x00020200, 0x08000008,
+ 0x08020000, 0x08000208, 0x00000208, 0x08020000,
+ 0x00020208, 0x00000008, 0x08020008, 0x00020200
+ };
+
+ private static readonly uint[] SP4 =
+ {
+ 0x00802001, 0x00002081, 0x00002081, 0x00000080,
+ 0x00802080, 0x00800081, 0x00800001, 0x00002001,
+ 0x00000000, 0x00802000, 0x00802000, 0x00802081,
+ 0x00000081, 0x00000000, 0x00800080, 0x00800001,
+ 0x00000001, 0x00002000, 0x00800000, 0x00802001,
+ 0x00000080, 0x00800000, 0x00002001, 0x00002080,
+ 0x00800081, 0x00000001, 0x00002080, 0x00800080,
+ 0x00002000, 0x00802080, 0x00802081, 0x00000081,
+ 0x00800080, 0x00800001, 0x00802000, 0x00802081,
+ 0x00000081, 0x00000000, 0x00000000, 0x00802000,
+ 0x00002080, 0x00800080, 0x00800081, 0x00000001,
+ 0x00802001, 0x00002081, 0x00002081, 0x00000080,
+ 0x00802081, 0x00000081, 0x00000001, 0x00002000,
+ 0x00800001, 0x00002001, 0x00802080, 0x00800081,
+ 0x00002001, 0x00002080, 0x00800000, 0x00802001,
+ 0x00000080, 0x00800000, 0x00002000, 0x00802080
+ };
+
+ private static readonly uint[] SP5 =
+ {
+ 0x00000100, 0x02080100, 0x02080000, 0x42000100,
+ 0x00080000, 0x00000100, 0x40000000, 0x02080000,
+ 0x40080100, 0x00080000, 0x02000100, 0x40080100,
+ 0x42000100, 0x42080000, 0x00080100, 0x40000000,
+ 0x02000000, 0x40080000, 0x40080000, 0x00000000,
+ 0x40000100, 0x42080100, 0x42080100, 0x02000100,
+ 0x42080000, 0x40000100, 0x00000000, 0x42000000,
+ 0x02080100, 0x02000000, 0x42000000, 0x00080100,
+ 0x00080000, 0x42000100, 0x00000100, 0x02000000,
+ 0x40000000, 0x02080000, 0x42000100, 0x40080100,
+ 0x02000100, 0x40000000, 0x42080000, 0x02080100,
+ 0x40080100, 0x00000100, 0x02000000, 0x42080000,
+ 0x42080100, 0x00080100, 0x42000000, 0x42080100,
+ 0x02080000, 0x00000000, 0x40080000, 0x42000000,
+ 0x00080100, 0x02000100, 0x40000100, 0x00080000,
+ 0x00000000, 0x40080000, 0x02080100, 0x40000100
+ };
+
+ private static readonly uint[] SP6 =
+ {
+ 0x20000010, 0x20400000, 0x00004000, 0x20404010,
+ 0x20400000, 0x00000010, 0x20404010, 0x00400000,
+ 0x20004000, 0x00404010, 0x00400000, 0x20000010,
+ 0x00400010, 0x20004000, 0x20000000, 0x00004010,
+ 0x00000000, 0x00400010, 0x20004010, 0x00004000,
+ 0x00404000, 0x20004010, 0x00000010, 0x20400010,
+ 0x20400010, 0x00000000, 0x00404010, 0x20404000,
+ 0x00004010, 0x00404000, 0x20404000, 0x20000000,
+ 0x20004000, 0x00000010, 0x20400010, 0x00404000,
+ 0x20404010, 0x00400000, 0x00004010, 0x20000010,
+ 0x00400000, 0x20004000, 0x20000000, 0x00004010,
+ 0x20000010, 0x20404010, 0x00404000, 0x20400000,
+ 0x00404010, 0x20404000, 0x00000000, 0x20400010,
+ 0x00000010, 0x00004000, 0x20400000, 0x00404010,
+ 0x00004000, 0x00400010, 0x20004010, 0x00000000,
+ 0x20404000, 0x20000000, 0x00400010, 0x20004010
+ };
+
+ private static readonly uint[] SP7 =
+ {
+ 0x00200000, 0x04200002, 0x04000802, 0x00000000,
+ 0x00000800, 0x04000802, 0x00200802, 0x04200800,
+ 0x04200802, 0x00200000, 0x00000000, 0x04000002,
+ 0x00000002, 0x04000000, 0x04200002, 0x00000802,
+ 0x04000800, 0x00200802, 0x00200002, 0x04000800,
+ 0x04000002, 0x04200000, 0x04200800, 0x00200002,
+ 0x04200000, 0x00000800, 0x00000802, 0x04200802,
+ 0x00200800, 0x00000002, 0x04000000, 0x00200800,
+ 0x04000000, 0x00200800, 0x00200000, 0x04000802,
+ 0x04000802, 0x04200002, 0x04200002, 0x00000002,
+ 0x00200002, 0x04000000, 0x04000800, 0x00200000,
+ 0x04200800, 0x00000802, 0x00200802, 0x04200800,
+ 0x00000802, 0x04000002, 0x04200802, 0x04200000,
+ 0x00200800, 0x00000000, 0x00000002, 0x04200802,
+ 0x00000000, 0x00200802, 0x04200000, 0x00000800,
+ 0x04000002, 0x04000800, 0x00000800, 0x00200002
+ };
+
+ private static readonly uint[] SP8 =
+ {
+ 0x10001040, 0x00001000, 0x00040000, 0x10041040,
+ 0x10000000, 0x10001040, 0x00000040, 0x10000000,
+ 0x00040040, 0x10040000, 0x10041040, 0x00041000,
+ 0x10041000, 0x00041040, 0x00001000, 0x00000040,
+ 0x10040000, 0x10000040, 0x10001000, 0x00001040,
+ 0x00041000, 0x00040040, 0x10040040, 0x10041000,
+ 0x00001040, 0x00000000, 0x00000000, 0x10040040,
+ 0x10000040, 0x10001000, 0x00041040, 0x00040000,
+ 0x00041040, 0x00040000, 0x10041000, 0x00001000,
+ 0x00000040, 0x10040040, 0x00001000, 0x00041040,
+ 0x10001000, 0x00000040, 0x10000040, 0x10040000,
+ 0x10040040, 0x10000000, 0x00040000, 0x10001040,
+ 0x00000000, 0x10041040, 0x00040040, 0x10000040,
+ 0x10040000, 0x10001000, 0x10001040, 0x00000000,
+ 0x10041040, 0x00041000, 0x00041000, 0x00001040,
+ 0x00001040, 0x00040040, 0x10000000, 0x10041000
+ };
+
+ /**
+ * Generate an integer based working key based on our secret key
+ * and what we processing we are planning to do.
+ *
+ * Acknowledgements for this routine go to James Gillogly and Phil Karn.
+ * (whoever, and wherever they are!).
+ */
+ protected static int[] GenerateWorkingKey(
+ bool encrypting,
+ byte[] key)
+ {
+ int[] newKey = new int[32];
+ bool[] pc1m = new bool[56];
+ bool[] pcr = new bool[56];
+
+ for (int j = 0; j < 56; j++ )
+ {
+ int l = pc1[j];
+
+ pc1m[j] = ((key[(uint) l >> 3] & bytebit[l & 07]) != 0);
+ }
+
+ for (int i = 0; i < 16; i++)
+ {
+ int l, m, n;
+
+ if (encrypting)
+ {
+ m = i << 1;
+ }
+ else
+ {
+ m = (15 - i) << 1;
+ }
+
+ n = m + 1;
+ newKey[m] = newKey[n] = 0;
+
+ for (int j = 0; j < 28; j++)
+ {
+ l = j + totrot[i];
+ if ( l < 28 )
+ {
+ pcr[j] = pc1m[l];
+ }
+ else
+ {
+ pcr[j] = pc1m[l - 28];
+ }
+ }
+
+ for (int j = 28; j < 56; j++)
+ {
+ l = j + totrot[i];
+ if (l < 56 )
+ {
+ pcr[j] = pc1m[l];
+ }
+ else
+ {
+ pcr[j] = pc1m[l - 28];
+ }
+ }
+
+ for (int j = 0; j < 24; j++)
+ {
+ if (pcr[pc2[j]])
+ {
+ newKey[m] |= bigbyte[j];
+ }
+
+ if (pcr[pc2[j + 24]])
+ {
+ newKey[n] |= bigbyte[j];
+ }
+ }
+ }
+
+ //
+ // store the processed key
+ //
+ for (int i = 0; i != 32; i += 2)
+ {
+ int i1, i2;
+
+ i1 = newKey[i];
+ i2 = newKey[i + 1];
+
+ newKey[i] = (int) ( (uint) ((i1 & 0x00fc0000) << 6) |
+ (uint) ((i1 & 0x00000fc0) << 10) |
+ ((uint) (i2 & 0x00fc0000) >> 10) |
+ ((uint) (i2 & 0x00000fc0) >> 6));
+
+ newKey[i + 1] = (int) ( (uint) ((i1 & 0x0003f000) << 12) |
+ (uint) ((i1 & 0x0000003f) << 16) |
+ ((uint) (i2 & 0x0003f000) >> 4) |
+ (uint) (i2 & 0x0000003f));
+ }
+
+ return newKey;
+ }
+
+ /**
+ * the DES engine.
+ */
+ internal static void DesFunc(
+ int[] wKey,
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ uint left = Pack.BE_To_UInt32(input, inOff);
+ uint right = Pack.BE_To_UInt32(input, inOff + 4);
+ uint work;
+
+ work = ((left >> 4) ^ right) & 0x0f0f0f0f;
+ right ^= work;
+ left ^= (work << 4);
+ work = ((left >> 16) ^ right) & 0x0000ffff;
+ right ^= work;
+ left ^= (work << 16);
+ work = ((right >> 2) ^ left) & 0x33333333;
+ left ^= work;
+ right ^= (work << 2);
+ work = ((right >> 8) ^ left) & 0x00ff00ff;
+ left ^= work;
+ right ^= (work << 8);
+ right = (right << 1) | (right >> 31);
+ work = (left ^ right) & 0xaaaaaaaa;
+ left ^= work;
+ right ^= work;
+ left = (left << 1) | (left >> 31);
+
+ for (int round = 0; round < 8; round++)
+ {
+ uint fval;
+
+ work = (right << 28) | (right >> 4);
+ work ^= (uint)wKey[round * 4 + 0];
+ fval = SP7[work & 0x3f];
+ fval |= SP5[(work >> 8) & 0x3f];
+ fval |= SP3[(work >> 16) & 0x3f];
+ fval |= SP1[(work >> 24) & 0x3f];
+ work = right ^ (uint)wKey[round * 4 + 1];
+ fval |= SP8[ work & 0x3f];
+ fval |= SP6[(work >> 8) & 0x3f];
+ fval |= SP4[(work >> 16) & 0x3f];
+ fval |= SP2[(work >> 24) & 0x3f];
+ left ^= fval;
+ work = (left << 28) | (left >> 4);
+ work ^= (uint)wKey[round * 4 + 2];
+ fval = SP7[ work & 0x3f];
+ fval |= SP5[(work >> 8) & 0x3f];
+ fval |= SP3[(work >> 16) & 0x3f];
+ fval |= SP1[(work >> 24) & 0x3f];
+ work = left ^ (uint)wKey[round * 4 + 3];
+ fval |= SP8[ work & 0x3f];
+ fval |= SP6[(work >> 8) & 0x3f];
+ fval |= SP4[(work >> 16) & 0x3f];
+ fval |= SP2[(work >> 24) & 0x3f];
+ right ^= fval;
+ }
+
+ right = (right << 31) | (right >> 1);
+ work = (left ^ right) & 0xaaaaaaaa;
+ left ^= work;
+ right ^= work;
+ left = (left << 31) | (left >> 1);
+ work = ((left >> 8) ^ right) & 0x00ff00ff;
+ right ^= work;
+ left ^= (work << 8);
+ work = ((left >> 2) ^ right) & 0x33333333;
+ right ^= work;
+ left ^= (work << 2);
+ work = ((right >> 16) ^ left) & 0x0000ffff;
+ left ^= work;
+ right ^= (work << 16);
+ work = ((right >> 4) ^ left) & 0x0f0f0f0f;
+ left ^= work;
+ right ^= (work << 4);
+
+ Pack.UInt32_To_BE(right, outBytes, outOff);
+ Pack.UInt32_To_BE(left, outBytes, outOff + 4);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/Dstu7624Engine.cs b/bc-sharp-crypto/src/crypto/engines/Dstu7624Engine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cdb0f50e011423fc205fa99a581514265a44535b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/Dstu7624Engine.cs
@@ -0,0 +1,766 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * implementation of DSTU 7624 (Kalyna)
+ */
+ public class Dstu7624Engine
+ : IBlockCipher
+ {
+ private static readonly int BITS_IN_WORD = 64;
+ private static readonly int BITS_IN_BYTE = 8;
+
+ private static readonly int REDUCTION_POLYNOMIAL = 0x011d; /* x^8 + x^4 + x^3 + x^2 + 1 */
+
+ private ulong[] internalState;
+ private ulong[] workingKey;
+ private ulong[][] roundKeys;
+
+ /* Number of 64-bit words in block */
+ private int wordsInBlock;
+
+ /* Number of 64-bit words in key */
+ private int wordsInKey;
+
+ /* Number of encryption rounds depending on key length */
+ private static int ROUNDS_128 = 10;
+ private static int ROUNDS_256 = 14;
+ private static int ROUNDS_512 = 18;
+
+ private int blockSizeBits;
+ private int roundsAmount;
+
+ private bool forEncryption;
+
+ private byte[] internalStateBytes;
+ private byte[] tempInternalStateBytes;
+
+ public Dstu7624Engine(int blockSizeBits)
+ {
+ /* DSTU7624 supports 128 | 256 | 512 key/block sizes */
+ if (blockSizeBits != 128 && blockSizeBits != 256 && blockSizeBits != 512)
+ {
+ throw new ArgumentException("Unsupported block length: only 128/256/512 are allowed");
+ }
+ this.blockSizeBits = blockSizeBits;
+
+ wordsInBlock = blockSizeBits / BITS_IN_WORD;
+ internalState = new ulong[wordsInBlock];
+
+ internalStateBytes = new byte[internalState.Length * 64 / BITS_IN_BYTE];
+ tempInternalStateBytes = new byte[internalState.Length * 64 / BITS_IN_BYTE];
+ }
+
+ #region INITIALIZATION
+ public virtual void Init(bool forEncryption, ICipherParameters parameters)
+ {
+ if (parameters is KeyParameter)
+ {
+ this.forEncryption = forEncryption;
+
+ byte[] keyBytes = ((KeyParameter)parameters).GetKey();
+ int keyBitLength = keyBytes.Length * BITS_IN_BYTE;
+ int blockBitLength = wordsInBlock * BITS_IN_WORD;
+
+ if (keyBitLength != 128 && keyBitLength != 256 && keyBitLength != 512)
+ {
+ throw new ArgumentException("unsupported key length: only 128/256/512 are allowed");
+ }
+
+ /* Limitations on key lengths depending on block lengths. See table 6.1 in standard */
+ if (blockBitLength == 128)
+ {
+ if (keyBitLength == 512)
+ {
+ throw new ArgumentException("Unsupported key length");
+ }
+ }
+
+ if (blockBitLength == 256)
+ {
+ if (keyBitLength == 128)
+ {
+ throw new ArgumentException("Unsupported key length");
+ }
+ }
+
+ if (blockBitLength == 512)
+ {
+ if (keyBitLength != 512)
+ {
+ throw new ArgumentException("Unsupported key length");
+ }
+ }
+
+ switch (keyBitLength)
+ {
+ case 128:
+ roundsAmount = ROUNDS_128;
+ break;
+ case 256:
+ roundsAmount = ROUNDS_256;
+ break;
+ case 512:
+ roundsAmount = ROUNDS_512;
+ break;
+ }
+
+ wordsInKey = keyBitLength / BITS_IN_WORD;
+
+ /* +1 round key as defined in standard */
+ roundKeys = new ulong[roundsAmount + 1][];
+ for (int roundKeyIndex = 0; roundKeyIndex < roundKeys.Length; roundKeyIndex++)
+ {
+ roundKeys[roundKeyIndex] = new ulong[wordsInBlock];
+ }
+
+ workingKey = new ulong[wordsInKey];
+
+ if (keyBytes.Length != wordsInKey * BITS_IN_WORD / BITS_IN_BYTE)
+ {
+ throw new ArgumentException("Invalid key parameter passed to DSTU7624Engine init");
+ }
+
+ /* Unpack encryption key bytes to words */
+ Pack.LE_To_UInt64(keyBytes, 0, workingKey);
+
+ ulong[] kt = new ulong[wordsInBlock];
+
+ KeyExpandKT(workingKey, kt);
+
+ KeyExpandEven(workingKey, kt);
+
+ KeyExpandOdd();
+
+ }
+ else if (parameters != null)
+ {
+ throw new ArgumentException("invalid parameter passed to Dstu7624 init - "
+ + Platform.GetTypeName(parameters));
+ }
+
+ this.forEncryption = forEncryption;
+ }
+
+ private void KeyExpandKT(ulong[] key, ulong[] kt)
+ {
+ ulong[] k0 = new ulong[wordsInBlock];
+ ulong[] k1 = new ulong[wordsInBlock];
+
+ internalState = new ulong[wordsInBlock];
+ internalState[0] += (ulong)(wordsInBlock + wordsInKey + 1);
+
+ if (wordsInBlock == wordsInKey)
+ {
+ Array.Copy(key, k0, k0.Length);
+ Array.Copy(key, k1, k1.Length);
+ }
+ else
+ {
+ Array.Copy(key, 0, k0, 0, wordsInBlock);
+ Array.Copy(key, wordsInBlock, k1, 0, wordsInBlock);
+ }
+
+ AddRoundKeyExpand(k0);
+
+ EncryptionRound();
+
+ XorRoundKeyExpand(k1);
+
+ EncryptionRound();
+
+ AddRoundKeyExpand(k0);
+
+ EncryptionRound();
+
+ Array.Copy(internalState, kt, wordsInBlock);
+ }
+
+ private void KeyExpandEven(ulong[] key, ulong[] kt)
+ {
+ ulong[] initial_data = new ulong[wordsInKey];
+
+ ulong[] kt_round = new ulong[wordsInBlock];
+
+ ulong[] tmv = new ulong[wordsInBlock];
+
+ int round = 0;
+
+ Array.Copy(key, initial_data, wordsInKey);
+
+ for (int i = 0; i < wordsInBlock; i++)
+ {
+ tmv[i] = 0x0001000100010001;
+ }
+
+ while (true)
+ {
+ Array.Copy(kt, internalState, wordsInBlock);
+
+ AddRoundKeyExpand(tmv);
+
+ Array.Copy(internalState, kt_round, wordsInBlock);
+ Array.Copy(initial_data, internalState, wordsInBlock);
+
+ AddRoundKeyExpand(kt_round);
+
+ EncryptionRound();
+
+ XorRoundKeyExpand(kt_round);
+
+ EncryptionRound();
+
+ AddRoundKeyExpand(kt_round);
+
+ Array.Copy(internalState, roundKeys[round], wordsInBlock);
+
+ if (roundsAmount == round)
+ {
+ break;
+ }
+ if (wordsInKey != wordsInBlock)
+ {
+ round += 2;
+
+ ShiftLeft(tmv);
+
+ Array.Copy(kt, internalState, wordsInBlock);
+
+ AddRoundKeyExpand(tmv);
+
+ Array.Copy(internalState, kt_round, wordsInBlock);
+ Array.Copy(initial_data, wordsInBlock, internalState, 0, wordsInBlock);
+
+ AddRoundKeyExpand(kt_round);
+
+ EncryptionRound();
+
+ XorRoundKeyExpand(kt_round);
+
+ EncryptionRound();
+
+ AddRoundKeyExpand(kt_round);
+
+ Array.Copy(internalState, roundKeys[round], wordsInBlock);
+
+ if (roundsAmount == round)
+ {
+ break;
+ }
+ }
+
+ round += 2;
+ ShiftLeft(tmv);
+
+ //Rotate initial data array on 1 element left
+ ulong temp = initial_data[0];
+ Array.Copy(initial_data, 1, initial_data, 0, initial_data.Length - 1);
+ initial_data[initial_data.Length - 1] = temp;
+ }
+ }
+ private void KeyExpandOdd()
+ {
+ for (int i = 1; i < roundsAmount; i += 2)
+ {
+ Array.Copy(roundKeys[i - 1], roundKeys[i], wordsInBlock);
+ RotateLeft(roundKeys[i]);
+ }
+ }
+ #endregion
+
+
+ public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
+ {
+ if (workingKey == null)
+ throw new InvalidOperationException("Dstu7624 engine not initialised");
+
+ Check.DataLength(input, inOff, GetBlockSize(), "input buffer too short");
+ Check.OutputLength(output, outOff, GetBlockSize(), "output buffer too short");
+
+ if (forEncryption)
+ {
+ Encrypt(input, inOff, output, outOff);
+ }
+ else
+ {
+ Decrypt(input, inOff, output, outOff);
+ }
+
+ return GetBlockSize();
+ }
+
+ private void Encrypt(byte[] plain, int inOff, byte[] cipherText, int outOff)
+ {
+ Pack.LE_To_UInt64(plain, inOff, internalState);
+
+ int round = 0;
+ AddRoundKey(round);
+
+ while (++round < roundsAmount)
+ {
+ EncryptionRound();
+ XorRoundKey(round);
+ }
+
+ EncryptionRound();
+ AddRoundKey(round);
+
+ Pack.UInt64_To_LE(internalState, cipherText, outOff);
+ }
+
+ private void Decrypt(byte[] cipherText, int inOff, byte[] decryptedText, int outOff)
+ {
+ Pack.LE_To_UInt64(cipherText, inOff, internalState);
+
+ int round = roundsAmount;
+ SubRoundKey(round);
+
+ while (--round > 0)
+ {
+ DecryptionRound();
+ XorRoundKey(round);
+ }
+
+ DecryptionRound();
+ SubRoundKey(round);
+
+ Pack.UInt64_To_LE(internalState, decryptedText, outOff);
+ }
+
+ private void AddRoundKeyExpand(ulong[] value)
+ {
+ for (int i = 0; i < wordsInBlock; i++)
+ {
+ internalState[i] += value[i];
+ }
+ }
+
+ private void EncryptionRound()
+ {
+ SubBytes();
+ ShiftRows();
+ MixColumns();
+ }
+
+ private void DecryptionRound()
+ {
+ InvMixColumns();
+ InvShiftRows();
+ InvSubBytes();
+ }
+
+ private void RotateLeft(ulong[] state_value)
+ {
+ int rotateBytesLength = 2 * state_value.Length + 3;
+ int bytesLength = state_value.Length * (BITS_IN_WORD / BITS_IN_BYTE);
+
+ byte[] bytes = Pack.UInt64_To_LE(state_value);
+ byte[] buffer = new byte[rotateBytesLength];
+
+ Array.Copy(bytes, buffer, rotateBytesLength);
+
+ Buffer.BlockCopy(bytes, rotateBytesLength, bytes, 0, bytesLength - rotateBytesLength);
+
+ Array.Copy(buffer, 0, bytes, bytesLength - rotateBytesLength, rotateBytesLength);
+
+ Pack.LE_To_UInt64(bytes, 0, state_value);
+ }
+
+ private void ShiftLeft(ulong[] state_value)
+ {
+ for (int i = 0; i < state_value.Length; i++)
+ {
+ state_value[i] <<= 1;
+ }
+ Array.Reverse(state_value);
+ }
+
+ private void XorRoundKeyExpand(ulong[] value)
+ {
+ for (int i = 0; i < wordsInBlock; i++)
+ {
+ internalState[i] ^= value[i];
+ }
+ }
+
+ private void XorRoundKey(int round)
+ {
+ ulong[] roundKey = roundKeys[round];
+ for (int i = 0; i < wordsInBlock; i++)
+ {
+ internalState[i] ^= roundKey[i];
+ }
+ }
+
+ private void ShiftRows()
+ {
+ int row, col;
+ int shift = -1;
+
+ byte[] stateBytes = Pack.UInt64_To_LE(internalState);
+ byte[] nstate = new byte[wordsInBlock * 8];
+
+ for (row = 0; row < 8; row++)
+ {
+ if (row % (8 / wordsInBlock) == 0)
+ {
+ shift += 1;
+ }
+
+ for (col = 0; col < wordsInBlock; col++)
+ {
+ nstate[row + ((col + shift) % wordsInBlock) * 8] = stateBytes[row + col * 8];
+ }
+ }
+
+ Pack.LE_To_UInt64(nstate, 0, internalState);
+ }
+
+ private void InvShiftRows()
+ {
+ int row, col;
+ int shift = -1;
+
+ byte[] stateBytes = Pack.UInt64_To_LE(internalState);
+ byte[] nstate = new byte[wordsInBlock * 8];
+
+ for (row = 0; row < 8; row++)
+ {
+ if (row % (8 / wordsInBlock) == 0)
+ {
+ shift += 1;
+ }
+
+ for (col = 0; col < wordsInBlock; col++)
+ {
+ nstate[row + col * 8] = stateBytes[row + ((col + shift) % wordsInBlock) * 8];
+ }
+ }
+
+ Pack.LE_To_UInt64(nstate, 0, internalState);
+ }
+
+ private void AddRoundKey(int round)
+ {
+ for (int i = 0; i < wordsInBlock; ++i)
+ {
+ internalState[i] += roundKeys[round][i];
+ }
+ }
+
+ private void SubRoundKey(int round)
+ {
+ for (int i = 0; i < wordsInBlock; ++i)
+ {
+ internalState[i] -= roundKeys[round][i];
+ }
+ }
+
+ private void MixColumns()
+ {
+ MatrixMultiply(mdsMatrix);
+ }
+
+ private void InvMixColumns()
+ {
+ MatrixMultiply(mdsInvMatrix);
+ }
+
+ private void MatrixMultiply(byte[][] matrix)
+ {
+ int col, row, b;
+ byte product;
+ ulong result;
+ byte[] stateBytes = Pack.UInt64_To_LE(internalState);
+
+ for (col = 0; col < wordsInBlock; ++col)
+ {
+ result = 0;
+ for (row = 8 - 1; row >= 0; --row)
+ {
+ product = 0;
+ for (b = 8 - 1; b >= 0; --b)
+ {
+ product ^= MultiplyGF(stateBytes[b + col * 8], matrix[row][b]);
+ }
+ result |= (ulong)product << (row * 8);
+ }
+ internalState[col] = result;
+ }
+ }
+
+ private byte MultiplyGF(byte x, byte y)
+ {
+ byte r = 0;
+ byte hbit = 0;
+
+ for (int i = 0; i < BITS_IN_BYTE; i++)
+ {
+ if ((y & 0x01) == 1)
+ {
+ r ^= x;
+ }
+
+ hbit = (byte)(x & 0x80);
+
+ x <<= 1;
+
+ if (hbit == 0x80)
+ {
+ x = (byte)((int)x ^ REDUCTION_POLYNOMIAL);
+ }
+ y >>= 1;
+ }
+ return r;
+ }
+
+ private void SubBytes()
+ {
+ for (int i = 0; i < wordsInBlock; i++)
+ {
+ internalState[i] = sboxesForEncryption[0][internalState[i] & 0x00000000000000FF] |
+ ((ulong)sboxesForEncryption[1][(internalState[i] & 0x000000000000FF00) >> 8] << 8) |
+ ((ulong)sboxesForEncryption[2][(internalState[i] & 0x0000000000FF0000) >> 16] << 16) |
+ ((ulong)sboxesForEncryption[3][(internalState[i] & 0x00000000FF000000) >> 24] << 24) |
+ ((ulong)sboxesForEncryption[0][(internalState[i] & 0x000000FF00000000) >> 32] << 32) |
+ ((ulong)sboxesForEncryption[1][(internalState[i] & 0x0000FF0000000000) >> 40] << 40) |
+ ((ulong)sboxesForEncryption[2][(internalState[i] & 0x00FF000000000000) >> 48] << 48) |
+ ((ulong)sboxesForEncryption[3][(internalState[i] & 0xFF00000000000000) >> 56] << 56);
+ }
+ }
+
+ private void InvSubBytes()
+ {
+ for (int i = 0; i < wordsInBlock; i++)
+ {
+ internalState[i] = sboxesForDecryption[0][internalState[i] & 0x00000000000000FF] |
+ ((ulong)sboxesForDecryption[1][(internalState[i] & 0x000000000000FF00) >> 8] << 8) |
+ ((ulong)sboxesForDecryption[2][(internalState[i] & 0x0000000000FF0000) >> 16] << 16) |
+ ((ulong)sboxesForDecryption[3][(internalState[i] & 0x00000000FF000000) >> 24] << 24) |
+ ((ulong)sboxesForDecryption[0][(internalState[i] & 0x000000FF00000000) >> 32] << 32) |
+ ((ulong)sboxesForDecryption[1][(internalState[i] & 0x0000FF0000000000) >> 40] << 40) |
+ ((ulong)sboxesForDecryption[2][(internalState[i] & 0x00FF000000000000) >> 48] << 48) |
+ ((ulong)sboxesForDecryption[3][(internalState[i] & 0xFF00000000000000) >> 56] << 56);
+ }
+ }
+
+ #region TABLES AND S-BOXES
+
+ private byte[][] mdsMatrix =
+ {
+ new byte[] { 0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04 },
+ new byte[] { 0x04, 0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07 },
+ new byte[] { 0x07, 0x04, 0x01, 0x01, 0x05, 0x01, 0x08, 0x06 },
+ new byte[] { 0x06, 0x07, 0x04, 0x01, 0x01, 0x05, 0x01, 0x08 },
+ new byte[] { 0x08, 0x06, 0x07, 0x04, 0x01, 0x01, 0x05, 0x01 },
+ new byte[] { 0x01, 0x08, 0x06, 0x07, 0x04, 0x01, 0x01, 0x05 },
+ new byte[] { 0x05, 0x01, 0x08, 0x06, 0x07, 0x04, 0x01, 0x01 },
+ new byte[] { 0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04, 0x01 },
+ };
+
+ private byte[][] mdsInvMatrix =
+ {
+ new byte[] { 0xAD, 0x95, 0x76, 0xA8, 0x2F, 0x49, 0xD7, 0xCA },
+ new byte[] { 0xCA, 0xAD, 0x95, 0x76, 0xA8, 0x2F, 0x49, 0xD7 },
+ new byte[] { 0xD7, 0xCA, 0xAD, 0x95, 0x76, 0xA8, 0x2F, 0x49 },
+ new byte[] { 0x49, 0xD7, 0xCA, 0xAD, 0x95, 0x76, 0xA8, 0x2F },
+ new byte[] { 0x2F, 0x49, 0xD7, 0xCA, 0xAD, 0x95, 0x76, 0xA8 },
+ new byte[] { 0xA8, 0x2F, 0x49, 0xD7, 0xCA, 0xAD, 0x95, 0x76 },
+ new byte[] { 0x76, 0xA8, 0x2F, 0x49, 0xD7, 0xCA, 0xAD, 0x95 },
+ new byte[] { 0x95, 0x76, 0xA8, 0x2F, 0x49, 0xD7, 0xCA, 0xAD },
+ };
+
+ private byte[][] sboxesForEncryption =
+ {
+ new byte[]
+ {
+ 0xa8, 0x43, 0x5f, 0x06, 0x6b, 0x75, 0x6c, 0x59, 0x71, 0xdf, 0x87, 0x95, 0x17, 0xf0, 0xd8, 0x09,
+ 0x6d, 0xf3, 0x1d, 0xcb, 0xc9, 0x4d, 0x2c, 0xaf, 0x79, 0xe0, 0x97, 0xfd, 0x6f, 0x4b, 0x45, 0x39,
+ 0x3e, 0xdd, 0xa3, 0x4f, 0xb4, 0xb6, 0x9a, 0x0e, 0x1f, 0xbf, 0x15, 0xe1, 0x49, 0xd2, 0x93, 0xc6,
+ 0x92, 0x72, 0x9e, 0x61, 0xd1, 0x63, 0xfa, 0xee, 0xf4, 0x19, 0xd5, 0xad, 0x58, 0xa4, 0xbb, 0xa1,
+ 0xdc, 0xf2, 0x83, 0x37, 0x42, 0xe4, 0x7a, 0x32, 0x9c, 0xcc, 0xab, 0x4a, 0x8f, 0x6e, 0x04, 0x27,
+ 0x2e, 0xe7, 0xe2, 0x5a, 0x96, 0x16, 0x23, 0x2b, 0xc2, 0x65, 0x66, 0x0f, 0xbc, 0xa9, 0x47, 0x41,
+ 0x34, 0x48, 0xfc, 0xb7, 0x6a, 0x88, 0xa5, 0x53, 0x86, 0xf9, 0x5b, 0xdb, 0x38, 0x7b, 0xc3, 0x1e,
+ 0x22, 0x33, 0x24, 0x28, 0x36, 0xc7, 0xb2, 0x3b, 0x8e, 0x77, 0xba, 0xf5, 0x14, 0x9f, 0x08, 0x55,
+ 0x9b, 0x4c, 0xfe, 0x60, 0x5c, 0xda, 0x18, 0x46, 0xcd, 0x7d, 0x21, 0xb0, 0x3f, 0x1b, 0x89, 0xff,
+ 0xeb, 0x84, 0x69, 0x3a, 0x9d, 0xd7, 0xd3, 0x70, 0x67, 0x40, 0xb5, 0xde, 0x5d, 0x30, 0x91, 0xb1,
+ 0x78, 0x11, 0x01, 0xe5, 0x00, 0x68, 0x98, 0xa0, 0xc5, 0x02, 0xa6, 0x74, 0x2d, 0x0b, 0xa2, 0x76,
+ 0xb3, 0xbe, 0xce, 0xbd, 0xae, 0xe9, 0x8a, 0x31, 0x1c, 0xec, 0xf1, 0x99, 0x94, 0xaa, 0xf6, 0x26,
+ 0x2f, 0xef, 0xe8, 0x8c, 0x35, 0x03, 0xd4, 0x7f, 0xfb, 0x05, 0xc1, 0x5e, 0x90, 0x20, 0x3d, 0x82,
+ 0xf7, 0xea, 0x0a, 0x0d, 0x7e, 0xf8, 0x50, 0x1a, 0xc4, 0x07, 0x57, 0xb8, 0x3c, 0x62, 0xe3, 0xc8,
+ 0xac, 0x52, 0x64, 0x10, 0xd0, 0xd9, 0x13, 0x0c, 0x12, 0x29, 0x51, 0xb9, 0xcf, 0xd6, 0x73, 0x8d,
+ 0x81, 0x54, 0xc0, 0xed, 0x4e, 0x44, 0xa7, 0x2a, 0x85, 0x25, 0xe6, 0xca, 0x7c, 0x8b, 0x56, 0x80
+ },
+
+ new byte[]
+ {
+ 0xce, 0xbb, 0xeb, 0x92, 0xea, 0xcb, 0x13, 0xc1, 0xe9, 0x3a, 0xd6, 0xb2, 0xd2, 0x90, 0x17, 0xf8,
+ 0x42, 0x15, 0x56, 0xb4, 0x65, 0x1c, 0x88, 0x43, 0xc5, 0x5c, 0x36, 0xba, 0xf5, 0x57, 0x67, 0x8d,
+ 0x31, 0xf6, 0x64, 0x58, 0x9e, 0xf4, 0x22, 0xaa, 0x75, 0x0f, 0x02, 0xb1, 0xdf, 0x6d, 0x73, 0x4d,
+ 0x7c, 0x26, 0x2e, 0xf7, 0x08, 0x5d, 0x44, 0x3e, 0x9f, 0x14, 0xc8, 0xae, 0x54, 0x10, 0xd8, 0xbc,
+ 0x1a, 0x6b, 0x69, 0xf3, 0xbd, 0x33, 0xab, 0xfa, 0xd1, 0x9b, 0x68, 0x4e, 0x16, 0x95, 0x91, 0xee,
+ 0x4c, 0x63, 0x8e, 0x5b, 0xcc, 0x3c, 0x19, 0xa1, 0x81, 0x49, 0x7b, 0xd9, 0x6f, 0x37, 0x60, 0xca,
+ 0xe7, 0x2b, 0x48, 0xfd, 0x96, 0x45, 0xfc, 0x41, 0x12, 0x0d, 0x79, 0xe5, 0x89, 0x8c, 0xe3, 0x20,
+ 0x30, 0xdc, 0xb7, 0x6c, 0x4a, 0xb5, 0x3f, 0x97, 0xd4, 0x62, 0x2d, 0x06, 0xa4, 0xa5, 0x83, 0x5f,
+ 0x2a, 0xda, 0xc9, 0x00, 0x7e, 0xa2, 0x55, 0xbf, 0x11, 0xd5, 0x9c, 0xcf, 0x0e, 0x0a, 0x3d, 0x51,
+ 0x7d, 0x93, 0x1b, 0xfe, 0xc4, 0x47, 0x09, 0x86, 0x0b, 0x8f, 0x9d, 0x6a, 0x07, 0xb9, 0xb0, 0x98,
+ 0x18, 0x32, 0x71, 0x4b, 0xef, 0x3b, 0x70, 0xa0, 0xe4, 0x40, 0xff, 0xc3, 0xa9, 0xe6, 0x78, 0xf9,
+ 0x8b, 0x46, 0x80, 0x1e, 0x38, 0xe1, 0xb8, 0xa8, 0xe0, 0x0c, 0x23, 0x76, 0x1d, 0x25, 0x24, 0x05,
+ 0xf1, 0x6e, 0x94, 0x28, 0x9a, 0x84, 0xe8, 0xa3, 0x4f, 0x77, 0xd3, 0x85, 0xe2, 0x52, 0xf2, 0x82,
+ 0x50, 0x7a, 0x2f, 0x74, 0x53, 0xb3, 0x61, 0xaf, 0x39, 0x35, 0xde, 0xcd, 0x1f, 0x99, 0xac, 0xad,
+ 0x72, 0x2c, 0xdd, 0xd0, 0x87, 0xbe, 0x5e, 0xa6, 0xec, 0x04, 0xc6, 0x03, 0x34, 0xfb, 0xdb, 0x59,
+ 0xb6, 0xc2, 0x01, 0xf0, 0x5a, 0xed, 0xa7, 0x66, 0x21, 0x7f, 0x8a, 0x27, 0xc7, 0xc0, 0x29, 0xd7
+ },
+
+ new byte[]
+ {
+ 0x93, 0xd9, 0x9a, 0xb5, 0x98, 0x22, 0x45, 0xfc, 0xba, 0x6a, 0xdf, 0x02, 0x9f, 0xdc, 0x51, 0x59,
+ 0x4a, 0x17, 0x2b, 0xc2, 0x94, 0xf4, 0xbb, 0xa3, 0x62, 0xe4, 0x71, 0xd4, 0xcd, 0x70, 0x16, 0xe1,
+ 0x49, 0x3c, 0xc0, 0xd8, 0x5c, 0x9b, 0xad, 0x85, 0x53, 0xa1, 0x7a, 0xc8, 0x2d, 0xe0, 0xd1, 0x72,
+ 0xa6, 0x2c, 0xc4, 0xe3, 0x76, 0x78, 0xb7, 0xb4, 0x09, 0x3b, 0x0e, 0x41, 0x4c, 0xde, 0xb2, 0x90,
+ 0x25, 0xa5, 0xd7, 0x03, 0x11, 0x00, 0xc3, 0x2e, 0x92, 0xef, 0x4e, 0x12, 0x9d, 0x7d, 0xcb, 0x35,
+ 0x10, 0xd5, 0x4f, 0x9e, 0x4d, 0xa9, 0x55, 0xc6, 0xd0, 0x7b, 0x18, 0x97, 0xd3, 0x36, 0xe6, 0x48,
+ 0x56, 0x81, 0x8f, 0x77, 0xcc, 0x9c, 0xb9, 0xe2, 0xac, 0xb8, 0x2f, 0x15, 0xa4, 0x7c, 0xda, 0x38,
+ 0x1e, 0x0b, 0x05, 0xd6, 0x14, 0x6e, 0x6c, 0x7e, 0x66, 0xfd, 0xb1, 0xe5, 0x60, 0xaf, 0x5e, 0x33,
+ 0x87, 0xc9, 0xf0, 0x5d, 0x6d, 0x3f, 0x88, 0x8d, 0xc7, 0xf7, 0x1d, 0xe9, 0xec, 0xed, 0x80, 0x29,
+ 0x27, 0xcf, 0x99, 0xa8, 0x50, 0x0f, 0x37, 0x24, 0x28, 0x30, 0x95, 0xd2, 0x3e, 0x5b, 0x40, 0x83,
+ 0xb3, 0x69, 0x57, 0x1f, 0x07, 0x1c, 0x8a, 0xbc, 0x20, 0xeb, 0xce, 0x8e, 0xab, 0xee, 0x31, 0xa2,
+ 0x73, 0xf9, 0xca, 0x3a, 0x1a, 0xfb, 0x0d, 0xc1, 0xfe, 0xfa, 0xf2, 0x6f, 0xbd, 0x96, 0xdd, 0x43,
+ 0x52, 0xb6, 0x08, 0xf3, 0xae, 0xbe, 0x19, 0x89, 0x32, 0x26, 0xb0, 0xea, 0x4b, 0x64, 0x84, 0x82,
+ 0x6b, 0xf5, 0x79, 0xbf, 0x01, 0x5f, 0x75, 0x63, 0x1b, 0x23, 0x3d, 0x68, 0x2a, 0x65, 0xe8, 0x91,
+ 0xf6, 0xff, 0x13, 0x58, 0xf1, 0x47, 0x0a, 0x7f, 0xc5, 0xa7, 0xe7, 0x61, 0x5a, 0x06, 0x46, 0x44,
+ 0x42, 0x04, 0xa0, 0xdb, 0x39, 0x86, 0x54, 0xaa, 0x8c, 0x34, 0x21, 0x8b, 0xf8, 0x0c, 0x74, 0x67
+ },
+
+ new byte[]
+ {
+ 0x68, 0x8d, 0xca, 0x4d, 0x73, 0x4b, 0x4e, 0x2a, 0xd4, 0x52, 0x26, 0xb3, 0x54, 0x1e, 0x19, 0x1f,
+ 0x22, 0x03, 0x46, 0x3d, 0x2d, 0x4a, 0x53, 0x83, 0x13, 0x8a, 0xb7, 0xd5, 0x25, 0x79, 0xf5, 0xbd,
+ 0x58, 0x2f, 0x0d, 0x02, 0xed, 0x51, 0x9e, 0x11, 0xf2, 0x3e, 0x55, 0x5e, 0xd1, 0x16, 0x3c, 0x66,
+ 0x70, 0x5d, 0xf3, 0x45, 0x40, 0xcc, 0xe8, 0x94, 0x56, 0x08, 0xce, 0x1a, 0x3a, 0xd2, 0xe1, 0xdf,
+ 0xb5, 0x38, 0x6e, 0x0e, 0xe5, 0xf4, 0xf9, 0x86, 0xe9, 0x4f, 0xd6, 0x85, 0x23, 0xcf, 0x32, 0x99,
+ 0x31, 0x14, 0xae, 0xee, 0xc8, 0x48, 0xd3, 0x30, 0xa1, 0x92, 0x41, 0xb1, 0x18, 0xc4, 0x2c, 0x71,
+ 0x72, 0x44, 0x15, 0xfd, 0x37, 0xbe, 0x5f, 0xaa, 0x9b, 0x88, 0xd8, 0xab, 0x89, 0x9c, 0xfa, 0x60,
+ 0xea, 0xbc, 0x62, 0x0c, 0x24, 0xa6, 0xa8, 0xec, 0x67, 0x20, 0xdb, 0x7c, 0x28, 0xdd, 0xac, 0x5b,
+ 0x34, 0x7e, 0x10, 0xf1, 0x7b, 0x8f, 0x63, 0xa0, 0x05, 0x9a, 0x43, 0x77, 0x21, 0xbf, 0x27, 0x09,
+ 0xc3, 0x9f, 0xb6, 0xd7, 0x29, 0xc2, 0xeb, 0xc0, 0xa4, 0x8b, 0x8c, 0x1d, 0xfb, 0xff, 0xc1, 0xb2,
+ 0x97, 0x2e, 0xf8, 0x65, 0xf6, 0x75, 0x07, 0x04, 0x49, 0x33, 0xe4, 0xd9, 0xb9, 0xd0, 0x42, 0xc7,
+ 0x6c, 0x90, 0x00, 0x8e, 0x6f, 0x50, 0x01, 0xc5, 0xda, 0x47, 0x3f, 0xcd, 0x69, 0xa2, 0xe2, 0x7a,
+ 0xa7, 0xc6, 0x93, 0x0f, 0x0a, 0x06, 0xe6, 0x2b, 0x96, 0xa3, 0x1c, 0xaf, 0x6a, 0x12, 0x84, 0x39,
+ 0xe7, 0xb0, 0x82, 0xf7, 0xfe, 0x9d, 0x87, 0x5c, 0x81, 0x35, 0xde, 0xb4, 0xa5, 0xfc, 0x80, 0xef,
+ 0xcb, 0xbb, 0x6b, 0x76, 0xba, 0x5a, 0x7d, 0x78, 0x0b, 0x95, 0xe3, 0xad, 0x74, 0x98, 0x3b, 0x36,
+ 0x64, 0x6d, 0xdc, 0xf0, 0x59, 0xa9, 0x4c, 0x17, 0x7f, 0x91, 0xb8, 0xc9, 0x57, 0x1b, 0xe0, 0x61
+ }
+ };
+
+ private byte[][] sboxesForDecryption =
+ {
+ new byte[]
+ {
+ 0xa4, 0xa2, 0xa9, 0xc5, 0x4e, 0xc9, 0x03, 0xd9, 0x7e, 0x0f, 0xd2, 0xad, 0xe7, 0xd3, 0x27, 0x5b,
+ 0xe3, 0xa1, 0xe8, 0xe6, 0x7c, 0x2a, 0x55, 0x0c, 0x86, 0x39, 0xd7, 0x8d, 0xb8, 0x12, 0x6f, 0x28,
+ 0xcd, 0x8a, 0x70, 0x56, 0x72, 0xf9, 0xbf, 0x4f, 0x73, 0xe9, 0xf7, 0x57, 0x16, 0xac, 0x50, 0xc0,
+ 0x9d, 0xb7, 0x47, 0x71, 0x60, 0xc4, 0x74, 0x43, 0x6c, 0x1f, 0x93, 0x77, 0xdc, 0xce, 0x20, 0x8c,
+ 0x99, 0x5f, 0x44, 0x01, 0xf5, 0x1e, 0x87, 0x5e, 0x61, 0x2c, 0x4b, 0x1d, 0x81, 0x15, 0xf4, 0x23,
+ 0xd6, 0xea, 0xe1, 0x67, 0xf1, 0x7f, 0xfe, 0xda, 0x3c, 0x07, 0x53, 0x6a, 0x84, 0x9c, 0xcb, 0x02,
+ 0x83, 0x33, 0xdd, 0x35, 0xe2, 0x59, 0x5a, 0x98, 0xa5, 0x92, 0x64, 0x04, 0x06, 0x10, 0x4d, 0x1c,
+ 0x97, 0x08, 0x31, 0xee, 0xab, 0x05, 0xaf, 0x79, 0xa0, 0x18, 0x46, 0x6d, 0xfc, 0x89, 0xd4, 0xc7,
+ 0xff, 0xf0, 0xcf, 0x42, 0x91, 0xf8, 0x68, 0x0a, 0x65, 0x8e, 0xb6, 0xfd, 0xc3, 0xef, 0x78, 0x4c,
+ 0xcc, 0x9e, 0x30, 0x2e, 0xbc, 0x0b, 0x54, 0x1a, 0xa6, 0xbb, 0x26, 0x80, 0x48, 0x94, 0x32, 0x7d,
+ 0xa7, 0x3f, 0xae, 0x22, 0x3d, 0x66, 0xaa, 0xf6, 0x00, 0x5d, 0xbd, 0x4a, 0xe0, 0x3b, 0xb4, 0x17,
+ 0x8b, 0x9f, 0x76, 0xb0, 0x24, 0x9a, 0x25, 0x63, 0xdb, 0xeb, 0x7a, 0x3e, 0x5c, 0xb3, 0xb1, 0x29,
+ 0xf2, 0xca, 0x58, 0x6e, 0xd8, 0xa8, 0x2f, 0x75, 0xdf, 0x14, 0xfb, 0x13, 0x49, 0x88, 0xb2, 0xec,
+ 0xe4, 0x34, 0x2d, 0x96, 0xc6, 0x3a, 0xed, 0x95, 0x0e, 0xe5, 0x85, 0x6b, 0x40, 0x21, 0x9b, 0x09,
+ 0x19, 0x2b, 0x52, 0xde, 0x45, 0xa3, 0xfa, 0x51, 0xc2, 0xb5, 0xd1, 0x90, 0xb9, 0xf3, 0x37, 0xc1,
+ 0x0d, 0xba, 0x41, 0x11, 0x38, 0x7b, 0xbe, 0xd0, 0xd5, 0x69, 0x36, 0xc8, 0x62, 0x1b, 0x82, 0x8f
+ },
+
+ new byte[]
+ {
+ 0x83, 0xf2, 0x2a, 0xeb, 0xe9, 0xbf, 0x7b, 0x9c, 0x34, 0x96, 0x8d, 0x98, 0xb9, 0x69, 0x8c, 0x29,
+ 0x3d, 0x88, 0x68, 0x06, 0x39, 0x11, 0x4c, 0x0e, 0xa0, 0x56, 0x40, 0x92, 0x15, 0xbc, 0xb3, 0xdc,
+ 0x6f, 0xf8, 0x26, 0xba, 0xbe, 0xbd, 0x31, 0xfb, 0xc3, 0xfe, 0x80, 0x61, 0xe1, 0x7a, 0x32, 0xd2,
+ 0x70, 0x20, 0xa1, 0x45, 0xec, 0xd9, 0x1a, 0x5d, 0xb4, 0xd8, 0x09, 0xa5, 0x55, 0x8e, 0x37, 0x76,
+ 0xa9, 0x67, 0x10, 0x17, 0x36, 0x65, 0xb1, 0x95, 0x62, 0x59, 0x74, 0xa3, 0x50, 0x2f, 0x4b, 0xc8,
+ 0xd0, 0x8f, 0xcd, 0xd4, 0x3c, 0x86, 0x12, 0x1d, 0x23, 0xef, 0xf4, 0x53, 0x19, 0x35, 0xe6, 0x7f,
+ 0x5e, 0xd6, 0x79, 0x51, 0x22, 0x14, 0xf7, 0x1e, 0x4a, 0x42, 0x9b, 0x41, 0x73, 0x2d, 0xc1, 0x5c,
+ 0xa6, 0xa2, 0xe0, 0x2e, 0xd3, 0x28, 0xbb, 0xc9, 0xae, 0x6a, 0xd1, 0x5a, 0x30, 0x90, 0x84, 0xf9,
+ 0xb2, 0x58, 0xcf, 0x7e, 0xc5, 0xcb, 0x97, 0xe4, 0x16, 0x6c, 0xfa, 0xb0, 0x6d, 0x1f, 0x52, 0x99,
+ 0x0d, 0x4e, 0x03, 0x91, 0xc2, 0x4d, 0x64, 0x77, 0x9f, 0xdd, 0xc4, 0x49, 0x8a, 0x9a, 0x24, 0x38,
+ 0xa7, 0x57, 0x85, 0xc7, 0x7c, 0x7d, 0xe7, 0xf6, 0xb7, 0xac, 0x27, 0x46, 0xde, 0xdf, 0x3b, 0xd7,
+ 0x9e, 0x2b, 0x0b, 0xd5, 0x13, 0x75, 0xf0, 0x72, 0xb6, 0x9d, 0x1b, 0x01, 0x3f, 0x44, 0xe5, 0x87,
+ 0xfd, 0x07, 0xf1, 0xab, 0x94, 0x18, 0xea, 0xfc, 0x3a, 0x82, 0x5f, 0x05, 0x54, 0xdb, 0x00, 0x8b,
+ 0xe3, 0x48, 0x0c, 0xca, 0x78, 0x89, 0x0a, 0xff, 0x3e, 0x5b, 0x81, 0xee, 0x71, 0xe2, 0xda, 0x2c,
+ 0xb8, 0xb5, 0xcc, 0x6e, 0xa8, 0x6b, 0xad, 0x60, 0xc6, 0x08, 0x04, 0x02, 0xe8, 0xf5, 0x4f, 0xa4,
+ 0xf3, 0xc0, 0xce, 0x43, 0x25, 0x1c, 0x21, 0x33, 0x0f, 0xaf, 0x47, 0xed, 0x66, 0x63, 0x93, 0xaa
+ },
+
+ new byte[]
+ {
+ 0x45, 0xd4, 0x0b, 0x43, 0xf1, 0x72, 0xed, 0xa4, 0xc2, 0x38, 0xe6, 0x71, 0xfd, 0xb6, 0x3a, 0x95,
+ 0x50, 0x44, 0x4b, 0xe2, 0x74, 0x6b, 0x1e, 0x11, 0x5a, 0xc6, 0xb4, 0xd8, 0xa5, 0x8a, 0x70, 0xa3,
+ 0xa8, 0xfa, 0x05, 0xd9, 0x97, 0x40, 0xc9, 0x90, 0x98, 0x8f, 0xdc, 0x12, 0x31, 0x2c, 0x47, 0x6a,
+ 0x99, 0xae, 0xc8, 0x7f, 0xf9, 0x4f, 0x5d, 0x96, 0x6f, 0xf4, 0xb3, 0x39, 0x21, 0xda, 0x9c, 0x85,
+ 0x9e, 0x3b, 0xf0, 0xbf, 0xef, 0x06, 0xee, 0xe5, 0x5f, 0x20, 0x10, 0xcc, 0x3c, 0x54, 0x4a, 0x52,
+ 0x94, 0x0e, 0xc0, 0x28, 0xf6, 0x56, 0x60, 0xa2, 0xe3, 0x0f, 0xec, 0x9d, 0x24, 0x83, 0x7e, 0xd5,
+ 0x7c, 0xeb, 0x18, 0xd7, 0xcd, 0xdd, 0x78, 0xff, 0xdb, 0xa1, 0x09, 0xd0, 0x76, 0x84, 0x75, 0xbb,
+ 0x1d, 0x1a, 0x2f, 0xb0, 0xfe, 0xd6, 0x34, 0x63, 0x35, 0xd2, 0x2a, 0x59, 0x6d, 0x4d, 0x77, 0xe7,
+ 0x8e, 0x61, 0xcf, 0x9f, 0xce, 0x27, 0xf5, 0x80, 0x86, 0xc7, 0xa6, 0xfb, 0xf8, 0x87, 0xab, 0x62,
+ 0x3f, 0xdf, 0x48, 0x00, 0x14, 0x9a, 0xbd, 0x5b, 0x04, 0x92, 0x02, 0x25, 0x65, 0x4c, 0x53, 0x0c,
+ 0xf2, 0x29, 0xaf, 0x17, 0x6c, 0x41, 0x30, 0xe9, 0x93, 0x55, 0xf7, 0xac, 0x68, 0x26, 0xc4, 0x7d,
+ 0xca, 0x7a, 0x3e, 0xa0, 0x37, 0x03, 0xc1, 0x36, 0x69, 0x66, 0x08, 0x16, 0xa7, 0xbc, 0xc5, 0xd3,
+ 0x22, 0xb7, 0x13, 0x46, 0x32, 0xe8, 0x57, 0x88, 0x2b, 0x81, 0xb2, 0x4e, 0x64, 0x1c, 0xaa, 0x91,
+ 0x58, 0x2e, 0x9b, 0x5c, 0x1b, 0x51, 0x73, 0x42, 0x23, 0x01, 0x6e, 0xf3, 0x0d, 0xbe, 0x3d, 0x0a,
+ 0x2d, 0x1f, 0x67, 0x33, 0x19, 0x7b, 0x5e, 0xea, 0xde, 0x8b, 0xcb, 0xa9, 0x8c, 0x8d, 0xad, 0x49,
+ 0x82, 0xe4, 0xba, 0xc3, 0x15, 0xd1, 0xe0, 0x89, 0xfc, 0xb1, 0xb9, 0xb5, 0x07, 0x79, 0xb8, 0xe1
+ },
+
+ new byte[]
+ {
+ 0xb2, 0xb6, 0x23, 0x11, 0xa7, 0x88, 0xc5, 0xa6, 0x39, 0x8f, 0xc4, 0xe8, 0x73, 0x22, 0x43, 0xc3,
+ 0x82, 0x27, 0xcd, 0x18, 0x51, 0x62, 0x2d, 0xf7, 0x5c, 0x0e, 0x3b, 0xfd, 0xca, 0x9b, 0x0d, 0x0f,
+ 0x79, 0x8c, 0x10, 0x4c, 0x74, 0x1c, 0x0a, 0x8e, 0x7c, 0x94, 0x07, 0xc7, 0x5e, 0x14, 0xa1, 0x21,
+ 0x57, 0x50, 0x4e, 0xa9, 0x80, 0xd9, 0xef, 0x64, 0x41, 0xcf, 0x3c, 0xee, 0x2e, 0x13, 0x29, 0xba,
+ 0x34, 0x5a, 0xae, 0x8a, 0x61, 0x33, 0x12, 0xb9, 0x55, 0xa8, 0x15, 0x05, 0xf6, 0x03, 0x06, 0x49,
+ 0xb5, 0x25, 0x09, 0x16, 0x0c, 0x2a, 0x38, 0xfc, 0x20, 0xf4, 0xe5, 0x7f, 0xd7, 0x31, 0x2b, 0x66,
+ 0x6f, 0xff, 0x72, 0x86, 0xf0, 0xa3, 0x2f, 0x78, 0x00, 0xbc, 0xcc, 0xe2, 0xb0, 0xf1, 0x42, 0xb4,
+ 0x30, 0x5f, 0x60, 0x04, 0xec, 0xa5, 0xe3, 0x8b, 0xe7, 0x1d, 0xbf, 0x84, 0x7b, 0xe6, 0x81, 0xf8,
+ 0xde, 0xd8, 0xd2, 0x17, 0xce, 0x4b, 0x47, 0xd6, 0x69, 0x6c, 0x19, 0x99, 0x9a, 0x01, 0xb3, 0x85,
+ 0xb1, 0xf9, 0x59, 0xc2, 0x37, 0xe9, 0xc8, 0xa0, 0xed, 0x4f, 0x89, 0x68, 0x6d, 0xd5, 0x26, 0x91,
+ 0x87, 0x58, 0xbd, 0xc9, 0x98, 0xdc, 0x75, 0xc0, 0x76, 0xf5, 0x67, 0x6b, 0x7e, 0xeb, 0x52, 0xcb,
+ 0xd1, 0x5b, 0x9f, 0x0b, 0xdb, 0x40, 0x92, 0x1a, 0xfa, 0xac, 0xe4, 0xe1, 0x71, 0x1f, 0x65, 0x8d,
+ 0x97, 0x9e, 0x95, 0x90, 0x5d, 0xb7, 0xc1, 0xaf, 0x54, 0xfb, 0x02, 0xe0, 0x35, 0xbb, 0x3a, 0x4d,
+ 0xad, 0x2c, 0x3d, 0x56, 0x08, 0x1b, 0x4a, 0x93, 0x6a, 0xab, 0xb8, 0x7a, 0xf2, 0x7d, 0xda, 0x3f,
+ 0xfe, 0x3e, 0xbe, 0xea, 0xaa, 0x44, 0xc6, 0xd0, 0x36, 0x48, 0x70, 0x96, 0x77, 0x24, 0x53, 0xdf,
+ 0xf3, 0x83, 0x28, 0x32, 0x45, 0x1e, 0xa4, 0xd3, 0xa2, 0x46, 0x6e, 0x9c, 0xdd, 0x63, 0xd4, 0x9d
+ }
+ };
+
+ #endregion
+
+ public virtual string AlgorithmName
+ {
+ get { return "Dstu7624"; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return blockSizeBits / BITS_IN_BYTE;
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual void Reset()
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/Dstu7624WrapEngine.cs b/bc-sharp-crypto/src/crypto/engines/Dstu7624WrapEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9cb98245fc5e59c0da937a232ecd937e4fb5f1f6
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/Dstu7624WrapEngine.cs
@@ -0,0 +1,216 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ public class Dstu7624WrapEngine
+ : IWrapper
+ {
+ private KeyParameter param;
+ private Dstu7624Engine engine;
+ private bool forWrapping;
+ private int blockSize;
+
+ public Dstu7624WrapEngine(int blockSizeBits)
+ {
+ engine = new Dstu7624Engine(blockSizeBits);
+ param = null;
+
+ blockSize = blockSizeBits / 8;
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Dstu7624WrapEngine"; }
+ }
+
+ public void Init(bool forWrapping, ICipherParameters parameters)
+ {
+ this.forWrapping = forWrapping;
+
+ if (parameters is KeyParameter)
+ {
+ this.param = (KeyParameter)parameters;
+
+ engine.Init(forWrapping, param);
+ }
+ else
+ {
+ throw new ArgumentException("Bad parameters passed to Dstu7624WrapEngine");
+ }
+ }
+
+ public byte[] Wrap(byte[] input, int inOff, int length)
+ {
+ if (!forWrapping)
+ throw new InvalidOperationException("Not set for wrapping");
+
+ if (length % blockSize != 0)
+ throw new ArgumentException("Padding not supported");
+
+ int n = 2 * (1 + length / blockSize);
+ int V = (n - 1) * 6;
+
+ byte[] buffer = new byte[length + blockSize];
+ Array.Copy(input, inOff, buffer, 0, length);
+ //Console.WriteLine(Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(buffer));
+
+ byte[] B = new byte[blockSize / 2];
+ Array.Copy(buffer, 0, B, 0, blockSize / 2);
+ //Console.WriteLine("B0: "+ Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(B));
+
+ IList bTemp = Platform.CreateArrayList();
+ int bHalfBlocksLen = buffer.Length - blockSize / 2;
+ int bufOff = blockSize / 2;
+ while (bHalfBlocksLen != 0)
+ {
+ byte[] temp = new byte[blockSize / 2];
+ Array.Copy(buffer, bufOff, temp, 0, blockSize / 2);
+ //Console.WriteLine(Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(buffer));
+ //Console.WriteLine(buffer.Length);
+ //Console.WriteLine("b: " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(temp));
+
+ bTemp.Add(temp);
+
+ bHalfBlocksLen -= blockSize / 2;
+ bufOff += blockSize / 2;
+ }
+
+ for (int j = 0; j < V; j++)
+ {
+ Array.Copy(B, 0, buffer, 0, blockSize / 2);
+ Array.Copy((byte[])bTemp[0], 0, buffer, blockSize / 2, blockSize / 2);
+
+ engine.ProcessBlock(buffer, 0, buffer, 0);
+
+ byte[] intArray = Pack.UInt32_To_LE((uint)(j + 1));
+ for (int byteNum = 0; byteNum < intArray.Length; byteNum++)
+ {
+ buffer[byteNum + blockSize / 2] ^= intArray[byteNum];
+ }
+
+ Array.Copy(buffer, blockSize / 2, B, 0, blockSize / 2);
+
+ for (int i = 2; i < n; i++)
+ {
+ Array.Copy((byte[])bTemp[i - 1], 0, (byte[])bTemp[i - 2], 0, blockSize / 2);
+ }
+
+ Array.Copy(buffer, 0, (byte[])bTemp[n - 2], 0, blockSize / 2);
+
+ //Console.WriteLine("B" + j.ToString() + ": " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(B));
+ //Console.WriteLine("b: " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(bTemp[0]));
+ //Console.WriteLine("b: " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(bTemp[1]));
+ //Console.WriteLine("b: " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(bTemp[2]));
+
+ //Console.WriteLine(Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(buffer));
+ }
+
+ Array.Copy(B, 0, buffer, 0, blockSize / 2);
+ bufOff = blockSize / 2;
+
+ for (int i = 0; i < n - 1; i++)
+ {
+ Array.Copy((byte[])bTemp[i], 0, buffer, bufOff, blockSize / 2);
+ bufOff += blockSize / 2;
+ }
+
+ return buffer;
+ }
+
+ public byte[] Unwrap(byte[] input, int inOff, int length)
+ {
+ if (forWrapping)
+ throw new InvalidOperationException("not set for unwrapping");
+
+ if (length % blockSize != 0)
+ throw new ArgumentException("Padding not supported");
+
+ int n = 2 * length / blockSize;
+ int V = (n - 1) * 6;
+
+ byte[] buffer = new byte[length];
+ Array.Copy(input, inOff, buffer, 0, length);
+
+ byte[] B = new byte[blockSize / 2];
+ Array.Copy(buffer, 0, B, 0, blockSize / 2);
+ //Console.WriteLine("B18: " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(B));
+
+ IList bTemp = Platform.CreateArrayList();
+
+ int bHalfBlocksLen = buffer.Length - blockSize / 2;
+ int bufOff = blockSize / 2;
+ while (bHalfBlocksLen != 0)
+ {
+ byte[] temp = new byte[blockSize / 2];
+ Array.Copy(buffer, bufOff, temp, 0, blockSize / 2);
+ //Console.WriteLine(Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(buffer));
+ //Console.WriteLine(buffer.Length);
+ //Console.WriteLine("b: " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(temp));
+
+ bTemp.Add(temp);
+
+ bHalfBlocksLen -= blockSize / 2;
+ bufOff += blockSize / 2;
+ }
+
+ for (int j = 0; j < V; j++)
+ {
+ Array.Copy((byte[])bTemp[n - 2], 0, buffer, 0, blockSize / 2);
+ Array.Copy(B, 0, buffer, blockSize / 2, blockSize / 2);
+
+ byte[] intArray = Pack.UInt32_To_LE((uint)(V - j));
+ for (int byteNum = 0; byteNum < intArray.Length; byteNum++)
+ {
+ buffer[byteNum + blockSize / 2] ^= intArray[byteNum];
+ }
+
+ //Console.WriteLine(Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(buffer));
+
+ engine.ProcessBlock(buffer, 0, buffer, 0);
+
+ //Console.WriteLine(Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(buffer));
+
+ Array.Copy(buffer, 0, B, 0, blockSize / 2);
+
+ for (int i = 2; i < n; i++)
+ {
+ Array.Copy((byte[])bTemp[n - i - 1], 0, (byte[])bTemp[n - i], 0, blockSize / 2);
+ }
+
+ Array.Copy(buffer, blockSize / 2, (byte[])bTemp[0], 0, blockSize / 2);
+
+ //Console.WriteLine("B" + (V - j - 1).ToString() + ": " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(B));
+ //Console.WriteLine("b: " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(bTemp[0]));
+ //Console.WriteLine("b: " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(bTemp[1]));
+ //Console.WriteLine("b: " + Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(bTemp[2]));
+
+ //Console.WriteLine(Org.BouncyCastle.Utilities.Encoders.Hex.ToHexString(buffer));
+ }
+
+ Array.Copy(B, 0, buffer, 0, blockSize / 2);
+ bufOff = blockSize / 2;
+
+ for (int i = 0; i < n - 1; i++)
+ {
+ Array.Copy((byte[])bTemp[i], 0, buffer, bufOff, blockSize / 2);
+ bufOff += blockSize / 2;
+ }
+
+ byte diff = 0;
+ for (int i = buffer.Length - blockSize; i < buffer.Length; ++i)
+ {
+ diff |= buffer[i];
+ }
+
+ if (diff != 0)
+ throw new InvalidCipherTextException("checksum failed");
+
+ return Arrays.CopyOfRange(buffer, 0, buffer.Length - blockSize);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/ElGamalEngine.cs b/bc-sharp-crypto/src/crypto/engines/ElGamalEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..197d7bc151f9bd1ff50007d26fc66c7c0aa36d87
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/ElGamalEngine.cs
@@ -0,0 +1,178 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * this does your basic ElGamal algorithm.
+ */
+ public class ElGamalEngine
+ : IAsymmetricBlockCipher
+ {
+ private ElGamalKeyParameters key;
+ private SecureRandom random;
+ private bool forEncryption;
+ private int bitSize;
+
+ public virtual string AlgorithmName
+ {
+ get { return "ElGamal"; }
+ }
+
+ /**
+ * initialise the ElGamal engine.
+ *
+ * @param forEncryption true if we are encrypting, false otherwise.
+ * @param param the necessary ElGamal key parameters.
+ */
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom p = (ParametersWithRandom) parameters;
+
+ this.key = (ElGamalKeyParameters) p.Parameters;
+ this.random = p.Random;
+ }
+ else
+ {
+ this.key = (ElGamalKeyParameters) parameters;
+ this.random = new SecureRandom();
+ }
+
+ this.forEncryption = forEncryption;
+ this.bitSize = key.Parameters.P.BitLength;
+
+ if (forEncryption)
+ {
+ if (!(key is ElGamalPublicKeyParameters))
+ {
+ throw new ArgumentException("ElGamalPublicKeyParameters are required for encryption.");
+ }
+ }
+ else
+ {
+ if (!(key is ElGamalPrivateKeyParameters))
+ {
+ throw new ArgumentException("ElGamalPrivateKeyParameters are required for decryption.");
+ }
+ }
+ }
+
+ /**
+ * Return the maximum size for an input block to this engine.
+ * For ElGamal this is always one byte less than the size of P on
+ * encryption, and twice the length as the size of P on decryption.
+ *
+ * @return maximum size for an input block.
+ */
+ public virtual int GetInputBlockSize()
+ {
+ if (forEncryption)
+ {
+ return (bitSize - 1) / 8;
+ }
+
+ return 2 * ((bitSize + 7) / 8);
+ }
+
+ /**
+ * Return the maximum size for an output block to this engine.
+ * For ElGamal this is always one byte less than the size of P on
+ * decryption, and twice the length as the size of P on encryption.
+ *
+ * @return maximum size for an output block.
+ */
+ public virtual int GetOutputBlockSize()
+ {
+ if (forEncryption)
+ {
+ return 2 * ((bitSize + 7) / 8);
+ }
+
+ return (bitSize - 1) / 8;
+ }
+
+ /**
+ * Process a single block using the basic ElGamal algorithm.
+ *
+ * @param in the input array.
+ * @param inOff the offset into the input buffer where the data starts.
+ * @param length the length of the data to be processed.
+ * @return the result of the ElGamal process.
+ * @exception DataLengthException the input block is too large.
+ */
+ public virtual byte[] ProcessBlock(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (key == null)
+ throw new InvalidOperationException("ElGamal engine not initialised");
+
+ int maxLength = forEncryption
+ ? (bitSize - 1 + 7) / 8
+ : GetInputBlockSize();
+
+ if (length > maxLength)
+ throw new DataLengthException("input too large for ElGamal cipher.\n");
+
+ BigInteger p = key.Parameters.P;
+
+ byte[] output;
+ if (key is ElGamalPrivateKeyParameters) // decryption
+ {
+ int halfLength = length / 2;
+ BigInteger gamma = new BigInteger(1, input, inOff, halfLength);
+ BigInteger phi = new BigInteger(1, input, inOff + halfLength, halfLength);
+
+ ElGamalPrivateKeyParameters priv = (ElGamalPrivateKeyParameters) key;
+
+ // a shortcut, which generally relies on p being prime amongst other things.
+ // if a problem with this shows up, check the p and g values!
+ BigInteger m = gamma.ModPow(p.Subtract(BigInteger.One).Subtract(priv.X), p).Multiply(phi).Mod(p);
+
+ output = m.ToByteArrayUnsigned();
+ }
+ else // encryption
+ {
+ BigInteger tmp = new BigInteger(1, input, inOff, length);
+
+ if (tmp.BitLength >= p.BitLength)
+ throw new DataLengthException("input too large for ElGamal cipher.\n");
+
+
+ ElGamalPublicKeyParameters pub = (ElGamalPublicKeyParameters) key;
+
+ BigInteger pSub2 = p.Subtract(BigInteger.Two);
+
+ // TODO In theory, a series of 'k', 'g.ModPow(k, p)' and 'y.ModPow(k, p)' can be pre-calculated
+ BigInteger k;
+ do
+ {
+ k = new BigInteger(p.BitLength, random);
+ }
+ while (k.SignValue == 0 || k.CompareTo(pSub2) > 0);
+
+ BigInteger g = key.Parameters.G;
+ BigInteger gamma = g.ModPow(k, p);
+ BigInteger phi = tmp.Multiply(pub.Y.ModPow(k, p)).Mod(p);
+
+ output = new byte[this.GetOutputBlockSize()];
+
+ // TODO Add methods to allow writing BigInteger to existing byte array?
+ byte[] out1 = gamma.ToByteArrayUnsigned();
+ byte[] out2 = phi.ToByteArrayUnsigned();
+ out1.CopyTo(output, output.Length / 2 - out1.Length);
+ out2.CopyTo(output, output.Length - out2.Length);
+ }
+
+ return output;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/GOST28147Engine.cs b/bc-sharp-crypto/src/crypto/engines/GOST28147Engine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..71e6d9e44b64d6cd2487d3f6488436238b7b779d
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/GOST28147Engine.cs
@@ -0,0 +1,368 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * implementation of GOST 28147-89
+ */
+ public class Gost28147Engine
+ : IBlockCipher
+ {
+ private const int BlockSize = 8;
+ private int[] workingKey = null;
+ private bool forEncryption;
+
+ private byte[] S = Sbox_Default;
+
+ // these are the S-boxes given in Applied Cryptography 2nd Ed., p. 333
+ // This is default S-box!
+ private static readonly byte[] Sbox_Default = {
+ 0x4,0xA,0x9,0x2,0xD,0x8,0x0,0xE,0x6,0xB,0x1,0xC,0x7,0xF,0x5,0x3,
+ 0xE,0xB,0x4,0xC,0x6,0xD,0xF,0xA,0x2,0x3,0x8,0x1,0x0,0x7,0x5,0x9,
+ 0x5,0x8,0x1,0xD,0xA,0x3,0x4,0x2,0xE,0xF,0xC,0x7,0x6,0x0,0x9,0xB,
+ 0x7,0xD,0xA,0x1,0x0,0x8,0x9,0xF,0xE,0x4,0x6,0xC,0xB,0x2,0x5,0x3,
+ 0x6,0xC,0x7,0x1,0x5,0xF,0xD,0x8,0x4,0xA,0x9,0xE,0x0,0x3,0xB,0x2,
+ 0x4,0xB,0xA,0x0,0x7,0x2,0x1,0xD,0x3,0x6,0x8,0x5,0x9,0xC,0xF,0xE,
+ 0xD,0xB,0x4,0x1,0x3,0xF,0x5,0x9,0x0,0xA,0xE,0x7,0x6,0x8,0x2,0xC,
+ 0x1,0xF,0xD,0x0,0x5,0x7,0xA,0x4,0x9,0x2,0x3,0xE,0x6,0xB,0x8,0xC
+ };
+
+ /*
+ * class content S-box parameters for encrypting
+ * getting from, see: http://tools.ietf.org/id/draft-popov-cryptopro-cpalgs-01.txt
+ * http://tools.ietf.org/id/draft-popov-cryptopro-cpalgs-02.txt
+ */
+ private static readonly byte[] ESbox_Test = {
+ 0x4,0x2,0xF,0x5,0x9,0x1,0x0,0x8,0xE,0x3,0xB,0xC,0xD,0x7,0xA,0x6,
+ 0xC,0x9,0xF,0xE,0x8,0x1,0x3,0xA,0x2,0x7,0x4,0xD,0x6,0x0,0xB,0x5,
+ 0xD,0x8,0xE,0xC,0x7,0x3,0x9,0xA,0x1,0x5,0x2,0x4,0x6,0xF,0x0,0xB,
+ 0xE,0x9,0xB,0x2,0x5,0xF,0x7,0x1,0x0,0xD,0xC,0x6,0xA,0x4,0x3,0x8,
+ 0x3,0xE,0x5,0x9,0x6,0x8,0x0,0xD,0xA,0xB,0x7,0xC,0x2,0x1,0xF,0x4,
+ 0x8,0xF,0x6,0xB,0x1,0x9,0xC,0x5,0xD,0x3,0x7,0xA,0x0,0xE,0x2,0x4,
+ 0x9,0xB,0xC,0x0,0x3,0x6,0x7,0x5,0x4,0x8,0xE,0xF,0x1,0xA,0x2,0xD,
+ 0xC,0x6,0x5,0x2,0xB,0x0,0x9,0xD,0x3,0xE,0x7,0xA,0xF,0x4,0x1,0x8
+ };
+
+ private static readonly byte[] ESbox_A = {
+ 0x9,0x6,0x3,0x2,0x8,0xB,0x1,0x7,0xA,0x4,0xE,0xF,0xC,0x0,0xD,0x5,
+ 0x3,0x7,0xE,0x9,0x8,0xA,0xF,0x0,0x5,0x2,0x6,0xC,0xB,0x4,0xD,0x1,
+ 0xE,0x4,0x6,0x2,0xB,0x3,0xD,0x8,0xC,0xF,0x5,0xA,0x0,0x7,0x1,0x9,
+ 0xE,0x7,0xA,0xC,0xD,0x1,0x3,0x9,0x0,0x2,0xB,0x4,0xF,0x8,0x5,0x6,
+ 0xB,0x5,0x1,0x9,0x8,0xD,0xF,0x0,0xE,0x4,0x2,0x3,0xC,0x7,0xA,0x6,
+ 0x3,0xA,0xD,0xC,0x1,0x2,0x0,0xB,0x7,0x5,0x9,0x4,0x8,0xF,0xE,0x6,
+ 0x1,0xD,0x2,0x9,0x7,0xA,0x6,0x0,0x8,0xC,0x4,0x5,0xF,0x3,0xB,0xE,
+ 0xB,0xA,0xF,0x5,0x0,0xC,0xE,0x8,0x6,0x2,0x3,0x9,0x1,0x7,0xD,0x4
+ };
+
+ private static readonly byte[] ESbox_B = {
+ 0x8,0x4,0xB,0x1,0x3,0x5,0x0,0x9,0x2,0xE,0xA,0xC,0xD,0x6,0x7,0xF,
+ 0x0,0x1,0x2,0xA,0x4,0xD,0x5,0xC,0x9,0x7,0x3,0xF,0xB,0x8,0x6,0xE,
+ 0xE,0xC,0x0,0xA,0x9,0x2,0xD,0xB,0x7,0x5,0x8,0xF,0x3,0x6,0x1,0x4,
+ 0x7,0x5,0x0,0xD,0xB,0x6,0x1,0x2,0x3,0xA,0xC,0xF,0x4,0xE,0x9,0x8,
+ 0x2,0x7,0xC,0xF,0x9,0x5,0xA,0xB,0x1,0x4,0x0,0xD,0x6,0x8,0xE,0x3,
+ 0x8,0x3,0x2,0x6,0x4,0xD,0xE,0xB,0xC,0x1,0x7,0xF,0xA,0x0,0x9,0x5,
+ 0x5,0x2,0xA,0xB,0x9,0x1,0xC,0x3,0x7,0x4,0xD,0x0,0x6,0xF,0x8,0xE,
+ 0x0,0x4,0xB,0xE,0x8,0x3,0x7,0x1,0xA,0x2,0x9,0x6,0xF,0xD,0x5,0xC
+ };
+
+ private static readonly byte[] ESbox_C = {
+ 0x1,0xB,0xC,0x2,0x9,0xD,0x0,0xF,0x4,0x5,0x8,0xE,0xA,0x7,0x6,0x3,
+ 0x0,0x1,0x7,0xD,0xB,0x4,0x5,0x2,0x8,0xE,0xF,0xC,0x9,0xA,0x6,0x3,
+ 0x8,0x2,0x5,0x0,0x4,0x9,0xF,0xA,0x3,0x7,0xC,0xD,0x6,0xE,0x1,0xB,
+ 0x3,0x6,0x0,0x1,0x5,0xD,0xA,0x8,0xB,0x2,0x9,0x7,0xE,0xF,0xC,0x4,
+ 0x8,0xD,0xB,0x0,0x4,0x5,0x1,0x2,0x9,0x3,0xC,0xE,0x6,0xF,0xA,0x7,
+ 0xC,0x9,0xB,0x1,0x8,0xE,0x2,0x4,0x7,0x3,0x6,0x5,0xA,0x0,0xF,0xD,
+ 0xA,0x9,0x6,0x8,0xD,0xE,0x2,0x0,0xF,0x3,0x5,0xB,0x4,0x1,0xC,0x7,
+ 0x7,0x4,0x0,0x5,0xA,0x2,0xF,0xE,0xC,0x6,0x1,0xB,0xD,0x9,0x3,0x8
+ };
+
+ private static readonly byte[] ESbox_D = {
+ 0xF,0xC,0x2,0xA,0x6,0x4,0x5,0x0,0x7,0x9,0xE,0xD,0x1,0xB,0x8,0x3,
+ 0xB,0x6,0x3,0x4,0xC,0xF,0xE,0x2,0x7,0xD,0x8,0x0,0x5,0xA,0x9,0x1,
+ 0x1,0xC,0xB,0x0,0xF,0xE,0x6,0x5,0xA,0xD,0x4,0x8,0x9,0x3,0x7,0x2,
+ 0x1,0x5,0xE,0xC,0xA,0x7,0x0,0xD,0x6,0x2,0xB,0x4,0x9,0x3,0xF,0x8,
+ 0x0,0xC,0x8,0x9,0xD,0x2,0xA,0xB,0x7,0x3,0x6,0x5,0x4,0xE,0xF,0x1,
+ 0x8,0x0,0xF,0x3,0x2,0x5,0xE,0xB,0x1,0xA,0x4,0x7,0xC,0x9,0xD,0x6,
+ 0x3,0x0,0x6,0xF,0x1,0xE,0x9,0x2,0xD,0x8,0xC,0x4,0xB,0xA,0x5,0x7,
+ 0x1,0xA,0x6,0x8,0xF,0xB,0x0,0x4,0xC,0x3,0x5,0x9,0x7,0xD,0x2,0xE
+ };
+
+ //S-box for digest
+ private static readonly byte[] DSbox_Test = {
+ 0x4,0xA,0x9,0x2,0xD,0x8,0x0,0xE,0x6,0xB,0x1,0xC,0x7,0xF,0x5,0x3,
+ 0xE,0xB,0x4,0xC,0x6,0xD,0xF,0xA,0x2,0x3,0x8,0x1,0x0,0x7,0x5,0x9,
+ 0x5,0x8,0x1,0xD,0xA,0x3,0x4,0x2,0xE,0xF,0xC,0x7,0x6,0x0,0x9,0xB,
+ 0x7,0xD,0xA,0x1,0x0,0x8,0x9,0xF,0xE,0x4,0x6,0xC,0xB,0x2,0x5,0x3,
+ 0x6,0xC,0x7,0x1,0x5,0xF,0xD,0x8,0x4,0xA,0x9,0xE,0x0,0x3,0xB,0x2,
+ 0x4,0xB,0xA,0x0,0x7,0x2,0x1,0xD,0x3,0x6,0x8,0x5,0x9,0xC,0xF,0xE,
+ 0xD,0xB,0x4,0x1,0x3,0xF,0x5,0x9,0x0,0xA,0xE,0x7,0x6,0x8,0x2,0xC,
+ 0x1,0xF,0xD,0x0,0x5,0x7,0xA,0x4,0x9,0x2,0x3,0xE,0x6,0xB,0x8,0xC
+ };
+
+ private static readonly byte[] DSbox_A = {
+ 0xA,0x4,0x5,0x6,0x8,0x1,0x3,0x7,0xD,0xC,0xE,0x0,0x9,0x2,0xB,0xF,
+ 0x5,0xF,0x4,0x0,0x2,0xD,0xB,0x9,0x1,0x7,0x6,0x3,0xC,0xE,0xA,0x8,
+ 0x7,0xF,0xC,0xE,0x9,0x4,0x1,0x0,0x3,0xB,0x5,0x2,0x6,0xA,0x8,0xD,
+ 0x4,0xA,0x7,0xC,0x0,0xF,0x2,0x8,0xE,0x1,0x6,0x5,0xD,0xB,0x9,0x3,
+ 0x7,0x6,0x4,0xB,0x9,0xC,0x2,0xA,0x1,0x8,0x0,0xE,0xF,0xD,0x3,0x5,
+ 0x7,0x6,0x2,0x4,0xD,0x9,0xF,0x0,0xA,0x1,0x5,0xB,0x8,0xE,0xC,0x3,
+ 0xD,0xE,0x4,0x1,0x7,0x0,0x5,0xA,0x3,0xC,0x8,0xF,0x6,0x2,0x9,0xB,
+ 0x1,0x3,0xA,0x9,0x5,0xB,0x4,0xF,0x8,0x6,0x7,0xE,0xD,0x0,0x2,0xC
+ };
+
+ //
+ // pre-defined sbox table
+ //
+ private static readonly IDictionary sBoxes = Platform.CreateHashtable();
+
+ static Gost28147Engine()
+ {
+ AddSBox("Default", Sbox_Default);
+ AddSBox("E-TEST", ESbox_Test);
+ AddSBox("E-A", ESbox_A);
+ AddSBox("E-B", ESbox_B);
+ AddSBox("E-C", ESbox_C);
+ AddSBox("E-D", ESbox_D);
+ AddSBox("D-TEST", DSbox_Test);
+ AddSBox("D-A", DSbox_A);
+ }
+
+ private static void AddSBox(string sBoxName, byte[] sBox)
+ {
+ sBoxes.Add(Platform.ToUpperInvariant(sBoxName), sBox);
+ }
+
+ /**
+ * standard constructor.
+ */
+ public Gost28147Engine()
+ {
+ }
+
+ /**
+ * initialise an Gost28147 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 virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithSBox)
+ {
+ ParametersWithSBox param = (ParametersWithSBox)parameters;
+
+ //
+ // Set the S-Box
+ //
+ byte[] sBox = param.GetSBox();
+ if (sBox.Length != Sbox_Default.Length)
+ throw new ArgumentException("invalid S-box passed to GOST28147 init");
+
+ this.S = Arrays.Clone(sBox);
+
+ //
+ // set key if there is one
+ //
+ if (param.Parameters != null)
+ {
+ workingKey = generateWorkingKey(forEncryption,
+ ((KeyParameter)param.Parameters).GetKey());
+ }
+ }
+ else if (parameters is KeyParameter)
+ {
+ workingKey = generateWorkingKey(forEncryption,
+ ((KeyParameter)parameters).GetKey());
+ }
+ else if (parameters != null)
+ {
+ throw new ArgumentException("invalid parameter passed to Gost28147 init - "
+ + Platform.GetTypeName(parameters));
+ }
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Gost28147"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BlockSize;
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (workingKey == null)
+ throw new InvalidOperationException("Gost28147 engine not initialised");
+
+ Check.DataLength(input, inOff, BlockSize, "input buffer too short");
+ Check.OutputLength(output, outOff, BlockSize, "output buffer too short");
+
+ Gost28147Func(workingKey, input, inOff, output, outOff);
+
+ return BlockSize;
+ }
+
+ 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++)
+ {
+ key[i] = bytesToint(userKey,i*4);
+ }
+
+ return key;
+ }
+
+ private int Gost28147_mainStep(int n1, int key)
+ {
+ int cm = (key + n1); // CM1
+
+ // S-box replacing
+
+ int om = S[ 0 + ((cm >> (0 * 4)) & 0xF)] << (0 * 4);
+ om += S[ 16 + ((cm >> (1 * 4)) & 0xF)] << (1 * 4);
+ om += S[ 32 + ((cm >> (2 * 4)) & 0xF)] << (2 * 4);
+ om += S[ 48 + ((cm >> (3 * 4)) & 0xF)] << (3 * 4);
+ om += S[ 64 + ((cm >> (4 * 4)) & 0xF)] << (4 * 4);
+ om += S[ 80 + ((cm >> (5 * 4)) & 0xF)] << (5 * 4);
+ om += S[ 96 + ((cm >> (6 * 4)) & 0xF)] << (6 * 4);
+ om += S[112 + ((cm >> (7 * 4)) & 0xF)] << (7 * 4);
+
+// return om << 11 | om >>> (32-11); // 11-leftshift
+ int omLeft = om << 11;
+ int omRight = (int)(((uint) om) >> (32 - 11)); // Note: Casts required to get unsigned bit rotation
+
+ return omLeft | omRight;
+ }
+
+ private void Gost28147Func(
+ int[] workingKey,
+ byte[] inBytes,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ int N1, N2, tmp; //tmp -> for saving N1
+ N1 = bytesToint(inBytes, inOff);
+ N2 = bytesToint(inBytes, inOff + 4);
+
+ 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)
+
+ intTobytes(N1, outBytes, outOff);
+ intTobytes(N2, outBytes, outOff + 4);
+ }
+
+ //array of bytes to type int
+ private static 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 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;
+ }
+
+ /**
+ * Return the S-Box associated with SBoxName
+ * @param sBoxName name of the S-Box
+ * @return byte array representing the S-Box
+ */
+ public static byte[] GetSBox(
+ string sBoxName)
+ {
+ byte[] sBox = (byte[])sBoxes[Platform.ToUpperInvariant(sBoxName)];
+
+ if (sBox == null)
+ {
+ throw new ArgumentException("Unknown S-Box - possible types: "
+ + "\"Default\", \"E-Test\", \"E-A\", \"E-B\", \"E-C\", \"E-D\", \"D-Test\", \"D-A\".");
+ }
+
+ return Arrays.Clone(sBox);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/HC128Engine.cs b/bc-sharp-crypto/src/crypto/engines/HC128Engine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b83eb70836187399780ef459bad47e859db7cf44
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/HC128Engine.cs
@@ -0,0 +1,235 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * HC-128 is a software-efficient stream cipher created by Hongjun Wu. It
+ * generates keystream from a 128-bit secret key and a 128-bit initialization
+ * vector.
+ *
+ * http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf
+ *
+ * It is a third phase candidate in the eStream contest, and is patent-free.
+ * No attacks are known as of today (April 2007). See
+ *
+ * http://www.ecrypt.eu.org/stream/hcp3.html
+ *
+ */
+ public class HC128Engine
+ : IStreamCipher
+ {
+ private uint[] p = new uint[512];
+ private uint[] q = new uint[512];
+ private uint cnt = 0;
+
+ private static uint F1(uint x)
+ {
+ return RotateRight(x, 7) ^ RotateRight(x, 18) ^ (x >> 3);
+ }
+
+ private static uint F2(uint x)
+ {
+ return RotateRight(x, 17) ^ RotateRight(x, 19) ^ (x >> 10);
+ }
+
+ private uint G1(uint x, uint y, uint z)
+ {
+ return (RotateRight(x, 10) ^ RotateRight(z, 23)) + RotateRight(y, 8);
+ }
+
+ private uint G2(uint x, uint y, uint z)
+ {
+ return (RotateLeft(x, 10) ^ RotateLeft(z, 23)) + RotateLeft(y, 8);
+ }
+
+ private static uint RotateLeft(uint x, int bits)
+ {
+ return (x << bits) | (x >> -bits);
+ }
+
+ private static uint RotateRight(uint x, int bits)
+ {
+ return (x >> bits) | (x << -bits);
+ }
+
+ private uint H1(uint x)
+ {
+ return q[x & 0xFF] + q[((x >> 16) & 0xFF) + 256];
+ }
+
+ private uint H2(uint x)
+ {
+ return p[x & 0xFF] + p[((x >> 16) & 0xFF) + 256];
+ }
+
+ private static uint Mod1024(uint x)
+ {
+ return x & 0x3FF;
+ }
+
+ private static uint Mod512(uint x)
+ {
+ return x & 0x1FF;
+ }
+
+ private static uint Dim(uint x, uint y)
+ {
+ return Mod512(x - y);
+ }
+
+ private uint Step()
+ {
+ uint j = Mod512(cnt);
+ uint ret;
+ if (cnt < 512)
+ {
+ p[j] += G1(p[Dim(j, 3)], p[Dim(j, 10)], p[Dim(j, 511)]);
+ ret = H1(p[Dim(j, 12)]) ^ p[j];
+ }
+ else
+ {
+ q[j] += G2(q[Dim(j, 3)], q[Dim(j, 10)], q[Dim(j, 511)]);
+ ret = H2(q[Dim(j, 12)]) ^ q[j];
+ }
+ cnt = Mod1024(cnt + 1);
+ return ret;
+ }
+
+ private byte[] key, iv;
+ private bool initialised;
+
+ private void Init()
+ {
+ if (key.Length != 16)
+ throw new ArgumentException("The key must be 128 bits long");
+
+ idx = 0;
+ cnt = 0;
+
+ uint[] w = new uint[1280];
+
+ for (int i = 0; i < 16; i++)
+ {
+ w[i >> 2] |= ((uint)key[i] << (8 * (i & 0x3)));
+ }
+ Array.Copy(w, 0, w, 4, 4);
+
+ for (int i = 0; i < iv.Length && i < 16; i++)
+ {
+ w[(i >> 2) + 8] |= ((uint)iv[i] << (8 * (i & 0x3)));
+ }
+ Array.Copy(w, 8, w, 12, 4);
+
+ for (uint i = 16; i < 1280; i++)
+ {
+ w[i] = F2(w[i - 2]) + w[i - 7] + F1(w[i - 15]) + w[i - 16] + i;
+ }
+
+ Array.Copy(w, 256, p, 0, 512);
+ Array.Copy(w, 768, q, 0, 512);
+
+ for (int i = 0; i < 512; i++)
+ {
+ p[i] = Step();
+ }
+ for (int i = 0; i < 512; i++)
+ {
+ q[i] = Step();
+ }
+
+ cnt = 0;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "HC-128"; }
+ }
+
+ /**
+ * Initialise a HC-128 cipher.
+ *
+ * @param forEncryption whether or not we are for encryption. Irrelevant, as
+ * encryption and decryption are the same.
+ * @param params the parameters required to set up the cipher.
+ * @throws ArgumentException if the params argument is
+ * inappropriate (ie. the key is not 128 bit long).
+ */
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ ICipherParameters keyParam = parameters;
+
+ if (parameters is ParametersWithIV)
+ {
+ iv = ((ParametersWithIV)parameters).GetIV();
+ keyParam = ((ParametersWithIV)parameters).Parameters;
+ }
+ else
+ {
+ iv = new byte[0];
+ }
+
+ if (keyParam is KeyParameter)
+ {
+ key = ((KeyParameter)keyParam).GetKey();
+ Init();
+ }
+ else
+ {
+ throw new ArgumentException(
+ "Invalid parameter passed to HC128 init - " + Platform.GetTypeName(parameters),
+ "parameters");
+ }
+
+ initialised = true;
+ }
+
+ private byte[] buf = new byte[4];
+ private int idx = 0;
+
+ private byte GetByte()
+ {
+ if (idx == 0)
+ {
+ Pack.UInt32_To_LE(Step(), buf);
+ }
+ byte ret = buf[idx];
+ idx = idx + 1 & 0x3;
+ return ret;
+ }
+
+ public virtual void ProcessBytes(
+ byte[] input,
+ int inOff,
+ int len,
+ byte[] output,
+ int outOff)
+ {
+ if (!initialised)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ Check.DataLength(input, inOff, len, "input buffer too short");
+ Check.OutputLength(output, outOff, len, "output buffer too short");
+
+ for (int i = 0; i < len; i++)
+ {
+ output[outOff + i] = (byte)(input[inOff + i] ^ GetByte());
+ }
+ }
+
+ public virtual void Reset()
+ {
+ Init();
+ }
+
+ public virtual byte ReturnByte(byte input)
+ {
+ return (byte)(input ^ GetByte());
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/HC256Engine.cs b/bc-sharp-crypto/src/crypto/engines/HC256Engine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d8d83a634d003316a3f08e9fc1b07e7e913267a0
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/HC256Engine.cs
@@ -0,0 +1,224 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * HC-256 is a software-efficient stream cipher created by Hongjun Wu. It
+ * generates keystream from a 256-bit secret key and a 256-bit initialization
+ * vector.
+ *
+ * http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc256_p3.pdf
+ *
+ * Its brother, HC-128, is a third phase candidate in the eStream contest.
+ * The algorithm is patent-free. No attacks are known as of today (April 2007).
+ * See
+ *
+ * http://www.ecrypt.eu.org/stream/hcp3.html
+ *
+ */
+ public class HC256Engine
+ : IStreamCipher
+ {
+ private uint[] p = new uint[1024];
+ private uint[] q = new uint[1024];
+ private uint cnt = 0;
+
+ private uint Step()
+ {
+ uint j = cnt & 0x3FF;
+ uint ret;
+ if (cnt < 1024)
+ {
+ uint x = p[(j - 3 & 0x3FF)];
+ uint y = p[(j - 1023 & 0x3FF)];
+ p[j] += p[(j - 10 & 0x3FF)]
+ + (RotateRight(x, 10) ^ RotateRight(y, 23))
+ + q[((x ^ y) & 0x3FF)];
+
+ x = p[(j - 12 & 0x3FF)];
+ ret = (q[x & 0xFF] + q[((x >> 8) & 0xFF) + 256]
+ + q[((x >> 16) & 0xFF) + 512] + q[((x >> 24) & 0xFF) + 768])
+ ^ p[j];
+ }
+ else
+ {
+ uint x = q[(j - 3 & 0x3FF)];
+ uint y = q[(j - 1023 & 0x3FF)];
+ q[j] += q[(j - 10 & 0x3FF)]
+ + (RotateRight(x, 10) ^ RotateRight(y, 23))
+ + p[((x ^ y) & 0x3FF)];
+
+ x = q[(j - 12 & 0x3FF)];
+ ret = (p[x & 0xFF] + p[((x >> 8) & 0xFF) + 256]
+ + p[((x >> 16) & 0xFF) + 512] + p[((x >> 24) & 0xFF) + 768])
+ ^ q[j];
+ }
+ cnt = cnt + 1 & 0x7FF;
+ return ret;
+ }
+
+ private byte[] key, iv;
+ private bool initialised;
+
+ private void Init()
+ {
+ if (key.Length != 32 && key.Length != 16)
+ throw new ArgumentException("The key must be 128/256 bits long");
+
+ if (iv.Length < 16)
+ throw new ArgumentException("The IV must be at least 128 bits long");
+
+ if (key.Length != 32)
+ {
+ byte[] k = new byte[32];
+
+ Array.Copy(key, 0, k, 0, key.Length);
+ Array.Copy(key, 0, k, 16, key.Length);
+
+ key = k;
+ }
+
+ if (iv.Length < 32)
+ {
+ byte[] newIV = new byte[32];
+
+ Array.Copy(iv, 0, newIV, 0, iv.Length);
+ Array.Copy(iv, 0, newIV, iv.Length, newIV.Length - iv.Length);
+
+ iv = newIV;
+ }
+
+ idx = 0;
+ cnt = 0;
+
+ uint[] w = new uint[2560];
+
+ for (int i = 0; i < 32; i++)
+ {
+ w[i >> 2] |= ((uint)key[i] << (8 * (i & 0x3)));
+ }
+
+ for (int i = 0; i < 32; i++)
+ {
+ w[(i >> 2) + 8] |= ((uint)iv[i] << (8 * (i & 0x3)));
+ }
+
+ for (uint i = 16; i < 2560; i++)
+ {
+ uint x = w[i - 2];
+ uint y = w[i - 15];
+ w[i] = (RotateRight(x, 17) ^ RotateRight(x, 19) ^ (x >> 10))
+ + w[i - 7]
+ + (RotateRight(y, 7) ^ RotateRight(y, 18) ^ (y >> 3))
+ + w[i - 16] + i;
+ }
+
+ Array.Copy(w, 512, p, 0, 1024);
+ Array.Copy(w, 1536, q, 0, 1024);
+
+ for (int i = 0; i < 4096; i++)
+ {
+ Step();
+ }
+
+ cnt = 0;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "HC-256"; }
+ }
+
+ /**
+ * Initialise a HC-256 cipher.
+ *
+ * @param forEncryption whether or not we are for encryption. Irrelevant, as
+ * encryption and decryption are the same.
+ * @param params the parameters required to set up the cipher.
+ * @throws ArgumentException if the params argument is
+ * inappropriate (ie. the key is not 256 bit long).
+ */
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ ICipherParameters keyParam = parameters;
+
+ if (parameters is ParametersWithIV)
+ {
+ iv = ((ParametersWithIV)parameters).GetIV();
+ keyParam = ((ParametersWithIV)parameters).Parameters;
+ }
+ else
+ {
+ iv = new byte[0];
+ }
+
+ if (keyParam is KeyParameter)
+ {
+ key = ((KeyParameter)keyParam).GetKey();
+ Init();
+ }
+ else
+ {
+ throw new ArgumentException(
+ "Invalid parameter passed to HC256 init - " + Platform.GetTypeName(parameters),
+ "parameters");
+ }
+
+ initialised = true;
+ }
+
+ private byte[] buf = new byte[4];
+ private int idx = 0;
+
+ private byte GetByte()
+ {
+ if (idx == 0)
+ {
+ Pack.UInt32_To_LE(Step(), buf);
+ }
+ byte ret = buf[idx];
+ idx = idx + 1 & 0x3;
+ return ret;
+ }
+
+ public virtual void ProcessBytes(
+ byte[] input,
+ int inOff,
+ int len,
+ byte[] output,
+ int outOff)
+ {
+ if (!initialised)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ Check.DataLength(input, inOff, len, "input buffer too short");
+ Check.OutputLength(output, outOff, len, "output buffer too short");
+
+ for (int i = 0; i < len; i++)
+ {
+ output[outOff + i] = (byte)(input[inOff + i] ^ GetByte());
+ }
+ }
+
+ public virtual void Reset()
+ {
+ Init();
+ }
+
+ public virtual byte ReturnByte(byte input)
+ {
+ return (byte)(input ^ GetByte());
+ }
+
+ private static uint RotateRight(uint x, int bits)
+ {
+ return (x >> bits) | (x << -bits);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/ISAACEngine.cs b/bc-sharp-crypto/src/crypto/engines/ISAACEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b94ee6ed9844953b12d042b21669e8cac3bbb065
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/ISAACEngine.cs
@@ -0,0 +1,212 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * Implementation of Bob Jenkin's ISAAC (Indirection Shift Accumulate Add and Count).
+ * see: http://www.burtleburtle.net/bob/rand/isaacafa.html
+ */
+ public class IsaacEngine
+ : IStreamCipher
+ {
+ // Constants
+ private static readonly int sizeL = 8,
+ stateArraySize = sizeL<<5; // 256
+
+ // Cipher's internal state
+ private uint[] engineState = null, // mm
+ results = null; // randrsl
+ private uint a = 0, b = 0, c = 0;
+
+ // Engine state
+ private int index = 0;
+ private byte[] keyStream = new byte[stateArraySize<<2], // results expanded into bytes
+ workingKey = null;
+ private bool initialised = false;
+
+ /**
+ * initialise an ISAAC cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception ArgumentException if the params argument is
+ * inappropriate.
+ */
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException(
+ "invalid parameter passed to ISAAC Init - " + Platform.GetTypeName(parameters),
+ "parameters");
+
+ /*
+ * ISAAC encryption and decryption is completely
+ * symmetrical, so the 'forEncryption' is
+ * irrelevant.
+ */
+ KeyParameter p = (KeyParameter) parameters;
+ setKey(p.GetKey());
+ }
+
+ public virtual byte ReturnByte(
+ byte input)
+ {
+ if (index == 0)
+ {
+ isaac();
+ keyStream = Pack.UInt32_To_BE(results);
+ }
+
+ byte output = (byte)(keyStream[index]^input);
+ index = (index + 1) & 1023;
+
+ return output;
+ }
+
+ public virtual void ProcessBytes(
+ byte[] input,
+ int inOff,
+ int len,
+ byte[] output,
+ int outOff)
+ {
+ if (!initialised)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ Check.DataLength(input, inOff, len, "input buffer too short");
+ Check.OutputLength(output, outOff, len, "output buffer too short");
+
+ for (int i = 0; i < len; i++)
+ {
+ if (index == 0)
+ {
+ isaac();
+ keyStream = Pack.UInt32_To_BE(results);
+ }
+ output[i+outOff] = (byte)(keyStream[index]^input[i+inOff]);
+ index = (index + 1) & 1023;
+ }
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "ISAAC"; }
+ }
+
+ public virtual void Reset()
+ {
+ setKey(workingKey);
+ }
+
+ // Private implementation
+ private void setKey(
+ byte[] keyBytes)
+ {
+ workingKey = keyBytes;
+
+ if (engineState == null)
+ {
+ engineState = new uint[stateArraySize];
+ }
+
+ if (results == null)
+ {
+ results = new uint[stateArraySize];
+ }
+
+ int i, j, k;
+
+ // Reset state
+ for (i = 0; i < stateArraySize; i++)
+ {
+ engineState[i] = results[i] = 0;
+ }
+ a = b = c = 0;
+
+ // Reset index counter for output
+ index = 0;
+
+ // Convert the key bytes to ints and put them into results[] for initialization
+ byte[] t = new byte[keyBytes.Length + (keyBytes.Length & 3)];
+ Array.Copy(keyBytes, 0, t, 0, keyBytes.Length);
+ for (i = 0; i < t.Length; i+=4)
+ {
+ results[i >> 2] = Pack.LE_To_UInt32(t, i);
+ }
+
+ // It has begun?
+ uint[] abcdefgh = new uint[sizeL];
+
+ for (i = 0; i < sizeL; i++)
+ {
+ abcdefgh[i] = 0x9e3779b9; // Phi (golden ratio)
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ mix(abcdefgh);
+ }
+
+ for (i = 0; i < 2; i++)
+ {
+ for (j = 0; j < stateArraySize; j+=sizeL)
+ {
+ for (k = 0; k < sizeL; k++)
+ {
+ abcdefgh[k] += (i<1) ? results[j+k] : engineState[j+k];
+ }
+
+ mix(abcdefgh);
+
+ for (k = 0; k < sizeL; k++)
+ {
+ engineState[j+k] = abcdefgh[k];
+ }
+ }
+ }
+
+ isaac();
+
+ initialised = true;
+ }
+
+ private void isaac()
+ {
+ uint x, y;
+
+ b += ++c;
+ for (int i = 0; i < stateArraySize; i++)
+ {
+ x = engineState[i];
+ switch (i & 3)
+ {
+ case 0: a ^= (a << 13); break;
+ case 1: a ^= (a >> 6); break;
+ case 2: a ^= (a << 2); break;
+ case 3: a ^= (a >> 16); break;
+ }
+ a += engineState[(i+128) & 0xFF];
+ engineState[i] = y = engineState[(int)((uint)x >> 2) & 0xFF] + a + b;
+ results[i] = b = engineState[(int)((uint)y >> 10) & 0xFF] + x;
+ }
+ }
+
+ private void mix(uint[] x)
+ {
+ x[0]^=x[1]<< 11; x[3]+=x[0]; x[1]+=x[2];
+ x[1]^=x[2]>> 2; x[4]+=x[1]; x[2]+=x[3];
+ x[2]^=x[3]<< 8; x[5]+=x[2]; x[3]+=x[4];
+ x[3]^=x[4]>> 16; x[6]+=x[3]; x[4]+=x[5];
+ x[4]^=x[5]<< 10; x[7]+=x[4]; x[5]+=x[6];
+ x[5]^=x[6]>> 4; x[0]+=x[5]; x[6]+=x[7];
+ x[6]^=x[7]<< 8; x[1]+=x[6]; x[7]+=x[0];
+ x[7]^=x[0]>> 9; x[2]+=x[7]; x[0]+=x[1];
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/IdeaEngine.cs b/bc-sharp-crypto/src/crypto/engines/IdeaEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..18a151c9343c46d228a9edb43f92a0bcf35c85ad
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/IdeaEngine.cs
@@ -0,0 +1,332 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * A class that provides a basic International Data Encryption Algorithm (IDEA) engine.
+ *
+ * This implementation is based on the "HOWTO: INTERNATIONAL DATA ENCRYPTION ALGORITHM"
+ * implementation summary by Fauzan Mirza (F.U.Mirza@sheffield.ac.uk). (baring 1 typo at the
+ * end of the mulinv function!).
+ *
+ *
+ * It can be found at ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/idea/
+ *
+ *
+ * Note 1: This algorithm is patented in the USA, Japan, and Europe including
+ * at least Austria, France, Germany, Italy, Netherlands, Spain, Sweden, Switzerland
+ * and the United Kingdom. Non-commercial use is free, however any commercial
+ * products are liable for royalties. Please see
+ * www.mediacrypt.com for
+ * further details. This announcement has been included at the request of
+ * the patent holders.
+ *
+ *
+ * Note 2: Due to the requests concerning the above, this algorithm is now only
+ * included in the extended assembly. It is not included in the default distributions.
+ *
+ */
+ public class IdeaEngine
+ : IBlockCipher
+ {
+ private const int BLOCK_SIZE = 8;
+ private int[] workingKey;
+ /**
+ * standard constructor.
+ */
+ public IdeaEngine()
+ {
+ }
+ /**
+ * initialise an IDEA 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 virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("invalid parameter passed to IDEA init - " + Platform.GetTypeName(parameters));
+
+ workingKey = GenerateWorkingKey(forEncryption,
+ ((KeyParameter)parameters).GetKey());
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "IDEA"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (workingKey == null)
+ throw new InvalidOperationException("IDEA engine not initialised");
+
+ Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+ IdeaFunc(workingKey, input, inOff, output, outOff);
+ return BLOCK_SIZE;
+ }
+ public virtual void Reset()
+ {
+ }
+ private static readonly int MASK = 0xffff;
+ private static readonly int BASE = 0x10001;
+ 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)
+ {
+ outBytes[outOff] = (byte)((uint) word >> 8);
+ outBytes[outOff + 1] = (byte)word;
+ }
+ /**
+ * return x = x * y where the multiplication is done modulo
+ * 65537 (0x10001) (as defined in the IDEA specification) and
+ * a zero input is taken to be 65536 (0x10000).
+ *
+ * @param x the x value
+ * @param y the y value
+ * @return x = x * y
+ */
+ private int Mul(
+ int x,
+ int y)
+ {
+ if (x == 0)
+ {
+ x = (BASE - y);
+ }
+ else if (y == 0)
+ {
+ x = (BASE - x);
+ }
+ else
+ {
+ int p = x * y;
+ y = p & MASK;
+ x = (int) ((uint) p >> 16);
+ x = y - x + ((y < x) ? 1 : 0);
+ }
+ return x & MASK;
+ }
+ 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);
+ 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++]), outBytes, outOff);
+ WordToBytes(x2 + workingKey[keyOff++], outBytes, outOff + 2); /* NB: Order */
+ WordToBytes(x1 + workingKey[keyOff++], outBytes, outOff + 4);
+ WordToBytes(Mul(x3, workingKey[keyOff]), outBytes, outOff + 6);
+ }
+ /**
+ * 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)
+ {
+ int[] key = new int[52];
+ if (uKey.Length < 16)
+ {
+ byte[] tmp = new byte[16];
+ Array.Copy(uKey, 0, tmp, tmp.Length - uKey.Length, uKey.Length);
+ uKey = tmp;
+ }
+ for (int i = 0; i < 8; i++)
+ {
+ key[i] = BytesToWord(uKey, i * 2);
+ }
+ for (int i = 8; i < 52; i++)
+ {
+ if ((i & 7) < 6)
+ {
+ key[i] = ((key[i - 7] & 127) << 9 | key[i - 6] >> 7) & MASK;
+ }
+ else if ((i & 7) == 6)
+ {
+ key[i] = ((key[i - 7] & 127) << 9 | key[i - 14] >> 7) & MASK;
+ }
+ else
+ {
+ key[i] = ((key[i - 15] & 127) << 9 | key[i - 14] >> 7) & MASK;
+ }
+ }
+ return key;
+ }
+ /**
+ * This function computes multiplicative inverse using Euclid's Greatest
+ * Common Divisor algorithm. Zero and one are self inverse.
+ *
+ * i.e. x * MulInv(x) == 1 (modulo BASE)
+ *
+ */
+ private int MulInv(
+ int x)
+ {
+ int t0, t1, q, y;
+
+ if (x < 2)
+ {
+ return x;
+ }
+ t0 = 1;
+ t1 = BASE / x;
+ y = BASE % x;
+ while (y != 1)
+ {
+ q = x / y;
+ x = x % y;
+ t0 = (t0 + (t1 * q)) & MASK;
+ if (x == 1)
+ {
+ return t0;
+ }
+ q = y / x;
+ y = y % x;
+ t1 = (t1 + (t0 * q)) & MASK;
+ }
+ return (1 - t1) & MASK;
+ }
+ /**
+ * Return the additive inverse of x.
+ *
+ * i.e. x + AddInv(x) == 0
+ *
+ */
+ int AddInv(
+ int x)
+ {
+ return (0 - x) & MASK;
+ }
+
+ /**
+ * The function to invert the encryption subkey to the decryption subkey.
+ * It also involves the multiplicative inverse and the additive inverse functions.
+ */
+ private int[] InvertKey(
+ int[] inKey)
+ {
+ int t1, t2, t3, t4;
+ int p = 52; /* We work backwards */
+ int[] key = new int[52];
+ int inOff = 0;
+
+ t1 = MulInv(inKey[inOff++]);
+ t2 = AddInv(inKey[inOff++]);
+ t3 = AddInv(inKey[inOff++]);
+ t4 = MulInv(inKey[inOff++]);
+ key[--p] = t4;
+ key[--p] = t3;
+ key[--p] = t2;
+ key[--p] = t1;
+
+ for (int round = 1; round < 8; round++)
+ {
+ t1 = inKey[inOff++];
+ t2 = inKey[inOff++];
+ key[--p] = t2;
+ key[--p] = t1;
+
+ t1 = MulInv(inKey[inOff++]);
+ t2 = AddInv(inKey[inOff++]);
+ t3 = AddInv(inKey[inOff++]);
+ t4 = MulInv(inKey[inOff++]);
+ key[--p] = t4;
+ key[--p] = t2; /* NB: Order */
+ key[--p] = t3;
+ key[--p] = t1;
+ }
+ t1 = inKey[inOff++];
+ t2 = inKey[inOff++];
+ key[--p] = t2;
+ key[--p] = t1;
+
+ t1 = MulInv(inKey[inOff++]);
+ t2 = AddInv(inKey[inOff++]);
+ t3 = AddInv(inKey[inOff++]);
+ t4 = MulInv(inKey[inOff]);
+ key[--p] = t4;
+ key[--p] = t3;
+ key[--p] = t2;
+ key[--p] = t1;
+ return key;
+ }
+
+ private int[] GenerateWorkingKey(
+ bool forEncryption,
+ byte[] userKey)
+ {
+ if (forEncryption)
+ {
+ return ExpandKey(userKey);
+ }
+ else
+ {
+ return InvertKey(ExpandKey(userKey));
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/IesEngine.cs b/bc-sharp-crypto/src/crypto/engines/IesEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..307cc7a80264642114c96cb59bd992c053c0e92d
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/IesEngine.cs
@@ -0,0 +1,243 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * support class for constructing intergrated encryption ciphers
+ * for doing basic message exchanges on top of key agreement ciphers
+ */
+ public class IesEngine
+ {
+ private readonly IBasicAgreement agree;
+ private readonly IDerivationFunction kdf;
+ private readonly IMac mac;
+ private readonly BufferedBlockCipher cipher;
+ private readonly byte[] macBuf;
+
+ private bool forEncryption;
+ private ICipherParameters privParam, pubParam;
+ private IesParameters param;
+
+ /**
+ * set up for use with stream mode, where the key derivation function
+ * is used to provide a stream of bytes to xor with the message.
+ *
+ * @param agree the key agreement used as the basis for the encryption
+ * @param kdf the key derivation function used for byte generation
+ * @param mac the message authentication code generator for the message
+ */
+ public IesEngine(
+ IBasicAgreement agree,
+ IDerivationFunction kdf,
+ IMac mac)
+ {
+ this.agree = agree;
+ this.kdf = kdf;
+ this.mac = mac;
+ this.macBuf = new byte[mac.GetMacSize()];
+// this.cipher = null;
+ }
+
+ /**
+ * set up for use in conjunction with a block cipher to handle the
+ * message.
+ *
+ * @param agree the key agreement used as the basis for the encryption
+ * @param kdf the key derivation function used for byte generation
+ * @param mac the message authentication code generator for the message
+ * @param cipher the cipher to used for encrypting the message
+ */
+ public IesEngine(
+ IBasicAgreement agree,
+ IDerivationFunction kdf,
+ IMac mac,
+ BufferedBlockCipher cipher)
+ {
+ this.agree = agree;
+ this.kdf = kdf;
+ this.mac = mac;
+ this.macBuf = new byte[mac.GetMacSize()];
+ this.cipher = cipher;
+ }
+
+ /**
+ * Initialise the encryptor.
+ *
+ * @param forEncryption whether or not this is encryption/decryption.
+ * @param privParam our private key parameters
+ * @param pubParam the recipient's/sender's public key parameters
+ * @param param encoding and derivation parameters.
+ */
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters privParameters,
+ ICipherParameters pubParameters,
+ ICipherParameters iesParameters)
+ {
+ this.forEncryption = forEncryption;
+ this.privParam = privParameters;
+ this.pubParam = pubParameters;
+ this.param = (IesParameters)iesParameters;
+ }
+
+ private byte[] DecryptBlock(
+ byte[] in_enc,
+ int inOff,
+ int inLen,
+ byte[] z)
+ {
+ byte[] M = null;
+ KeyParameter macKey = null;
+ KdfParameters kParam = new KdfParameters(z, param.GetDerivationV());
+ int macKeySize = param.MacKeySize;
+
+ kdf.Init(kParam);
+
+ // Ensure that the length of the input is greater than the MAC in bytes
+ if (inLen < mac.GetMacSize())
+ throw new InvalidCipherTextException("Length of input must be greater than the MAC");
+
+ inLen -= mac.GetMacSize();
+
+ if (cipher == null) // stream mode
+ {
+ byte[] Buffer = GenerateKdfBytes(kParam, inLen + (macKeySize / 8));
+
+ M = new byte[inLen];
+
+ for (int i = 0; i != inLen; i++)
+ {
+ M[i] = (byte)(in_enc[inOff + i] ^ Buffer[i]);
+ }
+
+ macKey = new KeyParameter(Buffer, inLen, (macKeySize / 8));
+ }
+ else
+ {
+ int cipherKeySize = ((IesWithCipherParameters)param).CipherKeySize;
+ byte[] Buffer = GenerateKdfBytes(kParam, (cipherKeySize / 8) + (macKeySize / 8));
+
+ cipher.Init(false, new KeyParameter(Buffer, 0, (cipherKeySize / 8)));
+
+ M = cipher.DoFinal(in_enc, inOff, inLen);
+
+ macKey = new KeyParameter(Buffer, (cipherKeySize / 8), (macKeySize / 8));
+ }
+
+ byte[] macIV = param.GetEncodingV();
+
+ mac.Init(macKey);
+ mac.BlockUpdate(in_enc, inOff, inLen);
+ mac.BlockUpdate(macIV, 0, macIV.Length);
+ mac.DoFinal(macBuf, 0);
+
+ inOff += inLen;
+
+ byte[] T1 = Arrays.CopyOfRange(in_enc, inOff, inOff + macBuf.Length);
+
+ if (!Arrays.ConstantTimeAreEqual(T1, macBuf))
+ throw (new InvalidCipherTextException("Invalid MAC."));
+
+ return M;
+ }
+
+ private byte[] EncryptBlock(
+ byte[] input,
+ int inOff,
+ int inLen,
+ byte[] z)
+ {
+ byte[] C = null;
+ KeyParameter macKey = null;
+ KdfParameters kParam = new KdfParameters(z, param.GetDerivationV());
+ int c_text_length = 0;
+ int macKeySize = param.MacKeySize;
+
+ if (cipher == null) // stream mode
+ {
+ byte[] Buffer = GenerateKdfBytes(kParam, inLen + (macKeySize / 8));
+
+ C = new byte[inLen + mac.GetMacSize()];
+ c_text_length = inLen;
+
+ for (int i = 0; i != inLen; i++)
+ {
+ C[i] = (byte)(input[inOff + i] ^ Buffer[i]);
+ }
+
+ macKey = new KeyParameter(Buffer, inLen, (macKeySize / 8));
+ }
+ else
+ {
+ int cipherKeySize = ((IesWithCipherParameters)param).CipherKeySize;
+ byte[] Buffer = GenerateKdfBytes(kParam, (cipherKeySize / 8) + (macKeySize / 8));
+
+ cipher.Init(true, new KeyParameter(Buffer, 0, (cipherKeySize / 8)));
+
+ c_text_length = cipher.GetOutputSize(inLen);
+ byte[] tmp = new byte[c_text_length];
+
+ int len = cipher.ProcessBytes(input, inOff, inLen, tmp, 0);
+ len += cipher.DoFinal(tmp, len);
+
+ C = new byte[len + mac.GetMacSize()];
+ c_text_length = len;
+
+ Array.Copy(tmp, 0, C, 0, len);
+
+ macKey = new KeyParameter(Buffer, (cipherKeySize / 8), (macKeySize / 8));
+ }
+
+ byte[] macIV = param.GetEncodingV();
+
+ mac.Init(macKey);
+ mac.BlockUpdate(C, 0, c_text_length);
+ mac.BlockUpdate(macIV, 0, macIV.Length);
+ //
+ // return the message and it's MAC
+ //
+ mac.DoFinal(C, c_text_length);
+ return C;
+ }
+
+ private byte[] GenerateKdfBytes(
+ KdfParameters kParam,
+ int length)
+ {
+ byte[] buf = new byte[length];
+
+ kdf.Init(kParam);
+
+ kdf.GenerateBytes(buf, 0, buf.Length);
+
+ return buf;
+ }
+
+ public virtual byte[] ProcessBlock(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ agree.Init(privParam);
+
+ BigInteger z = agree.CalculateAgreement(pubParam);
+
+ byte[] zBytes = BigIntegers.AsUnsignedByteArray(agree.GetFieldSize(), z);
+
+ try
+ {
+ return forEncryption
+ ? EncryptBlock(input, inOff, inLen, zBytes)
+ : DecryptBlock(input, inOff, inLen, zBytes);
+ }
+ finally
+ {
+ Array.Clear(zBytes, 0, zBytes.Length);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/NaccacheSternEngine.cs b/bc-sharp-crypto/src/crypto/engines/NaccacheSternEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..64665c1d45cab30b9f09d5e6b409b717a944935b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/NaccacheSternEngine.cs
@@ -0,0 +1,358 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * NaccacheStern Engine. For details on this cipher, please see
+ * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+ */
+ public class NaccacheSternEngine
+ : IAsymmetricBlockCipher
+ {
+ private bool forEncryption;
+
+ private NaccacheSternKeyParameters key;
+
+ private IList[] lookup = null;
+
+ public string AlgorithmName
+ {
+ get { return "NaccacheStern"; }
+ }
+
+ /**
+ * Initializes this algorithm. Must be called before all other Functions.
+ *
+ * @see org.bouncycastle.crypto.AsymmetricBlockCipher#init(bool,
+ * org.bouncycastle.crypto.CipherParameters)
+ */
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+
+ if (parameters is ParametersWithRandom)
+ {
+ parameters = ((ParametersWithRandom) parameters).Parameters;
+ }
+
+ key = (NaccacheSternKeyParameters)parameters;
+
+ // construct lookup table for faster decryption if necessary
+ if (!this.forEncryption)
+ {
+ NaccacheSternPrivateKeyParameters priv = (NaccacheSternPrivateKeyParameters)key;
+ IList primes = priv.SmallPrimesList;
+ lookup = new IList[primes.Count];
+ for (int i = 0; i < primes.Count; i++)
+ {
+ BigInteger actualPrime = (BigInteger) primes[i];
+ int actualPrimeValue = actualPrime.IntValue;
+
+ lookup[i] = Platform.CreateArrayList(actualPrimeValue);
+ lookup[i].Add(BigInteger.One);
+
+ BigInteger accJ = BigInteger.Zero;
+
+ for (int j = 1; j < actualPrimeValue; j++)
+ {
+// BigInteger bigJ = BigInteger.ValueOf(j);
+// accJ = priv.PhiN.Multiply(bigJ);
+ accJ = accJ.Add(priv.PhiN);
+ BigInteger comp = accJ.Divide(actualPrime);
+ lookup[i].Add(priv.G.ModPow(comp, priv.Modulus));
+ }
+ }
+ }
+ }
+
+ [Obsolete("Remove: no longer used")]
+ public virtual bool Debug
+ {
+ set {}
+ }
+
+ /**
+ * Returns the input block size of this algorithm.
+ *
+ * @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetInputBlockSize()
+ */
+ public virtual int GetInputBlockSize()
+ {
+ if (forEncryption)
+ {
+ // We can only encrypt values up to lowerSigmaBound
+ return (key.LowerSigmaBound + 7) / 8 - 1;
+ }
+ else
+ {
+ // We pad to modulus-size bytes for easier decryption.
+// return key.Modulus.ToByteArray().Length;
+ return key.Modulus.BitLength / 8 + 1;
+ }
+ }
+
+ /**
+ * Returns the output block size of this algorithm.
+ *
+ * @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetOutputBlockSize()
+ */
+ public virtual int GetOutputBlockSize()
+ {
+ if (forEncryption)
+ {
+ // encrypted Data is always padded up to modulus size
+// return key.Modulus.ToByteArray().Length;
+ return key.Modulus.BitLength / 8 + 1;
+ }
+ else
+ {
+ // decrypted Data has upper limit lowerSigmaBound
+ return (key.LowerSigmaBound + 7) / 8 - 1;
+ }
+ }
+
+ /**
+ * Process a single Block using the Naccache-Stern algorithm.
+ *
+ * @see org.bouncycastle.crypto.AsymmetricBlockCipher#ProcessBlock(byte[],
+ * int, int)
+ */
+ public virtual byte[] ProcessBlock(
+ byte[] inBytes,
+ int inOff,
+ int length)
+ {
+ if (key == null)
+ throw new InvalidOperationException("NaccacheStern engine not initialised");
+ if (length > (GetInputBlockSize() + 1))
+ throw new DataLengthException("input too large for Naccache-Stern cipher.\n");
+
+ if (!forEncryption)
+ {
+ // At decryption make sure that we receive padded data blocks
+ if (length < GetInputBlockSize())
+ {
+ throw new InvalidCipherTextException("BlockLength does not match modulus for Naccache-Stern cipher.\n");
+ }
+ }
+
+ // transform input into BigInteger
+ BigInteger input = new BigInteger(1, inBytes, inOff, length);
+
+ byte[] output;
+ if (forEncryption)
+ {
+ output = Encrypt(input);
+ }
+ else
+ {
+ IList plain = Platform.CreateArrayList();
+ NaccacheSternPrivateKeyParameters priv = (NaccacheSternPrivateKeyParameters)key;
+ IList primes = priv.SmallPrimesList;
+ // Get Chinese Remainders of CipherText
+ for (int i = 0; i < primes.Count; i++)
+ {
+ BigInteger exp = input.ModPow(priv.PhiN.Divide((BigInteger)primes[i]), priv.Modulus);
+ IList al = lookup[i];
+ if (lookup[i].Count != ((BigInteger)primes[i]).IntValue)
+ {
+ throw new InvalidCipherTextException("Error in lookup Array for "
+ + ((BigInteger)primes[i]).IntValue
+ + ": Size mismatch. Expected ArrayList with length "
+ + ((BigInteger)primes[i]).IntValue + " but found ArrayList of length "
+ + lookup[i].Count);
+ }
+ int lookedup = al.IndexOf(exp);
+
+ if (lookedup == -1)
+ {
+ throw new InvalidCipherTextException("Lookup failed");
+ }
+ plain.Add(BigInteger.ValueOf(lookedup));
+ }
+ BigInteger test = chineseRemainder(plain, primes);
+
+ // Should not be used as an oracle, so reencrypt output to see
+ // if it corresponds to input
+
+ // this breaks probabilisic encryption, so disable it. Anyway, we do
+ // use the first n primes for key generation, so it is pretty easy
+ // to guess them. But as stated in the paper, this is not a security
+ // breach. So we can just work with the correct sigma.
+
+ // if ((key.G.ModPow(test, key.Modulus)).Equals(input)) {
+ // output = test.ToByteArray();
+ // } else {
+ // output = null;
+ // }
+
+ output = test.ToByteArray();
+ }
+
+ return output;
+ }
+
+ /**
+ * Encrypts a BigInteger aka Plaintext with the public key.
+ *
+ * @param plain
+ * The BigInteger to encrypt
+ * @return The byte[] representation of the encrypted BigInteger (i.e.
+ * crypted.toByteArray())
+ */
+ public virtual byte[] Encrypt(
+ BigInteger plain)
+ {
+ // Always return modulus size values 0-padded at the beginning
+ // 0-padding at the beginning is correctly parsed by BigInteger :)
+// byte[] output = key.Modulus.ToByteArray();
+// Array.Clear(output, 0, output.Length);
+ byte[] output = new byte[key.Modulus.BitLength / 8 + 1];
+
+ byte[] tmp = key.G.ModPow(plain, key.Modulus).ToByteArray();
+ Array.Copy(tmp, 0, output, output.Length - tmp.Length, tmp.Length);
+ return output;
+ }
+
+ /**
+ * Adds the contents of two encrypted blocks mod sigma
+ *
+ * @param block1
+ * the first encrypted block
+ * @param block2
+ * the second encrypted block
+ * @return encrypt((block1 + block2) mod sigma)
+ * @throws InvalidCipherTextException
+ */
+ public virtual byte[] AddCryptedBlocks(
+ byte[] block1,
+ byte[] block2)
+ {
+ // check for correct blocksize
+ if (forEncryption)
+ {
+ if ((block1.Length > GetOutputBlockSize())
+ || (block2.Length > GetOutputBlockSize()))
+ {
+ throw new InvalidCipherTextException(
+ "BlockLength too large for simple addition.\n");
+ }
+ }
+ else
+ {
+ if ((block1.Length > GetInputBlockSize())
+ || (block2.Length > GetInputBlockSize()))
+ {
+ throw new InvalidCipherTextException(
+ "BlockLength too large for simple addition.\n");
+ }
+ }
+
+ // calculate resulting block
+ BigInteger m1Crypt = new BigInteger(1, block1);
+ BigInteger m2Crypt = new BigInteger(1, block2);
+ BigInteger m1m2Crypt = m1Crypt.Multiply(m2Crypt);
+ m1m2Crypt = m1m2Crypt.Mod(key.Modulus);
+
+ //byte[] output = key.Modulus.ToByteArray();
+ //Array.Clear(output, 0, output.Length);
+ byte[] output = new byte[key.Modulus.BitLength / 8 + 1];
+
+ byte[] m1m2CryptBytes = m1m2Crypt.ToByteArray();
+ Array.Copy(m1m2CryptBytes, 0, output,
+ output.Length - m1m2CryptBytes.Length, m1m2CryptBytes.Length);
+
+ return output;
+ }
+
+ /**
+ * Convenience Method for data exchange with the cipher.
+ *
+ * Determines blocksize and splits data to blocksize.
+ *
+ * @param data the data to be processed
+ * @return the data after it went through the NaccacheSternEngine.
+ * @throws InvalidCipherTextException
+ */
+ public virtual byte[] ProcessData(
+ byte[] data)
+ {
+ if (data.Length > GetInputBlockSize())
+ {
+ int inBlocksize = GetInputBlockSize();
+ int outBlocksize = GetOutputBlockSize();
+ int datapos = 0;
+ int retpos = 0;
+ byte[] retval = new byte[(data.Length / inBlocksize + 1) * outBlocksize];
+ while (datapos < data.Length)
+ {
+ byte[] tmp;
+ if (datapos + inBlocksize < data.Length)
+ {
+ tmp = ProcessBlock(data, datapos, inBlocksize);
+ datapos += inBlocksize;
+ }
+ else
+ {
+ tmp = ProcessBlock(data, datapos, data.Length - datapos);
+ datapos += data.Length - datapos;
+ }
+ if (tmp != null)
+ {
+ tmp.CopyTo(retval, retpos);
+ retpos += tmp.Length;
+ }
+ else
+ {
+ throw new InvalidCipherTextException("cipher returned null");
+ }
+ }
+ byte[] ret = new byte[retpos];
+ Array.Copy(retval, 0, ret, 0, retpos);
+ return ret;
+ }
+ else
+ {
+ return ProcessBlock(data, 0, data.Length);
+ }
+ }
+
+ /**
+ * Computes the integer x that is expressed through the given primes and the
+ * congruences with the chinese remainder theorem (CRT).
+ *
+ * @param congruences
+ * the congruences c_i
+ * @param primes
+ * the primes p_i
+ * @return an integer x for that x % p_i == c_i
+ */
+ private static BigInteger chineseRemainder(IList congruences, IList primes)
+ {
+ BigInteger retval = BigInteger.Zero;
+ BigInteger all = BigInteger.One;
+ for (int i = 0; i < primes.Count; i++)
+ {
+ all = all.Multiply((BigInteger)primes[i]);
+ }
+ for (int i = 0; i < primes.Count; i++)
+ {
+ BigInteger a = (BigInteger)primes[i];
+ BigInteger b = all.Divide(a);
+ BigInteger b2 = b.ModInverse(a);
+ BigInteger tmp = b.Multiply(b2);
+ tmp = tmp.Multiply((BigInteger)congruences[i]);
+ retval = retval.Add(tmp);
+ }
+
+ return retval.Mod(all);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/NoekeonEngine.cs b/bc-sharp-crypto/src/crypto/engines/NoekeonEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f64be50ba74073899be5f40c20ca7ef90139b206
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/NoekeonEngine.cs
@@ -0,0 +1,241 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * A Noekeon engine, using direct-key mode.
+ */
+ public class NoekeonEngine
+ : IBlockCipher
+ {
+ private const int GenericSize = 16; // Block and key size, as well as the amount of rounds.
+
+ private static readonly uint[] nullVector =
+ {
+ 0x00, 0x00, 0x00, 0x00 // Used in decryption
+ };
+
+ private static readonly uint[] roundConstants =
+ {
+ 0x80, 0x1b, 0x36, 0x6c,
+ 0xd8, 0xab, 0x4d, 0x9a,
+ 0x2f, 0x5e, 0xbc, 0x63,
+ 0xc6, 0x97, 0x35, 0x6a,
+ 0xd4
+ };
+
+ private uint[] state = new uint[4], // a
+ subKeys = new uint[4], // k
+ decryptKeys = new uint[4];
+
+ private bool _initialised, _forEncryption;
+
+ /**
+ * Create an instance of the Noekeon encryption algorithm
+ * and set some defaults
+ */
+ public NoekeonEngine()
+ {
+ _initialised = false;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Noekeon"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return GenericSize;
+ }
+
+ /**
+ * initialise
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception ArgumentException if the params argument is
+ * inappropriate.
+ */
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("Invalid parameters passed to Noekeon init - "
+ + Platform.GetTypeName(parameters), "parameters");
+
+ _forEncryption = forEncryption;
+ _initialised = true;
+
+ KeyParameter p = (KeyParameter) parameters;
+
+ setKey(p.GetKey());
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (!_initialised)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ Check.DataLength(input, inOff, GenericSize, "input buffer too short");
+ Check.OutputLength(output, outOff, GenericSize, "output buffer too short");
+
+ return _forEncryption
+ ? encryptBlock(input, inOff, output, outOff)
+ : decryptBlock(input, inOff, output, outOff);
+ }
+
+ public virtual void Reset()
+ {
+ // TODO This should do something in case the encryption is aborted
+ }
+
+ /**
+ * Re-key the cipher.
+ *
+ * @param key the key to be used
+ */
+ private void setKey(byte[] key)
+ {
+ subKeys[0] = Pack.BE_To_UInt32(key, 0);
+ subKeys[1] = Pack.BE_To_UInt32(key, 4);
+ subKeys[2] = Pack.BE_To_UInt32(key, 8);
+ subKeys[3] = Pack.BE_To_UInt32(key, 12);
+ }
+
+ private int encryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ state[0] = Pack.BE_To_UInt32(input, inOff);
+ state[1] = Pack.BE_To_UInt32(input, inOff+4);
+ state[2] = Pack.BE_To_UInt32(input, inOff+8);
+ state[3] = Pack.BE_To_UInt32(input, inOff+12);
+
+ int i;
+ for (i = 0; i < GenericSize; i++)
+ {
+ state[0] ^= roundConstants[i];
+ theta(state, subKeys);
+ pi1(state);
+ gamma(state);
+ pi2(state);
+ }
+
+ state[0] ^= roundConstants[i];
+ theta(state, subKeys);
+
+ Pack.UInt32_To_BE(state[0], output, outOff);
+ Pack.UInt32_To_BE(state[1], output, outOff+4);
+ Pack.UInt32_To_BE(state[2], output, outOff+8);
+ Pack.UInt32_To_BE(state[3], output, outOff+12);
+
+ return GenericSize;
+ }
+
+ private int decryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ state[0] = Pack.BE_To_UInt32(input, inOff);
+ state[1] = Pack.BE_To_UInt32(input, inOff+4);
+ state[2] = Pack.BE_To_UInt32(input, inOff+8);
+ state[3] = Pack.BE_To_UInt32(input, inOff+12);
+
+ Array.Copy(subKeys, 0, decryptKeys, 0, subKeys.Length);
+ theta(decryptKeys, nullVector);
+
+ int i;
+ for (i = GenericSize; i > 0; i--)
+ {
+ theta(state, decryptKeys);
+ state[0] ^= roundConstants[i];
+ pi1(state);
+ gamma(state);
+ pi2(state);
+ }
+
+ theta(state, decryptKeys);
+ state[0] ^= roundConstants[i];
+
+ Pack.UInt32_To_BE(state[0], output, outOff);
+ Pack.UInt32_To_BE(state[1], output, outOff+4);
+ Pack.UInt32_To_BE(state[2], output, outOff+8);
+ Pack.UInt32_To_BE(state[3], output, outOff+12);
+
+ return GenericSize;
+ }
+
+ private void gamma(uint[] a)
+ {
+ a[1] ^= ~a[3] & ~a[2];
+ a[0] ^= a[2] & a[1];
+
+ uint tmp = a[3];
+ a[3] = a[0];
+ a[0] = tmp;
+ a[2] ^= a[0]^a[1]^a[3];
+
+ a[1] ^= ~a[3] & ~a[2];
+ a[0] ^= a[2] & a[1];
+ }
+
+ private void theta(uint[] a, uint[] k)
+ {
+ uint tmp;
+ tmp = a[0]^a[2];
+ tmp ^= rotl(tmp,8)^rotl(tmp,24);
+ a[1] ^= tmp;
+ a[3] ^= tmp;
+
+ for (int i = 0; i < 4; i++)
+ {
+ a[i] ^= k[i];
+ }
+
+ tmp = a[1]^a[3];
+ tmp ^= rotl(tmp,8)^rotl(tmp,24);
+ a[0] ^= tmp;
+ a[2] ^= tmp;
+ }
+
+ private void pi1(uint[] a)
+ {
+ a[1] = rotl(a[1], 1);
+ a[2] = rotl(a[2], 5);
+ a[3] = rotl(a[3], 2);
+ }
+
+ private void pi2(uint[] a)
+ {
+ a[1] = rotl(a[1], 31);
+ a[2] = rotl(a[2], 27);
+ a[3] = rotl(a[3], 30);
+ }
+
+ // Helpers
+
+ private uint rotl(uint x, int y)
+ {
+ return (x << y) | (x >> (32-y));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/NullEngine.cs b/bc-sharp-crypto/src/crypto/engines/NullEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f883b7c292b456040103942451b284706f137be7
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/NullEngine.cs
@@ -0,0 +1,69 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * The no-op engine that just copies bytes through, irrespective of whether encrypting and decrypting.
+ * Provided for the sake of completeness.
+ */
+ public class NullEngine
+ : IBlockCipher
+ {
+ private bool initialised;
+ private const int BlockSize = 1;
+
+ public NullEngine()
+ {
+ }
+
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ // we don't mind any parameters that may come in
+ initialised = true;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Null"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return true; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BlockSize;
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (!initialised)
+ throw new InvalidOperationException("Null engine not initialised");
+
+ Check.DataLength(input, inOff, BlockSize, "input buffer too short");
+ Check.OutputLength(output, outOff, BlockSize, "output buffer too short");
+
+ for (int i = 0; i < BlockSize; ++i)
+ {
+ output[outOff + i] = input[inOff + i];
+ }
+
+ return BlockSize;
+ }
+
+ public virtual void Reset()
+ {
+ // nothing needs to be done
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/RC2Engine.cs b/bc-sharp-crypto/src/crypto/engines/RC2Engine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4aca1894f59d6f9f380019529405fcdadedbdf86
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/RC2Engine.cs
@@ -0,0 +1,311 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * an implementation of RC2 as described in RFC 2268
+ * "A Description of the RC2(r) Encryption Algorithm" R. Rivest.
+ */
+ public class RC2Engine
+ : IBlockCipher
+ {
+ //
+ // the values we use for key expansion (based on the digits of PI)
+ //
+ private static readonly byte[] piTable =
+ {
+ (byte)0xd9, (byte)0x78, (byte)0xf9, (byte)0xc4, (byte)0x19, (byte)0xdd, (byte)0xb5, (byte)0xed,
+ (byte)0x28, (byte)0xe9, (byte)0xfd, (byte)0x79, (byte)0x4a, (byte)0xa0, (byte)0xd8, (byte)0x9d,
+ (byte)0xc6, (byte)0x7e, (byte)0x37, (byte)0x83, (byte)0x2b, (byte)0x76, (byte)0x53, (byte)0x8e,
+ (byte)0x62, (byte)0x4c, (byte)0x64, (byte)0x88, (byte)0x44, (byte)0x8b, (byte)0xfb, (byte)0xa2,
+ (byte)0x17, (byte)0x9a, (byte)0x59, (byte)0xf5, (byte)0x87, (byte)0xb3, (byte)0x4f, (byte)0x13,
+ (byte)0x61, (byte)0x45, (byte)0x6d, (byte)0x8d, (byte)0x9, (byte)0x81, (byte)0x7d, (byte)0x32,
+ (byte)0xbd, (byte)0x8f, (byte)0x40, (byte)0xeb, (byte)0x86, (byte)0xb7, (byte)0x7b, (byte)0xb,
+ (byte)0xf0, (byte)0x95, (byte)0x21, (byte)0x22, (byte)0x5c, (byte)0x6b, (byte)0x4e, (byte)0x82,
+ (byte)0x54, (byte)0xd6, (byte)0x65, (byte)0x93, (byte)0xce, (byte)0x60, (byte)0xb2, (byte)0x1c,
+ (byte)0x73, (byte)0x56, (byte)0xc0, (byte)0x14, (byte)0xa7, (byte)0x8c, (byte)0xf1, (byte)0xdc,
+ (byte)0x12, (byte)0x75, (byte)0xca, (byte)0x1f, (byte)0x3b, (byte)0xbe, (byte)0xe4, (byte)0xd1,
+ (byte)0x42, (byte)0x3d, (byte)0xd4, (byte)0x30, (byte)0xa3, (byte)0x3c, (byte)0xb6, (byte)0x26,
+ (byte)0x6f, (byte)0xbf, (byte)0xe, (byte)0xda, (byte)0x46, (byte)0x69, (byte)0x7, (byte)0x57,
+ (byte)0x27, (byte)0xf2, (byte)0x1d, (byte)0x9b, (byte)0xbc, (byte)0x94, (byte)0x43, (byte)0x3,
+ (byte)0xf8, (byte)0x11, (byte)0xc7, (byte)0xf6, (byte)0x90, (byte)0xef, (byte)0x3e, (byte)0xe7,
+ (byte)0x6, (byte)0xc3, (byte)0xd5, (byte)0x2f, (byte)0xc8, (byte)0x66, (byte)0x1e, (byte)0xd7,
+ (byte)0x8, (byte)0xe8, (byte)0xea, (byte)0xde, (byte)0x80, (byte)0x52, (byte)0xee, (byte)0xf7,
+ (byte)0x84, (byte)0xaa, (byte)0x72, (byte)0xac, (byte)0x35, (byte)0x4d, (byte)0x6a, (byte)0x2a,
+ (byte)0x96, (byte)0x1a, (byte)0xd2, (byte)0x71, (byte)0x5a, (byte)0x15, (byte)0x49, (byte)0x74,
+ (byte)0x4b, (byte)0x9f, (byte)0xd0, (byte)0x5e, (byte)0x4, (byte)0x18, (byte)0xa4, (byte)0xec,
+ (byte)0xc2, (byte)0xe0, (byte)0x41, (byte)0x6e, (byte)0xf, (byte)0x51, (byte)0xcb, (byte)0xcc,
+ (byte)0x24, (byte)0x91, (byte)0xaf, (byte)0x50, (byte)0xa1, (byte)0xf4, (byte)0x70, (byte)0x39,
+ (byte)0x99, (byte)0x7c, (byte)0x3a, (byte)0x85, (byte)0x23, (byte)0xb8, (byte)0xb4, (byte)0x7a,
+ (byte)0xfc, (byte)0x2, (byte)0x36, (byte)0x5b, (byte)0x25, (byte)0x55, (byte)0x97, (byte)0x31,
+ (byte)0x2d, (byte)0x5d, (byte)0xfa, (byte)0x98, (byte)0xe3, (byte)0x8a, (byte)0x92, (byte)0xae,
+ (byte)0x5, (byte)0xdf, (byte)0x29, (byte)0x10, (byte)0x67, (byte)0x6c, (byte)0xba, (byte)0xc9,
+ (byte)0xd3, (byte)0x0, (byte)0xe6, (byte)0xcf, (byte)0xe1, (byte)0x9e, (byte)0xa8, (byte)0x2c,
+ (byte)0x63, (byte)0x16, (byte)0x1, (byte)0x3f, (byte)0x58, (byte)0xe2, (byte)0x89, (byte)0xa9,
+ (byte)0xd, (byte)0x38, (byte)0x34, (byte)0x1b, (byte)0xab, (byte)0x33, (byte)0xff, (byte)0xb0,
+ (byte)0xbb, (byte)0x48, (byte)0xc, (byte)0x5f, (byte)0xb9, (byte)0xb1, (byte)0xcd, (byte)0x2e,
+ (byte)0xc5, (byte)0xf3, (byte)0xdb, (byte)0x47, (byte)0xe5, (byte)0xa5, (byte)0x9c, (byte)0x77,
+ (byte)0xa, (byte)0xa6, (byte)0x20, (byte)0x68, (byte)0xfe, (byte)0x7f, (byte)0xc1, (byte)0xad
+ };
+
+ private const int BLOCK_SIZE = 8;
+
+ private int[] workingKey;
+ private bool encrypting;
+
+ private int[] GenerateWorkingKey(
+ byte[] key,
+ int bits)
+ {
+ int x;
+ int[] xKey = new int[128];
+
+ for (int i = 0; i != key.Length; i++)
+ {
+ xKey[i] = key[i] & 0xff;
+ }
+
+ // Phase 1: Expand input key to 128 bytes
+ int len = key.Length;
+
+ if (len < 128)
+ {
+ int index = 0;
+
+ x = xKey[len - 1];
+
+ do
+ {
+ x = piTable[(x + xKey[index++]) & 255] & 0xff;
+ xKey[len++] = x;
+ }
+ while (len < 128);
+ }
+
+ // Phase 2 - reduce effective key size to "bits"
+ len = (bits + 7) >> 3;
+ x = piTable[xKey[128 - len] & (255 >> (7 & -bits))] & 0xff;
+ xKey[128 - len] = x;
+
+ for (int i = 128 - len - 1; i >= 0; i--)
+ {
+ x = piTable[x ^ xKey[i + len]] & 0xff;
+ xKey[i] = x;
+ }
+
+ // Phase 3 - copy to newKey in little-endian order
+ int[] newKey = new int[64];
+
+ for (int i = 0; i != newKey.Length; i++)
+ {
+ newKey[i] = (xKey[2 * i] + (xKey[2 * i + 1] << 8));
+ }
+
+ return newKey;
+ }
+
+ /**
+ * initialise a RC2 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 virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.encrypting = forEncryption;
+
+ if (parameters is RC2Parameters)
+ {
+ RC2Parameters param = (RC2Parameters) parameters;
+
+ workingKey = GenerateWorkingKey(param.GetKey(), param.EffectiveKeyBits);
+ }
+ else if (parameters is KeyParameter)
+ {
+ KeyParameter param = (KeyParameter) parameters;
+ byte[] key = param.GetKey();
+
+ workingKey = GenerateWorkingKey(key, key.Length * 8);
+ }
+ else
+ {
+ throw new ArgumentException("invalid parameter passed to RC2 init - " + Platform.GetTypeName(parameters));
+ }
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "RC2"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (workingKey == null)
+ throw new InvalidOperationException("RC2 engine not initialised");
+
+ Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+ if (encrypting)
+ {
+ EncryptBlock(input, inOff, output, outOff);
+ }
+ else
+ {
+ DecryptBlock(input, inOff, output, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ /**
+ * return the result rotating the 16 bit number in x left by 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)
+ {
+ int x76, x54, x32, x10;
+
+ x76 = ((input[inOff + 7] & 0xff) << 8) + (input[inOff + 6] & 0xff);
+ x54 = ((input[inOff + 5] & 0xff) << 8) + (input[inOff + 4] & 0xff);
+ x32 = ((input[inOff + 3] & 0xff) << 8) + (input[inOff + 2] & 0xff);
+ x10 = ((input[inOff + 1] & 0xff) << 8) + (input[inOff + 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);
+ }
+
+ outBytes[outOff + 0] = (byte)x10;
+ outBytes[outOff + 1] = (byte)(x10 >> 8);
+ outBytes[outOff + 2] = (byte)x32;
+ outBytes[outOff + 3] = (byte)(x32 >> 8);
+ outBytes[outOff + 4] = (byte)x54;
+ outBytes[outOff + 5] = (byte)(x54 >> 8);
+ outBytes[outOff + 6] = (byte)x76;
+ outBytes[outOff + 7] = (byte)(x76 >> 8);
+ }
+
+ private void DecryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ int x76, x54, x32, x10;
+
+ x76 = ((input[inOff + 7] & 0xff) << 8) + (input[inOff + 6] & 0xff);
+ x54 = ((input[inOff + 5] & 0xff) << 8) + (input[inOff + 4] & 0xff);
+ x32 = ((input[inOff + 3] & 0xff) << 8) + (input[inOff + 2] & 0xff);
+ x10 = ((input[inOff + 1] & 0xff) << 8) + (input[inOff + 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 ]);
+ }
+
+ outBytes[outOff + 0] = (byte)x10;
+ outBytes[outOff + 1] = (byte)(x10 >> 8);
+ outBytes[outOff + 2] = (byte)x32;
+ outBytes[outOff + 3] = (byte)(x32 >> 8);
+ outBytes[outOff + 4] = (byte)x54;
+ outBytes[outOff + 5] = (byte)(x54 >> 8);
+ outBytes[outOff + 6] = (byte)x76;
+ outBytes[outOff + 7] = (byte)(x76 >> 8);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/RC2WrapEngine.cs b/bc-sharp-crypto/src/crypto/engines/RC2WrapEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5742aa8b77ff3fc5bcfffd57db43048cb7ecd28f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/RC2WrapEngine.cs
@@ -0,0 +1,370 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * Wrap keys according to RFC 3217 - RC2 mechanism
+ */
+ public class RC2WrapEngine
+ : IWrapper
+ {
+ /** Field engine */
+ private CbcBlockCipher engine;
+
+ /** Field param */
+ private ICipherParameters parameters;
+
+ /** Field paramPlusIV */
+ private ParametersWithIV paramPlusIV;
+
+ /** Field iv */
+ private byte[] iv;
+
+ /** Field forWrapping */
+ private bool forWrapping;
+
+ private SecureRandom sr;
+
+ /** Field IV2 */
+ private static readonly byte[] IV2 =
+ {
+ (byte) 0x4a, (byte) 0xdd, (byte) 0xa2,
+ (byte) 0x2c, (byte) 0x79, (byte) 0xe8,
+ (byte) 0x21, (byte) 0x05
+ };
+
+ //
+ // checksum digest
+ //
+ IDigest sha1 = new Sha1Digest();
+ byte[] digest = new byte[20];
+
+ /**
+ * Method init
+ *
+ * @param forWrapping
+ * @param param
+ */
+ public virtual void Init(
+ bool forWrapping,
+ ICipherParameters parameters)
+ {
+ this.forWrapping = forWrapping;
+ this.engine = new CbcBlockCipher(new RC2Engine());
+
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom pWithR = (ParametersWithRandom)parameters;
+ sr = pWithR.Random;
+ parameters = pWithR.Parameters;
+ }
+ else
+ {
+ sr = new SecureRandom();
+ }
+
+ if (parameters is ParametersWithIV)
+ {
+ if (!forWrapping)
+ throw new ArgumentException("You should not supply an IV for unwrapping");
+
+ this.paramPlusIV = (ParametersWithIV)parameters;
+ this.iv = this.paramPlusIV.GetIV();
+ this.parameters = this.paramPlusIV.Parameters;
+
+ if (this.iv.Length != 8)
+ throw new ArgumentException("IV is not 8 octets");
+ }
+ else
+ {
+ this.parameters = parameters;
+
+ if (this.forWrapping)
+ {
+ // Hm, we have no IV but we want to wrap ?!?
+ // well, then we have to create our own IV.
+ this.iv = new byte[8];
+ sr.NextBytes(iv);
+ this.paramPlusIV = new ParametersWithIV(this.parameters, this.iv);
+ }
+ }
+ }
+
+ /**
+ * Method GetAlgorithmName
+ *
+ * @return
+ */
+ public virtual string AlgorithmName
+ {
+ get { return "RC2"; }
+ }
+
+ /**
+ * Method wrap
+ *
+ * @param in
+ * @param inOff
+ * @param inLen
+ * @return
+ */
+ public virtual byte[] Wrap(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (!forWrapping)
+ {
+ throw new InvalidOperationException("Not initialized for wrapping");
+ }
+
+ int len = length + 1;
+ if ((len % 8) != 0)
+ {
+ len += 8 - (len % 8);
+ }
+
+ byte [] keyToBeWrapped = new byte[len];
+
+ keyToBeWrapped[0] = (byte)length;
+ Array.Copy(input, inOff, keyToBeWrapped, 1, length);
+
+ byte[] pad = new byte[keyToBeWrapped.Length - length - 1];
+
+ if (pad.Length > 0)
+ {
+ sr.NextBytes(pad);
+ Array.Copy(pad, 0, keyToBeWrapped, length + 1, pad.Length);
+ }
+
+ // Compute the CMS Key Checksum, (section 5.6.1), call this CKS.
+ byte[] CKS = CalculateCmsKeyChecksum(keyToBeWrapped);
+
+ // Let WKCKS = WK || CKS where || is concatenation.
+ byte[] WKCKS = new byte[keyToBeWrapped.Length + CKS.Length];
+
+ Array.Copy(keyToBeWrapped, 0, WKCKS, 0, keyToBeWrapped.Length);
+ Array.Copy(CKS, 0, WKCKS, keyToBeWrapped.Length, CKS.Length);
+
+ // Encrypt WKCKS in CBC mode using KEK as the key and IV as the
+ // initialization vector. Call the results TEMP1.
+ byte [] TEMP1 = new byte[WKCKS.Length];
+
+ Array.Copy(WKCKS, 0, TEMP1, 0, WKCKS.Length);
+
+ int noOfBlocks = WKCKS.Length / engine.GetBlockSize();
+ int extraBytes = WKCKS.Length % engine.GetBlockSize();
+
+ if (extraBytes != 0)
+ {
+ throw new InvalidOperationException("Not multiple of block length");
+ }
+
+ engine.Init(true, paramPlusIV);
+
+ for (int i = 0; i < noOfBlocks; i++)
+ {
+ int currentBytePos = i * engine.GetBlockSize();
+
+ engine.ProcessBlock(TEMP1, currentBytePos, TEMP1, currentBytePos);
+ }
+
+ // Left TEMP2 = IV || TEMP1.
+ byte[] TEMP2 = new byte[this.iv.Length + TEMP1.Length];
+
+ Array.Copy(this.iv, 0, TEMP2, 0, this.iv.Length);
+ Array.Copy(TEMP1, 0, TEMP2, this.iv.Length, TEMP1.Length);
+
+ // Reverse the order of the octets in TEMP2 and call the result TEMP3.
+ byte[] TEMP3 = new byte[TEMP2.Length];
+
+ for (int i = 0; i < TEMP2.Length; i++)
+ {
+ TEMP3[i] = TEMP2[TEMP2.Length - (i + 1)];
+ }
+
+ // Encrypt TEMP3 in CBC mode using the KEK and an initialization vector
+ // of 0x 4a dd a2 2c 79 e8 21 05. The resulting cipher text is the desired
+ // result. It is 40 octets long if a 168 bit key is being wrapped.
+ ParametersWithIV param2 = new ParametersWithIV(this.parameters, IV2);
+
+ this.engine.Init(true, param2);
+
+ for (int i = 0; i < noOfBlocks + 1; i++)
+ {
+ int currentBytePos = i * engine.GetBlockSize();
+
+ engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
+ }
+
+ return TEMP3;
+ }
+
+ /**
+ * Method unwrap
+ *
+ * @param in
+ * @param inOff
+ * @param inLen
+ * @return
+ * @throws InvalidCipherTextException
+ */
+ public virtual byte[] Unwrap(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (forWrapping)
+ {
+ throw new InvalidOperationException("Not set for unwrapping");
+ }
+
+ if (input == null)
+ {
+ throw new InvalidCipherTextException("Null pointer as ciphertext");
+ }
+
+ if (length % engine.GetBlockSize() != 0)
+ {
+ throw new InvalidCipherTextException("Ciphertext not multiple of "
+ + engine.GetBlockSize());
+ }
+
+ /*
+ // Check if the length of the cipher text is reasonable given the key
+ // type. It must be 40 bytes for a 168 bit key and either 32, 40, or
+ // 48 bytes for a 128, 192, or 256 bit key. If the length is not supported
+ // or inconsistent with the algorithm for which the key is intended,
+ // return error.
+ //
+ // we do not accept 168 bit keys. it has to be 192 bit.
+ int lengthA = (estimatedKeyLengthInBit / 8) + 16;
+ int lengthB = estimatedKeyLengthInBit % 8;
+
+ if ((lengthA != keyToBeUnwrapped.Length) || (lengthB != 0)) {
+ throw new XMLSecurityException("empty");
+ }
+ */
+
+ // Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK
+ // and an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP3.
+ ParametersWithIV param2 = new ParametersWithIV(this.parameters, IV2);
+
+ this.engine.Init(false, param2);
+
+ byte [] TEMP3 = new byte[length];
+
+ Array.Copy(input, inOff, TEMP3, 0, length);
+
+ for (int i = 0; i < (TEMP3.Length / engine.GetBlockSize()); i++)
+ {
+ int currentBytePos = i * engine.GetBlockSize();
+
+ engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
+ }
+
+ // Reverse the order of the octets in TEMP3 and call the result TEMP2.
+ byte[] TEMP2 = new byte[TEMP3.Length];
+
+ for (int i = 0; i < TEMP3.Length; i++)
+ {
+ TEMP2[i] = TEMP3[TEMP3.Length - (i + 1)];
+ }
+
+ // Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining octets.
+ this.iv = new byte[8];
+
+ byte[] TEMP1 = new byte[TEMP2.Length - 8];
+
+ Array.Copy(TEMP2, 0, this.iv, 0, 8);
+ Array.Copy(TEMP2, 8, TEMP1, 0, TEMP2.Length - 8);
+
+ // Decrypt TEMP1 using TRIPLedeS in CBC mode using the KEK and the IV
+ // found in the previous step. Call the result WKCKS.
+ this.paramPlusIV = new ParametersWithIV(this.parameters, this.iv);
+
+ this.engine.Init(false, this.paramPlusIV);
+
+ byte[] LCEKPADICV = new byte[TEMP1.Length];
+
+ Array.Copy(TEMP1, 0, LCEKPADICV, 0, TEMP1.Length);
+
+ for (int i = 0; i < (LCEKPADICV.Length / engine.GetBlockSize()); i++)
+ {
+ int currentBytePos = i * engine.GetBlockSize();
+
+ engine.ProcessBlock(LCEKPADICV, currentBytePos, LCEKPADICV, currentBytePos);
+ }
+
+ // Decompose LCEKPADICV. CKS is the last 8 octets and WK, the wrapped key, are
+ // those octets before the CKS.
+ byte[] result = new byte[LCEKPADICV.Length - 8];
+ byte[] CKStoBeVerified = new byte[8];
+
+ Array.Copy(LCEKPADICV, 0, result, 0, LCEKPADICV.Length - 8);
+ Array.Copy(LCEKPADICV, LCEKPADICV.Length - 8, CKStoBeVerified, 0, 8);
+
+ // Calculate a CMS Key Checksum, (section 5.6.1), over the WK and compare
+ // with the CKS extracted in the above step. If they are not equal, return error.
+ if (!CheckCmsKeyChecksum(result, CKStoBeVerified))
+ {
+ throw new InvalidCipherTextException(
+ "Checksum inside ciphertext is corrupted");
+ }
+
+ if ((result.Length - ((result[0] & 0xff) + 1)) > 7)
+ {
+ throw new InvalidCipherTextException(
+ "too many pad bytes (" + (result.Length - ((result[0] & 0xff) + 1)) + ")");
+ }
+
+ // CEK is the wrapped key, now extracted for use in data decryption.
+ byte[] CEK = new byte[result[0]];
+ Array.Copy(result, 1, CEK, 0, CEK.Length);
+ return CEK;
+ }
+
+ /**
+ * Some key wrap algorithms make use of the Key Checksum defined
+ * in CMS [CMS-Algorithms]. This is used to provide an integrity
+ * check value for the key being wrapped. The algorithm is
+ *
+ * - Compute the 20 octet SHA-1 hash on the key being wrapped.
+ * - Use the first 8 octets of this hash as the checksum value.
+ *
+ * @param key
+ * @return
+ * @throws Exception
+ * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+ */
+ private byte[] CalculateCmsKeyChecksum(
+ byte[] key)
+ {
+ sha1.BlockUpdate(key, 0, key.Length);
+ sha1.DoFinal(digest, 0);
+
+ byte[] result = new byte[8];
+ Array.Copy(digest, 0, result, 0, 8);
+ return result;
+ }
+
+ /**
+ * @param key
+ * @param checksum
+ * @return
+ * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+ */
+ private bool CheckCmsKeyChecksum(
+ byte[] key,
+ byte[] checksum)
+ {
+ return Arrays.ConstantTimeAreEqual(CalculateCmsKeyChecksum(key), checksum);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/RC4Engine.cs b/bc-sharp-crypto/src/crypto/engines/RC4Engine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a515bb04ef447d17cae974da7057e757e7dcfad2
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/RC4Engine.cs
@@ -0,0 +1,139 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ public class RC4Engine
+ : IStreamCipher
+ {
+ private readonly static int STATE_LENGTH = 256;
+
+ /*
+ * variables to hold the state of the RC4 engine
+ * during encryption and decryption
+ */
+
+ private byte[] engineState;
+ private int x;
+ private int y;
+ private byte[] workingKey;
+
+ /**
+ * initialise a RC4 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 virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (parameters is KeyParameter)
+ {
+ /*
+ * RC4 encryption and decryption is completely
+ * symmetrical, so the 'forEncryption' is
+ * irrelevant.
+ */
+ workingKey = ((KeyParameter)parameters).GetKey();
+ SetKey(workingKey);
+
+ return;
+ }
+
+ throw new ArgumentException("invalid parameter passed to RC4 init - " + Platform.GetTypeName(parameters));
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "RC4"; }
+ }
+
+ public virtual byte ReturnByte(
+ byte input)
+ {
+ x = (x + 1) & 0xff;
+ y = (engineState[x] + y) & 0xff;
+
+ // swap
+ byte tmp = engineState[x];
+ engineState[x] = engineState[y];
+ engineState[y] = tmp;
+
+ // xor
+ return (byte)(input ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
+ }
+
+ public virtual void ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] output,
+ int outOff)
+ {
+ Check.DataLength(input, inOff, length, "input buffer too short");
+ Check.OutputLength(output, outOff, length, "output buffer too short");
+
+ for (int i = 0; i < length ; i++)
+ {
+ x = (x + 1) & 0xff;
+ y = (engineState[x] + y) & 0xff;
+
+ // swap
+ byte tmp = engineState[x];
+ engineState[x] = engineState[y];
+ engineState[y] = tmp;
+
+ // xor
+ output[i+outOff] = (byte)(input[i + inOff]
+ ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
+ }
+ }
+
+ public virtual void Reset()
+ {
+ SetKey(workingKey);
+ }
+
+ // Private implementation
+
+ private void SetKey(
+ byte[] keyBytes)
+ {
+ workingKey = keyBytes;
+
+ // System.out.println("the key length is ; "+ workingKey.Length);
+
+ x = 0;
+ y = 0;
+
+ if (engineState == null)
+ {
+ engineState = new byte[STATE_LENGTH];
+ }
+
+ // reset the state of the engine
+ for (int i=0; i < STATE_LENGTH; i++)
+ {
+ engineState[i] = (byte)i;
+ }
+
+ int i1 = 0;
+ int i2 = 0;
+
+ for (int i=0; i < STATE_LENGTH; i++)
+ {
+ i2 = ((keyBytes[i1] & 0xff) + engineState[i] + i2) & 0xff;
+ // do the byte-swap inline
+ byte tmp = engineState[i];
+ engineState[i] = engineState[i2];
+ engineState[i2] = tmp;
+ i1 = (i1+1) % keyBytes.Length;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/RC532Engine.cs b/bc-sharp-crypto/src/crypto/engines/RC532Engine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d1c29e6241d5ace85a40352e928990d940cbe65b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/RC532Engine.cs
@@ -0,0 +1,294 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * The specification for RC5 came from the RC5 Encryption Algorithm
+ * publication in RSA CryptoBytes, Spring of 1995.
+ * http://www.rsasecurity.com/rsalabs/cryptobytes .
+ *
+ * This implementation has a word size of 32 bits.
+ */
+ public class RC532Engine
+ : IBlockCipher
+ {
+ /*
+ * the number of rounds to perform
+ */
+ private int _noRounds;
+
+ /*
+ * the expanded key array of size 2*(rounds + 1)
+ */
+ private int [] _S;
+
+ /*
+ * our "magic constants" for 32 32
+ *
+ * Pw = Odd((e-2) * 2^wordsize)
+ * Qw = Odd((o-2) * 2^wordsize)
+ *
+ * where e is the base of natural logarithms (2.718281828...)
+ * and o is the golden ratio (1.61803398...)
+ */
+ private static readonly int P32 = unchecked((int) 0xb7e15163);
+ private static readonly int Q32 = unchecked((int) 0x9e3779b9);
+
+ private bool forEncryption;
+
+ /**
+ * Create an instance of the RC5 encryption algorithm
+ * and set some defaults
+ */
+ public RC532Engine()
+ {
+ _noRounds = 12; // the default
+// _S = null;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "RC5-32"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return 2 * 4;
+ }
+
+ /**
+ * initialise a RC5-32 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 virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (typeof(RC5Parameters).IsInstanceOfType(parameters))
+ {
+ RC5Parameters p = (RC5Parameters)parameters;
+
+ _noRounds = p.Rounds;
+
+ SetKey(p.GetKey());
+ }
+ else if (typeof(KeyParameter).IsInstanceOfType(parameters))
+ {
+ KeyParameter p = (KeyParameter)parameters;
+
+ SetKey(p.GetKey());
+ }
+ else
+ {
+ throw new ArgumentException("invalid parameter passed to RC532 init - " + Platform.GetTypeName(parameters));
+ }
+
+ this.forEncryption = forEncryption;
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ return (forEncryption)
+ ? EncryptBlock(input, inOff, output, outOff)
+ : DecryptBlock(input, inOff, output, outOff);
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ /**
+ * Re-key the cipher.
+ *
+ * @param key the key to be used
+ */
+ private void SetKey(
+ byte[] key)
+ {
+ //
+ // KEY EXPANSION:
+ //
+ // There are 3 phases to the key expansion.
+ //
+ // Phase 1:
+ // Copy the secret key K[0...b-1] into an array L[0..c-1] of
+ // c = ceil(b/u), where u = 32/8 in little-endian order.
+ // In other words, we fill up L using u consecutive key bytes
+ // 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];
+
+ for (int i = 0; i != key.Length; i++)
+ {
+ L[i / 4] += (key[i] & 0xff) << (8 * (i % 4));
+ }
+
+ //
+ // Phase 2:
+ // Initialize S to a particular fixed pseudo-random bit pattern
+ // using an arithmetic progression modulo 2^wordsize determined
+ // by the magic numbers, Pw & Qw.
+ //
+ _S = new int[2*(_noRounds + 1)];
+
+ _S[0] = P32;
+ for (int i=1; i < _S.Length; i++)
+ {
+ _S[i] = (_S[i-1] + Q32);
+ }
+
+ //
+ // Phase 3:
+ // Mix in the user's secret key in 3 passes over the arrays S & L.
+ // The max of the arrays sizes is used as the loop control
+ //
+ int iter;
+
+ if (L.Length > _S.Length)
+ {
+ iter = 3 * L.Length;
+ }
+ else
+ {
+ iter = 3 * _S.Length;
+ }
+
+ int A = 0, B = 0;
+ int ii = 0, jj = 0;
+
+ 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);
+ 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)
+ {
+ int A = BytesToWord(input, inOff) + _S[0];
+ int B = BytesToWord(input, inOff + 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];
+ }
+
+ WordToBytes(A, outBytes, outOff);
+ WordToBytes(B, outBytes, outOff + 4);
+
+ return 2 * 4;
+ }
+
+ private int DecryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ int A = BytesToWord(input, inOff);
+ int B = BytesToWord(input, inOff + 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;
+ }
+
+ WordToBytes(A - _S[0], outBytes, outOff);
+ WordToBytes(B - _S[1], outBytes, outOff + 4);
+
+ return 2 * 4;
+ }
+
+
+ //////////////////////////////////////////////////////////////
+ //
+ // PRIVATE Helper Methods
+ //
+ //////////////////////////////////////////////////////////////
+
+ /**
+ * Perform a left "spin" of the word. The rotation of the given
+ * word x is rotated left by y bits.
+ * Only the lg(32) low-order bits of y
+ * 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 x is rotated left by y bits.
+ * Only the lg(32) low-order bits of y
+ * 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)))) )
+ );
+ }
+
+ private int BytesToWord(
+ byte[] src,
+ int srcOff)
+ {
+ return (src[srcOff] & 0xff) | ((src[srcOff + 1] & 0xff) << 8)
+ | ((src[srcOff + 2] & 0xff) << 16) | ((src[srcOff + 3] & 0xff) << 24);
+ }
+
+ 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);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/RC564Engine.cs b/bc-sharp-crypto/src/crypto/engines/RC564Engine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..097fd60bad1c379846cdd057e3f78bdd72a9e266
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/RC564Engine.cs
@@ -0,0 +1,295 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * The specification for RC5 came from the RC5 Encryption Algorithm
+ * publication in RSA CryptoBytes, Spring of 1995.
+ * http://www.rsasecurity.com/rsalabs/cryptobytes .
+ *
+ * This implementation is set to work with a 64 bit word size.
+ */
+ public class RC564Engine
+ : IBlockCipher
+ {
+ private static readonly int wordSize = 64;
+ private static readonly int bytesPerWord = wordSize / 8;
+
+ /*
+ * the number of rounds to perform
+ */
+ private int _noRounds;
+
+ /*
+ * the expanded key array of size 2*(rounds + 1)
+ */
+ private long [] _S;
+
+ /*
+ * our "magic constants" for wordSize 62
+ *
+ * Pw = Odd((e-2) * 2^wordsize)
+ * Qw = Odd((o-2) * 2^wordsize)
+ *
+ * where e is the base of natural logarithms (2.718281828...)
+ * and o is the golden ratio (1.61803398...)
+ */
+ private static readonly long P64 = unchecked( (long) 0xb7e151628aed2a6bL);
+ private static readonly long Q64 = unchecked( (long) 0x9e3779b97f4a7c15L);
+
+ private bool forEncryption;
+
+ /**
+ * Create an instance of the RC5 encryption algorithm
+ * and set some defaults
+ */
+ public RC564Engine()
+ {
+ _noRounds = 12;
+// _S = null;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "RC5-64"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return 2 * bytesPerWord;
+ }
+
+ /**
+ * initialise a RC5-64 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 virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(typeof(RC5Parameters).IsInstanceOfType(parameters)))
+ {
+ throw new ArgumentException("invalid parameter passed to RC564 init - " + Platform.GetTypeName(parameters));
+ }
+
+ RC5Parameters p = (RC5Parameters)parameters;
+
+ this.forEncryption = forEncryption;
+
+ _noRounds = p.Rounds;
+
+ SetKey(p.GetKey());
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ return (forEncryption) ? EncryptBlock(input, inOff, output, outOff)
+ : DecryptBlock(input, inOff, output, outOff);
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ /**
+ * Re-key the cipher.
+ *
+ * @param key the key to be used
+ */
+ private void SetKey(
+ byte[] key)
+ {
+ //
+ // KEY EXPANSION:
+ //
+ // There are 3 phases to the key expansion.
+ //
+ // Phase 1:
+ // Copy the secret key K[0...b-1] into an array L[0..c-1] of
+ // c = ceil(b/u), where u = wordSize/8 in little-endian order.
+ // In other words, we fill up L using u consecutive key bytes
+ // 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];
+
+ for (int i = 0; i != key.Length; i++)
+ {
+ L[i / bytesPerWord] += (long)(key[i] & 0xff) << (8 * (i % bytesPerWord));
+ }
+
+ //
+ // Phase 2:
+ // Initialize S to a particular fixed pseudo-random bit pattern
+ // using an arithmetic progression modulo 2^wordsize determined
+ // by the magic numbers, Pw & Qw.
+ //
+ _S = new long[2*(_noRounds + 1)];
+
+ _S[0] = P64;
+ for (int i=1; i < _S.Length; i++)
+ {
+ _S[i] = (_S[i-1] + Q64);
+ }
+
+ //
+ // Phase 3:
+ // Mix in the user's secret key in 3 passes over the arrays S & L.
+ // The max of the arrays sizes is used as the loop control
+ //
+ int iter;
+
+ if (L.Length > _S.Length)
+ {
+ iter = 3 * L.Length;
+ }
+ else
+ {
+ iter = 3 * _S.Length;
+ }
+
+ long A = 0, B = 0;
+ int ii = 0, jj = 0;
+
+ 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);
+ 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)
+ {
+ long A = BytesToWord(input, inOff) + _S[0];
+ long B = BytesToWord(input, inOff + bytesPerWord) + _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];
+ }
+
+ WordToBytes(A, outBytes, outOff);
+ WordToBytes(B, outBytes, outOff + bytesPerWord);
+
+ return 2 * bytesPerWord;
+ }
+
+ private int DecryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ long A = BytesToWord(input, inOff);
+ long B = BytesToWord(input, inOff + bytesPerWord);
+
+ for (int i = _noRounds; i >= 1; i--)
+ {
+ B = RotateRight(B - _S[2*i+1], A) ^ A;
+ A = RotateRight(A - _S[2*i], B) ^ B;
+ }
+
+ WordToBytes(A - _S[0], outBytes, outOff);
+ WordToBytes(B - _S[1], outBytes, outOff + bytesPerWord);
+
+ return 2 * bytesPerWord;
+ }
+
+
+ //////////////////////////////////////////////////////////////
+ //
+ // PRIVATE Helper Methods
+ //
+ //////////////////////////////////////////////////////////////
+
+ /**
+ * Perform a left "spin" of the word. The rotation of the given
+ * word x is rotated left by y bits.
+ * Only the lg(wordSize) low-order bits of y
+ * 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)))))
+ );
+ }
+
+ /**
+ * Perform a right "spin" of the word. The rotation of the given
+ * word x is rotated left by y bits.
+ * Only the lg(wordSize) low-order bits of y
+ * 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)))))
+ );
+ }
+
+ private long BytesToWord(
+ byte[] src,
+ int srcOff)
+ {
+ long word = 0;
+
+ for (int i = bytesPerWord - 1; i >= 0; i--)
+ {
+ word = (word << 8) + (src[i + srcOff] & 0xff);
+ }
+
+ return word;
+ }
+
+ 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);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/RC6Engine.cs b/bc-sharp-crypto/src/crypto/engines/RC6Engine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9aeb1e7cbdd2f5d4e3c95fc89758c29358e5afee
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/RC6Engine.cs
@@ -0,0 +1,361 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * An RC6 engine.
+ */
+ public class RC6Engine
+ : IBlockCipher
+ {
+ private static readonly int wordSize = 32;
+ private static readonly int bytesPerWord = wordSize / 8;
+
+ /*
+ * the number of rounds to perform
+ */
+ private static readonly int _noRounds = 20;
+
+ /*
+ * the expanded key array of size 2*(rounds + 1)
+ */
+ private int [] _S;
+
+ /*
+ * our "magic constants" for wordSize 32
+ *
+ * Pw = Odd((e-2) * 2^wordsize)
+ * Qw = Odd((o-2) * 2^wordsize)
+ *
+ * where e is the base of natural logarithms (2.718281828...)
+ * and o is the golden ratio (1.61803398...)
+ */
+ private static readonly int P32 = unchecked((int) 0xb7e15163);
+ private static readonly int Q32 = unchecked((int) 0x9e3779b9);
+
+ private static readonly int LGW = 5; // log2(32)
+
+ private bool forEncryption;
+
+ /**
+ * Create an instance of the RC6 encryption algorithm
+ * and set some defaults
+ */
+ public RC6Engine()
+ {
+// _S = null;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "RC6"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return 4 * bytesPerWord;
+ }
+
+ /**
+ * initialise a RC5-32 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 virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("invalid parameter passed to RC6 init - " + Platform.GetTypeName(parameters));
+
+ this.forEncryption = forEncryption;
+
+ KeyParameter p = (KeyParameter)parameters;
+ SetKey(p.GetKey());
+ }
+
+ 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");
+
+ 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);
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ /**
+ * Re-key the cipher.
+ *
+ * @param inKey the key to be used
+ */
+ private void SetKey(
+ byte[] key)
+ {
+ //
+ // KEY EXPANSION:
+ //
+ // There are 3 phases to the key expansion.
+ //
+ // Phase 1:
+ // Copy the secret key K[0...b-1] into an array L[0..c-1] of
+ // c = ceil(b/u), where u = wordSize/8 in little-endian order.
+ // In other words, we fill up L using u consecutive key bytes
+ // of K. Any unfilled byte positions in L are zeroed. In the
+ // case that b = c = 0, set c = 1 and L[0] = 0.
+ //
+ // compute number of dwords
+ int c = (key.Length + (bytesPerWord - 1)) / bytesPerWord;
+ if (c == 0)
+ {
+ c = 1;
+ }
+ int[] L = new int[(key.Length + bytesPerWord - 1) / bytesPerWord];
+
+ // 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);
+ }
+
+ //
+ // Phase 2:
+ // Key schedule is placed in a array of 2+2*ROUNDS+2 = 44 dwords.
+ // Initialize S to a particular fixed pseudo-random bit pattern
+ // using an arithmetic progression modulo 2^wordsize determined
+ // by the magic numbers, Pw & Qw.
+ //
+ _S = new int[2+2*_noRounds+2];
+
+ _S[0] = P32;
+ for (int i=1; i < _S.Length; i++)
+ {
+ _S[i] = (_S[i-1] + Q32);
+ }
+
+ //
+ // Phase 3:
+ // Mix in the user's secret key in 3 passes over the arrays S & L.
+ // The max of the arrays sizes is used as the loop control
+ //
+ int iter;
+
+ if (L.Length > _S.Length)
+ {
+ iter = 3 * L.Length;
+ }
+ else
+ {
+ iter = 3 * _S.Length;
+ }
+
+ int A = 0;
+ int B = 0;
+ int ii = 0, jj = 0;
+
+ 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);
+ ii = (ii+1) % _S.Length;
+ jj = (jj+1) % L.Length;
+ }
+ }
+
+ private int EncryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ // 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);
+
+ // Do pseudo-round #0: pre-whitening of B and D
+ B += _S[0];
+ D += _S[1];
+
+ // perform round #1,#2 ... #ROUNDS of encryption
+ for (int i = 1; i <= _noRounds; i++)
+ {
+ int t = 0,u = 0;
+
+ t = B*(2*B+1);
+ t = RotateLeft(t,5);
+
+ u = D*(2*D+1);
+ u = RotateLeft(u,5);
+
+ A ^= t;
+ A = RotateLeft(A,u);
+ A += _S[2*i];
+
+ C ^= u;
+ C = RotateLeft(C,t);
+ C += _S[2*i+1];
+
+ int temp = A;
+ A = B;
+ B = C;
+ 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];
+
+ // 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);
+
+ return 4 * bytesPerWord;
+ }
+
+ private int DecryptBlock(
+ byte[] input,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ // 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);
+
+ // 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--)
+ {
+ int t=0,u = 0;
+
+ int temp = D;
+ D = C;
+ C = B;
+ B = A;
+ A = temp;
+
+ t = B*(2*B+1);
+ t = RotateLeft(t, LGW);
+
+ u = D*(2*D+1);
+ u = RotateLeft(u, LGW);
+
+ C -= _S[2*i+1];
+ C = RotateRight(C,t);
+ C ^= u;
+
+ A -= _S[2*i];
+ A = 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);
+
+ return 4 * bytesPerWord;
+ }
+
+
+ //////////////////////////////////////////////////////////////
+ //
+ // PRIVATE Helper Methods
+ //
+ //////////////////////////////////////////////////////////////
+
+ /**
+ * Perform a left "spin" of the word. The rotation of the given
+ * word x is rotated left by y bits.
+ * Only the lg(wordSize) low-order bits of y
+ * 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))))));
+ }
+
+ /**
+ * Perform a right "spin" of the word. The rotation of the given
+ * word x is rotated left by y bits.
+ * Only the lg(wordSize) low-order bits of y
+ * 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))))));
+ }
+
+ private int BytesToWord(
+ byte[] src,
+ int srcOff)
+ {
+ int word = 0;
+
+ for (int i = bytesPerWord - 1; i >= 0; i--)
+ {
+ word = (word << 8) + (src[i + srcOff] & 0xff);
+ }
+
+ return word;
+ }
+
+ private void WordToBytes(
+ int word,
+ byte[] dst,
+ int dstOff)
+ {
+ for (int i = 0; i < bytesPerWord; i++)
+ {
+ dst[i + dstOff] = (byte)word;
+ word = (int) ((uint) word >> 8);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/RFC3211WrapEngine.cs b/bc-sharp-crypto/src/crypto/engines/RFC3211WrapEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4e3af52277e0f301ce85819695e22958ca0f81d8
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/RFC3211WrapEngine.cs
@@ -0,0 +1,168 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * an implementation of the RFC 3211 Key Wrap
+ * Specification.
+ */
+ public class Rfc3211WrapEngine
+ : IWrapper
+ {
+ private CbcBlockCipher engine;
+ private ParametersWithIV param;
+ private bool forWrapping;
+ private SecureRandom rand;
+
+ public Rfc3211WrapEngine(
+ IBlockCipher engine)
+ {
+ this.engine = new CbcBlockCipher(engine);
+ }
+
+ public virtual void Init(
+ bool forWrapping,
+ ICipherParameters param)
+ {
+ this.forWrapping = forWrapping;
+
+ if (param is ParametersWithRandom)
+ {
+ ParametersWithRandom p = (ParametersWithRandom) param;
+
+ this.rand = p.Random;
+ this.param = (ParametersWithIV) p.Parameters;
+ }
+ else
+ {
+ if (forWrapping)
+ {
+ rand = new SecureRandom();
+ }
+
+ this.param = (ParametersWithIV) param;
+ }
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return engine.GetUnderlyingCipher().AlgorithmName + "/RFC3211Wrap"; }
+ }
+
+ public virtual byte[] Wrap(
+ byte[] inBytes,
+ int inOff,
+ int inLen)
+ {
+ if (!forWrapping)
+ {
+ throw new InvalidOperationException("not set for wrapping");
+ }
+
+ engine.Init(true, param);
+
+ int blockSize = engine.GetBlockSize();
+ byte[] cekBlock;
+
+ if (inLen + 4 < blockSize * 2)
+ {
+ cekBlock = new byte[blockSize * 2];
+ }
+ else
+ {
+ cekBlock = new byte[(inLen + 4) % blockSize == 0 ? inLen + 4 : ((inLen + 4) / blockSize + 1) * blockSize];
+ }
+
+ cekBlock[0] = (byte)inLen;
+ cekBlock[1] = (byte)~inBytes[inOff];
+ cekBlock[2] = (byte)~inBytes[inOff + 1];
+ cekBlock[3] = (byte)~inBytes[inOff + 2];
+
+ Array.Copy(inBytes, inOff, cekBlock, 4, inLen);
+
+ rand.NextBytes(cekBlock, inLen + 4, cekBlock.Length - inLen - 4);
+
+ for (int i = 0; i < cekBlock.Length; i += blockSize)
+ {
+ engine.ProcessBlock(cekBlock, i, cekBlock, i);
+ }
+
+ for (int i = 0; i < cekBlock.Length; i += blockSize)
+ {
+ engine.ProcessBlock(cekBlock, i, cekBlock, i);
+ }
+
+ return cekBlock;
+ }
+
+ public virtual byte[] Unwrap(
+ byte[] inBytes,
+ int inOff,
+ int inLen)
+ {
+ if (forWrapping)
+ {
+ throw new InvalidOperationException("not set for unwrapping");
+ }
+
+ int blockSize = engine.GetBlockSize();
+
+ if (inLen < 2 * blockSize)
+ {
+ throw new InvalidCipherTextException("input too short");
+ }
+
+ byte[] cekBlock = new byte[inLen];
+ byte[] iv = new byte[blockSize];
+
+ Array.Copy(inBytes, inOff, cekBlock, 0, inLen);
+ Array.Copy(inBytes, inOff, iv, 0, iv.Length);
+
+ engine.Init(false, new ParametersWithIV(param.Parameters, iv));
+
+ for (int i = blockSize; i < cekBlock.Length; i += blockSize)
+ {
+ engine.ProcessBlock(cekBlock, i, cekBlock, i);
+ }
+
+ Array.Copy(cekBlock, cekBlock.Length - iv.Length, iv, 0, iv.Length);
+
+ engine.Init(false, new ParametersWithIV(param.Parameters, iv));
+
+ engine.ProcessBlock(cekBlock, 0, cekBlock, 0);
+
+ engine.Init(false, param);
+
+ for (int i = 0; i < cekBlock.Length; i += blockSize)
+ {
+ engine.ProcessBlock(cekBlock, i, cekBlock, i);
+ }
+
+ if ((cekBlock[0] & 0xff) > cekBlock.Length - 4)
+ {
+ throw new InvalidCipherTextException("wrapped key corrupted");
+ }
+
+ byte[] key = new byte[cekBlock[0] & 0xff];
+
+ Array.Copy(cekBlock, 4, key, 0, cekBlock[0]);
+
+ // Note: Using constant time comparison
+ int nonEqual = 0;
+ for (int i = 0; i != 3; i++)
+ {
+ byte check = (byte)~cekBlock[1 + i];
+ nonEqual |= (check ^ key[i]);
+ }
+
+ if (nonEqual != 0)
+ throw new InvalidCipherTextException("wrapped key fails checksum");
+
+ return key;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/RFC3394WrapEngine.cs b/bc-sharp-crypto/src/crypto/engines/RFC3394WrapEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4bb0e211413865f516a1ca51c9a21c32b5c4c876
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/RFC3394WrapEngine.cs
@@ -0,0 +1,178 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ ///
+ /// An implementation of the AES Key Wrapper from the NIST Key Wrap
+ /// Specification as described in RFC 3394.
+ ///
+ /// For further details see: http://www.ietf.org/rfc/rfc3394.txt
+ /// and http://csrc.nist.gov/encryption/kms/key-wrap.pdf .
+ ///
+ public class Rfc3394WrapEngine
+ : IWrapper
+ {
+ private readonly IBlockCipher engine;
+
+ private KeyParameter param;
+ private bool forWrapping;
+
+ private byte[] iv =
+ {
+ 0xa6, 0xa6, 0xa6, 0xa6,
+ 0xa6, 0xa6, 0xa6, 0xa6
+ };
+
+ public Rfc3394WrapEngine(
+ IBlockCipher engine)
+ {
+ this.engine = engine;
+ }
+
+ public virtual void Init(
+ bool forWrapping,
+ ICipherParameters parameters)
+ {
+ this.forWrapping = forWrapping;
+
+ if (parameters is ParametersWithRandom)
+ {
+ parameters = ((ParametersWithRandom) parameters).Parameters;
+ }
+
+ if (parameters is KeyParameter)
+ {
+ this.param = (KeyParameter) parameters;
+ }
+ else if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV pIV = (ParametersWithIV) parameters;
+ byte[] iv = pIV.GetIV();
+
+ if (iv.Length != 8)
+ throw new ArgumentException("IV length not equal to 8", "parameters");
+
+ this.iv = iv;
+ this.param = (KeyParameter) pIV.Parameters;
+ }
+ else
+ {
+ // TODO Throw an exception for bad parameters?
+ }
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return engine.AlgorithmName; }
+ }
+
+ public virtual byte[] Wrap(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ if (!forWrapping)
+ {
+ throw new InvalidOperationException("not set for wrapping");
+ }
+
+ int n = inLen / 8;
+
+ if ((n * 8) != inLen)
+ {
+ throw new DataLengthException("wrap data must be a multiple of 8 bytes");
+ }
+
+ byte[] block = new byte[inLen + iv.Length];
+ byte[] buf = new byte[8 + iv.Length];
+
+ Array.Copy(iv, 0, block, 0, iv.Length);
+ Array.Copy(input, inOff, block, iv.Length, inLen);
+
+ engine.Init(true, param);
+
+ for (int j = 0; j != 6; j++)
+ {
+ for (int i = 1; i <= n; i++)
+ {
+ Array.Copy(block, 0, buf, 0, iv.Length);
+ Array.Copy(block, 8 * i, buf, iv.Length, 8);
+ engine.ProcessBlock(buf, 0, buf, 0);
+
+ int t = n * j + i;
+ for (int k = 1; t != 0; k++)
+ {
+ byte v = (byte)t;
+
+ buf[iv.Length - k] ^= v;
+ t = (int) ((uint)t >> 8);
+ }
+
+ Array.Copy(buf, 0, block, 0, 8);
+ Array.Copy(buf, 8, block, 8 * i, 8);
+ }
+ }
+
+ return block;
+ }
+
+ public virtual byte[] Unwrap(
+ byte[] input,
+ int inOff,
+ int inLen)
+ {
+ if (forWrapping)
+ {
+ throw new InvalidOperationException("not set for unwrapping");
+ }
+
+ int n = inLen / 8;
+
+ if ((n * 8) != inLen)
+ {
+ throw new InvalidCipherTextException("unwrap data must be a multiple of 8 bytes");
+ }
+
+ byte[] block = new byte[inLen - iv.Length];
+ byte[] a = new byte[iv.Length];
+ byte[] buf = new byte[8 + iv.Length];
+
+ Array.Copy(input, inOff, a, 0, iv.Length);
+ Array.Copy(input, inOff + iv.Length, block, 0, inLen - iv.Length);
+
+ engine.Init(false, param);
+
+ n = n - 1;
+
+ for (int j = 5; j >= 0; j--)
+ {
+ for (int i = n; i >= 1; i--)
+ {
+ Array.Copy(a, 0, buf, 0, iv.Length);
+ Array.Copy(block, 8 * (i - 1), buf, iv.Length, 8);
+
+ int t = n * j + i;
+ for (int k = 1; t != 0; k++)
+ {
+ byte v = (byte)t;
+
+ buf[iv.Length - k] ^= v;
+ t = (int) ((uint)t >> 8);
+ }
+
+ engine.ProcessBlock(buf, 0, buf, 0);
+ Array.Copy(buf, 0, a, 0, 8);
+ Array.Copy(buf, 8, block, 8 * (i - 1), 8);
+ }
+ }
+
+ if (!Arrays.ConstantTimeAreEqual(a, iv))
+ throw new InvalidCipherTextException("checksum failed");
+
+ return block;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/RSABlindedEngine.cs b/bc-sharp-crypto/src/crypto/engines/RSABlindedEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f95f145f6417f750e2d2efd291fdc588ac7870cb
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/RSABlindedEngine.cs
@@ -0,0 +1,128 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * this does your basic RSA algorithm with blinding
+ */
+ public class RsaBlindedEngine
+ : IAsymmetricBlockCipher
+ {
+ private readonly RsaCoreEngine core = new RsaCoreEngine();
+ private RsaKeyParameters key;
+ private SecureRandom random;
+
+ public virtual string AlgorithmName
+ {
+ get { return "RSA"; }
+ }
+
+ /**
+ * initialise the RSA engine.
+ *
+ * @param forEncryption true if we are encrypting, false otherwise.
+ * @param param the necessary RSA key parameters.
+ */
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters param)
+ {
+ core.Init(forEncryption, param);
+
+ if (param is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ key = (RsaKeyParameters)rParam.Parameters;
+ random = rParam.Random;
+ }
+ else
+ {
+ key = (RsaKeyParameters)param;
+ random = new SecureRandom();
+ }
+ }
+
+ /**
+ * Return the maximum size for an input block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * encryption, and the same length as the key size on decryption.
+ *
+ * @return maximum size for an input block.
+ */
+ public virtual int GetInputBlockSize()
+ {
+ return core.GetInputBlockSize();
+ }
+
+ /**
+ * Return the maximum size for an output block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * decryption, and the same length as the key size on encryption.
+ *
+ * @return maximum size for an output block.
+ */
+ public virtual int GetOutputBlockSize()
+ {
+ return core.GetOutputBlockSize();
+ }
+
+ /**
+ * Process a single block using the basic RSA algorithm.
+ *
+ * @param inBuf the input array.
+ * @param inOff the offset into the input buffer where the data starts.
+ * @param inLen the length of the data to be processed.
+ * @return the result of the RSA process.
+ * @exception DataLengthException the input block is too large.
+ */
+ public virtual byte[] ProcessBlock(
+ byte[] inBuf,
+ int inOff,
+ int inLen)
+ {
+ if (key == null)
+ throw new InvalidOperationException("RSA engine not initialised");
+
+ BigInteger input = core.ConvertInput(inBuf, inOff, inLen);
+
+ BigInteger result;
+ if (key is RsaPrivateCrtKeyParameters)
+ {
+ RsaPrivateCrtKeyParameters k = (RsaPrivateCrtKeyParameters)key;
+ BigInteger e = k.PublicExponent;
+ if (e != null) // can't do blinding without a public exponent
+ {
+ BigInteger m = k.Modulus;
+ BigInteger r = BigIntegers.CreateRandomInRange(
+ BigInteger.One, m.Subtract(BigInteger.One), random);
+
+ BigInteger blindedInput = r.ModPow(e, m).Multiply(input).Mod(m);
+ BigInteger blindedResult = core.ProcessBlock(blindedInput);
+
+ BigInteger rInv = r.ModInverse(m);
+ result = blindedResult.Multiply(rInv).Mod(m);
+
+ // defence against Arjen Lenstras CRT attack
+ if (!input.Equals(result.ModPow(e, m)))
+ throw new InvalidOperationException("RSA engine faulty decryption/signing detected");
+ }
+ else
+ {
+ result = core.ProcessBlock(input);
+ }
+ }
+ else
+ {
+ result = core.ProcessBlock(input);
+ }
+
+ return core.ConvertOutput(result);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/RSABlindingEngine.cs b/bc-sharp-crypto/src/crypto/engines/RSABlindingEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c636627bfced589527d104d23b1482b02da18301
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/RSABlindingEngine.cs
@@ -0,0 +1,139 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * This does your basic RSA Chaum's blinding and unblinding as outlined in
+ * "Handbook of Applied Cryptography", page 475. You need to use this if you are
+ * trying to get another party to generate signatures without them being aware
+ * of the message they are signing.
+ */
+ public class RsaBlindingEngine
+ : IAsymmetricBlockCipher
+ {
+ private readonly RsaCoreEngine core = new RsaCoreEngine();
+
+ private RsaKeyParameters key;
+ private BigInteger blindingFactor;
+
+ private bool forEncryption;
+
+ public virtual string AlgorithmName
+ {
+ get { return "RSA"; }
+ }
+
+ /**
+ * Initialise the blinding engine.
+ *
+ * @param forEncryption true if we are encrypting (blinding), false otherwise.
+ * @param param the necessary RSA key parameters.
+ */
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters param)
+ {
+ RsaBlindingParameters p;
+
+ if (param is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ p = (RsaBlindingParameters)rParam.Parameters;
+ }
+ else
+ {
+ p = (RsaBlindingParameters)param;
+ }
+
+ core.Init(forEncryption, p.PublicKey);
+
+ this.forEncryption = forEncryption;
+ this.key = p.PublicKey;
+ this.blindingFactor = p.BlindingFactor;
+ }
+
+ /**
+ * Return the maximum size for an input block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * encryption, and the same length as the key size on decryption.
+ *
+ * @return maximum size for an input block.
+ */
+ public virtual int GetInputBlockSize()
+ {
+ return core.GetInputBlockSize();
+ }
+
+ /**
+ * Return the maximum size for an output block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * decryption, and the same length as the key size on encryption.
+ *
+ * @return maximum size for an output block.
+ */
+ public virtual int GetOutputBlockSize()
+ {
+ return core.GetOutputBlockSize();
+ }
+
+ /**
+ * Process a single block using the RSA blinding algorithm.
+ *
+ * @param in the input array.
+ * @param inOff the offset into the input buffer where the data starts.
+ * @param inLen the length of the data to be processed.
+ * @return the result of the RSA process.
+ * @throws DataLengthException the input block is too large.
+ */
+ public virtual byte[] ProcessBlock(
+ byte[] inBuf,
+ int inOff,
+ int inLen)
+ {
+ BigInteger msg = core.ConvertInput(inBuf, inOff, inLen);
+
+ if (forEncryption)
+ {
+ msg = BlindMessage(msg);
+ }
+ else
+ {
+ msg = UnblindMessage(msg);
+ }
+
+ return core.ConvertOutput(msg);
+ }
+
+ /*
+ * Blind message with the blind factor.
+ */
+ private BigInteger BlindMessage(
+ BigInteger msg)
+ {
+ BigInteger blindMsg = blindingFactor;
+ blindMsg = msg.Multiply(blindMsg.ModPow(key.Exponent, key.Modulus));
+ blindMsg = blindMsg.Mod(key.Modulus);
+
+ return blindMsg;
+ }
+
+ /*
+ * Unblind the message blinded with the blind factor.
+ */
+ private BigInteger UnblindMessage(
+ BigInteger blindedMsg)
+ {
+ BigInteger m = key.Modulus;
+ BigInteger msg = blindedMsg;
+ BigInteger blindFactorInverse = blindingFactor.ModInverse(m);
+ msg = msg.Multiply(blindFactorInverse);
+ msg = msg.Mod(m);
+
+ return msg;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/RSACoreEngine.cs b/bc-sharp-crypto/src/crypto/engines/RSACoreEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fd44e3cc10a9347089a131a7cd7b739447cc6f52
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/RSACoreEngine.cs
@@ -0,0 +1,156 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * this does your basic RSA algorithm.
+ */
+ class RsaCoreEngine
+ {
+ private RsaKeyParameters key;
+ private bool forEncryption;
+ private int bitSize;
+
+ /**
+ * initialise the RSA engine.
+ *
+ * @param forEncryption true if we are encrypting, false otherwise.
+ * @param param the necessary RSA key parameters.
+ */
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ parameters = ((ParametersWithRandom) parameters).Parameters;
+ }
+
+ if (!(parameters is RsaKeyParameters))
+ throw new InvalidKeyException("Not an RSA key");
+
+ this.key = (RsaKeyParameters) parameters;
+ this.forEncryption = forEncryption;
+ this.bitSize = key.Modulus.BitLength;
+ }
+
+ /**
+ * Return the maximum size for an input block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * encryption, and the same length as the key size on decryption.
+ *
+ * @return maximum size for an input block.
+ */
+ public virtual int GetInputBlockSize()
+ {
+ if (forEncryption)
+ {
+ return (bitSize - 1) / 8;
+ }
+
+ return (bitSize + 7) / 8;
+ }
+
+ /**
+ * Return the maximum size for an output block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * decryption, and the same length as the key size on encryption.
+ *
+ * @return maximum size for an output block.
+ */
+ public virtual int GetOutputBlockSize()
+ {
+ if (forEncryption)
+ {
+ return (bitSize + 7) / 8;
+ }
+
+ return (bitSize - 1) / 8;
+ }
+
+ public virtual BigInteger ConvertInput(
+ byte[] inBuf,
+ int inOff,
+ int inLen)
+ {
+ int maxLength = (bitSize + 7) / 8;
+
+ if (inLen > maxLength)
+ throw new DataLengthException("input too large for RSA cipher.");
+
+ BigInteger input = new BigInteger(1, inBuf, inOff, inLen);
+
+ if (input.CompareTo(key.Modulus) >= 0)
+ throw new DataLengthException("input too large for RSA cipher.");
+
+ return input;
+ }
+
+ public virtual byte[] ConvertOutput(
+ BigInteger result)
+ {
+ byte[] output = result.ToByteArrayUnsigned();
+
+ if (forEncryption)
+ {
+ int outSize = GetOutputBlockSize();
+
+ // TODO To avoid this, create version of BigInteger.ToByteArray that
+ // writes to an existing array
+ if (output.Length < outSize) // have ended up with less bytes than normal, lengthen
+ {
+ byte[] tmp = new byte[outSize];
+ output.CopyTo(tmp, tmp.Length - output.Length);
+ output = tmp;
+ }
+ }
+
+ return output;
+ }
+
+ public virtual BigInteger ProcessBlock(
+ BigInteger input)
+ {
+ if (key is RsaPrivateCrtKeyParameters)
+ {
+ //
+ // we have the extra factors, use the Chinese Remainder Theorem - the author
+ // wishes to express his thanks to Dirk Bonekaemper at rtsffm.com for
+ // advice regarding the expression of this.
+ //
+ RsaPrivateCrtKeyParameters crtKey = (RsaPrivateCrtKeyParameters)key;
+
+ BigInteger p = crtKey.P;
+ BigInteger q = crtKey.Q;
+ BigInteger dP = crtKey.DP;
+ BigInteger dQ = crtKey.DQ;
+ BigInteger qInv = crtKey.QInv;
+
+ BigInteger mP, mQ, h, m;
+
+ // mP = ((input Mod p) ^ dP)) Mod p
+ mP = (input.Remainder(p)).ModPow(dP, p);
+
+ // mQ = ((input Mod q) ^ dQ)) Mod q
+ mQ = (input.Remainder(q)).ModPow(dQ, q);
+
+ // h = qInv * (mP - mQ) Mod p
+ h = mP.Subtract(mQ);
+ h = h.Multiply(qInv);
+ h = h.Mod(p); // Mod (in Java) returns the positive residual
+
+ // m = h * q + mQ
+ m = h.Multiply(q);
+ m = m.Add(mQ);
+
+ return m;
+ }
+
+ return input.ModPow(key.Exponent, key.Modulus);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/RijndaelEngine.cs b/bc-sharp-crypto/src/crypto/engines/RijndaelEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7025cb5dc5040bc7ec37651dd230b95023b106bf
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/RijndaelEngine.cs
@@ -0,0 +1,738 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+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.
+ *
+ * Note: this implementation is based on information prior to readonly NIST publication.
+ *
+ */
+ public class RijndaelEngine
+ : IBlockCipher
+ {
+ private static readonly int MAXROUNDS = 14;
+
+ private static readonly int MAXKC = (256/4);
+
+ private static readonly byte[] Logtable =
+ {
+ 0, 0, 25, 1, 50, 2, 26, 198,
+ 75, 199, 27, 104, 51, 238, 223, 3,
+ 100, 4, 224, 14, 52, 141, 129, 239,
+ 76, 113, 8, 200, 248, 105, 28, 193,
+ 125, 194, 29, 181, 249, 185, 39, 106,
+ 77, 228, 166, 114, 154, 201, 9, 120,
+ 101, 47, 138, 5, 33, 15, 225, 36,
+ 18, 240, 130, 69, 53, 147, 218, 142,
+ 150, 143, 219, 189, 54, 208, 206, 148,
+ 19, 92, 210, 241, 64, 70, 131, 56,
+ 102, 221, 253, 48, 191, 6, 139, 98,
+ 179, 37, 226, 152, 34, 136, 145, 16,
+ 126, 110, 72, 195, 163, 182, 30, 66,
+ 58, 107, 40, 84, 250, 133, 61, 186,
+ 43, 121, 10, 21, 155, 159, 94, 202,
+ 78, 212, 172, 229, 243, 115, 167, 87,
+ 175, 88, 168, 80, 244, 234, 214, 116,
+ 79, 174, 233, 213, 231, 230, 173, 232,
+ 44, 215, 117, 122, 235, 22, 11, 245,
+ 89, 203, 95, 176, 156, 169, 81, 160,
+ 127, 12, 246, 111, 23, 196, 73, 236,
+ 216, 67, 31, 45, 164, 118, 123, 183,
+ 204, 187, 62, 90, 251, 96, 177, 134,
+ 59, 82, 161, 108, 170, 85, 41, 157,
+ 151, 178, 135, 144, 97, 190, 220, 252,
+ 188, 149, 207, 205, 55, 63, 91, 209,
+ 83, 57, 132, 60, 65, 162, 109, 71,
+ 20, 42, 158, 93, 86, 242, 211, 171,
+ 68, 17, 146, 217, 35, 32, 46, 137,
+ 180, 124, 184, 38, 119, 153, 227, 165,
+ 103, 74, 237, 222, 197, 49, 254, 24,
+ 13, 99, 140, 128, 192, 247, 112, 7
+ };
+
+ private static readonly byte[] Alogtable =
+ {
+ 0, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53,
+ 95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170,
+ 229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49,
+ 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205,
+ 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136,
+ 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154,
+ 181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163,
+ 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160,
+ 251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65,
+ 195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117,
+ 159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128,
+ 155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84,
+ 252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202,
+ 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14,
+ 18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23,
+ 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1,
+ 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53,
+ 95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170,
+ 229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49,
+ 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205,
+ 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136,
+ 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154,
+ 181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163,
+ 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160,
+ 251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65,
+ 195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117,
+ 159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128,
+ 155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84,
+ 252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202,
+ 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14,
+ 18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23,
+ 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1,
+ };
+
+ private static readonly byte[] S =
+ {
+ 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118,
+ 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192,
+ 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21,
+ 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117,
+ 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132,
+ 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207,
+ 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168,
+ 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210,
+ 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115,
+ 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219,
+ 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121,
+ 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8,
+ 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138,
+ 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158,
+ 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
+ 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22,
+ };
+
+ private static readonly byte[] Si =
+ {
+ 82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251,
+ 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203,
+ 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78,
+ 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37,
+ 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146,
+ 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132,
+ 144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6,
+ 208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107,
+ 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115,
+ 150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110,
+ 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27,
+ 252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244,
+ 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95,
+ 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239,
+ 160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97,
+ 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125,
+ };
+
+ private static readonly byte[] 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 virtual 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 - " + Platform.GetTypeName(parameters));
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Rijndael"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BC / 2;
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (workingKey == null)
+ throw new InvalidOperationException("Rijndael engine not initialised");
+
+ Check.DataLength(input, inOff, (BC / 2), "input buffer too short");
+ Check.OutputLength(output, outOff, (BC / 2), "output buffer too short");
+
+ UnPackBlock(input, inOff);
+
+ if (forEncryption)
+ {
+ EncryptBlock(workingKey);
+ }
+ else
+ {
+ DecryptBlock(workingKey);
+ }
+
+ PackBlock(output, outOff);
+
+ return BC / 2;
+ }
+
+ public virtual 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]);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/RsaEngine.cs b/bc-sharp-crypto/src/crypto/engines/RsaEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4399b4409f7a618f1e464bd8ad17e2a364af45dd
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/RsaEngine.cs
@@ -0,0 +1,78 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * this does your basic RSA algorithm.
+ */
+ public class RsaEngine
+ : IAsymmetricBlockCipher
+ {
+ private RsaCoreEngine core;
+
+ public virtual string AlgorithmName
+ {
+ get { return "RSA"; }
+ }
+
+ /**
+ * initialise the RSA engine.
+ *
+ * @param forEncryption true if we are encrypting, false otherwise.
+ * @param param the necessary RSA key parameters.
+ */
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (core == null)
+ core = new RsaCoreEngine();
+
+ core.Init(forEncryption, parameters);
+ }
+
+ /**
+ * Return the maximum size for an input block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * encryption, and the same length as the key size on decryption.
+ *
+ * @return maximum size for an input block.
+ */
+ public virtual int GetInputBlockSize()
+ {
+ return core.GetInputBlockSize();
+ }
+
+ /**
+ * Return the maximum size for an output block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * decryption, and the same length as the key size on encryption.
+ *
+ * @return maximum size for an output block.
+ */
+ public virtual int GetOutputBlockSize()
+ {
+ return core.GetOutputBlockSize();
+ }
+
+ /**
+ * Process a single block using the basic RSA algorithm.
+ *
+ * @param inBuf the input array.
+ * @param inOff the offset into the input buffer where the data starts.
+ * @param inLen the length of the data to be processed.
+ * @return the result of the RSA process.
+ * @exception DataLengthException the input block is too large.
+ */
+ public virtual byte[] ProcessBlock(
+ byte[] inBuf,
+ int inOff,
+ int inLen)
+ {
+ if (core == null)
+ throw new InvalidOperationException("RSA engine not initialised");
+
+ return core.ConvertOutput(core.ProcessBlock(core.ConvertInput(inBuf, inOff, inLen)));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/SEEDEngine.cs b/bc-sharp-crypto/src/crypto/engines/SEEDEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f615b8476b00c47374af676ffe4681d22a562fbd
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/SEEDEngine.cs
@@ -0,0 +1,360 @@
+using System;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * Implementation of the SEED algorithm as described in RFC 4009
+ */
+ public class SeedEngine
+ : IBlockCipher
+ {
+ private const int BlockSize = 16;
+
+ private static readonly uint[] SS0 =
+ {
+ 0x2989a1a8, 0x05858184, 0x16c6d2d4, 0x13c3d3d0, 0x14445054, 0x1d0d111c, 0x2c8ca0ac, 0x25052124,
+ 0x1d4d515c, 0x03434340, 0x18081018, 0x1e0e121c, 0x11415150, 0x3cccf0fc, 0x0acac2c8, 0x23436360,
+ 0x28082028, 0x04444044, 0x20002020, 0x1d8d919c, 0x20c0e0e0, 0x22c2e2e0, 0x08c8c0c8, 0x17071314,
+ 0x2585a1a4, 0x0f8f838c, 0x03030300, 0x3b4b7378, 0x3b8bb3b8, 0x13031310, 0x12c2d2d0, 0x2ecee2ec,
+ 0x30407070, 0x0c8c808c, 0x3f0f333c, 0x2888a0a8, 0x32023230, 0x1dcdd1dc, 0x36c6f2f4, 0x34447074,
+ 0x2ccce0ec, 0x15859194, 0x0b0b0308, 0x17475354, 0x1c4c505c, 0x1b4b5358, 0x3d8db1bc, 0x01010100,
+ 0x24042024, 0x1c0c101c, 0x33437370, 0x18889098, 0x10001010, 0x0cccc0cc, 0x32c2f2f0, 0x19c9d1d8,
+ 0x2c0c202c, 0x27c7e3e4, 0x32427270, 0x03838380, 0x1b8b9398, 0x11c1d1d0, 0x06868284, 0x09c9c1c8,
+ 0x20406060, 0x10405050, 0x2383a3a0, 0x2bcbe3e8, 0x0d0d010c, 0x3686b2b4, 0x1e8e929c, 0x0f4f434c,
+ 0x3787b3b4, 0x1a4a5258, 0x06c6c2c4, 0x38487078, 0x2686a2a4, 0x12021210, 0x2f8fa3ac, 0x15c5d1d4,
+ 0x21416160, 0x03c3c3c0, 0x3484b0b4, 0x01414140, 0x12425250, 0x3d4d717c, 0x0d8d818c, 0x08080008,
+ 0x1f0f131c, 0x19899198, 0x00000000, 0x19091118, 0x04040004, 0x13435350, 0x37c7f3f4, 0x21c1e1e0,
+ 0x3dcdf1fc, 0x36467274, 0x2f0f232c, 0x27072324, 0x3080b0b0, 0x0b8b8388, 0x0e0e020c, 0x2b8ba3a8,
+ 0x2282a2a0, 0x2e4e626c, 0x13839390, 0x0d4d414c, 0x29496168, 0x3c4c707c, 0x09090108, 0x0a0a0208,
+ 0x3f8fb3bc, 0x2fcfe3ec, 0x33c3f3f0, 0x05c5c1c4, 0x07878384, 0x14041014, 0x3ecef2fc, 0x24446064,
+ 0x1eced2dc, 0x2e0e222c, 0x0b4b4348, 0x1a0a1218, 0x06060204, 0x21012120, 0x2b4b6368, 0x26466264,
+ 0x02020200, 0x35c5f1f4, 0x12829290, 0x0a8a8288, 0x0c0c000c, 0x3383b3b0, 0x3e4e727c, 0x10c0d0d0,
+ 0x3a4a7278, 0x07474344, 0x16869294, 0x25c5e1e4, 0x26062224, 0x00808080, 0x2d8da1ac, 0x1fcfd3dc,
+ 0x2181a1a0, 0x30003030, 0x37073334, 0x2e8ea2ac, 0x36063234, 0x15051114, 0x22022220, 0x38083038,
+ 0x34c4f0f4, 0x2787a3a4, 0x05454144, 0x0c4c404c, 0x01818180, 0x29c9e1e8, 0x04848084, 0x17879394,
+ 0x35053134, 0x0bcbc3c8, 0x0ecec2cc, 0x3c0c303c, 0x31417170, 0x11011110, 0x07c7c3c4, 0x09898188,
+ 0x35457174, 0x3bcbf3f8, 0x1acad2d8, 0x38c8f0f8, 0x14849094, 0x19495158, 0x02828280, 0x04c4c0c4,
+ 0x3fcff3fc, 0x09494148, 0x39093138, 0x27476364, 0x00c0c0c0, 0x0fcfc3cc, 0x17c7d3d4, 0x3888b0b8,
+ 0x0f0f030c, 0x0e8e828c, 0x02424240, 0x23032320, 0x11819190, 0x2c4c606c, 0x1bcbd3d8, 0x2484a0a4,
+ 0x34043034, 0x31c1f1f0, 0x08484048, 0x02c2c2c0, 0x2f4f636c, 0x3d0d313c, 0x2d0d212c, 0x00404040,
+ 0x3e8eb2bc, 0x3e0e323c, 0x3c8cb0bc, 0x01c1c1c0, 0x2a8aa2a8, 0x3a8ab2b8, 0x0e4e424c, 0x15455154,
+ 0x3b0b3338, 0x1cccd0dc, 0x28486068, 0x3f4f737c, 0x1c8c909c, 0x18c8d0d8, 0x0a4a4248, 0x16465254,
+ 0x37477374, 0x2080a0a0, 0x2dcde1ec, 0x06464244, 0x3585b1b4, 0x2b0b2328, 0x25456164, 0x3acaf2f8,
+ 0x23c3e3e0, 0x3989b1b8, 0x3181b1b0, 0x1f8f939c, 0x1e4e525c, 0x39c9f1f8, 0x26c6e2e4, 0x3282b2b0,
+ 0x31013130, 0x2acae2e8, 0x2d4d616c, 0x1f4f535c, 0x24c4e0e4, 0x30c0f0f0, 0x0dcdc1cc, 0x08888088,
+ 0x16061214, 0x3a0a3238, 0x18485058, 0x14c4d0d4, 0x22426260, 0x29092128, 0x07070304, 0x33033330,
+ 0x28c8e0e8, 0x1b0b1318, 0x05050104, 0x39497178, 0x10809090, 0x2a4a6268, 0x2a0a2228, 0x1a8a9298
+ };
+
+ private static readonly uint[] SS1 =
+ {
+ 0x38380830, 0xe828c8e0, 0x2c2d0d21, 0xa42686a2, 0xcc0fcfc3, 0xdc1eced2, 0xb03383b3, 0xb83888b0,
+ 0xac2f8fa3, 0x60204060, 0x54154551, 0xc407c7c3, 0x44044440, 0x6c2f4f63, 0x682b4b63, 0x581b4b53,
+ 0xc003c3c3, 0x60224262, 0x30330333, 0xb43585b1, 0x28290921, 0xa02080a0, 0xe022c2e2, 0xa42787a3,
+ 0xd013c3d3, 0x90118191, 0x10110111, 0x04060602, 0x1c1c0c10, 0xbc3c8cb0, 0x34360632, 0x480b4b43,
+ 0xec2fcfe3, 0x88088880, 0x6c2c4c60, 0xa82888a0, 0x14170713, 0xc404c4c0, 0x14160612, 0xf434c4f0,
+ 0xc002c2c2, 0x44054541, 0xe021c1e1, 0xd416c6d2, 0x3c3f0f33, 0x3c3d0d31, 0x8c0e8e82, 0x98188890,
+ 0x28280820, 0x4c0e4e42, 0xf436c6f2, 0x3c3e0e32, 0xa42585a1, 0xf839c9f1, 0x0c0d0d01, 0xdc1fcfd3,
+ 0xd818c8d0, 0x282b0b23, 0x64264662, 0x783a4a72, 0x24270723, 0x2c2f0f23, 0xf031c1f1, 0x70324272,
+ 0x40024242, 0xd414c4d0, 0x40014141, 0xc000c0c0, 0x70334373, 0x64274763, 0xac2c8ca0, 0x880b8b83,
+ 0xf437c7f3, 0xac2d8da1, 0x80008080, 0x1c1f0f13, 0xc80acac2, 0x2c2c0c20, 0xa82a8aa2, 0x34340430,
+ 0xd012c2d2, 0x080b0b03, 0xec2ecee2, 0xe829c9e1, 0x5c1d4d51, 0x94148490, 0x18180810, 0xf838c8f0,
+ 0x54174753, 0xac2e8ea2, 0x08080800, 0xc405c5c1, 0x10130313, 0xcc0dcdc1, 0x84068682, 0xb83989b1,
+ 0xfc3fcff3, 0x7c3d4d71, 0xc001c1c1, 0x30310131, 0xf435c5f1, 0x880a8a82, 0x682a4a62, 0xb03181b1,
+ 0xd011c1d1, 0x20200020, 0xd417c7d3, 0x00020202, 0x20220222, 0x04040400, 0x68284860, 0x70314171,
+ 0x04070703, 0xd81bcbd3, 0x9c1d8d91, 0x98198991, 0x60214161, 0xbc3e8eb2, 0xe426c6e2, 0x58194951,
+ 0xdc1dcdd1, 0x50114151, 0x90108090, 0xdc1cccd0, 0x981a8a92, 0xa02383a3, 0xa82b8ba3, 0xd010c0d0,
+ 0x80018181, 0x0c0f0f03, 0x44074743, 0x181a0a12, 0xe023c3e3, 0xec2ccce0, 0x8c0d8d81, 0xbc3f8fb3,
+ 0x94168692, 0x783b4b73, 0x5c1c4c50, 0xa02282a2, 0xa02181a1, 0x60234363, 0x20230323, 0x4c0d4d41,
+ 0xc808c8c0, 0x9c1e8e92, 0x9c1c8c90, 0x383a0a32, 0x0c0c0c00, 0x2c2e0e22, 0xb83a8ab2, 0x6c2e4e62,
+ 0x9c1f8f93, 0x581a4a52, 0xf032c2f2, 0x90128292, 0xf033c3f3, 0x48094941, 0x78384870, 0xcc0cccc0,
+ 0x14150511, 0xf83bcbf3, 0x70304070, 0x74354571, 0x7c3f4f73, 0x34350531, 0x10100010, 0x00030303,
+ 0x64244460, 0x6c2d4d61, 0xc406c6c2, 0x74344470, 0xd415c5d1, 0xb43484b0, 0xe82acae2, 0x08090901,
+ 0x74364672, 0x18190911, 0xfc3ecef2, 0x40004040, 0x10120212, 0xe020c0e0, 0xbc3d8db1, 0x04050501,
+ 0xf83acaf2, 0x00010101, 0xf030c0f0, 0x282a0a22, 0x5c1e4e52, 0xa82989a1, 0x54164652, 0x40034343,
+ 0x84058581, 0x14140410, 0x88098981, 0x981b8b93, 0xb03080b0, 0xe425c5e1, 0x48084840, 0x78394971,
+ 0x94178793, 0xfc3cccf0, 0x1c1e0e12, 0x80028282, 0x20210121, 0x8c0c8c80, 0x181b0b13, 0x5c1f4f53,
+ 0x74374773, 0x54144450, 0xb03282b2, 0x1c1d0d11, 0x24250521, 0x4c0f4f43, 0x00000000, 0x44064642,
+ 0xec2dcde1, 0x58184850, 0x50124252, 0xe82bcbe3, 0x7c3e4e72, 0xd81acad2, 0xc809c9c1, 0xfc3dcdf1,
+ 0x30300030, 0x94158591, 0x64254561, 0x3c3c0c30, 0xb43686b2, 0xe424c4e0, 0xb83b8bb3, 0x7c3c4c70,
+ 0x0c0e0e02, 0x50104050, 0x38390931, 0x24260622, 0x30320232, 0x84048480, 0x68294961, 0x90138393,
+ 0x34370733, 0xe427c7e3, 0x24240420, 0xa42484a0, 0xc80bcbc3, 0x50134353, 0x080a0a02, 0x84078783,
+ 0xd819c9d1, 0x4c0c4c40, 0x80038383, 0x8c0f8f83, 0xcc0ecec2, 0x383b0b33, 0x480a4a42, 0xb43787b3
+ };
+
+ private static readonly uint[] SS2 =
+ {
+
+ 0xa1a82989, 0x81840585, 0xd2d416c6, 0xd3d013c3, 0x50541444, 0x111c1d0d, 0xa0ac2c8c, 0x21242505,
+ 0x515c1d4d, 0x43400343, 0x10181808, 0x121c1e0e, 0x51501141, 0xf0fc3ccc, 0xc2c80aca, 0x63602343,
+ 0x20282808, 0x40440444, 0x20202000, 0x919c1d8d, 0xe0e020c0, 0xe2e022c2, 0xc0c808c8, 0x13141707,
+ 0xa1a42585, 0x838c0f8f, 0x03000303, 0x73783b4b, 0xb3b83b8b, 0x13101303, 0xd2d012c2, 0xe2ec2ece,
+ 0x70703040, 0x808c0c8c, 0x333c3f0f, 0xa0a82888, 0x32303202, 0xd1dc1dcd, 0xf2f436c6, 0x70743444,
+ 0xe0ec2ccc, 0x91941585, 0x03080b0b, 0x53541747, 0x505c1c4c, 0x53581b4b, 0xb1bc3d8d, 0x01000101,
+ 0x20242404, 0x101c1c0c, 0x73703343, 0x90981888, 0x10101000, 0xc0cc0ccc, 0xf2f032c2, 0xd1d819c9,
+ 0x202c2c0c, 0xe3e427c7, 0x72703242, 0x83800383, 0x93981b8b, 0xd1d011c1, 0x82840686, 0xc1c809c9,
+ 0x60602040, 0x50501040, 0xa3a02383, 0xe3e82bcb, 0x010c0d0d, 0xb2b43686, 0x929c1e8e, 0x434c0f4f,
+ 0xb3b43787, 0x52581a4a, 0xc2c406c6, 0x70783848, 0xa2a42686, 0x12101202, 0xa3ac2f8f, 0xd1d415c5,
+ 0x61602141, 0xc3c003c3, 0xb0b43484, 0x41400141, 0x52501242, 0x717c3d4d, 0x818c0d8d, 0x00080808,
+ 0x131c1f0f, 0x91981989, 0x00000000, 0x11181909, 0x00040404, 0x53501343, 0xf3f437c7, 0xe1e021c1,
+ 0xf1fc3dcd, 0x72743646, 0x232c2f0f, 0x23242707, 0xb0b03080, 0x83880b8b, 0x020c0e0e, 0xa3a82b8b,
+ 0xa2a02282, 0x626c2e4e, 0x93901383, 0x414c0d4d, 0x61682949, 0x707c3c4c, 0x01080909, 0x02080a0a,
+ 0xb3bc3f8f, 0xe3ec2fcf, 0xf3f033c3, 0xc1c405c5, 0x83840787, 0x10141404, 0xf2fc3ece, 0x60642444,
+ 0xd2dc1ece, 0x222c2e0e, 0x43480b4b, 0x12181a0a, 0x02040606, 0x21202101, 0x63682b4b, 0x62642646,
+ 0x02000202, 0xf1f435c5, 0x92901282, 0x82880a8a, 0x000c0c0c, 0xb3b03383, 0x727c3e4e, 0xd0d010c0,
+ 0x72783a4a, 0x43440747, 0x92941686, 0xe1e425c5, 0x22242606, 0x80800080, 0xa1ac2d8d, 0xd3dc1fcf,
+ 0xa1a02181, 0x30303000, 0x33343707, 0xa2ac2e8e, 0x32343606, 0x11141505, 0x22202202, 0x30383808,
+ 0xf0f434c4, 0xa3a42787, 0x41440545, 0x404c0c4c, 0x81800181, 0xe1e829c9, 0x80840484, 0x93941787,
+ 0x31343505, 0xc3c80bcb, 0xc2cc0ece, 0x303c3c0c, 0x71703141, 0x11101101, 0xc3c407c7, 0x81880989,
+ 0x71743545, 0xf3f83bcb, 0xd2d81aca, 0xf0f838c8, 0x90941484, 0x51581949, 0x82800282, 0xc0c404c4,
+ 0xf3fc3fcf, 0x41480949, 0x31383909, 0x63642747, 0xc0c000c0, 0xc3cc0fcf, 0xd3d417c7, 0xb0b83888,
+ 0x030c0f0f, 0x828c0e8e, 0x42400242, 0x23202303, 0x91901181, 0x606c2c4c, 0xd3d81bcb, 0xa0a42484,
+ 0x30343404, 0xf1f031c1, 0x40480848, 0xc2c002c2, 0x636c2f4f, 0x313c3d0d, 0x212c2d0d, 0x40400040,
+ 0xb2bc3e8e, 0x323c3e0e, 0xb0bc3c8c, 0xc1c001c1, 0xa2a82a8a, 0xb2b83a8a, 0x424c0e4e, 0x51541545,
+ 0x33383b0b, 0xd0dc1ccc, 0x60682848, 0x737c3f4f, 0x909c1c8c, 0xd0d818c8, 0x42480a4a, 0x52541646,
+ 0x73743747, 0xa0a02080, 0xe1ec2dcd, 0x42440646, 0xb1b43585, 0x23282b0b, 0x61642545, 0xf2f83aca,
+ 0xe3e023c3, 0xb1b83989, 0xb1b03181, 0x939c1f8f, 0x525c1e4e, 0xf1f839c9, 0xe2e426c6, 0xb2b03282,
+ 0x31303101, 0xe2e82aca, 0x616c2d4d, 0x535c1f4f, 0xe0e424c4, 0xf0f030c0, 0xc1cc0dcd, 0x80880888,
+ 0x12141606, 0x32383a0a, 0x50581848, 0xd0d414c4, 0x62602242, 0x21282909, 0x03040707, 0x33303303,
+ 0xe0e828c8, 0x13181b0b, 0x01040505, 0x71783949, 0x90901080, 0x62682a4a, 0x22282a0a, 0x92981a8a
+ };
+
+ private static readonly uint[] SS3 =
+ {
+
+ 0x08303838, 0xc8e0e828, 0x0d212c2d, 0x86a2a426, 0xcfc3cc0f, 0xced2dc1e, 0x83b3b033, 0x88b0b838,
+ 0x8fa3ac2f, 0x40606020, 0x45515415, 0xc7c3c407, 0x44404404, 0x4f636c2f, 0x4b63682b, 0x4b53581b,
+ 0xc3c3c003, 0x42626022, 0x03333033, 0x85b1b435, 0x09212829, 0x80a0a020, 0xc2e2e022, 0x87a3a427,
+ 0xc3d3d013, 0x81919011, 0x01111011, 0x06020406, 0x0c101c1c, 0x8cb0bc3c, 0x06323436, 0x4b43480b,
+ 0xcfe3ec2f, 0x88808808, 0x4c606c2c, 0x88a0a828, 0x07131417, 0xc4c0c404, 0x06121416, 0xc4f0f434,
+ 0xc2c2c002, 0x45414405, 0xc1e1e021, 0xc6d2d416, 0x0f333c3f, 0x0d313c3d, 0x8e828c0e, 0x88909818,
+ 0x08202828, 0x4e424c0e, 0xc6f2f436, 0x0e323c3e, 0x85a1a425, 0xc9f1f839, 0x0d010c0d, 0xcfd3dc1f,
+ 0xc8d0d818, 0x0b23282b, 0x46626426, 0x4a72783a, 0x07232427, 0x0f232c2f, 0xc1f1f031, 0x42727032,
+ 0x42424002, 0xc4d0d414, 0x41414001, 0xc0c0c000, 0x43737033, 0x47636427, 0x8ca0ac2c, 0x8b83880b,
+ 0xc7f3f437, 0x8da1ac2d, 0x80808000, 0x0f131c1f, 0xcac2c80a, 0x0c202c2c, 0x8aa2a82a, 0x04303434,
+ 0xc2d2d012, 0x0b03080b, 0xcee2ec2e, 0xc9e1e829, 0x4d515c1d, 0x84909414, 0x08101818, 0xc8f0f838,
+ 0x47535417, 0x8ea2ac2e, 0x08000808, 0xc5c1c405, 0x03131013, 0xcdc1cc0d, 0x86828406, 0x89b1b839,
+ 0xcff3fc3f, 0x4d717c3d, 0xc1c1c001, 0x01313031, 0xc5f1f435, 0x8a82880a, 0x4a62682a, 0x81b1b031,
+ 0xc1d1d011, 0x00202020, 0xc7d3d417, 0x02020002, 0x02222022, 0x04000404, 0x48606828, 0x41717031,
+ 0x07030407, 0xcbd3d81b, 0x8d919c1d, 0x89919819, 0x41616021, 0x8eb2bc3e, 0xc6e2e426, 0x49515819,
+ 0xcdd1dc1d, 0x41515011, 0x80909010, 0xccd0dc1c, 0x8a92981a, 0x83a3a023, 0x8ba3a82b, 0xc0d0d010,
+ 0x81818001, 0x0f030c0f, 0x47434407, 0x0a12181a, 0xc3e3e023, 0xcce0ec2c, 0x8d818c0d, 0x8fb3bc3f,
+ 0x86929416, 0x4b73783b, 0x4c505c1c, 0x82a2a022, 0x81a1a021, 0x43636023, 0x03232023, 0x4d414c0d,
+ 0xc8c0c808, 0x8e929c1e, 0x8c909c1c, 0x0a32383a, 0x0c000c0c, 0x0e222c2e, 0x8ab2b83a, 0x4e626c2e,
+ 0x8f939c1f, 0x4a52581a, 0xc2f2f032, 0x82929012, 0xc3f3f033, 0x49414809, 0x48707838, 0xccc0cc0c,
+ 0x05111415, 0xcbf3f83b, 0x40707030, 0x45717435, 0x4f737c3f, 0x05313435, 0x00101010, 0x03030003,
+ 0x44606424, 0x4d616c2d, 0xc6c2c406, 0x44707434, 0xc5d1d415, 0x84b0b434, 0xcae2e82a, 0x09010809,
+ 0x46727436, 0x09111819, 0xcef2fc3e, 0x40404000, 0x02121012, 0xc0e0e020, 0x8db1bc3d, 0x05010405,
+ 0xcaf2f83a, 0x01010001, 0xc0f0f030, 0x0a22282a, 0x4e525c1e, 0x89a1a829, 0x46525416, 0x43434003,
+ 0x85818405, 0x04101414, 0x89818809, 0x8b93981b, 0x80b0b030, 0xc5e1e425, 0x48404808, 0x49717839,
+ 0x87939417, 0xccf0fc3c, 0x0e121c1e, 0x82828002, 0x01212021, 0x8c808c0c, 0x0b13181b, 0x4f535c1f,
+ 0x47737437, 0x44505414, 0x82b2b032, 0x0d111c1d, 0x05212425, 0x4f434c0f, 0x00000000, 0x46424406,
+ 0xcde1ec2d, 0x48505818, 0x42525012, 0xcbe3e82b, 0x4e727c3e, 0xcad2d81a, 0xc9c1c809, 0xcdf1fc3d,
+ 0x00303030, 0x85919415, 0x45616425, 0x0c303c3c, 0x86b2b436, 0xc4e0e424, 0x8bb3b83b, 0x4c707c3c,
+ 0x0e020c0e, 0x40505010, 0x09313839, 0x06222426, 0x02323032, 0x84808404, 0x49616829, 0x83939013,
+ 0x07333437, 0xc7e3e427, 0x04202424, 0x84a0a424, 0xcbc3c80b, 0x43535013, 0x0a02080a, 0x87838407,
+ 0xc9d1d819, 0x4c404c0c, 0x83838003, 0x8f838c0f, 0xcec2cc0e, 0x0b33383b, 0x4a42480a, 0x87b3b437
+ };
+
+ private static readonly uint[] KC =
+ {
+ 0x9e3779b9, 0x3c6ef373, 0x78dde6e6, 0xf1bbcdcc,
+ 0xe3779b99, 0xc6ef3733, 0x8dde6e67, 0x1bbcdccf,
+ 0x3779b99e, 0x6ef3733c, 0xdde6e678, 0xbbcdccf1,
+ 0x779b99e3, 0xef3733c6, 0xde6e678d, 0xbcdccf1b
+ };
+
+ private int[] wKey;
+ private bool forEncryption;
+
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+ wKey = createWorkingKey(((KeyParameter)parameters).GetKey());
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "SEED"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BlockSize;
+ }
+
+ public virtual int ProcessBlock(
+ byte[] inBuf,
+ int inOff,
+ byte[] outBuf,
+ int outOff)
+ {
+ if (wKey == null)
+ throw new InvalidOperationException("SEED engine not initialised");
+
+ 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);
+
+ 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;
+ }
+ }
+
+ longToBytes(outBuf, outOff + 0, r);
+ longToBytes(outBuf, outOff + 8, l);
+
+ return BlockSize;
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ private int[] createWorkingKey(
+ byte[] inKey)
+ {
+ int[] key = new int[32];
+ long lower = bytesToLong(inKey, 0);
+ long upper = bytesToLong(inKey, 8);
+
+ int key0 = extractW0(lower);
+ int key1 = extractW1(lower);
+ int key2 = extractW0(upper);
+ int key3 = extractW1(upper);
+
+ for (int i = 0; i < 16; i++)
+ {
+ key[2 * i] = G(key0 + key2 - (int)KC[i]);
+ key[2 * i + 1] = G(key1 - key3 + (int)KC[i]);
+
+ if (i % 2 == 0)
+ {
+ lower = rotateRight8(lower);
+ key0 = extractW0(lower);
+ key1 = extractW1(lower);
+ }
+ else
+ {
+ upper = rotateLeft8(upper);
+ key2 = extractW0(upper);
+ key3 = extractW1(upper);
+ }
+ }
+
+ return key;
+ }
+
+ private int extractW1(
+ long lVal)
+ {
+ return (int)lVal;
+ }
+
+ private int extractW0(
+ long lVal)
+ {
+ return (int)(lVal >> 32);
+ }
+
+ private long rotateLeft8(
+ long x)
+ {
+ return (x << 8) | ((long)((ulong) x >> 56));
+ }
+
+ private long rotateRight8(
+ long x)
+ {
+ 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)
+ {
+ return (int)(SS0[x & 0xff] ^ SS1[(x >> 8) & 0xff] ^ SS2[(x >> 16) & 0xff] ^ SS3[(x >> 24) & 0xff]);
+ }
+
+ private long F(
+ int ki0,
+ int ki1,
+ long r)
+ {
+ int r0 = (int)(r >> 32);
+ int r1 = (int)r;
+ int rd1 = phaseCalc2(r0, ki0, r1, ki1);
+ int rd0 = rd1 + phaseCalc1(r0, ki0, r1, ki1);
+
+ return ((long)rd0 << 32) | (rd1 & 0xffffffffL);
+ }
+
+ private int phaseCalc1(
+ int r0,
+ int ki0,
+ int r1,
+ int ki1)
+ {
+ return G(G((r0 ^ ki0) ^ (r1 ^ ki1)) + (r0 ^ ki0));
+ }
+
+ private int phaseCalc2(
+ int r0,
+ int ki0,
+ int r1,
+ int ki1)
+ {
+ return G(phaseCalc1(r0, ki0, r1, ki1) + G((r0 ^ ki0) ^ (r1 ^ ki1)));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/SEEDWrapEngine.cs b/bc-sharp-crypto/src/crypto/engines/SEEDWrapEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6b71f940bc76a1c26c1aad00b4fa3857d3e0d21a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/SEEDWrapEngine.cs
@@ -0,0 +1,16 @@
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ ///
+ /// An implementation of the SEED key wrapper based on RFC 4010/RFC 3394.
+ ///
+ /// For further details see: http://www.ietf.org/rfc/rfc4010.txt .
+ ///
+ public class SeedWrapEngine
+ : Rfc3394WrapEngine
+ {
+ public SeedWrapEngine()
+ : base(new SeedEngine())
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/Salsa20Engine.cs b/bc-sharp-crypto/src/crypto/engines/Salsa20Engine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..182eacd71cd417766f31a80e03334c5cd096d77c
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/Salsa20Engine.cs
@@ -0,0 +1,362 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ ///
+ /// Implementation of Daniel J. Bernstein's Salsa20 stream cipher, Snuffle 2005
+ ///
+ public class Salsa20Engine
+ : IStreamCipher
+ {
+ public static readonly int DEFAULT_ROUNDS = 20;
+
+ /** Constants */
+ private const int StateSize = 16; // 16, 32 bit ints = 64 bytes
+
+ private readonly static uint[] TAU_SIGMA = Pack.LE_To_UInt32(Strings.ToAsciiByteArray("expand 16-byte k" + "expand 32-byte k"), 0, 8);
+
+ internal void PackTauOrSigma(int keyLength, uint[] state, int stateOffset)
+ {
+ int tsOff = (keyLength - 16) / 4;
+ state[stateOffset] = TAU_SIGMA[tsOff];
+ state[stateOffset + 1] = TAU_SIGMA[tsOff + 1];
+ state[stateOffset + 2] = TAU_SIGMA[tsOff + 2];
+ state[stateOffset + 3] = TAU_SIGMA[tsOff + 3];
+ }
+
+ [Obsolete]
+ protected readonly static byte[]
+ sigma = Strings.ToAsciiByteArray("expand 32-byte k"),
+ tau = Strings.ToAsciiByteArray("expand 16-byte k");
+
+ protected int rounds;
+
+ /*
+ * variables to hold the state of the engine
+ * during encryption and decryption
+ */
+ private int index = 0;
+ internal uint[] engineState = new uint[StateSize]; // state
+ internal uint[] x = new uint[StateSize]; // internal buffer
+ private byte[] keyStream = new byte[StateSize * 4]; // expanded state, 64 bytes
+ private bool initialised = false;
+
+ /*
+ * internal counter
+ */
+ private uint cW0, cW1, cW2;
+
+ ///
+ /// Creates a 20 round Salsa20 engine.
+ ///
+ public Salsa20Engine()
+ : this(DEFAULT_ROUNDS)
+ {
+ }
+
+ ///
+ /// Creates a Salsa20 engine with a specific number of rounds.
+ ///
+ /// the number of rounds (must be an even number).
+ public Salsa20Engine(int rounds)
+ {
+ if (rounds <= 0 || (rounds & 1) != 0)
+ {
+ throw new ArgumentException("'rounds' must be a positive, even number");
+ }
+
+ this.rounds = rounds;
+ }
+
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ /*
+ * Salsa20 encryption and decryption is completely
+ * symmetrical, so the 'forEncryption' is
+ * irrelevant. (Like 90% of stream ciphers)
+ */
+
+ ParametersWithIV ivParams = parameters as ParametersWithIV;
+ if (ivParams == null)
+ throw new ArgumentException(AlgorithmName + " Init requires an IV", "parameters");
+
+ byte[] iv = ivParams.GetIV();
+ if (iv == null || iv.Length != NonceSize)
+ throw new ArgumentException(AlgorithmName + " requires exactly " + NonceSize + " bytes of IV");
+
+ ICipherParameters keyParam = ivParams.Parameters;
+ if (keyParam == null)
+ {
+ if (!initialised)
+ throw new InvalidOperationException(AlgorithmName + " KeyParameter can not be null for first initialisation");
+
+ SetKey(null, iv);
+ }
+ else if (keyParam is KeyParameter)
+ {
+ SetKey(((KeyParameter)keyParam).GetKey(), iv);
+ }
+ else
+ {
+ throw new ArgumentException(AlgorithmName + " Init parameters must contain a KeyParameter (or null for re-init)");
+ }
+
+ Reset();
+ initialised = true;
+ }
+
+ protected virtual int NonceSize
+ {
+ get { return 8; }
+ }
+
+ public virtual string AlgorithmName
+ {
+ get
+ {
+ string name = "Salsa20";
+ if (rounds != DEFAULT_ROUNDS)
+ {
+ name += "/" + rounds;
+ }
+ return name;
+ }
+ }
+
+ public virtual byte ReturnByte(
+ byte input)
+ {
+ if (LimitExceeded())
+ {
+ throw new MaxBytesExceededException("2^70 byte limit per IV; Change IV");
+ }
+
+ if (index == 0)
+ {
+ GenerateKeyStream(keyStream);
+ AdvanceCounter();
+ }
+
+ byte output = (byte)(keyStream[index] ^ input);
+ index = (index + 1) & 63;
+
+ return output;
+ }
+
+ protected virtual void AdvanceCounter()
+ {
+ if (++engineState[8] == 0)
+ {
+ ++engineState[9];
+ }
+ }
+
+ public virtual void ProcessBytes(
+ byte[] inBytes,
+ int inOff,
+ int len,
+ byte[] outBytes,
+ int outOff)
+ {
+ if (!initialised)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ Check.DataLength(inBytes, inOff, len, "input buffer too short");
+ Check.OutputLength(outBytes, outOff, len, "output buffer too short");
+
+ if (LimitExceeded((uint)len))
+ throw new MaxBytesExceededException("2^70 byte limit per IV would be exceeded; Change IV");
+
+ for (int i = 0; i < len; i++)
+ {
+ if (index == 0)
+ {
+ GenerateKeyStream(keyStream);
+ AdvanceCounter();
+ }
+ outBytes[i+outOff] = (byte)(keyStream[index]^inBytes[i+inOff]);
+ index = (index + 1) & 63;
+ }
+ }
+
+ public virtual void Reset()
+ {
+ index = 0;
+ ResetLimitCounter();
+ ResetCounter();
+ }
+
+ protected virtual void ResetCounter()
+ {
+ engineState[8] = engineState[9] = 0;
+ }
+
+ protected virtual void SetKey(byte[] keyBytes, byte[] ivBytes)
+ {
+ if (keyBytes != null)
+ {
+ if ((keyBytes.Length != 16) && (keyBytes.Length != 32))
+ throw new ArgumentException(AlgorithmName + " requires 128 bit or 256 bit key");
+
+ int tsOff = (keyBytes.Length - 16) / 4;
+ engineState[0] = TAU_SIGMA[tsOff];
+ engineState[5] = TAU_SIGMA[tsOff + 1];
+ engineState[10] = TAU_SIGMA[tsOff + 2];
+ engineState[15] = TAU_SIGMA[tsOff + 3];
+
+ // Key
+ Pack.LE_To_UInt32(keyBytes, 0, engineState, 1, 4);
+ Pack.LE_To_UInt32(keyBytes, keyBytes.Length - 16, engineState, 11, 4);
+ }
+
+ // IV
+ Pack.LE_To_UInt32(ivBytes, 0, engineState, 6, 2);
+ }
+
+ protected virtual void GenerateKeyStream(byte[] output)
+ {
+ SalsaCore(rounds, engineState, x);
+ Pack.UInt32_To_LE(x, output, 0);
+ }
+
+ internal static void SalsaCore(int rounds, uint[] input, uint[] x)
+ {
+ if (input.Length != 16)
+ throw new ArgumentException();
+ if (x.Length != 16)
+ throw new ArgumentException();
+ if (rounds % 2 != 0)
+ throw new ArgumentException("Number of rounds must be even");
+
+ uint x00 = input[ 0];
+ uint x01 = input[ 1];
+ uint x02 = input[ 2];
+ uint x03 = input[ 3];
+ uint x04 = input[ 4];
+ uint x05 = input[ 5];
+ uint x06 = input[ 6];
+ uint x07 = input[ 7];
+ uint x08 = input[ 8];
+ uint x09 = input[ 9];
+ uint x10 = input[10];
+ uint x11 = input[11];
+ uint x12 = input[12];
+ uint x13 = input[13];
+ uint x14 = input[14];
+ uint x15 = input[15];
+
+ for (int i = rounds; i > 0; i -= 2)
+ {
+ x04 ^= R((x00+x12), 7);
+ x08 ^= R((x04+x00), 9);
+ x12 ^= R((x08+x04),13);
+ x00 ^= R((x12+x08),18);
+ x09 ^= R((x05+x01), 7);
+ x13 ^= R((x09+x05), 9);
+ x01 ^= R((x13+x09),13);
+ x05 ^= R((x01+x13),18);
+ x14 ^= R((x10+x06), 7);
+ x02 ^= R((x14+x10), 9);
+ x06 ^= R((x02+x14),13);
+ x10 ^= R((x06+x02),18);
+ x03 ^= R((x15+x11), 7);
+ x07 ^= R((x03+x15), 9);
+ x11 ^= R((x07+x03),13);
+ x15 ^= R((x11+x07),18);
+
+ x01 ^= R((x00+x03), 7);
+ x02 ^= R((x01+x00), 9);
+ x03 ^= R((x02+x01),13);
+ x00 ^= R((x03+x02),18);
+ x06 ^= R((x05+x04), 7);
+ x07 ^= R((x06+x05), 9);
+ x04 ^= R((x07+x06),13);
+ x05 ^= R((x04+x07),18);
+ x11 ^= R((x10+x09), 7);
+ x08 ^= R((x11+x10), 9);
+ x09 ^= R((x08+x11),13);
+ x10 ^= R((x09+x08),18);
+ x12 ^= R((x15+x14), 7);
+ x13 ^= R((x12+x15), 9);
+ x14 ^= R((x13+x12),13);
+ x15 ^= R((x14+x13),18);
+ }
+
+ x[ 0] = x00 + input[ 0];
+ x[ 1] = x01 + input[ 1];
+ x[ 2] = x02 + input[ 2];
+ x[ 3] = x03 + input[ 3];
+ x[ 4] = x04 + input[ 4];
+ x[ 5] = x05 + input[ 5];
+ x[ 6] = x06 + input[ 6];
+ x[ 7] = x07 + input[ 7];
+ x[ 8] = x08 + input[ 8];
+ x[ 9] = x09 + input[ 9];
+ x[10] = x10 + input[10];
+ x[11] = x11 + input[11];
+ x[12] = x12 + input[12];
+ x[13] = x13 + input[13];
+ x[14] = x14 + input[14];
+ x[15] = x15 + input[15];
+ }
+
+ /**
+ * Rotate left
+ *
+ * @param x value to rotate
+ * @param y amount to rotate x
+ *
+ * @return rotated x
+ */
+ internal static uint R(uint x, int y)
+ {
+ return (x << y) | (x >> (32 - y));
+ }
+
+ private void ResetLimitCounter()
+ {
+ cW0 = 0;
+ cW1 = 0;
+ cW2 = 0;
+ }
+
+ private bool LimitExceeded()
+ {
+ if (++cW0 == 0)
+ {
+ if (++cW1 == 0)
+ {
+ return (++cW2 & 0x20) != 0; // 2^(32 + 32 + 6)
+ }
+ }
+
+ return false;
+ }
+
+ /*
+ * this relies on the fact len will always be positive.
+ */
+ private bool LimitExceeded(
+ uint len)
+ {
+ uint old = cW0;
+ cW0 += len;
+ if (cW0 < old)
+ {
+ if (++cW1 == 0)
+ {
+ return (++cW2 & 0x20) != 0; // 2^(32 + 32 + 6)
+ }
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/SerpentEngine.cs b/bc-sharp-crypto/src/crypto/engines/SerpentEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..76799f04505f1185434349649444e66bc5fd469e
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/SerpentEngine.cs
@@ -0,0 +1,292 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * Serpent is a 128-bit 32-round block cipher with variable key lengths,
+ * including 128, 192 and 256 bit keys conjectured to be at least as
+ * secure as three-key triple-DES.
+ *
+ * Serpent was designed by Ross Anderson, Eli Biham and Lars Knudsen as a
+ * candidate algorithm for the NIST AES Quest.
+ *
+ *
+ * For full details see The Serpent home page
+ *
+ */
+ public sealed class SerpentEngine
+ : SerpentEngineBase
+ {
+ /**
+ * Expand a user-supplied key material into a session key.
+ *
+ * @param key The user-key bytes (multiples of 4) to use.
+ * @exception ArgumentException
+ */
+ protected override int[] MakeWorkingKey(byte[] key)
+ {
+ //
+ // pad key to 256 bits
+ //
+ int[] kPad = new int[16];
+ int off = 0;
+ int length = 0;
+
+ for (off = 0; (off + 4) < key.Length; off += 4)
+ {
+ kPad[length++] = (int)Pack.LE_To_UInt32(key, off);
+ }
+
+ if (off % 4 == 0)
+ {
+ kPad[length++] = (int)Pack.LE_To_UInt32(key, off);
+ if (length < 8)
+ {
+ kPad[length] = 1;
+ }
+ }
+ else
+ {
+ throw new ArgumentException("key must be a multiple of 4 bytes");
+ }
+
+ //
+ // expand the padded key up to 33 x 128 bits of key material
+ //
+ int amount = (ROUNDS + 1) * 4;
+ int[] w = new int[amount];
+
+ //
+ // compute w0 to w7 from w-8 to w-1
+ //
+ for (int i = 8; i < 16; i++)
+ {
+ kPad[i] = RotateLeft(kPad[i - 8] ^ kPad[i - 5] ^ kPad[i - 3] ^ kPad[i - 1] ^ PHI ^ (i - 8), 11);
+ }
+
+ Array.Copy(kPad, 8, w, 0, 8);
+
+ //
+ // compute w8 to w136
+ //
+ for (int i = 8; i < amount; i++)
+ {
+ w[i] = RotateLeft(w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ i, 11);
+ }
+
+ //
+ // create the working keys by processing w with the Sbox and IP
+ //
+ Sb3(w[0], w[1], w[2], w[3]);
+ w[0] = X0; w[1] = X1; w[2] = X2; w[3] = X3;
+ Sb2(w[4], w[5], w[6], w[7]);
+ w[4] = X0; w[5] = X1; w[6] = X2; w[7] = X3;
+ Sb1(w[8], w[9], w[10], w[11]);
+ w[8] = X0; w[9] = X1; w[10] = X2; w[11] = X3;
+ Sb0(w[12], w[13], w[14], w[15]);
+ w[12] = X0; w[13] = X1; w[14] = X2; w[15] = X3;
+ Sb7(w[16], w[17], w[18], w[19]);
+ w[16] = X0; w[17] = X1; w[18] = X2; w[19] = X3;
+ Sb6(w[20], w[21], w[22], w[23]);
+ w[20] = X0; w[21] = X1; w[22] = X2; w[23] = X3;
+ Sb5(w[24], w[25], w[26], w[27]);
+ w[24] = X0; w[25] = X1; w[26] = X2; w[27] = X3;
+ Sb4(w[28], w[29], w[30], w[31]);
+ w[28] = X0; w[29] = X1; w[30] = X2; w[31] = X3;
+ Sb3(w[32], w[33], w[34], w[35]);
+ w[32] = X0; w[33] = X1; w[34] = X2; w[35] = X3;
+ Sb2(w[36], w[37], w[38], w[39]);
+ w[36] = X0; w[37] = X1; w[38] = X2; w[39] = X3;
+ Sb1(w[40], w[41], w[42], w[43]);
+ w[40] = X0; w[41] = X1; w[42] = X2; w[43] = X3;
+ Sb0(w[44], w[45], w[46], w[47]);
+ w[44] = X0; w[45] = X1; w[46] = X2; w[47] = X3;
+ Sb7(w[48], w[49], w[50], w[51]);
+ w[48] = X0; w[49] = X1; w[50] = X2; w[51] = X3;
+ Sb6(w[52], w[53], w[54], w[55]);
+ w[52] = X0; w[53] = X1; w[54] = X2; w[55] = X3;
+ Sb5(w[56], w[57], w[58], w[59]);
+ w[56] = X0; w[57] = X1; w[58] = X2; w[59] = X3;
+ Sb4(w[60], w[61], w[62], w[63]);
+ w[60] = X0; w[61] = X1; w[62] = X2; w[63] = X3;
+ Sb3(w[64], w[65], w[66], w[67]);
+ w[64] = X0; w[65] = X1; w[66] = X2; w[67] = X3;
+ Sb2(w[68], w[69], w[70], w[71]);
+ w[68] = X0; w[69] = X1; w[70] = X2; w[71] = X3;
+ Sb1(w[72], w[73], w[74], w[75]);
+ w[72] = X0; w[73] = X1; w[74] = X2; w[75] = X3;
+ Sb0(w[76], w[77], w[78], w[79]);
+ w[76] = X0; w[77] = X1; w[78] = X2; w[79] = X3;
+ Sb7(w[80], w[81], w[82], w[83]);
+ w[80] = X0; w[81] = X1; w[82] = X2; w[83] = X3;
+ Sb6(w[84], w[85], w[86], w[87]);
+ w[84] = X0; w[85] = X1; w[86] = X2; w[87] = X3;
+ Sb5(w[88], w[89], w[90], w[91]);
+ w[88] = X0; w[89] = X1; w[90] = X2; w[91] = X3;
+ Sb4(w[92], w[93], w[94], w[95]);
+ w[92] = X0; w[93] = X1; w[94] = X2; w[95] = X3;
+ Sb3(w[96], w[97], w[98], w[99]);
+ w[96] = X0; w[97] = X1; w[98] = X2; w[99] = X3;
+ Sb2(w[100], w[101], w[102], w[103]);
+ w[100] = X0; w[101] = X1; w[102] = X2; w[103] = X3;
+ Sb1(w[104], w[105], w[106], w[107]);
+ w[104] = X0; w[105] = X1; w[106] = X2; w[107] = X3;
+ Sb0(w[108], w[109], w[110], w[111]);
+ w[108] = X0; w[109] = X1; w[110] = X2; w[111] = X3;
+ Sb7(w[112], w[113], w[114], w[115]);
+ w[112] = X0; w[113] = X1; w[114] = X2; w[115] = X3;
+ Sb6(w[116], w[117], w[118], w[119]);
+ w[116] = X0; w[117] = X1; w[118] = X2; w[119] = X3;
+ Sb5(w[120], w[121], w[122], w[123]);
+ w[120] = X0; w[121] = X1; w[122] = X2; w[123] = X3;
+ Sb4(w[124], w[125], w[126], w[127]);
+ w[124] = X0; w[125] = X1; w[126] = X2; w[127] = X3;
+ Sb3(w[128], w[129], w[130], w[131]);
+ w[128] = X0; w[129] = X1; w[130] = X2; w[131] = X3;
+
+ 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.
+ */
+ protected override void EncryptBlock(byte[] input, int inOff, byte[] output, int outOff)
+ {
+ X0 = (int)Pack.LE_To_UInt32(input, inOff);
+ X1 = (int)Pack.LE_To_UInt32(input, inOff + 4);
+ X2 = (int)Pack.LE_To_UInt32(input, inOff + 8);
+ X3 = (int)Pack.LE_To_UInt32(input, inOff + 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, outOff);
+ Pack.UInt32_To_LE((uint)(wKey[129] ^ X1), output, outOff + 4);
+ Pack.UInt32_To_LE((uint)(wKey[130] ^ X2), output, outOff + 8);
+ 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);
+ X1 = wKey[129] ^ (int)Pack.LE_To_UInt32(input, inOff + 4);
+ X2 = wKey[130] ^ (int)Pack.LE_To_UInt32(input, inOff + 8);
+ X3 = wKey[131] ^ (int)Pack.LE_To_UInt32(input, inOff + 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, outOff);
+ Pack.UInt32_To_LE((uint)(X1 ^ wKey[1]), output, outOff + 4);
+ Pack.UInt32_To_LE((uint)(X2 ^ wKey[2]), output, outOff + 8);
+ Pack.UInt32_To_LE((uint)(X3 ^ wKey[3]), output, outOff + 12);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/SerpentEngineBase.cs b/bc-sharp-crypto/src/crypto/engines/SerpentEngineBase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9de552233ff92d7d5aa48252cecc1da79fa1829c
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/SerpentEngineBase.cs
@@ -0,0 +1,469 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ public abstract class SerpentEngineBase
+ : IBlockCipher
+ {
+ protected static readonly int BlockSize = 16;
+
+ internal const int ROUNDS = 32;
+ internal const int PHI = unchecked((int)0x9E3779B9); // (sqrt(5) - 1) * 2**31
+
+ protected bool encrypting;
+ protected int[] wKey;
+
+ protected int X0, X1, X2, X3; // registers
+
+ protected SerpentEngineBase()
+ {
+ }
+
+ /**
+ * initialise a Serpent cipher.
+ *
+ * @param encrypting whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @throws IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public virtual void Init(bool encrypting, ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("invalid parameter passed to " + AlgorithmName + " init - " + Platform.GetTypeName(parameters));
+
+ this.encrypting = encrypting;
+ this.wKey = MakeWorkingKey(((KeyParameter)parameters).GetKey());
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Serpent"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ 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.
+ * @return the number of bytes processed and produced.
+ * @throws DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @throws IllegalStateException if the cipher isn't initialised.
+ */
+ public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
+ {
+ if (wKey == null)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ Check.DataLength(input, inOff, BlockSize, "input buffer too short");
+ Check.OutputLength(output, outOff, BlockSize, "output buffer too short");
+
+ if (encrypting)
+ {
+ EncryptBlock(input, inOff, output, outOff);
+ }
+ else
+ {
+ DecryptBlock(input, inOff, output, outOff);
+ }
+
+ return BlockSize;
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ protected static int RotateLeft(int x, int bits)
+ {
+ return ((x << bits) | (int) ((uint)x >> (32 - bits)));
+ }
+
+ private static int RotateRight(int x, int bits)
+ {
+ return ( (int)((uint)x >> bits) | (x << (32 - bits)));
+ }
+
+ /*
+ * The sboxes below are based on the work of Brian Gladman and
+ * Sam Simpson, whose original notice appears below.
+ *
+ * For further details see:
+ * http://fp.gladman.plus.com/cryptography_technology/serpent/
+ *
+ */
+
+ /* Partially optimised Serpent S Box boolean functions derived */
+ /* using a recursive descent analyser but without a full search */
+ /* of all subtrees. This set of S boxes is the result of work */
+ /* by Sam Simpson and Brian Gladman using the spare time on a */
+ /* cluster of high capacity servers to search for S boxes with */
+ /* this customised search engine. There are now an average of */
+ /* 15.375 terms per S box. */
+ /* */
+ /* Copyright: Dr B. R Gladman (gladman@seven77.demon.co.uk) */
+ /* and Sam Simpson (s.simpson@mia.co.uk) */
+ /* 17th December 1998 */
+ /* */
+ /* We hereby give permission for information in this file to be */
+ /* used freely subject only to acknowledgement of its origin. */
+
+ /*
+ * S0 - { 3, 8,15, 1,10, 6, 5,11,14,13, 4, 2, 7, 0, 9,12 } - 15 terms.
+ */
+ protected void Sb0(int a, int b, int c, int d)
+ {
+ int t1 = a ^ d;
+ int t3 = c ^ t1;
+ int t4 = b ^ t3;
+ X3 = (a & d) ^ t4;
+ int t7 = a ^ (b & t1);
+ X2 = t4 ^ (c | t7);
+ int t12 = X3 & (t3 ^ t7);
+ X1 = (~t3) ^ t12;
+ X0 = t12 ^ (~t7);
+ }
+
+ /**
+ * InvSO - {13, 3,11, 0,10, 6, 5,12, 1,14, 4, 7,15, 9, 8, 2 } - 15 terms.
+ */
+ protected void Ib0(int a, int b, int c, int d)
+ {
+ int t1 = ~a;
+ int t2 = a ^ b;
+ int t4 = d ^ (t1 | t2);
+ int t5 = c ^ t4;
+ X2 = t2 ^ t5;
+ int t8 = t1 ^ (d & t2);
+ X1 = t4 ^ (X2 & t8);
+ X3 = (a & t4) ^ (t5 | X1);
+ X0 = X3 ^ (t5 ^ t8);
+ }
+
+ /**
+ * S1 - {15,12, 2, 7, 9, 0, 5,10, 1,11,14, 8, 6,13, 3, 4 } - 14 terms.
+ */
+ protected void Sb1(int a, int b, int c, int d)
+ {
+ int t2 = b ^ (~a);
+ int t5 = c ^ (a | t2);
+ X2 = d ^ t5;
+ int t7 = b ^ (d | t2);
+ int t8 = t2 ^ X2;
+ X3 = t8 ^ (t5 & t7);
+ int t11 = t5 ^ t7;
+ X1 = X3 ^ t11;
+ X0 = t5 ^ (t8 & t11);
+ }
+
+ /**
+ * InvS1 - { 5, 8, 2,14,15, 6,12, 3,11, 4, 7, 9, 1,13,10, 0 } - 14 steps.
+ */
+ protected void Ib1(int a, int b, int c, int d)
+ {
+ int t1 = b ^ d;
+ int t3 = a ^ (b & t1);
+ int t4 = t1 ^ t3;
+ X3 = c ^ t4;
+ int t7 = b ^ (t1 & t3);
+ int t8 = X3 | t7;
+ X1 = t3 ^ t8;
+ int t10 = ~X1;
+ int t11 = X3 ^ t7;
+ X0 = t10 ^ t11;
+ X2 = t4 ^ (t10 | t11);
+ }
+
+ /**
+ * S2 - { 8, 6, 7, 9, 3,12,10,15,13, 1,14, 4, 0,11, 5, 2 } - 16 terms.
+ */
+ protected void Sb2(int a, int b, int c, int d)
+ {
+ int t1 = ~a;
+ int t2 = b ^ d;
+ int t3 = c & t1;
+ X0 = t2 ^ t3;
+ int t5 = c ^ t1;
+ int t6 = c ^ X0;
+ int t7 = b & t6;
+ X3 = t5 ^ t7;
+ X2 = a ^ ((d | t7) & (X0 | t5));
+ X1 = (t2 ^ X3) ^ (X2 ^ (d | t1));
+ }
+
+ /**
+ * InvS2 - {12, 9,15, 4,11,14, 1, 2, 0, 3, 6,13, 5, 8,10, 7 } - 16 steps.
+ */
+ protected void Ib2(int a, int b, int c, int d)
+ {
+ int t1 = b ^ d;
+ int t2 = ~t1;
+ int t3 = a ^ c;
+ int t4 = c ^ t1;
+ int t5 = b & t4;
+ X0 = t3 ^ t5;
+ int t7 = a | t2;
+ int t8 = d ^ t7;
+ int t9 = t3 | t8;
+ X3 = t1 ^ t9;
+ int t11 = ~t4;
+ int t12 = X0 | X3;
+ X1 = t11 ^ t12;
+ X2 = (d & t11) ^ (t3 ^ t12);
+ }
+
+ /**
+ * S3 - { 0,15,11, 8,12, 9, 6, 3,13, 1, 2, 4,10, 7, 5,14 } - 16 terms.
+ */
+ protected void Sb3(int a, int b, int c, int d)
+ {
+ int t1 = a ^ b;
+ int t2 = a & c;
+ int t3 = a | d;
+ int t4 = c ^ d;
+ int t5 = t1 & t3;
+ int t6 = t2 | t5;
+ X2 = t4 ^ t6;
+ int t8 = b ^ t3;
+ int t9 = t6 ^ t8;
+ int t10 = t4 & t9;
+ X0 = t1 ^ t10;
+ int t12 = X2 & X0;
+ X1 = t9 ^ t12;
+ X3 = (b | d) ^ (t4 ^ t12);
+ }
+
+ /**
+ * InvS3 - { 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1 } - 15 terms
+ */
+ protected void Ib3(int a, int b, int c, int d)
+ {
+ int t1 = a | b;
+ int t2 = b ^ c;
+ int t3 = b & t2;
+ int t4 = a ^ t3;
+ int t5 = c ^ t4;
+ int t6 = d | t4;
+ X0 = t2 ^ t6;
+ int t8 = t2 | t6;
+ int t9 = d ^ t8;
+ X2 = t5 ^ t9;
+ int t11 = t1 ^ t9;
+ int t12 = X0 & t11;
+ X3 = t4 ^ t12;
+ X1 = X3 ^ (X0 ^ t11);
+ }
+
+ /**
+ * S4 - { 1,15, 8, 3,12, 0,11, 6, 2, 5, 4,10, 9,14, 7,13 } - 15 terms.
+ */
+ protected void Sb4(int a, int b, int c, int d)
+ {
+ int t1 = a ^ d;
+ int t2 = d & t1;
+ int t3 = c ^ t2;
+ int t4 = b | t3;
+ X3 = t1 ^ t4;
+ int t6 = ~b;
+ int t7 = t1 | t6;
+ X0 = t3 ^ t7;
+ int t9 = a & X0;
+ int t10 = t1 ^ t6;
+ int t11 = t4 & t10;
+ X2 = t9 ^ t11;
+ X1 = (a ^ t3) ^ (t10 & X2);
+ }
+
+ /**
+ * InvS4 - { 5, 0, 8, 3,10, 9, 7,14, 2,12,11, 6, 4,15,13, 1 } - 15 terms.
+ */
+ protected void Ib4(int a, int b, int c, int d)
+ {
+ int t1 = c | d;
+ int t2 = a & t1;
+ int t3 = b ^ t2;
+ int t4 = a & t3;
+ int t5 = c ^ t4;
+ X1 = d ^ t5;
+ int t7 = ~a;
+ int t8 = t5 & X1;
+ X3 = t3 ^ t8;
+ int t10 = X1 | t7;
+ int t11 = d ^ t10;
+ X0 = X3 ^ t11;
+ X2 = (t3 & t11) ^ (X1 ^ t7);
+ }
+
+ /**
+ * S5 - {15, 5, 2,11, 4,10, 9,12, 0, 3,14, 8,13, 6, 7, 1 } - 16 terms.
+ */
+ protected void Sb5(int a, int b, int c, int d)
+ {
+ int t1 = ~a;
+ int t2 = a ^ b;
+ int t3 = a ^ d;
+ int t4 = c ^ t1;
+ int t5 = t2 | t3;
+ X0 = t4 ^ t5;
+ int t7 = d & X0;
+ int t8 = t2 ^ X0;
+ X1 = t7 ^ t8;
+ int t10 = t1 | X0;
+ int t11 = t2 | t7;
+ int t12 = t3 ^ t10;
+ X2 = t11 ^ t12;
+ X3 = (b ^ t7) ^ (X1 & t12);
+ }
+
+ /**
+ * InvS5 - { 8,15, 2, 9, 4, 1,13,14,11, 6, 5, 3, 7,12,10, 0 } - 16 terms.
+ */
+ protected void Ib5(int a, int b, int c, int d)
+ {
+ int t1 = ~c;
+ int t2 = b & t1;
+ int t3 = d ^ t2;
+ int t4 = a & t3;
+ int t5 = b ^ t1;
+ X3 = t4 ^ t5;
+ int t7 = b | X3;
+ int t8 = a & t7;
+ X1 = t3 ^ t8;
+ int t10 = a | d;
+ int t11 = t1 ^ t7;
+ X0 = t10 ^ t11;
+ X2 = (b & t10) ^ (t4 | (a ^ c));
+ }
+
+ /**
+ * S6 - { 7, 2,12, 5, 8, 4, 6,11,14, 9, 1,15,13, 3,10, 0 } - 15 terms.
+ */
+ protected void Sb6(int a, int b, int c, int d)
+ {
+ int t1 = ~a;
+ int t2 = a ^ d;
+ int t3 = b ^ t2;
+ int t4 = t1 | t2;
+ int t5 = c ^ t4;
+ X1 = b ^ t5;
+ int t7 = t2 | X1;
+ int t8 = d ^ t7;
+ int t9 = t5 & t8;
+ X2 = t3 ^ t9;
+ int t11 = t5 ^ t8;
+ X0 = X2 ^ t11;
+ X3 = (~t5) ^ (t3 & t11);
+ }
+
+ /**
+ * InvS6 - {15,10, 1,13, 5, 3, 6, 0, 4, 9,14, 7, 2,12, 8,11 } - 15 terms.
+ */
+ protected void Ib6(int a, int b, int c, int d)
+ {
+ int t1 = ~a;
+ int t2 = a ^ b;
+ int t3 = c ^ t2;
+ int t4 = c | t1;
+ int t5 = d ^ t4;
+ X1 = t3 ^ t5;
+ int t7 = t3 & t5;
+ int t8 = t2 ^ t7;
+ int t9 = b | t8;
+ X3 = t5 ^ t9;
+ int t11 = b | X3;
+ X0 = t8 ^ t11;
+ X2 = (d & t1) ^ (t3 ^ t11);
+ }
+
+ /**
+ * S7 - { 1,13,15, 0,14, 8, 2,11, 7, 4,12,10, 9, 3, 5, 6 } - 16 terms.
+ */
+ protected void Sb7(int a, int b, int c, int d)
+ {
+ int t1 = b ^ c;
+ int t2 = c & t1;
+ int t3 = d ^ t2;
+ int t4 = a ^ t3;
+ int t5 = d | t1;
+ int t6 = t4 & t5;
+ X1 = b ^ t6;
+ int t8 = t3 | X1;
+ int t9 = a & t4;
+ X3 = t1 ^ t9;
+ int t11 = t4 ^ t8;
+ int t12 = X3 & t11;
+ X2 = t3 ^ t12;
+ X0 = (~t11) ^ (X3 & X2);
+ }
+
+ /**
+ * InvS7 - { 3, 0, 6,13, 9,14,15, 8, 5,12,11, 7,10, 1, 4, 2 } - 17 terms.
+ */
+ protected void Ib7(int a, int b, int c, int d)
+ {
+ int t3 = c | (a & b);
+ int t4 = d & (a | b);
+ X3 = t3 ^ t4;
+ int t6 = ~d;
+ int t7 = b ^ t4;
+ int t9 = t7 | (X3 ^ t6);
+ X1 = a ^ t9;
+ X0 = (c ^ t7) ^ (d | X1);
+ X2 = (t3 ^ X1) ^ (X0 ^ (a & X3));
+ }
+
+ /**
+ * Apply the linear transformation to the register set.
+ */
+ protected void LT()
+ {
+ int x0 = RotateLeft(X0, 13);
+ int x2 = RotateLeft(X2, 3);
+ int x1 = X1 ^ x0 ^ x2;
+ int x3 = X3 ^ x2 ^ x0 << 3;
+
+ X1 = RotateLeft(x1, 1);
+ X3 = RotateLeft(x3, 7);
+ X0 = RotateLeft(x0 ^ X1 ^ X3, 5);
+ X2 = RotateLeft(x2 ^ X3 ^ (X1 << 7), 22);
+ }
+
+ /**
+ * Apply the inverse of the linear transformation to the register set.
+ */
+ protected void InverseLT()
+ {
+ int x2 = RotateRight(X2, 22) ^ X3 ^ (X1 << 7);
+ int x0 = RotateRight(X0, 5) ^ X1 ^ X3;
+ int x3 = RotateRight(X3, 7);
+ int x1 = RotateRight(X1, 1);
+ X3 = x3 ^ x2 ^ x0 << 3;
+ X1 = x1 ^ x0 ^ x2;
+ X2 = RotateRight(x2, 3);
+ X0 = RotateRight(x0, 13);
+ }
+
+ protected abstract int[] MakeWorkingKey(byte[] key);
+
+ protected abstract void EncryptBlock(byte[] input, int inOff, byte[] output, int outOff);
+
+ protected abstract void DecryptBlock(byte[] input, int inOff, byte[] output, int outOff);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/SkipjackEngine.cs b/bc-sharp-crypto/src/crypto/engines/SkipjackEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c90646cc41c535d2aab400c362406846025b627f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/SkipjackEngine.cs
@@ -0,0 +1,254 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * a class that provides a basic SKIPJACK engine.
+ */
+ public class SkipjackEngine
+ : IBlockCipher
+ {
+ const int BLOCK_SIZE = 8;
+
+ static readonly short [] ftable =
+ {
+ 0xa3, 0xd7, 0x09, 0x83, 0xf8, 0x48, 0xf6, 0xf4, 0xb3, 0x21, 0x15, 0x78, 0x99, 0xb1, 0xaf, 0xf9,
+ 0xe7, 0x2d, 0x4d, 0x8a, 0xce, 0x4c, 0xca, 0x2e, 0x52, 0x95, 0xd9, 0x1e, 0x4e, 0x38, 0x44, 0x28,
+ 0x0a, 0xdf, 0x02, 0xa0, 0x17, 0xf1, 0x60, 0x68, 0x12, 0xb7, 0x7a, 0xc3, 0xe9, 0xfa, 0x3d, 0x53,
+ 0x96, 0x84, 0x6b, 0xba, 0xf2, 0x63, 0x9a, 0x19, 0x7c, 0xae, 0xe5, 0xf5, 0xf7, 0x16, 0x6a, 0xa2,
+ 0x39, 0xb6, 0x7b, 0x0f, 0xc1, 0x93, 0x81, 0x1b, 0xee, 0xb4, 0x1a, 0xea, 0xd0, 0x91, 0x2f, 0xb8,
+ 0x55, 0xb9, 0xda, 0x85, 0x3f, 0x41, 0xbf, 0xe0, 0x5a, 0x58, 0x80, 0x5f, 0x66, 0x0b, 0xd8, 0x90,
+ 0x35, 0xd5, 0xc0, 0xa7, 0x33, 0x06, 0x65, 0x69, 0x45, 0x00, 0x94, 0x56, 0x6d, 0x98, 0x9b, 0x76,
+ 0x97, 0xfc, 0xb2, 0xc2, 0xb0, 0xfe, 0xdb, 0x20, 0xe1, 0xeb, 0xd6, 0xe4, 0xdd, 0x47, 0x4a, 0x1d,
+ 0x42, 0xed, 0x9e, 0x6e, 0x49, 0x3c, 0xcd, 0x43, 0x27, 0xd2, 0x07, 0xd4, 0xde, 0xc7, 0x67, 0x18,
+ 0x89, 0xcb, 0x30, 0x1f, 0x8d, 0xc6, 0x8f, 0xaa, 0xc8, 0x74, 0xdc, 0xc9, 0x5d, 0x5c, 0x31, 0xa4,
+ 0x70, 0x88, 0x61, 0x2c, 0x9f, 0x0d, 0x2b, 0x87, 0x50, 0x82, 0x54, 0x64, 0x26, 0x7d, 0x03, 0x40,
+ 0x34, 0x4b, 0x1c, 0x73, 0xd1, 0xc4, 0xfd, 0x3b, 0xcc, 0xfb, 0x7f, 0xab, 0xe6, 0x3e, 0x5b, 0xa5,
+ 0xad, 0x04, 0x23, 0x9c, 0x14, 0x51, 0x22, 0xf0, 0x29, 0x79, 0x71, 0x7e, 0xff, 0x8c, 0x0e, 0xe2,
+ 0x0c, 0xef, 0xbc, 0x72, 0x75, 0x6f, 0x37, 0xa1, 0xec, 0xd3, 0x8e, 0x62, 0x8b, 0x86, 0x10, 0xe8,
+ 0x08, 0x77, 0x11, 0xbe, 0x92, 0x4f, 0x24, 0xc5, 0x32, 0x36, 0x9d, 0xcf, 0xf3, 0xa6, 0xbb, 0xac,
+ 0x5e, 0x6c, 0xa9, 0x13, 0x57, 0x25, 0xb5, 0xe3, 0xbd, 0xa8, 0x3a, 0x01, 0x05, 0x59, 0x2a, 0x46
+ };
+
+ private int[] key0, key1, key2, key3;
+ private bool encrypting;
+
+ /**
+ * initialise a SKIPJACK 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 virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("invalid parameter passed to SKIPJACK init - " + Platform.GetTypeName(parameters));
+
+ byte[] keyBytes = ((KeyParameter)parameters).GetKey();
+
+ this.encrypting = forEncryption;
+ this.key0 = new int[32];
+ this.key1 = new int[32];
+ this.key2 = new int[32];
+ this.key3 = new int[32];
+
+ //
+ // expand the key to 128 bytes in 4 parts (saving us a modulo, multiply
+ // and an addition).
+ //
+ for (int i = 0; i < 32; i ++)
+ {
+ key0[i] = keyBytes[(i * 4) % 10] & 0xff;
+ key1[i] = keyBytes[(i * 4 + 1) % 10] & 0xff;
+ key2[i] = keyBytes[(i * 4 + 2) % 10] & 0xff;
+ key3[i] = keyBytes[(i * 4 + 3) % 10] & 0xff;
+ }
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "SKIPJACK"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (key1 == null)
+ throw new InvalidOperationException("SKIPJACK engine not initialised");
+
+ Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+ if (encrypting)
+ {
+ EncryptBlock(input, inOff, output, outOff);
+ }
+ else
+ {
+ DecryptBlock(input, inOff, output, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ /**
+ * The G permutation
+ */
+ private int G(
+ int k,
+ int w)
+ {
+ int g1, g2, g3, g4, g5, g6;
+
+ g1 = (w >> 8) & 0xff;
+ g2 = w & 0xff;
+
+ g3 = ftable[g2 ^ key0[k]] ^ g1;
+ g4 = ftable[g3 ^ key1[k]] ^ g2;
+ g5 = ftable[g4 ^ key2[k]] ^ g3;
+ g6 = ftable[g5 ^ key3[k]] ^ g4;
+
+ return ((g5 << 8) + g6);
+ }
+
+ 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);
+ int w3 = (input[inOff + 4] << 8) + (input[inOff + 5] & 0xff);
+ int w4 = (input[inOff + 6] << 8) + (input[inOff + 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++;
+ }
+ }
+
+ outBytes[outOff + 0] = (byte)((w1 >> 8));
+ outBytes[outOff + 1] = (byte)(w1);
+ outBytes[outOff + 2] = (byte)((w2 >> 8));
+ outBytes[outOff + 3] = (byte)(w2);
+ outBytes[outOff + 4] = (byte)((w3 >> 8));
+ outBytes[outOff + 5] = (byte)(w3);
+ outBytes[outOff + 6] = (byte)((w4 >> 8));
+ outBytes[outOff + 7] = (byte)(w4);
+
+ 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)
+ {
+ int w2 = (input[inOff + 0] << 8) + (input[inOff + 1] & 0xff);
+ int w1 = (input[inOff + 2] << 8) + (input[inOff + 3] & 0xff);
+ int w4 = (input[inOff + 4] << 8) + (input[inOff + 5] & 0xff);
+ int w3 = (input[inOff + 6] << 8) + (input[inOff + 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--;
+ }
+ }
+
+ outBytes[outOff + 0] = (byte)((w2 >> 8));
+ outBytes[outOff + 1] = (byte)(w2);
+ outBytes[outOff + 2] = (byte)((w1 >> 8));
+ outBytes[outOff + 3] = (byte)(w1);
+ outBytes[outOff + 4] = (byte)((w4 >> 8));
+ outBytes[outOff + 5] = (byte)(w4);
+ outBytes[outOff + 6] = (byte)((w3 >> 8));
+ outBytes[outOff + 7] = (byte)(w3);
+
+ return BLOCK_SIZE;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/TEAEngine.cs b/bc-sharp-crypto/src/crypto/engines/TEAEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7b700145ee5982685cc523e891b53d3868c177c9
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/TEAEngine.cs
@@ -0,0 +1,166 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * An TEA engine.
+ */
+ public class TeaEngine
+ : IBlockCipher
+ {
+ private const int
+ rounds = 32,
+ block_size = 8;
+// key_size = 16,
+
+ private const uint
+ delta = 0x9E3779B9,
+ d_sum = 0xC6EF3720; // sum on decrypt
+
+ /*
+ * the expanded key array of 4 subkeys
+ */
+ private uint _a, _b, _c, _d;
+ private bool _initialised;
+ private bool _forEncryption;
+
+ /**
+ * Create an instance of the TEA encryption algorithm
+ * and set some defaults
+ */
+ public TeaEngine()
+ {
+ _initialised = false;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "TEA"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return block_size;
+ }
+
+ /**
+ * initialise
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception ArgumentException if the params argument is
+ * inappropriate.
+ */
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ {
+ throw new ArgumentException("invalid parameter passed to TEA init - "
+ + Platform.GetTypeName(parameters));
+ }
+
+ _forEncryption = forEncryption;
+ _initialised = true;
+
+ KeyParameter p = (KeyParameter) parameters;
+
+ setKey(p.GetKey());
+ }
+
+ public virtual int ProcessBlock(
+ byte[] inBytes,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ if (!_initialised)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ 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);
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ /**
+ * Re-key the cipher.
+ *
+ * @param key the key to be used
+ */
+ private void setKey(
+ byte[] key)
+ {
+ _a = Pack.BE_To_UInt32(key, 0);
+ _b = Pack.BE_To_UInt32(key, 4);
+ _c = Pack.BE_To_UInt32(key, 8);
+ _d = Pack.BE_To_UInt32(key, 12);
+ }
+
+ 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;
+ v0 += ((v1 << 4) + _a) ^ (v1 + sum) ^ ((v1 >> 5) + _b);
+ v1 += ((v0 << 4) + _c) ^ (v0 + sum) ^ ((v0 >> 5) + _d);
+ }
+
+ Pack.UInt32_To_BE(v0, outBytes, outOff);
+ Pack.UInt32_To_BE(v1, outBytes, outOff + 4);
+
+ return block_size;
+ }
+
+ private int decryptBlock(
+ 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 = 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, outBytes, outOff);
+ Pack.UInt32_To_BE(v1, outBytes, outOff + 4);
+
+ return block_size;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/ThreefishEngine.cs b/bc-sharp-crypto/src/crypto/engines/ThreefishEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..eade3cc728c7b1837cb552987a29bf8a65259ba2
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/ThreefishEngine.cs
@@ -0,0 +1,1491 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ ///
+ /// Implementation of the Threefish tweakable large block cipher in 256, 512 and 1024 bit block
+ /// sizes.
+ ///
+ ///
+ /// This is the 1.3 version of Threefish defined in the Skein hash function submission to the NIST
+ /// SHA-3 competition in October 2010.
+ ///
+ /// Threefish was designed by Niels Ferguson - Stefan Lucks - Bruce Schneier - Doug Whiting - Mihir
+ /// Bellare - Tadayoshi Kohno - Jon Callas - Jesse Walker.
+ ///
+ /// This implementation inlines all round functions, unrolls 8 rounds, and uses 1.2k of static tables
+ /// to speed up key schedule injection.
+ /// 2 x block size state is retained by each cipher instance.
+ ///
+ public class ThreefishEngine
+ : IBlockCipher
+ {
+ ///
+ /// 256 bit block size - Threefish-256
+ ///
+ public const int BLOCKSIZE_256 = 256;
+ ///
+ /// 512 bit block size - Threefish-512
+ ///
+ public const int BLOCKSIZE_512 = 512;
+ ///
+ /// 1024 bit block size - Threefish-1024
+ ///
+ public const int BLOCKSIZE_1024 = 1024;
+
+ /**
+ * Size of the tweak in bytes (always 128 bit/16 bytes)
+ */
+ private const int TWEAK_SIZE_BYTES = 16;
+ private const int TWEAK_SIZE_WORDS = TWEAK_SIZE_BYTES / 8;
+
+ /**
+ * Rounds in Threefish-256
+ */
+ private const int ROUNDS_256 = 72;
+ /**
+ * Rounds in Threefish-512
+ */
+ private const int ROUNDS_512 = 72;
+ /**
+ * Rounds in Threefish-1024
+ */
+ private const int ROUNDS_1024 = 80;
+
+ /**
+ * Max rounds of any of the variants
+ */
+ private const int MAX_ROUNDS = ROUNDS_1024;
+
+ /**
+ * Key schedule parity constant
+ */
+ private const ulong C_240 = 0x1BD11BDAA9FC1A22L;
+
+ /* Pre-calculated modulo arithmetic tables for key schedule lookups */
+ private static readonly int[] MOD9 = new int[MAX_ROUNDS];
+ private static readonly int[] MOD17 = new int[MOD9.Length];
+ private static readonly int[] MOD5 = new int[MOD9.Length];
+ private static readonly int[] MOD3 = new int[MOD9.Length];
+
+ static ThreefishEngine()
+ {
+ for (int i = 0; i < MOD9.Length; i++)
+ {
+ MOD17[i] = i % 17;
+ MOD9[i] = i % 9;
+ MOD5[i] = i % 5;
+ MOD3[i] = i % 3;
+ }
+ }
+
+ /**
+ * Block size in bytes
+ */
+ private readonly int blocksizeBytes;
+
+ /**
+ * Block size in 64 bit words
+ */
+ private readonly int blocksizeWords;
+
+ /**
+ * Buffer for byte oriented processBytes to call internal word API
+ */
+ private readonly ulong[] currentBlock;
+
+ /**
+ * Tweak bytes (2 byte t1,t2, calculated t3 and repeat of t1,t2 for modulo free lookup
+ */
+ private readonly ulong[] t = new ulong[5];
+
+ /**
+ * Key schedule words
+ */
+ private readonly ulong[] kw;
+
+ /**
+ * The internal cipher implementation (varies by blocksize)
+ */
+ private readonly ThreefishCipher cipher;
+
+ private bool forEncryption;
+
+ ///
+ /// Constructs a new Threefish cipher, with a specified block size.
+ ///
+ /// the block size in bits, one of , ,
+ /// .
+ public ThreefishEngine(int blocksizeBits)
+ {
+ this.blocksizeBytes = (blocksizeBits / 8);
+ this.blocksizeWords = (this.blocksizeBytes / 8);
+ this.currentBlock = new ulong[blocksizeWords];
+
+ /*
+ * Provide room for original key words, extended key word and repeat of key words for modulo
+ * free lookup of key schedule words.
+ */
+ this.kw = new ulong[2 * blocksizeWords + 1];
+
+ switch (blocksizeBits)
+ {
+ case BLOCKSIZE_256:
+ cipher = new Threefish256Cipher(kw, t);
+ break;
+ case BLOCKSIZE_512:
+ cipher = new Threefish512Cipher(kw, t);
+ break;
+ case BLOCKSIZE_1024:
+ cipher = new Threefish1024Cipher(kw, t);
+ break;
+ default:
+ throw new ArgumentException(
+ "Invalid blocksize - Threefish is defined with block size of 256, 512, or 1024 bits");
+ }
+ }
+
+ ///
+ /// Initialise the engine.
+ ///
+ /// Initialise for encryption if true, for decryption if false.
+ /// an instance of or (to
+ /// use a 0 tweak)
+ public virtual void Init(bool forEncryption, ICipherParameters parameters)
+ {
+ byte[] keyBytes;
+ byte[] tweakBytes;
+
+ if (parameters is TweakableBlockCipherParameters)
+ {
+ TweakableBlockCipherParameters tParams = (TweakableBlockCipherParameters)parameters;
+ keyBytes = tParams.Key.GetKey();
+ tweakBytes = tParams.Tweak;
+ }
+ else if (parameters is KeyParameter)
+ {
+ keyBytes = ((KeyParameter)parameters).GetKey();
+ tweakBytes = null;
+ }
+ else
+ {
+ throw new ArgumentException("Invalid parameter passed to Threefish init - "
+ + Platform.GetTypeName(parameters));
+ }
+
+ ulong[] keyWords = null;
+ ulong[] tweakWords = null;
+
+ if (keyBytes != null)
+ {
+ if (keyBytes.Length != this.blocksizeBytes)
+ {
+ throw new ArgumentException("Threefish key must be same size as block (" + blocksizeBytes
+ + " bytes)");
+ }
+ keyWords = new ulong[blocksizeWords];
+ for (int i = 0; i < keyWords.Length; i++)
+ {
+ keyWords[i] = BytesToWord(keyBytes, i * 8);
+ }
+ }
+ if (tweakBytes != null)
+ {
+ if (tweakBytes.Length != TWEAK_SIZE_BYTES)
+ {
+ throw new ArgumentException("Threefish tweak must be " + TWEAK_SIZE_BYTES + " bytes");
+ }
+ tweakWords = new ulong[]{BytesToWord(tweakBytes, 0), BytesToWord(tweakBytes, 8)};
+ }
+ Init(forEncryption, keyWords, tweakWords);
+ }
+
+ ///
+ /// Initialise the engine, specifying the key and tweak directly.
+ ///
+ /// the cipher mode.
+ /// the words of the key, or null
to use the current key.
+ /// the 2 word (128 bit) tweak, or null
to use the current tweak.
+ internal void Init(bool forEncryption, ulong[] key, ulong[] tweak)
+ {
+ this.forEncryption = forEncryption;
+ if (key != null)
+ {
+ SetKey(key);
+ }
+ if (tweak != null)
+ {
+ SetTweak(tweak);
+ }
+ }
+
+ private void SetKey(ulong[] key)
+ {
+ if (key.Length != this.blocksizeWords)
+ {
+ throw new ArgumentException("Threefish key must be same size as block (" + blocksizeWords
+ + " words)");
+ }
+
+ /*
+ * Full subkey schedule is deferred to execution to avoid per cipher overhead (10k for 512,
+ * 20k for 1024).
+ *
+ * Key and tweak word sequences are repeated, and static MOD17/MOD9/MOD5/MOD3 calculations
+ * used, to avoid expensive mod computations during cipher operation.
+ */
+
+ ulong knw = C_240;
+ for (int i = 0; i < blocksizeWords; i++)
+ {
+ kw[i] = key[i];
+ knw = knw ^ kw[i];
+ }
+ kw[blocksizeWords] = knw;
+ Array.Copy(kw, 0, kw, blocksizeWords + 1, blocksizeWords);
+ }
+
+ private void SetTweak(ulong[] tweak)
+ {
+ if (tweak.Length != TWEAK_SIZE_WORDS)
+ {
+ throw new ArgumentException("Tweak must be " + TWEAK_SIZE_WORDS + " words.");
+ }
+
+ /*
+ * Tweak schedule partially repeated to avoid mod computations during cipher operation
+ */
+ t[0] = tweak[0];
+ t[1] = tweak[1];
+ t[2] = t[0] ^ t[1];
+ t[3] = t[0];
+ t[4] = t[1];
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Threefish-" + (blocksizeBytes * 8); }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return blocksizeBytes;
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ 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");
+ }
+
+ for (int i = 0; i < blocksizeBytes; i += 8)
+ {
+ currentBlock[i >> 3] = BytesToWord(inBytes, inOff + i);
+ }
+ ProcessBlock(this.currentBlock, this.currentBlock);
+ for (int i = 0; i < blocksizeBytes; i += 8)
+ {
+ WordToBytes(this.currentBlock[i >> 3], outBytes, outOff + i);
+ }
+
+ return blocksizeBytes;
+ }
+
+ ///
+ /// Process a block of data represented as 64 bit words.
+ ///
+ /// the number of 8 byte words processed (which will be the same as the block size).
+ /// a block sized buffer of words to process.
+ /// a block sized buffer of words to receive the output of the operation.
+ /// if either the input or output is not block sized
+ /// if this engine is not initialised
+ internal int ProcessBlock(ulong[] inWords, ulong[] outWords)
+ {
+ if (kw[blocksizeWords] == 0)
+ {
+ throw new InvalidOperationException("Threefish engine not initialised");
+ }
+
+ if (inWords.Length != blocksizeWords)
+ {
+ throw new DataLengthException("Input buffer too short");
+ }
+ if (outWords.Length != blocksizeWords)
+ {
+ throw new DataLengthException("Output buffer too short");
+ }
+
+ if (forEncryption)
+ {
+ cipher.EncryptBlock(inWords, outWords);
+ }
+ else
+ {
+ cipher.DecryptBlock(inWords, outWords);
+ }
+
+ return blocksizeWords;
+ }
+
+ ///
+ /// Read a single 64 bit word from input in LSB first order.
+ ///
+ internal static ulong BytesToWord(byte[] bytes, int off)
+ {
+ if ((off + 8) > bytes.Length)
+ {
+ // Help the JIT avoid index checks
+ throw new ArgumentException();
+ }
+
+ ulong word = 0;
+ int index = off;
+
+ word = (bytes[index++] & 0xffUL);
+ word |= (bytes[index++] & 0xffUL) << 8;
+ word |= (bytes[index++] & 0xffUL) << 16;
+ word |= (bytes[index++] & 0xffUL) << 24;
+ word |= (bytes[index++] & 0xffUL) << 32;
+ word |= (bytes[index++] & 0xffUL) << 40;
+ word |= (bytes[index++] & 0xffUL) << 48;
+ word |= (bytes[index++] & 0xffUL) << 56;
+
+ return word;
+ }
+
+ ///
+ /// Write a 64 bit word to output in LSB first order.
+ ///
+ internal static void WordToBytes(ulong word, byte[] bytes, int off)
+ {
+ if ((off + 8) > bytes.Length)
+ {
+ // Help the JIT avoid index checks
+ throw new ArgumentException();
+ }
+ int index = off;
+
+ bytes[index++] = (byte)word;
+ bytes[index++] = (byte)(word >> 8);
+ bytes[index++] = (byte)(word >> 16);
+ bytes[index++] = (byte)(word >> 24);
+ bytes[index++] = (byte)(word >> 32);
+ bytes[index++] = (byte)(word >> 40);
+ bytes[index++] = (byte)(word >> 48);
+ bytes[index++] = (byte)(word >> 56);
+ }
+
+ /**
+ * Rotate left + xor part of the mix operation.
+ */
+ private static ulong RotlXor(ulong x, int n, ulong xor)
+ {
+ return ((x << n) | (x >> (64 - n))) ^ xor;
+ }
+
+ /**
+ * Rotate xor + rotate right part of the unmix operation.
+ */
+ private static ulong XorRotr(ulong x, int n, ulong xor)
+ {
+ ulong xored = x ^ xor;
+ return (xored >> n) | (xored << (64 - n));
+ }
+
+ private abstract class ThreefishCipher
+ {
+ /**
+ * The extended + repeated tweak words
+ */
+ protected readonly ulong[] t;
+ /**
+ * The extended + repeated key words
+ */
+ protected readonly ulong[] kw;
+
+ protected ThreefishCipher(ulong[] kw, ulong[] t)
+ {
+ this.kw = kw;
+ this.t = t;
+ }
+
+ internal abstract void EncryptBlock(ulong[] block, ulong[] outWords);
+
+ internal abstract void DecryptBlock(ulong[] block, ulong[] outWords);
+
+ }
+
+ private sealed class Threefish256Cipher
+ : ThreefishCipher
+ {
+ /**
+ * Mix rotation constants defined in Skein 1.3 specification
+ */
+ private const int ROTATION_0_0 = 14, ROTATION_0_1 = 16;
+ private const int ROTATION_1_0 = 52, ROTATION_1_1 = 57;
+ private const int ROTATION_2_0 = 23, ROTATION_2_1 = 40;
+ private const int ROTATION_3_0 = 5, ROTATION_3_1 = 37;
+
+ private const int ROTATION_4_0 = 25, ROTATION_4_1 = 33;
+ private const int ROTATION_5_0 = 46, ROTATION_5_1 = 12;
+ private const int ROTATION_6_0 = 58, ROTATION_6_1 = 22;
+ private const int ROTATION_7_0 = 32, ROTATION_7_1 = 32;
+
+ public Threefish256Cipher(ulong[] kw, ulong[] t)
+ : base(kw, t)
+ {
+ }
+
+ internal override void EncryptBlock(ulong[] block, ulong[] outWords)
+ {
+ ulong[] kw = this.kw;
+ ulong[] t = this.t;
+ int[] mod5 = MOD5;
+ int[] mod3 = MOD3;
+
+ /* Help the JIT avoid index bounds checks */
+ if (kw.Length != 9)
+ {
+ throw new ArgumentException();
+ }
+ if (t.Length != 5)
+ {
+ throw new ArgumentException();
+ }
+
+ /*
+ * Read 4 words of plaintext data, not using arrays for cipher state
+ */
+ ulong b0 = block[0];
+ ulong b1 = block[1];
+ ulong b2 = block[2];
+ ulong b3 = block[3];
+
+ /*
+ * First subkey injection.
+ */
+ b0 += kw[0];
+ b1 += kw[1] + t[0];
+ b2 += kw[2] + t[1];
+ b3 += kw[3];
+
+ /*
+ * Rounds loop, unrolled to 8 rounds per iteration.
+ *
+ * Unrolling to multiples of 4 avoids the mod 4 check for key injection, and allows
+ * inlining of the permutations, which cycle every of 2 rounds (avoiding array
+ * index/lookup).
+ *
+ * Unrolling to multiples of 8 avoids the mod 8 rotation constant lookup, and allows
+ * inlining constant rotation values (avoiding array index/lookup).
+ */
+
+ for (int d = 1; d < (ROUNDS_256 / 4); d += 2)
+ {
+ int dm5 = mod5[d];
+ int dm3 = mod3[d];
+
+ /*
+ * 4 rounds of mix and permute.
+ *
+ * Permute schedule has a 2 round cycle, so permutes are inlined in the mix
+ * operations in each 4 round block.
+ */
+ b1 = RotlXor(b1, ROTATION_0_0, b0 += b1);
+ b3 = RotlXor(b3, ROTATION_0_1, b2 += b3);
+
+ b3 = RotlXor(b3, ROTATION_1_0, b0 += b3);
+ b1 = RotlXor(b1, ROTATION_1_1, b2 += b1);
+
+ b1 = RotlXor(b1, ROTATION_2_0, b0 += b1);
+ b3 = RotlXor(b3, ROTATION_2_1, b2 += b3);
+
+ b3 = RotlXor(b3, ROTATION_3_0, b0 += b3);
+ b1 = RotlXor(b1, ROTATION_3_1, b2 += b1);
+
+ /*
+ * Subkey injection for first 4 rounds.
+ */
+ b0 += kw[dm5];
+ b1 += kw[dm5 + 1] + t[dm3];
+ b2 += kw[dm5 + 2] + t[dm3 + 1];
+ b3 += kw[dm5 + 3] + (uint)d;
+
+ /*
+ * 4 more rounds of mix/permute
+ */
+ b1 = RotlXor(b1, ROTATION_4_0, b0 += b1);
+ b3 = RotlXor(b3, ROTATION_4_1, b2 += b3);
+
+ b3 = RotlXor(b3, ROTATION_5_0, b0 += b3);
+ b1 = RotlXor(b1, ROTATION_5_1, b2 += b1);
+
+ b1 = RotlXor(b1, ROTATION_6_0, b0 += b1);
+ b3 = RotlXor(b3, ROTATION_6_1, b2 += b3);
+
+ b3 = RotlXor(b3, ROTATION_7_0, b0 += b3);
+ b1 = RotlXor(b1, ROTATION_7_1, b2 += b1);
+
+ /*
+ * Subkey injection for next 4 rounds.
+ */
+ b0 += kw[dm5 + 1];
+ b1 += kw[dm5 + 2] + t[dm3 + 1];
+ b2 += kw[dm5 + 3] + t[dm3 + 2];
+ b3 += kw[dm5 + 4] + (uint)d + 1;
+ }
+
+ /*
+ * Output cipher state.
+ */
+ outWords[0] = b0;
+ outWords[1] = b1;
+ outWords[2] = b2;
+ outWords[3] = b3;
+ }
+
+ internal override void DecryptBlock(ulong[] block, ulong[] state)
+ {
+ ulong[] kw = this.kw;
+ ulong[] t = this.t;
+ int[] mod5 = MOD5;
+ int[] mod3 = MOD3;
+
+ /* Help the JIT avoid index bounds checks */
+ if (kw.Length != 9)
+ {
+ throw new ArgumentException();
+ }
+ if (t.Length != 5)
+ {
+ throw new ArgumentException();
+ }
+
+ ulong b0 = block[0];
+ ulong b1 = block[1];
+ ulong b2 = block[2];
+ ulong b3 = block[3];
+
+ for (int d = (ROUNDS_256 / 4) - 1; d >= 1; d -= 2)
+ {
+ int dm5 = mod5[d];
+ int dm3 = mod3[d];
+
+ /* Reverse key injection for second 4 rounds */
+ b0 -= kw[dm5 + 1];
+ b1 -= kw[dm5 + 2] + t[dm3 + 1];
+ b2 -= kw[dm5 + 3] + t[dm3 + 2];
+ b3 -= kw[dm5 + 4] + (uint)d + 1;
+
+ /* Reverse second 4 mix/permute rounds */
+
+ b3 = XorRotr(b3, ROTATION_7_0, b0);
+ b0 -= b3;
+ b1 = XorRotr(b1, ROTATION_7_1, b2);
+ b2 -= b1;
+
+ b1 = XorRotr(b1, ROTATION_6_0, b0);
+ b0 -= b1;
+ b3 = XorRotr(b3, ROTATION_6_1, b2);
+ b2 -= b3;
+
+ b3 = XorRotr(b3, ROTATION_5_0, b0);
+ b0 -= b3;
+ b1 = XorRotr(b1, ROTATION_5_1, b2);
+ b2 -= b1;
+
+ b1 = XorRotr(b1, ROTATION_4_0, b0);
+ b0 -= b1;
+ b3 = XorRotr(b3, ROTATION_4_1, b2);
+ b2 -= b3;
+
+ /* Reverse key injection for first 4 rounds */
+ b0 -= kw[dm5];
+ b1 -= kw[dm5 + 1] + t[dm3];
+ b2 -= kw[dm5 + 2] + t[dm3 + 1];
+ b3 -= kw[dm5 + 3] + (uint)d;
+
+ /* Reverse first 4 mix/permute rounds */
+ b3 = XorRotr(b3, ROTATION_3_0, b0);
+ b0 -= b3;
+ b1 = XorRotr(b1, ROTATION_3_1, b2);
+ b2 -= b1;
+
+ b1 = XorRotr(b1, ROTATION_2_0, b0);
+ b0 -= b1;
+ b3 = XorRotr(b3, ROTATION_2_1, b2);
+ b2 -= b3;
+
+ b3 = XorRotr(b3, ROTATION_1_0, b0);
+ b0 -= b3;
+ b1 = XorRotr(b1, ROTATION_1_1, b2);
+ b2 -= b1;
+
+ b1 = XorRotr(b1, ROTATION_0_0, b0);
+ b0 -= b1;
+ b3 = XorRotr(b3, ROTATION_0_1, b2);
+ b2 -= b3;
+ }
+
+ /*
+ * First subkey uninjection.
+ */
+ b0 -= kw[0];
+ b1 -= kw[1] + t[0];
+ b2 -= kw[2] + t[1];
+ b3 -= kw[3];
+
+ /*
+ * Output cipher state.
+ */
+ state[0] = b0;
+ state[1] = b1;
+ state[2] = b2;
+ state[3] = b3;
+ }
+
+ }
+
+ private sealed class Threefish512Cipher
+ : ThreefishCipher
+ {
+ /**
+ * Mix rotation constants defined in Skein 1.3 specification
+ */
+ private const int ROTATION_0_0 = 46, ROTATION_0_1 = 36, ROTATION_0_2 = 19, ROTATION_0_3 = 37;
+ private const int ROTATION_1_0 = 33, ROTATION_1_1 = 27, ROTATION_1_2 = 14, ROTATION_1_3 = 42;
+ private const int ROTATION_2_0 = 17, ROTATION_2_1 = 49, ROTATION_2_2 = 36, ROTATION_2_3 = 39;
+ private const int ROTATION_3_0 = 44, ROTATION_3_1 = 9, ROTATION_3_2 = 54, ROTATION_3_3 = 56;
+
+ private const int ROTATION_4_0 = 39, ROTATION_4_1 = 30, ROTATION_4_2 = 34, ROTATION_4_3 = 24;
+ private const int ROTATION_5_0 = 13, ROTATION_5_1 = 50, ROTATION_5_2 = 10, ROTATION_5_3 = 17;
+ private const int ROTATION_6_0 = 25, ROTATION_6_1 = 29, ROTATION_6_2 = 39, ROTATION_6_3 = 43;
+ private const int ROTATION_7_0 = 8, ROTATION_7_1 = 35, ROTATION_7_2 = 56, ROTATION_7_3 = 22;
+
+ internal Threefish512Cipher(ulong[] kw, ulong[] t)
+ : base(kw, t)
+ {
+ }
+
+ internal override void EncryptBlock(ulong[] block, ulong[] outWords)
+ {
+ ulong[] kw = this.kw;
+ ulong[] t = this.t;
+ int[] mod9 = MOD9;
+ int[] mod3 = MOD3;
+
+ /* Help the JIT avoid index bounds checks */
+ if (kw.Length != 17)
+ {
+ throw new ArgumentException();
+ }
+ if (t.Length != 5)
+ {
+ throw new ArgumentException();
+ }
+
+ /*
+ * Read 8 words of plaintext data, not using arrays for cipher state
+ */
+ ulong b0 = block[0];
+ ulong b1 = block[1];
+ ulong b2 = block[2];
+ ulong b3 = block[3];
+ ulong b4 = block[4];
+ ulong b5 = block[5];
+ ulong b6 = block[6];
+ ulong b7 = block[7];
+
+ /*
+ * First subkey injection.
+ */
+ b0 += kw[0];
+ b1 += kw[1];
+ b2 += kw[2];
+ b3 += kw[3];
+ b4 += kw[4];
+ b5 += kw[5] + t[0];
+ b6 += kw[6] + t[1];
+ b7 += kw[7];
+
+ /*
+ * Rounds loop, unrolled to 8 rounds per iteration.
+ *
+ * Unrolling to multiples of 4 avoids the mod 4 check for key injection, and allows
+ * inlining of the permutations, which cycle every of 4 rounds (avoiding array
+ * index/lookup).
+ *
+ * Unrolling to multiples of 8 avoids the mod 8 rotation constant lookup, and allows
+ * inlining constant rotation values (avoiding array index/lookup).
+ */
+
+ for (int d = 1; d < (ROUNDS_512 / 4); d += 2)
+ {
+ int dm9 = mod9[d];
+ int dm3 = mod3[d];
+
+ /*
+ * 4 rounds of mix and permute.
+ *
+ * Permute schedule has a 4 round cycle, so permutes are inlined in the mix
+ * operations in each 4 round block.
+ */
+ b1 = RotlXor(b1, ROTATION_0_0, b0 += b1);
+ b3 = RotlXor(b3, ROTATION_0_1, b2 += b3);
+ b5 = RotlXor(b5, ROTATION_0_2, b4 += b5);
+ b7 = RotlXor(b7, ROTATION_0_3, b6 += b7);
+
+ b1 = RotlXor(b1, ROTATION_1_0, b2 += b1);
+ b7 = RotlXor(b7, ROTATION_1_1, b4 += b7);
+ b5 = RotlXor(b5, ROTATION_1_2, b6 += b5);
+ b3 = RotlXor(b3, ROTATION_1_3, b0 += b3);
+
+ b1 = RotlXor(b1, ROTATION_2_0, b4 += b1);
+ b3 = RotlXor(b3, ROTATION_2_1, b6 += b3);
+ b5 = RotlXor(b5, ROTATION_2_2, b0 += b5);
+ b7 = RotlXor(b7, ROTATION_2_3, b2 += b7);
+
+ b1 = RotlXor(b1, ROTATION_3_0, b6 += b1);
+ b7 = RotlXor(b7, ROTATION_3_1, b0 += b7);
+ b5 = RotlXor(b5, ROTATION_3_2, b2 += b5);
+ b3 = RotlXor(b3, ROTATION_3_3, b4 += b3);
+
+ /*
+ * Subkey injection for first 4 rounds.
+ */
+ b0 += kw[dm9];
+ b1 += kw[dm9 + 1];
+ b2 += kw[dm9 + 2];
+ b3 += kw[dm9 + 3];
+ b4 += kw[dm9 + 4];
+ b5 += kw[dm9 + 5] + t[dm3];
+ b6 += kw[dm9 + 6] + t[dm3 + 1];
+ b7 += kw[dm9 + 7] + (uint)d;
+
+ /*
+ * 4 more rounds of mix/permute
+ */
+ b1 = RotlXor(b1, ROTATION_4_0, b0 += b1);
+ b3 = RotlXor(b3, ROTATION_4_1, b2 += b3);
+ b5 = RotlXor(b5, ROTATION_4_2, b4 += b5);
+ b7 = RotlXor(b7, ROTATION_4_3, b6 += b7);
+
+ b1 = RotlXor(b1, ROTATION_5_0, b2 += b1);
+ b7 = RotlXor(b7, ROTATION_5_1, b4 += b7);
+ b5 = RotlXor(b5, ROTATION_5_2, b6 += b5);
+ b3 = RotlXor(b3, ROTATION_5_3, b0 += b3);
+
+ b1 = RotlXor(b1, ROTATION_6_0, b4 += b1);
+ b3 = RotlXor(b3, ROTATION_6_1, b6 += b3);
+ b5 = RotlXor(b5, ROTATION_6_2, b0 += b5);
+ b7 = RotlXor(b7, ROTATION_6_3, b2 += b7);
+
+ b1 = RotlXor(b1, ROTATION_7_0, b6 += b1);
+ b7 = RotlXor(b7, ROTATION_7_1, b0 += b7);
+ b5 = RotlXor(b5, ROTATION_7_2, b2 += b5);
+ b3 = RotlXor(b3, ROTATION_7_3, b4 += b3);
+
+ /*
+ * Subkey injection for next 4 rounds.
+ */
+ b0 += kw[dm9 + 1];
+ b1 += kw[dm9 + 2];
+ b2 += kw[dm9 + 3];
+ b3 += kw[dm9 + 4];
+ b4 += kw[dm9 + 5];
+ b5 += kw[dm9 + 6] + t[dm3 + 1];
+ b6 += kw[dm9 + 7] + t[dm3 + 2];
+ b7 += kw[dm9 + 8] + (uint)d + 1;
+ }
+
+ /*
+ * Output cipher state.
+ */
+ outWords[0] = b0;
+ outWords[1] = b1;
+ outWords[2] = b2;
+ outWords[3] = b3;
+ outWords[4] = b4;
+ outWords[5] = b5;
+ outWords[6] = b6;
+ outWords[7] = b7;
+ }
+
+ internal override void DecryptBlock(ulong[] block, ulong[] state)
+ {
+ ulong[] kw = this.kw;
+ ulong[] t = this.t;
+ int[] mod9 = MOD9;
+ int[] mod3 = MOD3;
+
+ /* Help the JIT avoid index bounds checks */
+ if (kw.Length != 17)
+ {
+ throw new ArgumentException();
+ }
+ if (t.Length != 5)
+ {
+ throw new ArgumentException();
+ }
+
+ ulong b0 = block[0];
+ ulong b1 = block[1];
+ ulong b2 = block[2];
+ ulong b3 = block[3];
+ ulong b4 = block[4];
+ ulong b5 = block[5];
+ ulong b6 = block[6];
+ ulong b7 = block[7];
+
+ for (int d = (ROUNDS_512 / 4) - 1; d >= 1; d -= 2)
+ {
+ int dm9 = mod9[d];
+ int dm3 = mod3[d];
+
+ /* Reverse key injection for second 4 rounds */
+ b0 -= kw[dm9 + 1];
+ b1 -= kw[dm9 + 2];
+ b2 -= kw[dm9 + 3];
+ b3 -= kw[dm9 + 4];
+ b4 -= kw[dm9 + 5];
+ b5 -= kw[dm9 + 6] + t[dm3 + 1];
+ b6 -= kw[dm9 + 7] + t[dm3 + 2];
+ b7 -= kw[dm9 + 8] + (uint)d + 1;
+
+ /* Reverse second 4 mix/permute rounds */
+
+ b1 = XorRotr(b1, ROTATION_7_0, b6);
+ b6 -= b1;
+ b7 = XorRotr(b7, ROTATION_7_1, b0);
+ b0 -= b7;
+ b5 = XorRotr(b5, ROTATION_7_2, b2);
+ b2 -= b5;
+ b3 = XorRotr(b3, ROTATION_7_3, b4);
+ b4 -= b3;
+
+ b1 = XorRotr(b1, ROTATION_6_0, b4);
+ b4 -= b1;
+ b3 = XorRotr(b3, ROTATION_6_1, b6);
+ b6 -= b3;
+ b5 = XorRotr(b5, ROTATION_6_2, b0);
+ b0 -= b5;
+ b7 = XorRotr(b7, ROTATION_6_3, b2);
+ b2 -= b7;
+
+ b1 = XorRotr(b1, ROTATION_5_0, b2);
+ b2 -= b1;
+ b7 = XorRotr(b7, ROTATION_5_1, b4);
+ b4 -= b7;
+ b5 = XorRotr(b5, ROTATION_5_2, b6);
+ b6 -= b5;
+ b3 = XorRotr(b3, ROTATION_5_3, b0);
+ b0 -= b3;
+
+ b1 = XorRotr(b1, ROTATION_4_0, b0);
+ b0 -= b1;
+ b3 = XorRotr(b3, ROTATION_4_1, b2);
+ b2 -= b3;
+ b5 = XorRotr(b5, ROTATION_4_2, b4);
+ b4 -= b5;
+ b7 = XorRotr(b7, ROTATION_4_3, b6);
+ b6 -= b7;
+
+ /* Reverse key injection for first 4 rounds */
+ b0 -= kw[dm9];
+ b1 -= kw[dm9 + 1];
+ b2 -= kw[dm9 + 2];
+ b3 -= kw[dm9 + 3];
+ b4 -= kw[dm9 + 4];
+ b5 -= kw[dm9 + 5] + t[dm3];
+ b6 -= kw[dm9 + 6] + t[dm3 + 1];
+ b7 -= kw[dm9 + 7] + (uint)d;
+
+ /* Reverse first 4 mix/permute rounds */
+ b1 = XorRotr(b1, ROTATION_3_0, b6);
+ b6 -= b1;
+ b7 = XorRotr(b7, ROTATION_3_1, b0);
+ b0 -= b7;
+ b5 = XorRotr(b5, ROTATION_3_2, b2);
+ b2 -= b5;
+ b3 = XorRotr(b3, ROTATION_3_3, b4);
+ b4 -= b3;
+
+ b1 = XorRotr(b1, ROTATION_2_0, b4);
+ b4 -= b1;
+ b3 = XorRotr(b3, ROTATION_2_1, b6);
+ b6 -= b3;
+ b5 = XorRotr(b5, ROTATION_2_2, b0);
+ b0 -= b5;
+ b7 = XorRotr(b7, ROTATION_2_3, b2);
+ b2 -= b7;
+
+ b1 = XorRotr(b1, ROTATION_1_0, b2);
+ b2 -= b1;
+ b7 = XorRotr(b7, ROTATION_1_1, b4);
+ b4 -= b7;
+ b5 = XorRotr(b5, ROTATION_1_2, b6);
+ b6 -= b5;
+ b3 = XorRotr(b3, ROTATION_1_3, b0);
+ b0 -= b3;
+
+ b1 = XorRotr(b1, ROTATION_0_0, b0);
+ b0 -= b1;
+ b3 = XorRotr(b3, ROTATION_0_1, b2);
+ b2 -= b3;
+ b5 = XorRotr(b5, ROTATION_0_2, b4);
+ b4 -= b5;
+ b7 = XorRotr(b7, ROTATION_0_3, b6);
+ b6 -= b7;
+ }
+
+ /*
+ * First subkey uninjection.
+ */
+ b0 -= kw[0];
+ b1 -= kw[1];
+ b2 -= kw[2];
+ b3 -= kw[3];
+ b4 -= kw[4];
+ b5 -= kw[5] + t[0];
+ b6 -= kw[6] + t[1];
+ b7 -= kw[7];
+
+ /*
+ * Output cipher state.
+ */
+ state[0] = b0;
+ state[1] = b1;
+ state[2] = b2;
+ state[3] = b3;
+ state[4] = b4;
+ state[5] = b5;
+ state[6] = b6;
+ state[7] = b7;
+ }
+ }
+
+ private sealed class Threefish1024Cipher
+ : ThreefishCipher
+ {
+ /**
+ * Mix rotation constants defined in Skein 1.3 specification
+ */
+ private const int ROTATION_0_0 = 24, ROTATION_0_1 = 13, ROTATION_0_2 = 8, ROTATION_0_3 = 47;
+ private const int ROTATION_0_4 = 8, ROTATION_0_5 = 17, ROTATION_0_6 = 22, ROTATION_0_7 = 37;
+ private const int ROTATION_1_0 = 38, ROTATION_1_1 = 19, ROTATION_1_2 = 10, ROTATION_1_3 = 55;
+ private const int ROTATION_1_4 = 49, ROTATION_1_5 = 18, ROTATION_1_6 = 23, ROTATION_1_7 = 52;
+ private const int ROTATION_2_0 = 33, ROTATION_2_1 = 4, ROTATION_2_2 = 51, ROTATION_2_3 = 13;
+ private const int ROTATION_2_4 = 34, ROTATION_2_5 = 41, ROTATION_2_6 = 59, ROTATION_2_7 = 17;
+ private const int ROTATION_3_0 = 5, ROTATION_3_1 = 20, ROTATION_3_2 = 48, ROTATION_3_3 = 41;
+ private const int ROTATION_3_4 = 47, ROTATION_3_5 = 28, ROTATION_3_6 = 16, ROTATION_3_7 = 25;
+
+ private const int ROTATION_4_0 = 41, ROTATION_4_1 = 9, ROTATION_4_2 = 37, ROTATION_4_3 = 31;
+ private const int ROTATION_4_4 = 12, ROTATION_4_5 = 47, ROTATION_4_6 = 44, ROTATION_4_7 = 30;
+ private const int ROTATION_5_0 = 16, ROTATION_5_1 = 34, ROTATION_5_2 = 56, ROTATION_5_3 = 51;
+ private const int ROTATION_5_4 = 4, ROTATION_5_5 = 53, ROTATION_5_6 = 42, ROTATION_5_7 = 41;
+ private const int ROTATION_6_0 = 31, ROTATION_6_1 = 44, ROTATION_6_2 = 47, ROTATION_6_3 = 46;
+ private const int ROTATION_6_4 = 19, ROTATION_6_5 = 42, ROTATION_6_6 = 44, ROTATION_6_7 = 25;
+ private const int ROTATION_7_0 = 9, ROTATION_7_1 = 48, ROTATION_7_2 = 35, ROTATION_7_3 = 52;
+ private const int ROTATION_7_4 = 23, ROTATION_7_5 = 31, ROTATION_7_6 = 37, ROTATION_7_7 = 20;
+
+ public Threefish1024Cipher(ulong[] kw, ulong[] t)
+ : base(kw, t)
+ {
+ }
+
+ internal override void EncryptBlock(ulong[] block, ulong[] outWords)
+ {
+ ulong[] kw = this.kw;
+ ulong[] t = this.t;
+ int[] mod17 = MOD17;
+ int[] mod3 = MOD3;
+
+ /* Help the JIT avoid index bounds checks */
+ if (kw.Length != 33)
+ {
+ throw new ArgumentException();
+ }
+ if (t.Length != 5)
+ {
+ throw new ArgumentException();
+ }
+
+ /*
+ * Read 16 words of plaintext data, not using arrays for cipher state
+ */
+ ulong b0 = block[0];
+ ulong b1 = block[1];
+ ulong b2 = block[2];
+ ulong b3 = block[3];
+ ulong b4 = block[4];
+ ulong b5 = block[5];
+ ulong b6 = block[6];
+ ulong b7 = block[7];
+ ulong b8 = block[8];
+ ulong b9 = block[9];
+ ulong b10 = block[10];
+ ulong b11 = block[11];
+ ulong b12 = block[12];
+ ulong b13 = block[13];
+ ulong b14 = block[14];
+ ulong b15 = block[15];
+
+ /*
+ * First subkey injection.
+ */
+ b0 += kw[0];
+ b1 += kw[1];
+ b2 += kw[2];
+ b3 += kw[3];
+ b4 += kw[4];
+ b5 += kw[5];
+ b6 += kw[6];
+ b7 += kw[7];
+ b8 += kw[8];
+ b9 += kw[9];
+ b10 += kw[10];
+ b11 += kw[11];
+ b12 += kw[12];
+ b13 += kw[13] + t[0];
+ b14 += kw[14] + t[1];
+ b15 += kw[15];
+
+ /*
+ * Rounds loop, unrolled to 8 rounds per iteration.
+ *
+ * Unrolling to multiples of 4 avoids the mod 4 check for key injection, and allows
+ * inlining of the permutations, which cycle every of 4 rounds (avoiding array
+ * index/lookup).
+ *
+ * Unrolling to multiples of 8 avoids the mod 8 rotation constant lookup, and allows
+ * inlining constant rotation values (avoiding array index/lookup).
+ */
+
+ for (int d = 1; d < (ROUNDS_1024 / 4); d += 2)
+ {
+ int dm17 = mod17[d];
+ int dm3 = mod3[d];
+
+ /*
+ * 4 rounds of mix and permute.
+ *
+ * Permute schedule has a 4 round cycle, so permutes are inlined in the mix
+ * operations in each 4 round block.
+ */
+ b1 = RotlXor(b1, ROTATION_0_0, b0 += b1);
+ b3 = RotlXor(b3, ROTATION_0_1, b2 += b3);
+ b5 = RotlXor(b5, ROTATION_0_2, b4 += b5);
+ b7 = RotlXor(b7, ROTATION_0_3, b6 += b7);
+ b9 = RotlXor(b9, ROTATION_0_4, b8 += b9);
+ b11 = RotlXor(b11, ROTATION_0_5, b10 += b11);
+ b13 = RotlXor(b13, ROTATION_0_6, b12 += b13);
+ b15 = RotlXor(b15, ROTATION_0_7, b14 += b15);
+
+ b9 = RotlXor(b9, ROTATION_1_0, b0 += b9);
+ b13 = RotlXor(b13, ROTATION_1_1, b2 += b13);
+ b11 = RotlXor(b11, ROTATION_1_2, b6 += b11);
+ b15 = RotlXor(b15, ROTATION_1_3, b4 += b15);
+ b7 = RotlXor(b7, ROTATION_1_4, b10 += b7);
+ b3 = RotlXor(b3, ROTATION_1_5, b12 += b3);
+ b5 = RotlXor(b5, ROTATION_1_6, b14 += b5);
+ b1 = RotlXor(b1, ROTATION_1_7, b8 += b1);
+
+ b7 = RotlXor(b7, ROTATION_2_0, b0 += b7);
+ b5 = RotlXor(b5, ROTATION_2_1, b2 += b5);
+ b3 = RotlXor(b3, ROTATION_2_2, b4 += b3);
+ b1 = RotlXor(b1, ROTATION_2_3, b6 += b1);
+ b15 = RotlXor(b15, ROTATION_2_4, b12 += b15);
+ b13 = RotlXor(b13, ROTATION_2_5, b14 += b13);
+ b11 = RotlXor(b11, ROTATION_2_6, b8 += b11);
+ b9 = RotlXor(b9, ROTATION_2_7, b10 += b9);
+
+ b15 = RotlXor(b15, ROTATION_3_0, b0 += b15);
+ b11 = RotlXor(b11, ROTATION_3_1, b2 += b11);
+ b13 = RotlXor(b13, ROTATION_3_2, b6 += b13);
+ b9 = RotlXor(b9, ROTATION_3_3, b4 += b9);
+ b1 = RotlXor(b1, ROTATION_3_4, b14 += b1);
+ b5 = RotlXor(b5, ROTATION_3_5, b8 += b5);
+ b3 = RotlXor(b3, ROTATION_3_6, b10 += b3);
+ b7 = RotlXor(b7, ROTATION_3_7, b12 += b7);
+
+ /*
+ * Subkey injection for first 4 rounds.
+ */
+ b0 += kw[dm17];
+ b1 += kw[dm17 + 1];
+ b2 += kw[dm17 + 2];
+ b3 += kw[dm17 + 3];
+ b4 += kw[dm17 + 4];
+ b5 += kw[dm17 + 5];
+ b6 += kw[dm17 + 6];
+ b7 += kw[dm17 + 7];
+ b8 += kw[dm17 + 8];
+ b9 += kw[dm17 + 9];
+ b10 += kw[dm17 + 10];
+ b11 += kw[dm17 + 11];
+ b12 += kw[dm17 + 12];
+ b13 += kw[dm17 + 13] + t[dm3];
+ b14 += kw[dm17 + 14] + t[dm3 + 1];
+ b15 += kw[dm17 + 15] + (uint)d;
+
+ /*
+ * 4 more rounds of mix/permute
+ */
+ b1 = RotlXor(b1, ROTATION_4_0, b0 += b1);
+ b3 = RotlXor(b3, ROTATION_4_1, b2 += b3);
+ b5 = RotlXor(b5, ROTATION_4_2, b4 += b5);
+ b7 = RotlXor(b7, ROTATION_4_3, b6 += b7);
+ b9 = RotlXor(b9, ROTATION_4_4, b8 += b9);
+ b11 = RotlXor(b11, ROTATION_4_5, b10 += b11);
+ b13 = RotlXor(b13, ROTATION_4_6, b12 += b13);
+ b15 = RotlXor(b15, ROTATION_4_7, b14 += b15);
+
+ b9 = RotlXor(b9, ROTATION_5_0, b0 += b9);
+ b13 = RotlXor(b13, ROTATION_5_1, b2 += b13);
+ b11 = RotlXor(b11, ROTATION_5_2, b6 += b11);
+ b15 = RotlXor(b15, ROTATION_5_3, b4 += b15);
+ b7 = RotlXor(b7, ROTATION_5_4, b10 += b7);
+ b3 = RotlXor(b3, ROTATION_5_5, b12 += b3);
+ b5 = RotlXor(b5, ROTATION_5_6, b14 += b5);
+ b1 = RotlXor(b1, ROTATION_5_7, b8 += b1);
+
+ b7 = RotlXor(b7, ROTATION_6_0, b0 += b7);
+ b5 = RotlXor(b5, ROTATION_6_1, b2 += b5);
+ b3 = RotlXor(b3, ROTATION_6_2, b4 += b3);
+ b1 = RotlXor(b1, ROTATION_6_3, b6 += b1);
+ b15 = RotlXor(b15, ROTATION_6_4, b12 += b15);
+ b13 = RotlXor(b13, ROTATION_6_5, b14 += b13);
+ b11 = RotlXor(b11, ROTATION_6_6, b8 += b11);
+ b9 = RotlXor(b9, ROTATION_6_7, b10 += b9);
+
+ b15 = RotlXor(b15, ROTATION_7_0, b0 += b15);
+ b11 = RotlXor(b11, ROTATION_7_1, b2 += b11);
+ b13 = RotlXor(b13, ROTATION_7_2, b6 += b13);
+ b9 = RotlXor(b9, ROTATION_7_3, b4 += b9);
+ b1 = RotlXor(b1, ROTATION_7_4, b14 += b1);
+ b5 = RotlXor(b5, ROTATION_7_5, b8 += b5);
+ b3 = RotlXor(b3, ROTATION_7_6, b10 += b3);
+ b7 = RotlXor(b7, ROTATION_7_7, b12 += b7);
+
+ /*
+ * Subkey injection for next 4 rounds.
+ */
+ b0 += kw[dm17 + 1];
+ b1 += kw[dm17 + 2];
+ b2 += kw[dm17 + 3];
+ b3 += kw[dm17 + 4];
+ b4 += kw[dm17 + 5];
+ b5 += kw[dm17 + 6];
+ b6 += kw[dm17 + 7];
+ b7 += kw[dm17 + 8];
+ b8 += kw[dm17 + 9];
+ b9 += kw[dm17 + 10];
+ b10 += kw[dm17 + 11];
+ b11 += kw[dm17 + 12];
+ b12 += kw[dm17 + 13];
+ b13 += kw[dm17 + 14] + t[dm3 + 1];
+ b14 += kw[dm17 + 15] + t[dm3 + 2];
+ b15 += kw[dm17 + 16] + (uint)d + 1;
+
+ }
+
+ /*
+ * Output cipher state.
+ */
+ outWords[0] = b0;
+ outWords[1] = b1;
+ outWords[2] = b2;
+ outWords[3] = b3;
+ outWords[4] = b4;
+ outWords[5] = b5;
+ outWords[6] = b6;
+ outWords[7] = b7;
+ outWords[8] = b8;
+ outWords[9] = b9;
+ outWords[10] = b10;
+ outWords[11] = b11;
+ outWords[12] = b12;
+ outWords[13] = b13;
+ outWords[14] = b14;
+ outWords[15] = b15;
+ }
+
+ internal override void DecryptBlock(ulong[] block, ulong[] state)
+ {
+ ulong[] kw = this.kw;
+ ulong[] t = this.t;
+ int[] mod17 = MOD17;
+ int[] mod3 = MOD3;
+
+ /* Help the JIT avoid index bounds checks */
+ if (kw.Length != 33)
+ {
+ throw new ArgumentException();
+ }
+ if (t.Length != 5)
+ {
+ throw new ArgumentException();
+ }
+
+ ulong b0 = block[0];
+ ulong b1 = block[1];
+ ulong b2 = block[2];
+ ulong b3 = block[3];
+ ulong b4 = block[4];
+ ulong b5 = block[5];
+ ulong b6 = block[6];
+ ulong b7 = block[7];
+ ulong b8 = block[8];
+ ulong b9 = block[9];
+ ulong b10 = block[10];
+ ulong b11 = block[11];
+ ulong b12 = block[12];
+ ulong b13 = block[13];
+ ulong b14 = block[14];
+ ulong b15 = block[15];
+
+ for (int d = (ROUNDS_1024 / 4) - 1; d >= 1; d -= 2)
+ {
+ int dm17 = mod17[d];
+ int dm3 = mod3[d];
+
+ /* Reverse key injection for second 4 rounds */
+ b0 -= kw[dm17 + 1];
+ b1 -= kw[dm17 + 2];
+ b2 -= kw[dm17 + 3];
+ b3 -= kw[dm17 + 4];
+ b4 -= kw[dm17 + 5];
+ b5 -= kw[dm17 + 6];
+ b6 -= kw[dm17 + 7];
+ b7 -= kw[dm17 + 8];
+ b8 -= kw[dm17 + 9];
+ b9 -= kw[dm17 + 10];
+ b10 -= kw[dm17 + 11];
+ b11 -= kw[dm17 + 12];
+ b12 -= kw[dm17 + 13];
+ b13 -= kw[dm17 + 14] + t[dm3 + 1];
+ b14 -= kw[dm17 + 15] + t[dm3 + 2];
+ b15 -= kw[dm17 + 16] + (uint)d + 1;
+
+ /* Reverse second 4 mix/permute rounds */
+ b15 = XorRotr(b15, ROTATION_7_0, b0);
+ b0 -= b15;
+ b11 = XorRotr(b11, ROTATION_7_1, b2);
+ b2 -= b11;
+ b13 = XorRotr(b13, ROTATION_7_2, b6);
+ b6 -= b13;
+ b9 = XorRotr(b9, ROTATION_7_3, b4);
+ b4 -= b9;
+ b1 = XorRotr(b1, ROTATION_7_4, b14);
+ b14 -= b1;
+ b5 = XorRotr(b5, ROTATION_7_5, b8);
+ b8 -= b5;
+ b3 = XorRotr(b3, ROTATION_7_6, b10);
+ b10 -= b3;
+ b7 = XorRotr(b7, ROTATION_7_7, b12);
+ b12 -= b7;
+
+ b7 = XorRotr(b7, ROTATION_6_0, b0);
+ b0 -= b7;
+ b5 = XorRotr(b5, ROTATION_6_1, b2);
+ b2 -= b5;
+ b3 = XorRotr(b3, ROTATION_6_2, b4);
+ b4 -= b3;
+ b1 = XorRotr(b1, ROTATION_6_3, b6);
+ b6 -= b1;
+ b15 = XorRotr(b15, ROTATION_6_4, b12);
+ b12 -= b15;
+ b13 = XorRotr(b13, ROTATION_6_5, b14);
+ b14 -= b13;
+ b11 = XorRotr(b11, ROTATION_6_6, b8);
+ b8 -= b11;
+ b9 = XorRotr(b9, ROTATION_6_7, b10);
+ b10 -= b9;
+
+ b9 = XorRotr(b9, ROTATION_5_0, b0);
+ b0 -= b9;
+ b13 = XorRotr(b13, ROTATION_5_1, b2);
+ b2 -= b13;
+ b11 = XorRotr(b11, ROTATION_5_2, b6);
+ b6 -= b11;
+ b15 = XorRotr(b15, ROTATION_5_3, b4);
+ b4 -= b15;
+ b7 = XorRotr(b7, ROTATION_5_4, b10);
+ b10 -= b7;
+ b3 = XorRotr(b3, ROTATION_5_5, b12);
+ b12 -= b3;
+ b5 = XorRotr(b5, ROTATION_5_6, b14);
+ b14 -= b5;
+ b1 = XorRotr(b1, ROTATION_5_7, b8);
+ b8 -= b1;
+
+ b1 = XorRotr(b1, ROTATION_4_0, b0);
+ b0 -= b1;
+ b3 = XorRotr(b3, ROTATION_4_1, b2);
+ b2 -= b3;
+ b5 = XorRotr(b5, ROTATION_4_2, b4);
+ b4 -= b5;
+ b7 = XorRotr(b7, ROTATION_4_3, b6);
+ b6 -= b7;
+ b9 = XorRotr(b9, ROTATION_4_4, b8);
+ b8 -= b9;
+ b11 = XorRotr(b11, ROTATION_4_5, b10);
+ b10 -= b11;
+ b13 = XorRotr(b13, ROTATION_4_6, b12);
+ b12 -= b13;
+ b15 = XorRotr(b15, ROTATION_4_7, b14);
+ b14 -= b15;
+
+ /* Reverse key injection for first 4 rounds */
+ b0 -= kw[dm17];
+ b1 -= kw[dm17 + 1];
+ b2 -= kw[dm17 + 2];
+ b3 -= kw[dm17 + 3];
+ b4 -= kw[dm17 + 4];
+ b5 -= kw[dm17 + 5];
+ b6 -= kw[dm17 + 6];
+ b7 -= kw[dm17 + 7];
+ b8 -= kw[dm17 + 8];
+ b9 -= kw[dm17 + 9];
+ b10 -= kw[dm17 + 10];
+ b11 -= kw[dm17 + 11];
+ b12 -= kw[dm17 + 12];
+ b13 -= kw[dm17 + 13] + t[dm3];
+ b14 -= kw[dm17 + 14] + t[dm3 + 1];
+ b15 -= kw[dm17 + 15] + (uint)d;
+
+ /* Reverse first 4 mix/permute rounds */
+ b15 = XorRotr(b15, ROTATION_3_0, b0);
+ b0 -= b15;
+ b11 = XorRotr(b11, ROTATION_3_1, b2);
+ b2 -= b11;
+ b13 = XorRotr(b13, ROTATION_3_2, b6);
+ b6 -= b13;
+ b9 = XorRotr(b9, ROTATION_3_3, b4);
+ b4 -= b9;
+ b1 = XorRotr(b1, ROTATION_3_4, b14);
+ b14 -= b1;
+ b5 = XorRotr(b5, ROTATION_3_5, b8);
+ b8 -= b5;
+ b3 = XorRotr(b3, ROTATION_3_6, b10);
+ b10 -= b3;
+ b7 = XorRotr(b7, ROTATION_3_7, b12);
+ b12 -= b7;
+
+ b7 = XorRotr(b7, ROTATION_2_0, b0);
+ b0 -= b7;
+ b5 = XorRotr(b5, ROTATION_2_1, b2);
+ b2 -= b5;
+ b3 = XorRotr(b3, ROTATION_2_2, b4);
+ b4 -= b3;
+ b1 = XorRotr(b1, ROTATION_2_3, b6);
+ b6 -= b1;
+ b15 = XorRotr(b15, ROTATION_2_4, b12);
+ b12 -= b15;
+ b13 = XorRotr(b13, ROTATION_2_5, b14);
+ b14 -= b13;
+ b11 = XorRotr(b11, ROTATION_2_6, b8);
+ b8 -= b11;
+ b9 = XorRotr(b9, ROTATION_2_7, b10);
+ b10 -= b9;
+
+ b9 = XorRotr(b9, ROTATION_1_0, b0);
+ b0 -= b9;
+ b13 = XorRotr(b13, ROTATION_1_1, b2);
+ b2 -= b13;
+ b11 = XorRotr(b11, ROTATION_1_2, b6);
+ b6 -= b11;
+ b15 = XorRotr(b15, ROTATION_1_3, b4);
+ b4 -= b15;
+ b7 = XorRotr(b7, ROTATION_1_4, b10);
+ b10 -= b7;
+ b3 = XorRotr(b3, ROTATION_1_5, b12);
+ b12 -= b3;
+ b5 = XorRotr(b5, ROTATION_1_6, b14);
+ b14 -= b5;
+ b1 = XorRotr(b1, ROTATION_1_7, b8);
+ b8 -= b1;
+
+ b1 = XorRotr(b1, ROTATION_0_0, b0);
+ b0 -= b1;
+ b3 = XorRotr(b3, ROTATION_0_1, b2);
+ b2 -= b3;
+ b5 = XorRotr(b5, ROTATION_0_2, b4);
+ b4 -= b5;
+ b7 = XorRotr(b7, ROTATION_0_3, b6);
+ b6 -= b7;
+ b9 = XorRotr(b9, ROTATION_0_4, b8);
+ b8 -= b9;
+ b11 = XorRotr(b11, ROTATION_0_5, b10);
+ b10 -= b11;
+ b13 = XorRotr(b13, ROTATION_0_6, b12);
+ b12 -= b13;
+ b15 = XorRotr(b15, ROTATION_0_7, b14);
+ b14 -= b15;
+ }
+
+ /*
+ * First subkey uninjection.
+ */
+ b0 -= kw[0];
+ b1 -= kw[1];
+ b2 -= kw[2];
+ b3 -= kw[3];
+ b4 -= kw[4];
+ b5 -= kw[5];
+ b6 -= kw[6];
+ b7 -= kw[7];
+ b8 -= kw[8];
+ b9 -= kw[9];
+ b10 -= kw[10];
+ b11 -= kw[11];
+ b12 -= kw[12];
+ b13 -= kw[13] + t[0];
+ b14 -= kw[14] + t[1];
+ b15 -= kw[15];
+
+ /*
+ * Output cipher state.
+ */
+ state[0] = b0;
+ state[1] = b1;
+ state[2] = b2;
+ state[3] = b3;
+ state[4] = b4;
+ state[5] = b5;
+ state[6] = b6;
+ state[7] = b7;
+ state[8] = b8;
+ state[9] = b9;
+ state[10] = b10;
+ state[11] = b11;
+ state[12] = b12;
+ state[13] = b13;
+ state[14] = b14;
+ state[15] = b15;
+ }
+
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/crypto/engines/TnepresEngine.cs b/bc-sharp-crypto/src/crypto/engines/TnepresEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ce687d1e59f7c2457e15e43360412b443f2430ae
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/TnepresEngine.cs
@@ -0,0 +1,299 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * Tnepres is a 128-bit 32-round block cipher with variable key lengths,
+ * including 128, 192 and 256 bit keys conjectured to be at least as
+ * secure as three-key triple-DES.
+ *
+ * Tnepres is based on Serpent which was designed by Ross Anderson, Eli Biham and Lars Knudsen as a
+ * candidate algorithm for the NIST AES Quest. Unfortunately there was an endianness issue
+ * with test vectors in the AES submission and the resulting confusion lead to the Tnepres cipher
+ * as well, which is a byte swapped version of Serpent.
+ *
+ *
+ * For full details see The Serpent home page
+ *
+ */
+ public sealed class TnepresEngine
+ : SerpentEngineBase
+ {
+ public override string AlgorithmName
+ {
+ get { return "Tnepres"; }
+ }
+
+ /**
+ * Expand a user-supplied key material into a session key.
+ *
+ * @param key The user-key bytes (multiples of 4) to use.
+ * @exception ArgumentException
+ */
+ protected override int[] MakeWorkingKey(byte[] key)
+ {
+ //
+ // pad key to 256 bits
+ //
+ int[] kPad = new int[16];
+ int off = 0;
+ int length = 0;
+
+ for (off = key.Length - 4; off > 0; off -= 4)
+ {
+ kPad[length++] = (int)Pack.BE_To_UInt32(key, off);
+ }
+
+ if (off == 0)
+ {
+ kPad[length++] = (int)Pack.BE_To_UInt32(key, 0);
+ if (length < 8)
+ {
+ kPad[length] = 1;
+ }
+ }
+ else
+ {
+ throw new ArgumentException("key must be a multiple of 4 bytes");
+ }
+
+ //
+ // expand the padded key up to 33 x 128 bits of key material
+ //
+ int amount = (ROUNDS + 1) * 4;
+ int[] w = new int[amount];
+
+ //
+ // compute w0 to w7 from w-8 to w-1
+ //
+ for (int i = 8; i < 16; i++)
+ {
+ kPad[i] = RotateLeft(kPad[i - 8] ^ kPad[i - 5] ^ kPad[i - 3] ^ kPad[i - 1] ^ PHI ^ (i - 8), 11);
+ }
+
+ Array.Copy(kPad, 8, w, 0, 8);
+
+ //
+ // compute w8 to w136
+ //
+ for (int i = 8; i < amount; i++)
+ {
+ w[i] = RotateLeft(w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ i, 11);
+ }
+
+ //
+ // create the working keys by processing w with the Sbox and IP
+ //
+ Sb3(w[0], w[1], w[2], w[3]);
+ w[0] = X0; w[1] = X1; w[2] = X2; w[3] = X3;
+ Sb2(w[4], w[5], w[6], w[7]);
+ w[4] = X0; w[5] = X1; w[6] = X2; w[7] = X3;
+ Sb1(w[8], w[9], w[10], w[11]);
+ w[8] = X0; w[9] = X1; w[10] = X2; w[11] = X3;
+ Sb0(w[12], w[13], w[14], w[15]);
+ w[12] = X0; w[13] = X1; w[14] = X2; w[15] = X3;
+ Sb7(w[16], w[17], w[18], w[19]);
+ w[16] = X0; w[17] = X1; w[18] = X2; w[19] = X3;
+ Sb6(w[20], w[21], w[22], w[23]);
+ w[20] = X0; w[21] = X1; w[22] = X2; w[23] = X3;
+ Sb5(w[24], w[25], w[26], w[27]);
+ w[24] = X0; w[25] = X1; w[26] = X2; w[27] = X3;
+ Sb4(w[28], w[29], w[30], w[31]);
+ w[28] = X0; w[29] = X1; w[30] = X2; w[31] = X3;
+ Sb3(w[32], w[33], w[34], w[35]);
+ w[32] = X0; w[33] = X1; w[34] = X2; w[35] = X3;
+ Sb2(w[36], w[37], w[38], w[39]);
+ w[36] = X0; w[37] = X1; w[38] = X2; w[39] = X3;
+ Sb1(w[40], w[41], w[42], w[43]);
+ w[40] = X0; w[41] = X1; w[42] = X2; w[43] = X3;
+ Sb0(w[44], w[45], w[46], w[47]);
+ w[44] = X0; w[45] = X1; w[46] = X2; w[47] = X3;
+ Sb7(w[48], w[49], w[50], w[51]);
+ w[48] = X0; w[49] = X1; w[50] = X2; w[51] = X3;
+ Sb6(w[52], w[53], w[54], w[55]);
+ w[52] = X0; w[53] = X1; w[54] = X2; w[55] = X3;
+ Sb5(w[56], w[57], w[58], w[59]);
+ w[56] = X0; w[57] = X1; w[58] = X2; w[59] = X3;
+ Sb4(w[60], w[61], w[62], w[63]);
+ w[60] = X0; w[61] = X1; w[62] = X2; w[63] = X3;
+ Sb3(w[64], w[65], w[66], w[67]);
+ w[64] = X0; w[65] = X1; w[66] = X2; w[67] = X3;
+ Sb2(w[68], w[69], w[70], w[71]);
+ w[68] = X0; w[69] = X1; w[70] = X2; w[71] = X3;
+ Sb1(w[72], w[73], w[74], w[75]);
+ w[72] = X0; w[73] = X1; w[74] = X2; w[75] = X3;
+ Sb0(w[76], w[77], w[78], w[79]);
+ w[76] = X0; w[77] = X1; w[78] = X2; w[79] = X3;
+ Sb7(w[80], w[81], w[82], w[83]);
+ w[80] = X0; w[81] = X1; w[82] = X2; w[83] = X3;
+ Sb6(w[84], w[85], w[86], w[87]);
+ w[84] = X0; w[85] = X1; w[86] = X2; w[87] = X3;
+ Sb5(w[88], w[89], w[90], w[91]);
+ w[88] = X0; w[89] = X1; w[90] = X2; w[91] = X3;
+ Sb4(w[92], w[93], w[94], w[95]);
+ w[92] = X0; w[93] = X1; w[94] = X2; w[95] = X3;
+ Sb3(w[96], w[97], w[98], w[99]);
+ w[96] = X0; w[97] = X1; w[98] = X2; w[99] = X3;
+ Sb2(w[100], w[101], w[102], w[103]);
+ w[100] = X0; w[101] = X1; w[102] = X2; w[103] = X3;
+ Sb1(w[104], w[105], w[106], w[107]);
+ w[104] = X0; w[105] = X1; w[106] = X2; w[107] = X3;
+ Sb0(w[108], w[109], w[110], w[111]);
+ w[108] = X0; w[109] = X1; w[110] = X2; w[111] = X3;
+ Sb7(w[112], w[113], w[114], w[115]);
+ w[112] = X0; w[113] = X1; w[114] = X2; w[115] = X3;
+ Sb6(w[116], w[117], w[118], w[119]);
+ w[116] = X0; w[117] = X1; w[118] = X2; w[119] = X3;
+ Sb5(w[120], w[121], w[122], w[123]);
+ w[120] = X0; w[121] = X1; w[122] = X2; w[123] = X3;
+ Sb4(w[124], w[125], w[126], w[127]);
+ w[124] = X0; w[125] = X1; w[126] = X2; w[127] = X3;
+ Sb3(w[128], w[129], w[130], w[131]);
+ w[128] = X0; w[129] = X1; w[130] = X2; w[131] = X3;
+
+ 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.
+ */
+ protected override void EncryptBlock(byte[] input, int inOff, byte[] output, int outOff)
+ {
+ X3 = (int)Pack.BE_To_UInt32(input, inOff);
+ X2 = (int)Pack.BE_To_UInt32(input, inOff + 4);
+ X1 = (int)Pack.BE_To_UInt32(input, inOff + 8);
+ X0 = (int)Pack.BE_To_UInt32(input, inOff + 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, outOff);
+ Pack.UInt32_To_BE((uint)(wKey[130] ^ X2), output, outOff + 4);
+ Pack.UInt32_To_BE((uint)(wKey[129] ^ X1), output, outOff + 8);
+ 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);
+ X2 = wKey[130] ^ (int)Pack.BE_To_UInt32(input, inOff + 4);
+ X1 = wKey[129] ^ (int)Pack.BE_To_UInt32(input, inOff + 8);
+ X0 = wKey[128] ^ (int)Pack.BE_To_UInt32(input, inOff + 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, outOff);
+ Pack.UInt32_To_BE((uint)(X2 ^ wKey[2]), output, outOff + 4);
+ Pack.UInt32_To_BE((uint)(X1 ^ wKey[1]), output, outOff + 8);
+ Pack.UInt32_To_BE((uint)(X0 ^ wKey[0]), output, outOff + 12);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/TwofishEngine.cs b/bc-sharp-crypto/src/crypto/engines/TwofishEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..71c24659466eec76d88f4afd14b74b719a5f551f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/TwofishEngine.cs
@@ -0,0 +1,675 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * A class that provides Twofish encryption operations.
+ *
+ * This Java implementation is based on the Java reference
+ * implementation provided by Bruce Schneier and developed
+ * by Raif S. Naffah.
+ */
+ public sealed class TwofishEngine
+ : IBlockCipher
+ {
+ private static readonly byte[,] P = {
+ { // p0
+ (byte) 0xA9, (byte) 0x67, (byte) 0xB3, (byte) 0xE8,
+ (byte) 0x04, (byte) 0xFD, (byte) 0xA3, (byte) 0x76,
+ (byte) 0x9A, (byte) 0x92, (byte) 0x80, (byte) 0x78,
+ (byte) 0xE4, (byte) 0xDD, (byte) 0xD1, (byte) 0x38,
+ (byte) 0x0D, (byte) 0xC6, (byte) 0x35, (byte) 0x98,
+ (byte) 0x18, (byte) 0xF7, (byte) 0xEC, (byte) 0x6C,
+ (byte) 0x43, (byte) 0x75, (byte) 0x37, (byte) 0x26,
+ (byte) 0xFA, (byte) 0x13, (byte) 0x94, (byte) 0x48,
+ (byte) 0xF2, (byte) 0xD0, (byte) 0x8B, (byte) 0x30,
+ (byte) 0x84, (byte) 0x54, (byte) 0xDF, (byte) 0x23,
+ (byte) 0x19, (byte) 0x5B, (byte) 0x3D, (byte) 0x59,
+ (byte) 0xF3, (byte) 0xAE, (byte) 0xA2, (byte) 0x82,
+ (byte) 0x63, (byte) 0x01, (byte) 0x83, (byte) 0x2E,
+ (byte) 0xD9, (byte) 0x51, (byte) 0x9B, (byte) 0x7C,
+ (byte) 0xA6, (byte) 0xEB, (byte) 0xA5, (byte) 0xBE,
+ (byte) 0x16, (byte) 0x0C, (byte) 0xE3, (byte) 0x61,
+ (byte) 0xC0, (byte) 0x8C, (byte) 0x3A, (byte) 0xF5,
+ (byte) 0x73, (byte) 0x2C, (byte) 0x25, (byte) 0x0B,
+ (byte) 0xBB, (byte) 0x4E, (byte) 0x89, (byte) 0x6B,
+ (byte) 0x53, (byte) 0x6A, (byte) 0xB4, (byte) 0xF1,
+ (byte) 0xE1, (byte) 0xE6, (byte) 0xBD, (byte) 0x45,
+ (byte) 0xE2, (byte) 0xF4, (byte) 0xB6, (byte) 0x66,
+ (byte) 0xCC, (byte) 0x95, (byte) 0x03, (byte) 0x56,
+ (byte) 0xD4, (byte) 0x1C, (byte) 0x1E, (byte) 0xD7,
+ (byte) 0xFB, (byte) 0xC3, (byte) 0x8E, (byte) 0xB5,
+ (byte) 0xE9, (byte) 0xCF, (byte) 0xBF, (byte) 0xBA,
+ (byte) 0xEA, (byte) 0x77, (byte) 0x39, (byte) 0xAF,
+ (byte) 0x33, (byte) 0xC9, (byte) 0x62, (byte) 0x71,
+ (byte) 0x81, (byte) 0x79, (byte) 0x09, (byte) 0xAD,
+ (byte) 0x24, (byte) 0xCD, (byte) 0xF9, (byte) 0xD8,
+ (byte) 0xE5, (byte) 0xC5, (byte) 0xB9, (byte) 0x4D,
+ (byte) 0x44, (byte) 0x08, (byte) 0x86, (byte) 0xE7,
+ (byte) 0xA1, (byte) 0x1D, (byte) 0xAA, (byte) 0xED,
+ (byte) 0x06, (byte) 0x70, (byte) 0xB2, (byte) 0xD2,
+ (byte) 0x41, (byte) 0x7B, (byte) 0xA0, (byte) 0x11,
+ (byte) 0x31, (byte) 0xC2, (byte) 0x27, (byte) 0x90,
+ (byte) 0x20, (byte) 0xF6, (byte) 0x60, (byte) 0xFF,
+ (byte) 0x96, (byte) 0x5C, (byte) 0xB1, (byte) 0xAB,
+ (byte) 0x9E, (byte) 0x9C, (byte) 0x52, (byte) 0x1B,
+ (byte) 0x5F, (byte) 0x93, (byte) 0x0A, (byte) 0xEF,
+ (byte) 0x91, (byte) 0x85, (byte) 0x49, (byte) 0xEE,
+ (byte) 0x2D, (byte) 0x4F, (byte) 0x8F, (byte) 0x3B,
+ (byte) 0x47, (byte) 0x87, (byte) 0x6D, (byte) 0x46,
+ (byte) 0xD6, (byte) 0x3E, (byte) 0x69, (byte) 0x64,
+ (byte) 0x2A, (byte) 0xCE, (byte) 0xCB, (byte) 0x2F,
+ (byte) 0xFC, (byte) 0x97, (byte) 0x05, (byte) 0x7A,
+ (byte) 0xAC, (byte) 0x7F, (byte) 0xD5, (byte) 0x1A,
+ (byte) 0x4B, (byte) 0x0E, (byte) 0xA7, (byte) 0x5A,
+ (byte) 0x28, (byte) 0x14, (byte) 0x3F, (byte) 0x29,
+ (byte) 0x88, (byte) 0x3C, (byte) 0x4C, (byte) 0x02,
+ (byte) 0xB8, (byte) 0xDA, (byte) 0xB0, (byte) 0x17,
+ (byte) 0x55, (byte) 0x1F, (byte) 0x8A, (byte) 0x7D,
+ (byte) 0x57, (byte) 0xC7, (byte) 0x8D, (byte) 0x74,
+ (byte) 0xB7, (byte) 0xC4, (byte) 0x9F, (byte) 0x72,
+ (byte) 0x7E, (byte) 0x15, (byte) 0x22, (byte) 0x12,
+ (byte) 0x58, (byte) 0x07, (byte) 0x99, (byte) 0x34,
+ (byte) 0x6E, (byte) 0x50, (byte) 0xDE, (byte) 0x68,
+ (byte) 0x65, (byte) 0xBC, (byte) 0xDB, (byte) 0xF8,
+ (byte) 0xC8, (byte) 0xA8, (byte) 0x2B, (byte) 0x40,
+ (byte) 0xDC, (byte) 0xFE, (byte) 0x32, (byte) 0xA4,
+ (byte) 0xCA, (byte) 0x10, (byte) 0x21, (byte) 0xF0,
+ (byte) 0xD3, (byte) 0x5D, (byte) 0x0F, (byte) 0x00,
+ (byte) 0x6F, (byte) 0x9D, (byte) 0x36, (byte) 0x42,
+ (byte) 0x4A, (byte) 0x5E, (byte) 0xC1, (byte) 0xE0 },
+ { // p1
+ (byte) 0x75, (byte) 0xF3, (byte) 0xC6, (byte) 0xF4,
+ (byte) 0xDB, (byte) 0x7B, (byte) 0xFB, (byte) 0xC8,
+ (byte) 0x4A, (byte) 0xD3, (byte) 0xE6, (byte) 0x6B,
+ (byte) 0x45, (byte) 0x7D, (byte) 0xE8, (byte) 0x4B,
+ (byte) 0xD6, (byte) 0x32, (byte) 0xD8, (byte) 0xFD,
+ (byte) 0x37, (byte) 0x71, (byte) 0xF1, (byte) 0xE1,
+ (byte) 0x30, (byte) 0x0F, (byte) 0xF8, (byte) 0x1B,
+ (byte) 0x87, (byte) 0xFA, (byte) 0x06, (byte) 0x3F,
+ (byte) 0x5E, (byte) 0xBA, (byte) 0xAE, (byte) 0x5B,
+ (byte) 0x8A, (byte) 0x00, (byte) 0xBC, (byte) 0x9D,
+ (byte) 0x6D, (byte) 0xC1, (byte) 0xB1, (byte) 0x0E,
+ (byte) 0x80, (byte) 0x5D, (byte) 0xD2, (byte) 0xD5,
+ (byte) 0xA0, (byte) 0x84, (byte) 0x07, (byte) 0x14,
+ (byte) 0xB5, (byte) 0x90, (byte) 0x2C, (byte) 0xA3,
+ (byte) 0xB2, (byte) 0x73, (byte) 0x4C, (byte) 0x54,
+ (byte) 0x92, (byte) 0x74, (byte) 0x36, (byte) 0x51,
+ (byte) 0x38, (byte) 0xB0, (byte) 0xBD, (byte) 0x5A,
+ (byte) 0xFC, (byte) 0x60, (byte) 0x62, (byte) 0x96,
+ (byte) 0x6C, (byte) 0x42, (byte) 0xF7, (byte) 0x10,
+ (byte) 0x7C, (byte) 0x28, (byte) 0x27, (byte) 0x8C,
+ (byte) 0x13, (byte) 0x95, (byte) 0x9C, (byte) 0xC7,
+ (byte) 0x24, (byte) 0x46, (byte) 0x3B, (byte) 0x70,
+ (byte) 0xCA, (byte) 0xE3, (byte) 0x85, (byte) 0xCB,
+ (byte) 0x11, (byte) 0xD0, (byte) 0x93, (byte) 0xB8,
+ (byte) 0xA6, (byte) 0x83, (byte) 0x20, (byte) 0xFF,
+ (byte) 0x9F, (byte) 0x77, (byte) 0xC3, (byte) 0xCC,
+ (byte) 0x03, (byte) 0x6F, (byte) 0x08, (byte) 0xBF,
+ (byte) 0x40, (byte) 0xE7, (byte) 0x2B, (byte) 0xE2,
+ (byte) 0x79, (byte) 0x0C, (byte) 0xAA, (byte) 0x82,
+ (byte) 0x41, (byte) 0x3A, (byte) 0xEA, (byte) 0xB9,
+ (byte) 0xE4, (byte) 0x9A, (byte) 0xA4, (byte) 0x97,
+ (byte) 0x7E, (byte) 0xDA, (byte) 0x7A, (byte) 0x17,
+ (byte) 0x66, (byte) 0x94, (byte) 0xA1, (byte) 0x1D,
+ (byte) 0x3D, (byte) 0xF0, (byte) 0xDE, (byte) 0xB3,
+ (byte) 0x0B, (byte) 0x72, (byte) 0xA7, (byte) 0x1C,
+ (byte) 0xEF, (byte) 0xD1, (byte) 0x53, (byte) 0x3E,
+ (byte) 0x8F, (byte) 0x33, (byte) 0x26, (byte) 0x5F,
+ (byte) 0xEC, (byte) 0x76, (byte) 0x2A, (byte) 0x49,
+ (byte) 0x81, (byte) 0x88, (byte) 0xEE, (byte) 0x21,
+ (byte) 0xC4, (byte) 0x1A, (byte) 0xEB, (byte) 0xD9,
+ (byte) 0xC5, (byte) 0x39, (byte) 0x99, (byte) 0xCD,
+ (byte) 0xAD, (byte) 0x31, (byte) 0x8B, (byte) 0x01,
+ (byte) 0x18, (byte) 0x23, (byte) 0xDD, (byte) 0x1F,
+ (byte) 0x4E, (byte) 0x2D, (byte) 0xF9, (byte) 0x48,
+ (byte) 0x4F, (byte) 0xF2, (byte) 0x65, (byte) 0x8E,
+ (byte) 0x78, (byte) 0x5C, (byte) 0x58, (byte) 0x19,
+ (byte) 0x8D, (byte) 0xE5, (byte) 0x98, (byte) 0x57,
+ (byte) 0x67, (byte) 0x7F, (byte) 0x05, (byte) 0x64,
+ (byte) 0xAF, (byte) 0x63, (byte) 0xB6, (byte) 0xFE,
+ (byte) 0xF5, (byte) 0xB7, (byte) 0x3C, (byte) 0xA5,
+ (byte) 0xCE, (byte) 0xE9, (byte) 0x68, (byte) 0x44,
+ (byte) 0xE0, (byte) 0x4D, (byte) 0x43, (byte) 0x69,
+ (byte) 0x29, (byte) 0x2E, (byte) 0xAC, (byte) 0x15,
+ (byte) 0x59, (byte) 0xA8, (byte) 0x0A, (byte) 0x9E,
+ (byte) 0x6E, (byte) 0x47, (byte) 0xDF, (byte) 0x34,
+ (byte) 0x35, (byte) 0x6A, (byte) 0xCF, (byte) 0xDC,
+ (byte) 0x22, (byte) 0xC9, (byte) 0xC0, (byte) 0x9B,
+ (byte) 0x89, (byte) 0xD4, (byte) 0xED, (byte) 0xAB,
+ (byte) 0x12, (byte) 0xA2, (byte) 0x0D, (byte) 0x52,
+ (byte) 0xBB, (byte) 0x02, (byte) 0x2F, (byte) 0xA9,
+ (byte) 0xD7, (byte) 0x61, (byte) 0x1E, (byte) 0xB4,
+ (byte) 0x50, (byte) 0x04, (byte) 0xF6, (byte) 0xC2,
+ (byte) 0x16, (byte) 0x25, (byte) 0x86, (byte) 0x56,
+ (byte) 0x55, (byte) 0x09, (byte) 0xBE, (byte) 0x91 }
+ };
+
+ /**
+ * Define the fixed p0/p1 permutations used in keyed S-box lookup.
+ * By changing the following constant definitions, the S-boxes will
+ * automatically Get changed in the Twofish engine.
+ */
+ private const int P_00 = 1;
+ private const int P_01 = 0;
+ private const int P_02 = 0;
+ private const int P_03 = P_01 ^ 1;
+ private const int P_04 = 1;
+
+ private const int P_10 = 0;
+ private const int P_11 = 0;
+ private const int P_12 = 1;
+ private const int P_13 = P_11 ^ 1;
+ private const int P_14 = 0;
+
+ private const int P_20 = 1;
+ private const int P_21 = 1;
+ private const int P_22 = 0;
+ private const int P_23 = P_21 ^ 1;
+ private const int P_24 = 0;
+
+ private const int P_30 = 0;
+ private const int P_31 = 1;
+ private const int P_32 = 1;
+ private const int P_33 = P_31 ^ 1;
+ private const int P_34 = 1;
+
+ /* Primitive polynomial for GF(256) */
+ private const int GF256_FDBK = 0x169;
+ private const int GF256_FDBK_2 = GF256_FDBK / 2;
+ private const int GF256_FDBK_4 = GF256_FDBK / 4;
+
+ private const int RS_GF_FDBK = 0x14D; // field generator
+
+ //====================================
+ // Useful constants
+ //====================================
+
+ private const int ROUNDS = 16;
+ private const int MAX_ROUNDS = 16; // bytes = 128 bits
+ private const int BLOCK_SIZE = 16; // bytes = 128 bits
+ private const int MAX_KEY_BITS = 256;
+
+ private const int INPUT_WHITEN=0;
+ private const int OUTPUT_WHITEN=INPUT_WHITEN+BLOCK_SIZE/4; // 4
+ private const int ROUND_SUBKEYS=OUTPUT_WHITEN+BLOCK_SIZE/4;// 8
+
+ private const int TOTAL_SUBKEYS=ROUND_SUBKEYS+2*MAX_ROUNDS;// 40
+
+ private const int SK_STEP = 0x02020202;
+ private const int SK_BUMP = 0x01010101;
+ private const int SK_ROTL = 9;
+
+ private bool encrypting;
+
+ private int[] gMDS0 = new int[MAX_KEY_BITS];
+ private int[] gMDS1 = new int[MAX_KEY_BITS];
+ private int[] gMDS2 = new int[MAX_KEY_BITS];
+ private int[] gMDS3 = new int[MAX_KEY_BITS];
+
+ /**
+ * gSubKeys[] and gSBox[] are eventually used in the
+ * encryption and decryption methods.
+ */
+ private int[] gSubKeys;
+ private int[] gSBox;
+
+ private int k64Cnt;
+
+ private byte[] workingKey;
+
+ public TwofishEngine()
+ {
+ // calculate the MDS matrix
+ int[] m1 = new int[2];
+ int[] mX = new int[2];
+ int[] mY = new int[2];
+ int j;
+
+ for (int i=0; i< MAX_KEY_BITS ; i++)
+ {
+ j = P[0,i] & 0xff;
+ m1[0] = j;
+ mX[0] = Mx_X(j) & 0xff;
+ mY[0] = Mx_Y(j) & 0xff;
+
+ j = P[1,i] & 0xff;
+ m1[1] = j;
+ mX[1] = Mx_X(j) & 0xff;
+ mY[1] = Mx_Y(j) & 0xff;
+
+ gMDS0[i] = m1[P_00] | mX[P_00] << 8 |
+ mY[P_00] << 16 | mY[P_00] << 24;
+
+ gMDS1[i] = mY[P_10] | mY[P_10] << 8 |
+ mX[P_10] << 16 | m1[P_10] << 24;
+
+ gMDS2[i] = mX[P_20] | mY[P_20] << 8 |
+ m1[P_20] << 16 | mY[P_20] << 24;
+
+ gMDS3[i] = mX[P_30] | m1[P_30] << 8 |
+ mY[P_30] << 16 | mX[P_30] << 24;
+ }
+ }
+
+ /**
+ * initialise a Twofish 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 (!(parameters is KeyParameter))
+ throw new ArgumentException("invalid parameter passed to Twofish init - " + Platform.GetTypeName(parameters));
+
+ this.encrypting = forEncryption;
+ this.workingKey = ((KeyParameter)parameters).GetKey();
+ this.k64Cnt = (this.workingKey.Length / 8); // pre-padded ?
+ SetKey(this.workingKey);
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Twofish"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ if (workingKey == null)
+ throw new InvalidOperationException("Twofish not initialised");
+
+ Check.DataLength(input, inOff, BLOCK_SIZE, "input buffer too short");
+ Check.OutputLength(output, outOff, BLOCK_SIZE, "output buffer too short");
+
+ if (encrypting)
+ {
+ EncryptBlock(input, inOff, output, outOff);
+ }
+ else
+ {
+ DecryptBlock(input, inOff, output, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ public void Reset()
+ {
+ if (this.workingKey != null)
+ {
+ SetKey(this.workingKey);
+ }
+ }
+
+ public int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ //==================================
+ // Private Implementation
+ //==================================
+
+ private void SetKey(byte[] key)
+ {
+ int[] k32e = new int[MAX_KEY_BITS/64]; // 4
+ int[] k32o = new int[MAX_KEY_BITS/64]; // 4
+
+ int[] sBoxKeys = new int[MAX_KEY_BITS/64]; // 4
+ gSubKeys = new int[TOTAL_SUBKEYS];
+
+ if (k64Cnt < 1)
+ {
+ throw new ArgumentException("Key size less than 64 bits");
+ }
+
+ if (k64Cnt > 4)
+ {
+ throw new ArgumentException("Key size larger than 256 bits");
+ }
+
+ /*
+ * k64Cnt is the number of 8 byte blocks (64 chunks)
+ * that are in the input key. The input key is a
+ * maximum of 32 bytes ( 256 bits ), so the range
+ * for k64Cnt is 1..4
+ */
+ for (int i=0,p=0; i> 24);
+ A += B;
+ gSubKeys[i*2] = A;
+ A += B;
+ gSubKeys[i*2 + 1] = A << SK_ROTL | (int)((uint)A >> (32-SK_ROTL));
+ }
+
+ /*
+ * fully expand the table for speed
+ */
+ int k0 = sBoxKeys[0];
+ int k1 = sBoxKeys[1];
+ int k2 = sBoxKeys[2];
+ int k3 = sBoxKeys[3];
+ int b0, b1, b2, b3;
+ gSBox = new int[4*MAX_KEY_BITS];
+ for (int i=0; i>1) | x2 << 31;
+ x3 = (x3 << 1 | (int) ((uint)x3 >> 31)) ^ (t0 + 2*t1 + gSubKeys[k++]);
+
+ t0 = Fe32_0(x2);
+ t1 = Fe32_3(x3);
+ x0 ^= t0 + t1 + gSubKeys[k++];
+ x0 = (int) ((uint)x0 >>1) | x0 << 31;
+ x1 = (x1 << 1 | (int)((uint)x1 >> 31)) ^ (t0 + 2*t1 + gSubKeys[k++]);
+ }
+
+ Bits32ToBytes(x2 ^ gSubKeys[OUTPUT_WHITEN], dst, dstIndex);
+ Bits32ToBytes(x3 ^ gSubKeys[OUTPUT_WHITEN + 1], dst, dstIndex + 4);
+ Bits32ToBytes(x0 ^ gSubKeys[OUTPUT_WHITEN + 2], dst, dstIndex + 8);
+ Bits32ToBytes(x1 ^ gSubKeys[OUTPUT_WHITEN + 3], dst, dstIndex + 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(
+ byte[] src,
+ int srcIndex,
+ byte[] dst,
+ int dstIndex)
+ {
+ int x2 = BytesTo32Bits(src, srcIndex) ^ gSubKeys[OUTPUT_WHITEN];
+ int x3 = BytesTo32Bits(src, srcIndex+4) ^ gSubKeys[OUTPUT_WHITEN + 1];
+ int x0 = BytesTo32Bits(src, srcIndex+8) ^ gSubKeys[OUTPUT_WHITEN + 2];
+ int x1 = BytesTo32Bits(src, srcIndex+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 = (x0 << 1 | (int)((uint) x0 >> 31)) ^ (t0 + t1 + gSubKeys[k--]);
+ x1 = (int) ((uint)x1 >>1) | x1 << 31;
+
+ t0 = Fe32_0(x0);
+ t1 = Fe32_3(x1);
+ x3 ^= t0 + 2*t1 + gSubKeys[k--];
+ x2 = (x2 << 1 | (int)((uint)x2 >> 31)) ^ (t0 + t1 + gSubKeys[k--]);
+ x3 = (int)((uint)x3 >>1) | x3 << 31;
+ }
+
+ Bits32ToBytes(x0 ^ gSubKeys[INPUT_WHITEN], dst, dstIndex);
+ Bits32ToBytes(x1 ^ gSubKeys[INPUT_WHITEN + 1], dst, dstIndex + 4);
+ Bits32ToBytes(x2 ^ gSubKeys[INPUT_WHITEN + 2], dst, dstIndex + 8);
+ Bits32ToBytes(x3 ^ gSubKeys[INPUT_WHITEN + 3], dst, dstIndex + 12);
+ }
+
+ /*
+ * TODO: This can be optimised and made cleaner by combining
+ * the functionality in this function and applying it appropriately
+ * to the creation of the subkeys during key setup.
+ */
+ private int F32(int x, int[] k32)
+ {
+ int b0 = M_b0(x);
+ int b1 = M_b1(x);
+ int b2 = M_b2(x);
+ int b3 = M_b3(x);
+ int k0 = k32[0];
+ int k1 = k32[1];
+ int k2 = k32[2];
+ int k3 = k32[3];
+
+ int result = 0;
+ switch (k64Cnt & 3)
+ {
+ case 1:
+ result = gMDS0[(P[P_01,b0] & 0xff) ^ M_b0(k0)] ^
+ gMDS1[(P[P_11,b1] & 0xff) ^ M_b1(k0)] ^
+ gMDS2[(P[P_21,b2] & 0xff) ^ M_b2(k0)] ^
+ gMDS3[(P[P_31,b3] & 0xff) ^ M_b3(k0)];
+ break;
+ case 0: /* 256 bits of key */
+ b0 = (P[P_04,b0] & 0xff) ^ M_b0(k3);
+ b1 = (P[P_14,b1] & 0xff) ^ M_b1(k3);
+ b2 = (P[P_24,b2] & 0xff) ^ M_b2(k3);
+ b3 = (P[P_34,b3] & 0xff) ^ M_b3(k3);
+ goto case 3;
+ case 3:
+ b0 = (P[P_03,b0] & 0xff) ^ M_b0(k2);
+ b1 = (P[P_13,b1] & 0xff) ^ M_b1(k2);
+ b2 = (P[P_23,b2] & 0xff) ^ M_b2(k2);
+ b3 = (P[P_33,b3] & 0xff) ^ M_b3(k2);
+ goto case 2;
+ case 2:
+ result =
+ gMDS0[(P[P_01,(P[P_02,b0]&0xff)^M_b0(k1)]&0xff)^M_b0(k0)] ^
+ gMDS1[(P[P_11,(P[P_12,b1]&0xff)^M_b1(k1)]&0xff)^M_b1(k0)] ^
+ gMDS2[(P[P_21,(P[P_22,b2]&0xff)^M_b2(k1)]&0xff)^M_b2(k0)] ^
+ gMDS3[(P[P_31,(P[P_32,b3]&0xff)^M_b3(k1)]&0xff)^M_b3(k0)];
+ break;
+ }
+ return result;
+ }
+
+ /**
+ * Use (12, 8) Reed-Solomon code over GF(256) to produce
+ * a key S-box 32-bit entity from 2 key material 32-bit
+ * entities.
+ *
+ * @param k0 first 32-bit entity
+ * @param k1 second 32-bit entity
+ * @return Remainder polynomial Generated using RS code
+ */
+ private int RS_MDS_Encode(int k0, int k1)
+ {
+ int r = k1;
+ for (int i = 0 ; i < 4 ; i++) // shift 1 byte at a time
+ {
+ r = RS_rem(r);
+ }
+ r ^= k0;
+ for (int i=0 ; i < 4 ; i++)
+ {
+ r = RS_rem(r);
+ }
+
+ return r;
+ }
+
+ /**
+ * Reed-Solomon code parameters: (12,8) reversible code:
+ *
+ *
+ * G(x) = x^4 + (a+1/a)x^3 + ax^2 + (a+1/a)x + 1
+ *
+ * where a = primitive root of field generator 0x14D
+ *
+ */
+ private int RS_rem(int x)
+ {
+ int b = (int) (((uint)x >> 24) & 0xff);
+ int g2 = ((b << 1) ^
+ ((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xff;
+ int g3 = ( (int)((uint)b >> 1) ^
+ ((b & 0x01) != 0 ? (int)((uint)RS_GF_FDBK >> 1) : 0)) ^ g2 ;
+ return ((x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b);
+ }
+
+ private int LFSR1(int x)
+ {
+ return (x >> 1) ^
+ (((x & 0x01) != 0) ? GF256_FDBK_2 : 0);
+ }
+
+ private int LFSR2(int x)
+ {
+ return (x >> 2) ^
+ (((x & 0x02) != 0) ? GF256_FDBK_2 : 0) ^
+ (((x & 0x01) != 0) ? GF256_FDBK_4 : 0);
+ }
+
+ private int Mx_X(int x)
+ {
+ return x ^ LFSR2(x);
+ } // 5B
+
+ private int Mx_Y(int x)
+ {
+ return x ^ LFSR1(x) ^ LFSR2(x);
+ } // EF
+
+ private int M_b0(int x)
+ {
+ return x & 0xff;
+ }
+
+ private int M_b1(int x)
+ {
+ return (int)((uint)x >> 8) & 0xff;
+ }
+
+ private int M_b2(int x)
+ {
+ return (int)((uint)x >> 16) & 0xff;
+ }
+
+ private int M_b3(int x)
+ {
+ return (int)((uint)x >> 24) & 0xff;
+ }
+
+ private int Fe32_0(int x)
+ {
+ return gSBox[ 0x000 + 2*(x & 0xff) ] ^
+ gSBox[ 0x001 + 2*((int)((uint)x >> 8) & 0xff) ] ^
+ gSBox[ 0x200 + 2*((int)((uint)x >> 16) & 0xff) ] ^
+ gSBox[ 0x201 + 2*((int)((uint)x >> 24) & 0xff) ];
+ }
+
+ private int Fe32_3(int x)
+ {
+ return gSBox[ 0x000 + 2*((int)((uint)x >> 24) & 0xff) ] ^
+ gSBox[ 0x001 + 2*(x & 0xff) ] ^
+ gSBox[ 0x200 + 2*((int)((uint)x >> 8) & 0xff) ] ^
+ gSBox[ 0x201 + 2*((int)((uint)x >> 16) & 0xff) ];
+ }
+
+ private int BytesTo32Bits(byte[] b, int p)
+ {
+ return ((b[p] & 0xff) ) |
+ ((b[p+1] & 0xff) << 8) |
+ ((b[p+2] & 0xff) << 16) |
+ ((b[p+3] & 0xff) << 24);
+ }
+
+ private void Bits32ToBytes(int inData, byte[] b, int offset)
+ {
+ b[offset] = (byte)inData;
+ b[offset + 1] = (byte)(inData >> 8);
+ b[offset + 2] = (byte)(inData >> 16);
+ b[offset + 3] = (byte)(inData >> 24);
+ }
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/VMPCEngine.cs b/bc-sharp-crypto/src/crypto/engines/VMPCEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..852901e367bb243ca810a523872d6f1196167095
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/VMPCEngine.cs
@@ -0,0 +1,133 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ public class VmpcEngine
+ : IStreamCipher
+ {
+ /*
+ * variables to hold the state of the VMPC engine during encryption and
+ * decryption
+ */
+ protected byte n = 0;
+ protected byte[] P = null;
+ protected byte s = 0;
+
+ protected byte[] workingIV;
+ protected byte[] workingKey;
+
+ public virtual string AlgorithmName
+ {
+ get { return "VMPC"; }
+ }
+
+ /**
+ * initialise a VMPC cipher.
+ *
+ * @param forEncryption
+ * whether or not we are for encryption.
+ * @param params
+ * the parameters required to set up the cipher.
+ * @exception ArgumentException
+ * if the params argument is inappropriate.
+ */
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is ParametersWithIV))
+ throw new ArgumentException("VMPC Init parameters must include an IV");
+
+ ParametersWithIV ivParams = (ParametersWithIV) parameters;
+
+ if (!(ivParams.Parameters is KeyParameter))
+ throw new ArgumentException("VMPC Init parameters must include a key");
+
+ KeyParameter key = (KeyParameter)ivParams.Parameters;
+
+ this.workingIV = ivParams.GetIV();
+
+ if (workingIV == null || workingIV.Length < 1 || workingIV.Length > 768)
+ throw new ArgumentException("VMPC requires 1 to 768 bytes of IV");
+
+ this.workingKey = key.GetKey();
+
+ InitKey(this.workingKey, this.workingIV);
+ }
+
+ protected virtual void InitKey(
+ byte[] keyBytes,
+ byte[] ivBytes)
+ {
+ s = 0;
+ P = new byte[256];
+ for (int i = 0; i < 256; i++)
+ {
+ P[i] = (byte) i;
+ }
+
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.Length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+ n = 0;
+ }
+
+ public virtual void ProcessBytes(
+ byte[] input,
+ int inOff,
+ int len,
+ byte[] output,
+ int outOff)
+ {
+ Check.DataLength(input, inOff, len, "input buffer too short");
+ Check.OutputLength(output, outOff, len, "output buffer too short");
+
+ for (int i = 0; i < len; i++)
+ {
+ s = P[(s + P[n & 0xff]) & 0xff];
+ byte z = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+ // encryption
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte) ((n + 1) & 0xff);
+
+ // xor
+ output[i + outOff] = (byte) (input[i + inOff] ^ z);
+ }
+ }
+
+ public virtual void Reset()
+ {
+ InitKey(this.workingKey, this.workingIV);
+ }
+
+ public virtual byte ReturnByte(
+ byte input)
+ {
+ s = P[(s + P[n & 0xff]) & 0xff];
+ byte z = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+ // encryption
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte) ((n + 1) & 0xff);
+
+ // xor
+ return (byte) (input ^ z);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/VMPCKSA3Engine.cs b/bc-sharp-crypto/src/crypto/engines/VMPCKSA3Engine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..95b6813b7e2c1cf8db34f4bb9f75d4a1b2ac86a7
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/VMPCKSA3Engine.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ public class VmpcKsa3Engine
+ : VmpcEngine
+ {
+ public override string AlgorithmName
+ {
+ get { return "VMPC-KSA3"; }
+ }
+
+ protected override void InitKey(
+ byte[] keyBytes,
+ byte[] ivBytes)
+ {
+ s = 0;
+ P = new byte[256];
+ for (int i = 0; i < 256; i++)
+ {
+ P[i] = (byte) i;
+ }
+
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.Length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+
+ n = 0;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/XSalsa20Engine.cs b/bc-sharp-crypto/src/crypto/engines/XSalsa20Engine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..50c51a82fc42d09d0bb0e3b79b56300b46d4e0ac
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/XSalsa20Engine.cs
@@ -0,0 +1,64 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ ///
+ /// Implementation of Daniel J. Bernstein's XSalsa20 stream cipher - Salsa20 with an extended nonce.
+ ///
+ ///
+ /// XSalsa20 requires a 256 bit key, and a 192 bit nonce.
+ ///
+ public class XSalsa20Engine
+ : Salsa20Engine
+ {
+ public override string AlgorithmName
+ {
+ get { return "XSalsa20"; }
+ }
+
+ protected override int NonceSize
+ {
+ get { return 24; }
+ }
+
+ ///
+ /// XSalsa20 key generation: process 256 bit input key and 128 bits of the input nonce
+ /// using a core Salsa20 function without input addition to produce 256 bit working key
+ /// and use that with the remaining 64 bits of nonce to initialize a standard Salsa20 engine state.
+ ///
+ protected override void SetKey(byte[] keyBytes, byte[] ivBytes)
+ {
+ if (keyBytes == null)
+ throw new ArgumentException(AlgorithmName + " doesn't support re-init with null key");
+
+ if (keyBytes.Length != 32)
+ throw new ArgumentException(AlgorithmName + " requires a 256 bit key");
+
+ // Set key for HSalsa20
+ base.SetKey(keyBytes, ivBytes);
+
+ // Pack next 64 bits of IV into engine state instead of counter
+ Pack.LE_To_UInt32(ivBytes, 8, engineState, 8, 2);
+
+ // Process engine state to generate Salsa20 key
+ uint[] hsalsa20Out = new uint[engineState.Length];
+ SalsaCore(20, engineState, hsalsa20Out);
+
+ // Set new key, removing addition in last round of salsaCore
+ engineState[1] = hsalsa20Out[0] - engineState[0];
+ engineState[2] = hsalsa20Out[5] - engineState[5];
+ engineState[3] = hsalsa20Out[10] - engineState[10];
+ engineState[4] = hsalsa20Out[15] - engineState[15];
+
+ engineState[11] = hsalsa20Out[6] - engineState[6];
+ engineState[12] = hsalsa20Out[7] - engineState[7];
+ engineState[13] = hsalsa20Out[8] - engineState[8];
+ engineState[14] = hsalsa20Out[9] - engineState[9];
+
+ // Last 64 bits of input IV
+ Pack.LE_To_UInt32(ivBytes, 16, engineState, 6, 2);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/engines/XTEAEngine.cs b/bc-sharp-crypto/src/crypto/engines/XTEAEngine.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5fcfa4a57f59099d5ad77e5ea2410cfa5b14cb37
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/engines/XTEAEngine.cs
@@ -0,0 +1,166 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+ /**
+ * An XTEA engine.
+ */
+ public class XteaEngine
+ : IBlockCipher
+ {
+ private const int
+ rounds = 32,
+ block_size = 8,
+// key_size = 16,
+ delta = unchecked((int) 0x9E3779B9);
+
+ /*
+ * the expanded key array of 4 subkeys
+ */
+ private uint[] _S = new uint[4],
+ _sum0 = new uint[32],
+ _sum1 = new uint[32];
+ private bool _initialised, _forEncryption;
+
+ /**
+ * Create an instance of the TEA encryption algorithm
+ * and set some defaults
+ */
+ public XteaEngine()
+ {
+ _initialised = false;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "XTEA"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return block_size;
+ }
+
+ /**
+ * initialise
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception ArgumentException if the params argument is
+ * inappropriate.
+ */
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (!(parameters is KeyParameter))
+ {
+ throw new ArgumentException("invalid parameter passed to TEA init - "
+ + Platform.GetTypeName(parameters));
+ }
+
+ _forEncryption = forEncryption;
+ _initialised = true;
+
+ KeyParameter p = (KeyParameter) parameters;
+
+ setKey(p.GetKey());
+ }
+
+ public virtual int ProcessBlock(
+ byte[] inBytes,
+ int inOff,
+ byte[] outBytes,
+ int outOff)
+ {
+ if (!_initialised)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ 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);
+ }
+
+ public virtual void Reset()
+ {
+ }
+
+ /**
+ * Re-key the cipher.
+ *
+ * @param key the key to be used
+ */
+ private void setKey(
+ byte[] key)
+ {
+ int i, j;
+ for (i = j = 0; i < 4; i++,j+=4)
+ {
+ _S[i] = Pack.BE_To_UInt32(key, j);
+ }
+
+ for (i = j = 0; i < rounds; i++)
+ {
+ _sum0[i] = ((uint)j + _S[j & 3]);
+ j += delta;
+ _sum1[i] = ((uint)j + _S[j >> 11 & 3]);
+ }
+ }
+
+ 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);
+
+ 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, outBytes, outOff);
+ Pack.UInt32_To_BE(v1, outBytes, outOff + 4);
+
+ return block_size;
+ }
+
+ private int decryptBlock(
+ 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);
+
+ 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, outBytes, outOff);
+ Pack.UInt32_To_BE(v1, outBytes, outOff + 4);
+
+ return block_size;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/BCrypt.cs b/bc-sharp-crypto/src/crypto/generators/BCrypt.cs
new file mode 100644
index 0000000000000000000000000000000000000000..af8029a1ba002e25183aec3f808e5ebb1736a1ca
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/BCrypt.cs
@@ -0,0 +1,617 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Core of password hashing scheme Bcrypt,
+ * designed by Niels Provos and David Mazières,
+ * corresponds to the C reference implementation.
+ *
+ * This implementation does not correspondent to the 1999 published paper
+ * "A Future-Adaptable Password Scheme" of Niels Provos and David Mazières,
+ * see: https://www.usenix.org/legacy/events/usenix99/provos/provos_html/node1.html.
+ * In contrast to the paper, the order of key setup and salt setup is reversed:
+ * state <- ExpandKey(state, 0, key)
+ * state %lt;- ExpandKey(state, 0, salt)
+ * This corresponds to the OpenBSD reference implementation of Bcrypt.
+ *
+ * Note:
+ * There is no successful cryptanalysis (status 2015), but
+ * the amount of memory and the band width of Bcrypt
+ * may be insufficient to effectively prevent attacks
+ * with custom hardware like FPGAs, ASICs
+ *
+ * This implementation uses some parts of Bouncy Castle's BlowfishEngine.
+ *
+ */
+ public sealed class BCrypt
+ {
+ // magic String "OrpheanBeholderScryDoubt" is used as clear text for encryption
+ private static readonly uint[] MAGIC_STRING =
+ {
+ 0x4F727068, 0x65616E42, 0x65686F6C,
+ 0x64657253, 0x63727944, 0x6F756274
+ };
+
+ internal const int MAGIC_STRING_LENGTH = 6;
+
+ private static readonly uint[]
+ KP = {
+ 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344,
+ 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89,
+ 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C,
+ 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917,
+ 0x9216D5D9, 0x8979FB1B
+ },
+
+ KS0 = {
+ 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7,
+ 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99,
+ 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16,
+ 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E,
+ 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE,
+ 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013,
+ 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF,
+ 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E,
+ 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60,
+ 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440,
+ 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE,
+ 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A,
+ 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E,
+ 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677,
+ 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193,
+ 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032,
+ 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88,
+ 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239,
+ 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E,
+ 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0,
+ 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3,
+ 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98,
+ 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88,
+ 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE,
+ 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6,
+ 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D,
+ 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B,
+ 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7,
+ 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA,
+ 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463,
+ 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F,
+ 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09,
+ 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3,
+ 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB,
+ 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279,
+ 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8,
+ 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB,
+ 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82,
+ 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB,
+ 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573,
+ 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0,
+ 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B,
+ 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790,
+ 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8,
+ 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4,
+ 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0,
+ 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7,
+ 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C,
+ 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD,
+ 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1,
+ 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299,
+ 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9,
+ 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477,
+ 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF,
+ 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49,
+ 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF,
+ 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA,
+ 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5,
+ 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41,
+ 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915,
+ 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400,
+ 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915,
+ 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664,
+ 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A
+ },
+
+ KS1 = {
+ 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623,
+ 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266,
+ 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1,
+ 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E,
+ 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6,
+ 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1,
+ 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E,
+ 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1,
+ 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737,
+ 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8,
+ 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF,
+ 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD,
+ 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701,
+ 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7,
+ 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41,
+ 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331,
+ 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF,
+ 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF,
+ 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E,
+ 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87,
+ 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C,
+ 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2,
+ 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16,
+ 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD,
+ 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B,
+ 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509,
+ 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E,
+ 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3,
+ 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F,
+ 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A,
+ 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4,
+ 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960,
+ 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66,
+ 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28,
+ 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802,
+ 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84,
+ 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510,
+ 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF,
+ 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14,
+ 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E,
+ 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50,
+ 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7,
+ 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8,
+ 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281,
+ 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99,
+ 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696,
+ 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128,
+ 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73,
+ 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0,
+ 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0,
+ 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105,
+ 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250,
+ 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3,
+ 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285,
+ 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00,
+ 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061,
+ 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB,
+ 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E,
+ 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735,
+ 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC,
+ 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9,
+ 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340,
+ 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20,
+ 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7
+ },
+
+ KS2 = {
+ 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934,
+ 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068,
+ 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF,
+ 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840,
+ 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45,
+ 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504,
+ 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A,
+ 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB,
+ 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE,
+ 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6,
+ 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42,
+ 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B,
+ 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2,
+ 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB,
+ 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527,
+ 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B,
+ 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33,
+ 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C,
+ 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3,
+ 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC,
+ 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17,
+ 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564,
+ 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B,
+ 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115,
+ 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922,
+ 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728,
+ 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0,
+ 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E,
+ 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37,
+ 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D,
+ 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804,
+ 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B,
+ 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3,
+ 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB,
+ 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D,
+ 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C,
+ 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350,
+ 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9,
+ 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A,
+ 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE,
+ 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D,
+ 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC,
+ 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F,
+ 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61,
+ 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2,
+ 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9,
+ 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2,
+ 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C,
+ 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E,
+ 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633,
+ 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10,
+ 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169,
+ 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52,
+ 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027,
+ 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5,
+ 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62,
+ 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634,
+ 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76,
+ 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24,
+ 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC,
+ 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4,
+ 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C,
+ 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837,
+ 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0
+ },
+
+ KS3 = {
+ 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B,
+ 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE,
+ 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B,
+ 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4,
+ 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8,
+ 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6,
+ 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304,
+ 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22,
+ 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4,
+ 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6,
+ 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9,
+ 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59,
+ 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593,
+ 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51,
+ 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28,
+ 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C,
+ 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B,
+ 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28,
+ 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C,
+ 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD,
+ 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A,
+ 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319,
+ 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB,
+ 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F,
+ 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991,
+ 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32,
+ 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680,
+ 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166,
+ 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE,
+ 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB,
+ 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5,
+ 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47,
+ 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370,
+ 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D,
+ 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84,
+ 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048,
+ 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8,
+ 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD,
+ 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9,
+ 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7,
+ 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38,
+ 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F,
+ 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C,
+ 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525,
+ 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1,
+ 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442,
+ 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964,
+ 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E,
+ 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8,
+ 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D,
+ 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F,
+ 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299,
+ 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02,
+ 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC,
+ 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614,
+ 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A,
+ 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6,
+ 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B,
+ 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0,
+ 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060,
+ 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E,
+ 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9,
+ 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F,
+ 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6
+ };
+
+ //====================================
+ // Useful constants
+ //====================================
+
+ private const int ROUNDS = 16;
+ private const int SBOX_SK = 256;
+ private const int SBOX_SK2 = SBOX_SK * 2;
+ private const int SBOX_SK3 = SBOX_SK * 3;
+ private const int P_SZ = ROUNDS + 2;
+
+ private readonly uint[] S; // the s-boxes
+ private readonly uint[] P; // the p-array
+
+ private BCrypt()
+ {
+ S = new uint[SBOX_SK * 4];
+ P = new uint[P_SZ];
+ }
+
+ //==================================
+ // Private Implementation
+ //==================================
+
+ private uint F(uint x)
+ {
+ return (((S[(x >> 24)] + S[SBOX_SK + ((x >> 16) & 0xff)])
+ ^ S[SBOX_SK2 + ((x >> 8) & 0xff)]) + S[SBOX_SK3 + (x & 0xff)]);
+ }
+
+ /*
+ * apply the encryption cycle to each value pair in the table.
+ */
+ private void ProcessTable(uint xl, uint xr, uint[] table)
+ {
+ int size = table.Length;
+
+ for (int s = 0; s < size; s += 2)
+ {
+ 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];
+
+ table[s] = xr;
+ table[s + 1] = xl;
+
+ xr = xl; // end of cycle swap
+ xl = table[s];
+ }
+ }
+
+ /*
+ * Initialize the S-boxes and the P-array, with a fixed string
+ * This string contains the hexadecimal digits of pi (3.141...)
+ */
+ private void InitState()
+ {
+ Array.Copy(KS0, 0, S, 0, SBOX_SK);
+ Array.Copy(KS1, 0, S, SBOX_SK, SBOX_SK);
+ Array.Copy(KS2, 0, S, SBOX_SK2, SBOX_SK);
+ Array.Copy(KS3, 0, S, SBOX_SK3, SBOX_SK);
+
+ Array.Copy(KP, 0, P, 0, P_SZ);
+ }
+
+ /*
+ * XOR P with key cyclic.
+ * This is the first part of ExpandKey function
+ */
+ private void CyclicXorKey(byte[] key)
+ {
+ int keyLength = key.Length;
+ int keyIndex = 0;
+
+ for (int i = 0; i < P_SZ; i++)
+ {
+ // get the 32 bits of the key, in 4 * 8 bit chunks
+ uint data = 0x0000000;
+ for (int j = 0; j < 4; j++)
+ {
+ // create a 32 bit block
+ data = (data << 8) | key[keyIndex];
+
+ // wrap when we get to the end of the key
+ if (++keyIndex >= keyLength)
+ {
+ keyIndex = 0;
+ }
+ }
+ // XOR the newly created 32 bit chunk onto the P-array
+ P[i] ^= data;
+ }
+ }
+
+
+ /*
+ * encrypt magic String 64 times in ECB
+ */
+ private byte[] EncryptMagicString()
+ {
+ uint[] text = {
+ MAGIC_STRING[0], MAGIC_STRING[1],
+ MAGIC_STRING[2], MAGIC_STRING[3],
+ MAGIC_STRING[4], MAGIC_STRING[5]
+ };
+ for (int i = 0; i < 64; i++)
+ {
+ for (int j = 0; j < MAGIC_STRING_LENGTH; j += 2)
+ {
+ uint left = text[j];
+ uint right = text[j + 1];
+
+ left ^= P[0];
+ for (int k = 1; k < ROUNDS; k += 2)
+ {
+ right ^= F(left) ^ P[k];
+ left ^= F(right) ^ P[k + 1];
+ }
+ right ^= P[ROUNDS + 1];
+ // swap values:
+ text[j] = right;
+ text[j + 1] = left;
+ }
+ }
+ byte[] result = new byte[24]; // holds 192 bit key
+ Pack.UInt32_To_BE(text, result, 0);
+ Array.Clear(text, 0, text.Length);
+ Array.Clear(P, 0, P.Length);
+ Array.Clear(S, 0, S.Length);
+
+ return result;
+ }
+
+ /*
+ * This is a part of Eksblowfish function
+ *
+ * @param table: sub-keys or working key
+ * @param salt32Bit: a 16 byte salt as two 32 bit words
+ * @param iv1: value from last proceeded table
+ * @param iv2: value from last proceeded table
+ */
+ private void ProcessTableWithSalt(uint[] table, uint[] salt32Bit, uint iv1, uint iv2)
+ {
+ uint xl = iv1 ^ salt32Bit[0];
+ uint xr = iv2 ^ salt32Bit[1];
+
+ uint yl;
+ uint yr;
+ int size = table.Length;
+
+ for (int s = 0; s < size; s += 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];
+
+ table[s] = xr;
+ table[s + 1] = xl;
+
+ yl = salt32Bit[2] ^ xr;
+ yr = salt32Bit[3] ^ xl;
+
+ if (s + 2 >= size) // P holds 18 values
+ {
+ break;
+ }
+
+ yl ^= P[0];
+ for (int i = 1; i < ROUNDS; i += 2)
+ {
+ yr ^= F(yl) ^ P[i];
+ yl ^= F(yr) ^ P[i + 1];
+ }
+ yr ^= P[ROUNDS + 1];
+
+ table[s + 2] = yr;
+ table[s + 3] = yl;
+
+ xl = salt32Bit[0] ^ yr;
+ xr = salt32Bit[1] ^ yl;
+ }
+ }
+
+ /**
+ * Derives a raw 192 bit Bcrypt key
+ *
+ * @param cost the cost factor, treated as an exponent of 2
+ * @param salt a 16 byte salt
+ * @param psw the password
+ * @return a 192 bit key
+ */
+ private byte[] DeriveRawKey(int cost, byte[] salt, byte[] psw)
+ {
+ if (salt.Length != 16)
+ throw new DataLengthException("Invalid salt size: 16 bytes expected.");
+ if (cost < 4 || cost > 31)
+ throw new ArgumentException("Illegal cost factor: 4 - 31 expected.", "cost");
+
+ if (psw.Length == 0)
+ {
+ psw = new byte[4];
+ }
+
+ // state <- InitState()
+ InitState();
+
+ uint[] salt32Bit = new uint[4]; // holds 16 byte salt
+ Pack.BE_To_UInt32(salt, 0, salt32Bit);
+
+ uint[] salt32Bit2 = new uint[salt.Length]; // swapped values
+ salt32Bit2[0] = salt32Bit[2];
+ salt32Bit2[1] = salt32Bit[3];
+ salt32Bit2[2] = salt32Bit[0];
+ salt32Bit2[3] = salt32Bit[1];
+
+ // ExpandKey( state, salt, key):
+ CyclicXorKey(psw);
+ ProcessTableWithSalt(P, salt32Bit, 0, 0);
+ Array.Clear(salt32Bit, 0, salt32Bit.Length);
+ ProcessTableWithSalt(S, salt32Bit2, P[P.Length - 2], P[P.Length - 1]);
+ Array.Clear(salt32Bit2, 0, salt32Bit2.Length);
+
+ int rounds = 1 << cost;
+ for (int i = 0; i != rounds; i++) // rounds may be negative if cost is 31
+ {
+ // state <- ExpandKey(state, 0, key);
+ CyclicXorKey(psw);
+ ProcessTable(0, 0, P);
+ ProcessTable(P[P_SZ - 2], P[P_SZ - 1], S);
+
+ // state <- ExpandKey(state, 0, salt);
+ CyclicXorKey(salt);
+ ProcessTable(0, 0, P);
+ ProcessTable(P[P_SZ - 2], P[P_SZ - 1], S);
+ }
+
+ // encrypt magicString 64 times
+ return EncryptMagicString();
+ }
+
+ /**
+ * Size of the salt parameter in bytes
+ */
+ internal const int SALT_SIZE_BYTES = 16;
+
+ /**
+ * Minimum value of cost parameter, equal to log2(bytes of salt)
+ */
+ internal const int MIN_COST = 4;
+
+ /**
+ * Maximum value of cost parameter (31 == 2,147,483,648)
+ */
+ internal const int MAX_COST = 31;
+
+ /**
+ * Maximum size of password == max (unrestricted) size of Blowfish key
+ */
+ // Blowfish spec limits keys to 448bit/56 bytes to ensure all bits of key affect all ciphertext
+ // bits, but technically algorithm handles 72 byte keys and most implementations support this.
+ internal const int MAX_PASSWORD_BYTES = 72;
+
+ /**
+ * Calculates the bcrypt hash of a password.
+ *
+ * This implements the raw bcrypt function as defined in the bcrypt specification, not
+ * the crypt encoded version implemented in OpenBSD.
+ *
+ * @param password the password bytes (up to 72 bytes) to use for this invocation.
+ * @param salt the 128 bit salt to use for this invocation.
+ * @param cost the bcrypt cost parameter. The cost of the bcrypt function grows as
+ * 2^cost
. Legal values are 4..31 inclusive.
+ * @return the output of the raw bcrypt operation: a 192 bit (24 byte) hash.
+ */
+ public static byte[] Generate(byte[] password, byte[] salt, int cost)
+ {
+ if (password == null)
+ throw new ArgumentNullException("password");
+ if (password.Length > MAX_PASSWORD_BYTES)
+ throw new ArgumentException("BCrypt password must be <= 72 bytes", "password");
+ if (salt == null)
+ throw new ArgumentNullException("salt");
+ if (salt.Length != SALT_SIZE_BYTES)
+ throw new ArgumentException("BCrypt salt must be 128 bits", "salt");
+ if (cost < MIN_COST || cost > MAX_COST)
+ throw new ArgumentException("BCrypt cost must be from 4..31", "cost");
+
+ return new BCrypt().DeriveRawKey(cost, salt, password);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/BaseKdfBytesGenerator.cs b/bc-sharp-crypto/src/crypto/generators/BaseKdfBytesGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bca420711b2404718ca000a5a0b7f7148fec695d
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/BaseKdfBytesGenerator.cs
@@ -0,0 +1,132 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+ *
+ * This implementation is based on ISO 18033/P1363a.
+ */
+ public class BaseKdfBytesGenerator
+ : IDerivationFunction
+ {
+ private int counterStart;
+ private IDigest digest;
+ private byte[] shared;
+ private byte[] iv;
+
+ /**
+ * Construct a KDF Parameters generator.
+ *
+ * @param counterStart value of counter.
+ * @param digest the digest to be used as the source of derived keys.
+ */
+ public BaseKdfBytesGenerator(int counterStart, IDigest digest)
+ {
+ this.counterStart = counterStart;
+ this.digest = digest;
+ }
+
+ public virtual void Init(IDerivationParameters parameters)
+ {
+ if (parameters is KdfParameters)
+ {
+ KdfParameters p = (KdfParameters)parameters;
+
+ shared = p.GetSharedSecret();
+ iv = p.GetIV();
+ }
+ else if (parameters is Iso18033KdfParameters)
+ {
+ Iso18033KdfParameters p = (Iso18033KdfParameters)parameters;
+
+ shared = p.GetSeed();
+ iv = null;
+ }
+ else
+ {
+ throw new ArgumentException("KDF parameters required for KDF Generator");
+ }
+ }
+
+ /**
+ * return the underlying digest.
+ */
+ public virtual IDigest Digest
+ {
+ get { return digest; }
+ }
+
+ /**
+ * fill len bytes of the output buffer with bytes generated from
+ * the derivation function.
+ *
+ * @throws ArgumentException if the size of the request will cause an overflow.
+ * @throws DataLengthException if the out buffer is too small.
+ */
+ public virtual int GenerateBytes(byte[] output, int outOff, int length)
+ {
+ if ((output.Length - length) < outOff)
+ throw new DataLengthException("output buffer too small");
+
+ long oBytes = length;
+ int outLen = digest.GetDigestSize();
+
+ //
+ // this is at odds with the standard implementation, the
+ // maximum value should be hBits * (2^32 - 1) where hBits
+ // is the digest output size in bits. We can't have an
+ // array with a long index at the moment...
+ //
+ if (oBytes > ((2L << 32) - 1))
+ throw new ArgumentException("Output length too large");
+
+ int cThreshold = (int)((oBytes + outLen - 1) / outLen);
+
+ byte[] dig = new byte[digest.GetDigestSize()];
+
+ byte[] C = new byte[4];
+ Pack.UInt32_To_BE((uint)counterStart, C, 0);
+
+ uint counterBase = (uint)(counterStart & ~0xFF);
+
+ for (int i = 0; i < cThreshold; i++)
+ {
+ digest.BlockUpdate(shared, 0, shared.Length);
+ digest.BlockUpdate(C, 0, 4);
+
+ if (iv != null)
+ {
+ digest.BlockUpdate(iv, 0, iv.Length);
+ }
+
+ digest.DoFinal(dig, 0);
+
+ if (length > outLen)
+ {
+ Array.Copy(dig, 0, output, outOff, outLen);
+ outOff += outLen;
+ length -= outLen;
+ }
+ else
+ {
+ Array.Copy(dig, 0, output, outOff, length);
+ }
+
+ if (++C[3] == 0)
+ {
+ counterBase += 0x100;
+ Pack.UInt32_To_BE(counterBase, C, 0);
+ }
+ }
+
+ digest.Reset();
+
+ return (int)oBytes;
+ }
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/crypto/generators/DHBasicKeyPairGenerator.cs b/bc-sharp-crypto/src/crypto/generators/DHBasicKeyPairGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..51b3af68723ea089f482c947177a42587d6f3f4a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/DHBasicKeyPairGenerator.cs
@@ -0,0 +1,38 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * a basic Diffie-Hellman key pair generator.
+ *
+ * This generates keys consistent for use with the basic algorithm for
+ * Diffie-Hellman.
+ */
+ public class DHBasicKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private DHKeyGenerationParameters param;
+
+ public virtual void Init(
+ KeyGenerationParameters parameters)
+ {
+ this.param = (DHKeyGenerationParameters)parameters;
+ }
+
+ public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.Instance;
+ DHParameters dhp = param.Parameters;
+
+ BigInteger x = helper.CalculatePrivate(dhp, param.Random);
+ BigInteger y = helper.CalculatePublic(dhp, x);
+
+ return new AsymmetricCipherKeyPair(
+ new DHPublicKeyParameters(y, dhp),
+ new DHPrivateKeyParameters(x, dhp));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/DHKeyGeneratorHelper.cs b/bc-sharp-crypto/src/crypto/generators/DHKeyGeneratorHelper.cs
new file mode 100644
index 0000000000000000000000000000000000000000..68aba64f79f3f27c2d7b20236aa252ff3d7912d5
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/DHKeyGeneratorHelper.cs
@@ -0,0 +1,72 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ class DHKeyGeneratorHelper
+ {
+ internal static readonly DHKeyGeneratorHelper Instance = new DHKeyGeneratorHelper();
+
+ private DHKeyGeneratorHelper()
+ {
+ }
+
+ internal BigInteger CalculatePrivate(
+ DHParameters dhParams,
+ SecureRandom random)
+ {
+ int limit = dhParams.L;
+
+ if (limit != 0)
+ {
+ int minWeight = limit >> 2;
+ for (;;)
+ {
+ BigInteger x = new BigInteger(limit, random).SetBit(limit - 1);
+ if (WNafUtilities.GetNafWeight(x) >= minWeight)
+ {
+ return x;
+ }
+ }
+ }
+
+ BigInteger min = BigInteger.Two;
+ int m = dhParams.M;
+ if (m != 0)
+ {
+ min = BigInteger.One.ShiftLeft(m - 1);
+ }
+
+ BigInteger q = dhParams.Q;
+ if (q == null)
+ {
+ q = dhParams.P;
+ }
+ BigInteger max = q.Subtract(BigInteger.Two);
+
+ {
+ int minWeight = max.BitLength >> 2;
+ for (;;)
+ {
+ BigInteger x = BigIntegers.CreateRandomInRange(min, max, random);
+ if (WNafUtilities.GetNafWeight(x) >= minWeight)
+ {
+ return x;
+ }
+ }
+ }
+ }
+
+ internal BigInteger CalculatePublic(
+ DHParameters dhParams,
+ BigInteger x)
+ {
+ return dhParams.G.ModPow(x, dhParams.P);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/DHKeyPairGenerator.cs b/bc-sharp-crypto/src/crypto/generators/DHKeyPairGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3bf58ba1b92fce5b8a18ebcd850c66c478b9defd
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/DHKeyPairGenerator.cs
@@ -0,0 +1,38 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * a Diffie-Hellman key pair generator.
+ *
+ * This generates keys consistent for use in the MTI/A0 key agreement protocol
+ * as described in "Handbook of Applied Cryptography", Pages 516-519.
+ */
+ public class DHKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private DHKeyGenerationParameters param;
+
+ public virtual void Init(
+ KeyGenerationParameters parameters)
+ {
+ this.param = (DHKeyGenerationParameters)parameters;
+ }
+
+ public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.Instance;
+ DHParameters dhp = param.Parameters;
+
+ BigInteger x = helper.CalculatePrivate(dhp, param.Random);
+ BigInteger y = helper.CalculatePublic(dhp, x);
+
+ return new AsymmetricCipherKeyPair(
+ new DHPublicKeyParameters(y, dhp),
+ new DHPrivateKeyParameters(x, dhp));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/DHParametersGenerator.cs b/bc-sharp-crypto/src/crypto/generators/DHParametersGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e752c84560de257b8eeb20cec4a3457ab6d0cd0f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/DHParametersGenerator.cs
@@ -0,0 +1,45 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class DHParametersGenerator
+ {
+ private int size;
+ private int certainty;
+ private SecureRandom random;
+
+ public virtual void Init(
+ int size,
+ int certainty,
+ SecureRandom random)
+ {
+ this.size = size;
+ this.certainty = certainty;
+ this.random = random;
+ }
+
+ /**
+ * which Generates the p and g values from the given parameters,
+ * returning the DHParameters object.
+ *
+ * Note: can take a while...
+ */
+ public virtual DHParameters GenerateParameters()
+ {
+ //
+ // find a safe prime p where p = 2*q + 1, where p and q are prime.
+ //
+ BigInteger[] safePrimes = DHParametersHelper.GenerateSafePrimes(size, certainty, random);
+
+ BigInteger p = safePrimes[0];
+ BigInteger q = safePrimes[1];
+ BigInteger g = DHParametersHelper.SelectGenerator(p, q, random);
+
+ return new DHParameters(p, g, q, BigInteger.Two, null);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/DHParametersHelper.cs b/bc-sharp-crypto/src/crypto/generators/DHParametersHelper.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3856904300ef83b5405f5bf51b2d6bd082df2c65
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/DHParametersHelper.cs
@@ -0,0 +1,156 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ internal class DHParametersHelper
+ {
+ private static readonly BigInteger Six = BigInteger.ValueOf(6);
+
+ private static readonly int[][] primeLists = BigInteger.primeLists;
+ private static readonly int[] primeProducts = BigInteger.primeProducts;
+ private static readonly BigInteger[] BigPrimeProducts = ConstructBigPrimeProducts(primeProducts);
+
+ private static BigInteger[] ConstructBigPrimeProducts(int[] primeProducts)
+ {
+ BigInteger[] bpp = new BigInteger[primeProducts.Length];
+ for (int i = 0; i < bpp.Length; ++i)
+ {
+ bpp[i] = BigInteger.ValueOf(primeProducts[i]);
+ }
+ return bpp;
+ }
+
+ /*
+ * Finds a pair of prime BigInteger's {p, q: p = 2q + 1}
+ *
+ * (see: Handbook of Applied Cryptography 4.86)
+ */
+ internal static BigInteger[] GenerateSafePrimes(int size, int certainty, SecureRandom random)
+ {
+ BigInteger p, q;
+ int qLength = size - 1;
+ int minWeight = size >> 2;
+
+ if (size <= 32)
+ {
+ for (;;)
+ {
+ q = new BigInteger(qLength, 2, random);
+
+ p = q.ShiftLeft(1).Add(BigInteger.One);
+
+ if (!p.IsProbablePrime(certainty, true))
+ continue;
+
+ if (certainty > 2 && !q.IsProbablePrime(certainty, true))
+ continue;
+
+ break;
+ }
+ }
+ else
+ {
+ // Note: Modified from Java version for speed
+ for (;;)
+ {
+ q = new BigInteger(qLength, 0, random);
+
+ retry:
+ for (int i = 0; i < primeLists.Length; ++i)
+ {
+ int test = q.Remainder(BigPrimeProducts[i]).IntValue;
+
+ if (i == 0)
+ {
+ int rem3 = test % 3;
+ if (rem3 != 2)
+ {
+ int diff = 2 * rem3 + 2;
+ q = q.Add(BigInteger.ValueOf(diff));
+ test = (test + diff) % primeProducts[i];
+ }
+ }
+
+ int[] primeList = primeLists[i];
+ for (int j = 0; j < primeList.Length; ++j)
+ {
+ int prime = primeList[j];
+ int qRem = test % prime;
+ if (qRem == 0 || qRem == (prime >> 1))
+ {
+ q = q.Add(Six);
+ goto retry;
+ }
+ }
+ }
+
+ if (q.BitLength != qLength)
+ continue;
+
+ if (!q.RabinMillerTest(2, random, true))
+ continue;
+
+ p = q.ShiftLeft(1).Add(BigInteger.One);
+
+ if (!p.RabinMillerTest(certainty, random, true))
+ continue;
+
+ if (certainty > 2 && !q.RabinMillerTest(certainty - 2, random, true))
+ continue;
+
+ /*
+ * Require a minimum weight of the NAF representation, since low-weight primes may be
+ * weak against a version of the number-field-sieve for the discrete-logarithm-problem.
+ *
+ * See "The number field sieve for integers of low weight", Oliver Schirokauer.
+ */
+ if (WNafUtilities.GetNafWeight(p) < minWeight)
+ continue;
+
+ break;
+ }
+ }
+
+ return new BigInteger[] { p, q };
+ }
+
+ /*
+ * Select a high order element of the multiplicative group Zp*
+ *
+ * p and q must be s.t. p = 2*q + 1, where p and q are prime (see generateSafePrimes)
+ */
+ internal static BigInteger SelectGenerator(BigInteger p, BigInteger q, SecureRandom random)
+ {
+ BigInteger pMinusTwo = p.Subtract(BigInteger.Two);
+ BigInteger g;
+
+ /*
+ * (see: Handbook of Applied Cryptography 4.80)
+ */
+// do
+// {
+// g = BigIntegers.CreateRandomInRange(BigInteger.Two, pMinusTwo, random);
+// }
+// while (g.ModPow(BigInteger.Two, p).Equals(BigInteger.One)
+// || g.ModPow(q, p).Equals(BigInteger.One));
+
+ /*
+ * RFC 2631 2.2.1.2 (and see: Handbook of Applied Cryptography 4.81)
+ */
+ do
+ {
+ BigInteger h = BigIntegers.CreateRandomInRange(BigInteger.Two, pMinusTwo, random);
+
+ g = h.ModPow(BigInteger.Two, p);
+ }
+ while (g.Equals(BigInteger.One));
+
+ return g;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/DesEdeKeyGenerator.cs b/bc-sharp-crypto/src/crypto/generators/DesEdeKeyGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..904cc71f170ae31b006348e09aeeb25c187caebc
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/DesEdeKeyGenerator.cs
@@ -0,0 +1,67 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class DesEdeKeyGenerator
+ : DesKeyGenerator
+ {
+ public DesEdeKeyGenerator()
+ {
+ }
+
+ internal DesEdeKeyGenerator(
+ int defaultStrength)
+ : base(defaultStrength)
+ {
+ }
+
+ /**
+ * initialise the key generator - if strength is set to zero
+ * the key Generated will be 192 bits in size, otherwise
+ * strength can be 128 or 192 (or 112 or 168 if you don't count
+ * parity bits), depending on whether you wish to do 2-key or 3-key
+ * triple DES.
+ *
+ * @param param the parameters to be used for key generation
+ */
+ protected override void engineInit(
+ KeyGenerationParameters parameters)
+ {
+ this.random = parameters.Random;
+ this.strength = (parameters.Strength + 7) / 8;
+
+ if (strength == 0 || strength == (168 / 8))
+ {
+ strength = DesEdeParameters.DesEdeKeyLength;
+ }
+ else if (strength == (112 / 8))
+ {
+ strength = 2 * DesEdeParameters.DesKeyLength;
+ }
+ else if (strength != DesEdeParameters.DesEdeKeyLength
+ && strength != (2 * DesEdeParameters.DesKeyLength))
+ {
+ throw new ArgumentException("DESede key must be "
+ + (DesEdeParameters.DesEdeKeyLength * 8) + " or "
+ + (2 * 8 * DesEdeParameters.DesKeyLength)
+ + " bits long.");
+ }
+ }
+
+ protected override byte[] engineGenerateKey()
+ {
+ byte[] newKey = new byte[strength];
+
+ do
+ {
+ random.NextBytes(newKey);
+ DesEdeParameters.SetOddParity(newKey);
+ }
+ while (DesEdeParameters.IsWeakKey(newKey, 0, newKey.Length) || !DesEdeParameters.IsRealEdeKey(newKey, 0));
+
+ return newKey;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/DesKeyGenerator.cs b/bc-sharp-crypto/src/crypto/generators/DesKeyGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4c2051d895bea9c41b21ad35780bd59d330df14d
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/DesKeyGenerator.cs
@@ -0,0 +1,57 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class DesKeyGenerator
+ : CipherKeyGenerator
+ {
+ public DesKeyGenerator()
+ {
+ }
+
+ internal DesKeyGenerator(
+ int defaultStrength)
+ : base(defaultStrength)
+ {
+ }
+
+ /**
+ * initialise the key generator - if strength is set to zero
+ * the key generated will be 64 bits in size, otherwise
+ * strength can be 64 or 56 bits (if you don't count the parity bits).
+ *
+ * @param param the parameters to be used for key generation
+ */
+ protected override void engineInit(
+ KeyGenerationParameters parameters)
+ {
+ base.engineInit(parameters);
+
+ if (strength == 0 || strength == (56 / 8))
+ {
+ strength = DesParameters.DesKeyLength;
+ }
+ else if (strength != DesParameters.DesKeyLength)
+ {
+ throw new ArgumentException(
+ "DES key must be " + (DesParameters.DesKeyLength * 8) + " bits long.");
+ }
+ }
+
+ protected override byte[] engineGenerateKey()
+ {
+ byte[] newKey = new byte[DesParameters.DesKeyLength];
+
+ do
+ {
+ random.NextBytes(newKey);
+ DesParameters.SetOddParity(newKey);
+ }
+ while (DesParameters.IsWeakKey(newKey, 0));
+
+ return newKey;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/DsaKeyPairGenerator.cs b/bc-sharp-crypto/src/crypto/generators/DsaKeyPairGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1c9ce5a16a7e761c072ce0af2a28eaf1e09da434
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/DsaKeyPairGenerator.cs
@@ -0,0 +1,72 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * a DSA key pair generator.
+ *
+ * This Generates DSA keys in line with the method described
+ * in FIPS 186-3 B.1 FFC Key Pair Generation .
+ */
+ public class DsaKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private static readonly BigInteger One = BigInteger.One;
+
+ private DsaKeyGenerationParameters param;
+
+ public void Init(
+ KeyGenerationParameters parameters)
+ {
+ if (parameters == null)
+ throw new ArgumentNullException("parameters");
+
+ // Note: If we start accepting instances of KeyGenerationParameters,
+ // must apply constraint checking on strength (see DsaParametersGenerator.Init)
+
+ this.param = (DsaKeyGenerationParameters) parameters;
+ }
+
+ public AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ DsaParameters dsaParams = param.Parameters;
+
+ BigInteger x = GeneratePrivateKey(dsaParams.Q, param.Random);
+ BigInteger y = CalculatePublicKey(dsaParams.P, dsaParams.G, x);
+
+ return new AsymmetricCipherKeyPair(
+ new DsaPublicKeyParameters(y, dsaParams),
+ new DsaPrivateKeyParameters(x, dsaParams));
+ }
+
+ private static BigInteger GeneratePrivateKey(BigInteger q, SecureRandom random)
+ {
+ // B.1.2 Key Pair Generation by Testing Candidates
+ int minWeight = q.BitLength >> 2;
+ for (;;)
+ {
+ // TODO Prefer this method? (change test cases that used fixed random)
+ // B.1.1 Key Pair Generation Using Extra Random Bits
+ //BigInteger x = new BigInteger(q.BitLength + 64, random).Mod(q.Subtract(One)).Add(One);
+
+ BigInteger x = BigIntegers.CreateRandomInRange(One, q.Subtract(One), random);
+ if (WNafUtilities.GetNafWeight(x) >= minWeight)
+ {
+ return x;
+ }
+ }
+ }
+
+ private static BigInteger CalculatePublicKey(BigInteger p, BigInteger g, BigInteger x)
+ {
+ return g.ModPow(x, p);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/DsaParametersGenerator.cs b/bc-sharp-crypto/src/crypto/generators/DsaParametersGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d7ae3ec5482968945b53b5009f659b5f45863e37
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/DsaParametersGenerator.cs
@@ -0,0 +1,355 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generate suitable parameters for DSA, in line with FIPS 186-2, or FIPS 186-3.
+ */
+ public class DsaParametersGenerator
+ {
+ private IDigest digest;
+ private int L, N;
+ private int certainty;
+ private SecureRandom random;
+ private bool use186_3;
+ private int usageIndex;
+
+ public DsaParametersGenerator()
+ : this(new Sha1Digest())
+ {
+ }
+
+ public DsaParametersGenerator(IDigest digest)
+ {
+ this.digest = digest;
+ }
+
+ /// Initialise the generator
+ /// This form can only be used for older DSA (pre-DSA2) parameters
+ /// the size of keys in bits (from 512 up to 1024, and a multiple of 64)
+ /// measure of robustness of primes (at least 80 for FIPS 186-2 compliance)
+ /// the source of randomness to use
+ public virtual void Init(
+ int size,
+ int certainty,
+ SecureRandom random)
+ {
+ if (!IsValidDsaStrength(size))
+ throw new ArgumentException("size must be from 512 - 1024 and a multiple of 64", "size");
+
+ this.use186_3 = false;
+ this.L = size;
+ this.N = GetDefaultN(size);
+ this.certainty = certainty;
+ this.random = random;
+ }
+
+ /// Initialise the generator for DSA 2
+ /// You must use this Init method if you need to generate parameters for DSA 2 keys
+ /// An instance of DsaParameterGenerationParameters used to configure this generator
+ public virtual void Init(DsaParameterGenerationParameters parameters)
+ {
+ // TODO Should we enforce the minimum 'certainty' values as per C.3 Table C.1?
+ this.use186_3 = true;
+ this.L = parameters.L;
+ this.N = parameters.N;
+ this.certainty = parameters.Certainty;
+ this.random = parameters.Random;
+ this.usageIndex = parameters.UsageIndex;
+
+ if ((L < 1024 || L > 3072) || L % 1024 != 0)
+ throw new ArgumentException("Values must be between 1024 and 3072 and a multiple of 1024", "L");
+ if (L == 1024 && N != 160)
+ throw new ArgumentException("N must be 160 for L = 1024");
+ if (L == 2048 && (N != 224 && N != 256))
+ throw new ArgumentException("N must be 224 or 256 for L = 2048");
+ if (L == 3072 && N != 256)
+ throw new ArgumentException("N must be 256 for L = 3072");
+
+ if (digest.GetDigestSize() * 8 < N)
+ throw new InvalidOperationException("Digest output size too small for value of N");
+ }
+
+ /// Generates a set of DsaParameters
+ /// Can take a while...
+ public virtual DsaParameters GenerateParameters()
+ {
+ return use186_3
+ ? GenerateParameters_FIPS186_3()
+ : GenerateParameters_FIPS186_2();
+ }
+
+ protected virtual DsaParameters GenerateParameters_FIPS186_2()
+ {
+ byte[] seed = new byte[20];
+ byte[] part1 = new byte[20];
+ byte[] part2 = new byte[20];
+ byte[] u = new byte[20];
+ int n = (L - 1) / 160;
+ byte[] w = new byte[L / 8];
+
+ if (!(digest is Sha1Digest))
+ throw new InvalidOperationException("can only use SHA-1 for generating FIPS 186-2 parameters");
+
+ for (;;)
+ {
+ random.NextBytes(seed);
+
+ Hash(digest, seed, part1);
+ Array.Copy(seed, 0, part2, 0, seed.Length);
+ Inc(part2);
+ Hash(digest, part2, part2);
+
+ for (int i = 0; i != u.Length; i++)
+ {
+ u[i] = (byte)(part1[i] ^ part2[i]);
+ }
+
+ u[0] |= (byte)0x80;
+ u[19] |= (byte)0x01;
+
+ BigInteger q = new BigInteger(1, u);
+
+ if (!q.IsProbablePrime(certainty))
+ continue;
+
+ byte[] offset = Arrays.Clone(seed);
+ Inc(offset);
+
+ for (int counter = 0; counter < 4096; ++counter)
+ {
+ for (int k = 0; k < n; k++)
+ {
+ Inc(offset);
+ Hash(digest, offset, part1);
+ Array.Copy(part1, 0, w, w.Length - (k + 1) * part1.Length, part1.Length);
+ }
+
+ Inc(offset);
+ Hash(digest, offset, part1);
+ Array.Copy(part1, part1.Length - ((w.Length - (n) * part1.Length)), w, 0, w.Length - n * part1.Length);
+
+ w[0] |= (byte)0x80;
+
+ BigInteger x = new BigInteger(1, w);
+
+ BigInteger c = x.Mod(q.ShiftLeft(1));
+
+ BigInteger p = x.Subtract(c.Subtract(BigInteger.One));
+
+ if (p.BitLength != L)
+ continue;
+
+ if (p.IsProbablePrime(certainty))
+ {
+ BigInteger g = CalculateGenerator_FIPS186_2(p, q, random);
+
+ return new DsaParameters(p, q, g, new DsaValidationParameters(seed, counter));
+ }
+ }
+ }
+ }
+
+ protected virtual BigInteger CalculateGenerator_FIPS186_2(BigInteger p, BigInteger q, SecureRandom r)
+ {
+ BigInteger e = p.Subtract(BigInteger.One).Divide(q);
+ BigInteger pSub2 = p.Subtract(BigInteger.Two);
+
+ for (;;)
+ {
+ BigInteger h = BigIntegers.CreateRandomInRange(BigInteger.Two, pSub2, r);
+ BigInteger g = h.ModPow(e, p);
+
+ if (g.BitLength > 1)
+ return g;
+ }
+ }
+
+ /**
+ * generate suitable parameters for DSA, in line with
+ * FIPS 186-3 A.1 Generation of the FFC Primes p and q .
+ */
+ protected virtual DsaParameters GenerateParameters_FIPS186_3()
+ {
+// A.1.1.2 Generation of the Probable Primes p and q Using an Approved Hash Function
+ IDigest d = digest;
+ int outlen = d.GetDigestSize() * 8;
+
+// 1. Check that the (L, N) pair is in the list of acceptable (L, N pairs) (see Section 4.2). If
+// the pair is not in the list, then return INVALID.
+ // Note: checked at initialisation
+
+// 2. If (seedlen < N), then return INVALID.
+ // FIXME This should be configurable (must be >= N)
+ int seedlen = N;
+ byte[] seed = new byte[seedlen / 8];
+
+// 3. n = ceiling(L ⁄ outlen) – 1.
+ int n = (L - 1) / outlen;
+
+// 4. b = L – 1 – (n ∗ outlen).
+ int b = (L - 1) % outlen;
+
+ byte[] output = new byte[d.GetDigestSize()];
+ for (;;)
+ {
+// 5. Get an arbitrary sequence of seedlen bits as the domain_parameter_seed.
+ random.NextBytes(seed);
+
+// 6. U = Hash (domain_parameter_seed) mod 2^(N–1).
+ Hash(d, seed, output);
+ BigInteger U = new BigInteger(1, output).Mod(BigInteger.One.ShiftLeft(N - 1));
+
+// 7. q = 2^(N–1) + U + 1 – ( U mod 2).
+ BigInteger q = U.SetBit(0).SetBit(N - 1);
+
+// 8. Test whether or not q is prime as specified in Appendix C.3.
+ // TODO Review C.3 for primality checking
+ if (!q.IsProbablePrime(certainty))
+ {
+// 9. If q is not a prime, then go to step 5.
+ continue;
+ }
+
+// 10. offset = 1.
+ // Note: 'offset' value managed incrementally
+ byte[] offset = Arrays.Clone(seed);
+
+// 11. For counter = 0 to (4L – 1) do
+ int counterLimit = 4 * L;
+ for (int counter = 0; counter < counterLimit; ++counter)
+ {
+// 11.1 For j = 0 to n do
+// Vj = Hash ((domain_parameter_seed + offset + j) mod 2^seedlen).
+// 11.2 W = V0 + (V1 ∗ 2^outlen) + ... + (V^(n–1) ∗ 2^((n–1) ∗ outlen)) + ((Vn mod 2^b) ∗ 2^(n ∗ outlen)).
+ // TODO Assemble w as a byte array
+ BigInteger W = BigInteger.Zero;
+ for (int j = 0, exp = 0; j <= n; ++j, exp += outlen)
+ {
+ Inc(offset);
+ Hash(d, offset, output);
+
+ BigInteger Vj = new BigInteger(1, output);
+ if (j == n)
+ {
+ Vj = Vj.Mod(BigInteger.One.ShiftLeft(b));
+ }
+
+ W = W.Add(Vj.ShiftLeft(exp));
+ }
+
+// 11.3 X = W + 2^(L–1). Comment: 0 ≤ W < 2L–1; hence, 2L–1 ≤ X < 2L.
+ BigInteger X = W.Add(BigInteger.One.ShiftLeft(L - 1));
+
+// 11.4 c = X mod 2q.
+ BigInteger c = X.Mod(q.ShiftLeft(1));
+
+// 11.5 p = X - (c - 1). Comment: p ≡ 1 (mod 2q).
+ BigInteger p = X.Subtract(c.Subtract(BigInteger.One));
+
+ // 11.6 If (p < 2^(L - 1)), then go to step 11.9
+ if (p.BitLength != L)
+ continue;
+
+// 11.7 Test whether or not p is prime as specified in Appendix C.3.
+ // TODO Review C.3 for primality checking
+ if (p.IsProbablePrime(certainty))
+ {
+// 11.8 If p is determined to be prime, then return VALID and the values of p, q and
+// (optionally) the values of domain_parameter_seed and counter.
+ // TODO Make configurable (8-bit unsigned)?
+
+ if (usageIndex >= 0)
+ {
+ BigInteger g = CalculateGenerator_FIPS186_3_Verifiable(d, p, q, seed, usageIndex);
+ if (g != null)
+ return new DsaParameters(p, q, g, new DsaValidationParameters(seed, counter, usageIndex));
+ }
+
+ {
+ BigInteger g = CalculateGenerator_FIPS186_3_Unverifiable(p, q, random);
+
+ return new DsaParameters(p, q, g, new DsaValidationParameters(seed, counter));
+ }
+ }
+
+// 11.9 offset = offset + n + 1. Comment: Increment offset; then, as part of
+// the loop in step 11, increment counter; if
+// counter < 4L, repeat steps 11.1 through 11.8.
+ // Note: 'offset' value already incremented in inner loop
+ }
+// 12. Go to step 5.
+ }
+ }
+
+ protected virtual BigInteger CalculateGenerator_FIPS186_3_Unverifiable(BigInteger p, BigInteger q,
+ SecureRandom r)
+ {
+ return CalculateGenerator_FIPS186_2(p, q, r);
+ }
+
+ protected virtual BigInteger CalculateGenerator_FIPS186_3_Verifiable(IDigest d, BigInteger p, BigInteger q,
+ byte[] seed, int index)
+ {
+ // A.2.3 Verifiable Canonical Generation of the Generator g
+ BigInteger e = p.Subtract(BigInteger.One).Divide(q);
+ byte[] ggen = Hex.Decode("6767656E");
+
+ // 7. U = domain_parameter_seed || "ggen" || index || count.
+ byte[] U = new byte[seed.Length + ggen.Length + 1 + 2];
+ Array.Copy(seed, 0, U, 0, seed.Length);
+ Array.Copy(ggen, 0, U, seed.Length, ggen.Length);
+ U[U.Length - 3] = (byte)index;
+
+ byte[] w = new byte[d.GetDigestSize()];
+ for (int count = 1; count < (1 << 16); ++count)
+ {
+ Inc(U);
+ Hash(d, U, w);
+ BigInteger W = new BigInteger(1, w);
+ BigInteger g = W.ModPow(e, p);
+
+ if (g.CompareTo(BigInteger.Two) >= 0)
+ return g;
+ }
+
+ return null;
+ }
+
+ private static bool IsValidDsaStrength(
+ int strength)
+ {
+ return strength >= 512 && strength <= 1024 && strength % 64 == 0;
+ }
+
+ protected static void Hash(IDigest d, byte[] input, byte[] output)
+ {
+ d.BlockUpdate(input, 0, input.Length);
+ d.DoFinal(output, 0);
+ }
+
+ private static int GetDefaultN(int L)
+ {
+ return L > 1024 ? 256 : 160;
+ }
+
+ protected static void Inc(byte[] buf)
+ {
+ for (int i = buf.Length - 1; i >= 0; --i)
+ {
+ byte b = (byte)(buf[i] + 1);
+ buf[i] = b;
+
+ if (b != 0)
+ break;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/ECKeyPairGenerator.cs b/bc-sharp-crypto/src/crypto/generators/ECKeyPairGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..26bc06e145d1c47011450e02fb0fbd3aade6e45b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/ECKeyPairGenerator.cs
@@ -0,0 +1,162 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.EC;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class ECKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private readonly string algorithm;
+
+ private ECDomainParameters parameters;
+ private DerObjectIdentifier publicKeyParamSet;
+ private SecureRandom random;
+
+ public ECKeyPairGenerator()
+ : this("EC")
+ {
+ }
+
+ public ECKeyPairGenerator(
+ string algorithm)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+
+ this.algorithm = ECKeyParameters.VerifyAlgorithmName(algorithm);
+ }
+
+ public void Init(
+ KeyGenerationParameters parameters)
+ {
+ if (parameters is ECKeyGenerationParameters)
+ {
+ ECKeyGenerationParameters ecP = (ECKeyGenerationParameters) parameters;
+
+ this.publicKeyParamSet = ecP.PublicKeyParamSet;
+ this.parameters = ecP.DomainParameters;
+ }
+ else
+ {
+ DerObjectIdentifier oid;
+ switch (parameters.Strength)
+ {
+ case 192:
+ oid = X9ObjectIdentifiers.Prime192v1;
+ break;
+ case 224:
+ oid = SecObjectIdentifiers.SecP224r1;
+ break;
+ case 239:
+ oid = X9ObjectIdentifiers.Prime239v1;
+ break;
+ case 256:
+ oid = X9ObjectIdentifiers.Prime256v1;
+ break;
+ case 384:
+ oid = SecObjectIdentifiers.SecP384r1;
+ break;
+ case 521:
+ oid = SecObjectIdentifiers.SecP521r1;
+ break;
+ default:
+ throw new InvalidParameterException("unknown key size.");
+ }
+
+ X9ECParameters ecps = FindECCurveByOid(oid);
+
+ this.publicKeyParamSet = oid;
+ this.parameters = new ECDomainParameters(
+ ecps.Curve, ecps.G, ecps.N, ecps.H, ecps.GetSeed());
+ }
+
+ this.random = parameters.Random;
+
+ if (this.random == null)
+ {
+ this.random = new SecureRandom();
+ }
+ }
+
+ /**
+ * Given the domain parameters this routine generates an EC key
+ * pair in accordance with X9.62 section 5.2.1 pages 26, 27.
+ */
+ public AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ BigInteger n = parameters.N;
+ BigInteger d;
+ int minWeight = n.BitLength >> 2;
+
+ for (;;)
+ {
+ d = new BigInteger(n.BitLength, random);
+
+ if (d.CompareTo(BigInteger.Two) < 0 || d.CompareTo(n) >= 0)
+ continue;
+
+ if (WNafUtilities.GetNafWeight(d) < minWeight)
+ continue;
+
+ break;
+ }
+
+ ECPoint q = CreateBasePointMultiplier().Multiply(parameters.G, d);
+
+ if (publicKeyParamSet != null)
+ {
+ return new AsymmetricCipherKeyPair(
+ new ECPublicKeyParameters(algorithm, q, publicKeyParamSet),
+ new ECPrivateKeyParameters(algorithm, d, publicKeyParamSet));
+ }
+
+ return new AsymmetricCipherKeyPair(
+ new ECPublicKeyParameters(algorithm, q, parameters),
+ new ECPrivateKeyParameters(algorithm, d, parameters));
+ }
+
+ protected virtual ECMultiplier CreateBasePointMultiplier()
+ {
+ return new FixedPointCombMultiplier();
+ }
+
+ internal static X9ECParameters FindECCurveByOid(DerObjectIdentifier oid)
+ {
+ // TODO ECGost3410NamedCurves support (returns ECDomainParameters though)
+
+ X9ECParameters ecP = CustomNamedCurves.GetByOid(oid);
+ if (ecP == null)
+ {
+ ecP = ECNamedCurveTable.GetByOid(oid);
+ }
+ return ecP;
+ }
+
+ internal static ECPublicKeyParameters GetCorrespondingPublicKey(
+ ECPrivateKeyParameters privKey)
+ {
+ ECDomainParameters ec = privKey.Parameters;
+ ECPoint q = new FixedPointCombMultiplier().Multiply(ec.G, privKey.D);
+
+ if (privKey.PublicKeyParamSet != null)
+ {
+ return new ECPublicKeyParameters(privKey.AlgorithmName, q, privKey.PublicKeyParamSet);
+ }
+
+ return new ECPublicKeyParameters(privKey.AlgorithmName, q, ec);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/ElGamalKeyPairGenerator.cs b/bc-sharp-crypto/src/crypto/generators/ElGamalKeyPairGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..227e7fe94f6ee15b0145b2c984d35d20a4527639
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/ElGamalKeyPairGenerator.cs
@@ -0,0 +1,40 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * a ElGamal key pair generator.
+ *
+ * This Generates keys consistent for use with ElGamal as described in
+ * page 164 of "Handbook of Applied Cryptography".
+ */
+ public class ElGamalKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private ElGamalKeyGenerationParameters param;
+
+ public void Init(
+ KeyGenerationParameters parameters)
+ {
+ this.param = (ElGamalKeyGenerationParameters) parameters;
+ }
+
+ public AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.Instance;
+ ElGamalParameters egp = param.Parameters;
+ DHParameters dhp = new DHParameters(egp.P, egp.G, null, 0, egp.L);
+
+ BigInteger x = helper.CalculatePrivate(dhp, param.Random);
+ BigInteger y = helper.CalculatePublic(dhp, x);
+
+ return new AsymmetricCipherKeyPair(
+ new ElGamalPublicKeyParameters(y, egp),
+ new ElGamalPrivateKeyParameters(x, egp));
+ }
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/ElGamalParametersGenerator.cs b/bc-sharp-crypto/src/crypto/generators/ElGamalParametersGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8443bb00e9ba2ee0fa17675de0e4d6a893c4ca4f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/ElGamalParametersGenerator.cs
@@ -0,0 +1,46 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class ElGamalParametersGenerator
+ {
+ private int size;
+ private int certainty;
+ private SecureRandom random;
+
+ public void Init(
+ int size,
+ int certainty,
+ SecureRandom random)
+ {
+ this.size = size;
+ this.certainty = certainty;
+ this.random = random;
+ }
+
+ /**
+ * which Generates the p and g values from the given parameters,
+ * returning the ElGamalParameters object.
+ *
+ * Note: can take a while...
+ *
+ */
+ public ElGamalParameters GenerateParameters()
+ {
+ //
+ // find a safe prime p where p = 2*q + 1, where p and q are prime.
+ //
+ BigInteger[] safePrimes = DHParametersHelper.GenerateSafePrimes(size, certainty, random);
+
+ BigInteger p = safePrimes[0];
+ BigInteger q = safePrimes[1];
+ BigInteger g = DHParametersHelper.SelectGenerator(p, q, random);
+
+ return new ElGamalParameters(p, g);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/GOST3410KeyPairGenerator.cs b/bc-sharp-crypto/src/crypto/generators/GOST3410KeyPairGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..520820bfaade2319981cda4860dc4ae71f91ee7e
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/GOST3410KeyPairGenerator.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * a GOST3410 key pair generator.
+ * This generates GOST3410 keys in line with the method described
+ * in GOST R 34.10-94.
+ */
+ public class Gost3410KeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private Gost3410KeyGenerationParameters param;
+
+ public void Init(
+ KeyGenerationParameters parameters)
+ {
+ if (parameters is Gost3410KeyGenerationParameters)
+ {
+ this.param = (Gost3410KeyGenerationParameters) parameters;
+ }
+ else
+ {
+ Gost3410KeyGenerationParameters kgp = new Gost3410KeyGenerationParameters(
+ parameters.Random,
+ CryptoProObjectIdentifiers.GostR3410x94CryptoProA);
+
+ if (parameters.Strength != kgp.Parameters.P.BitLength - 1)
+ {
+ // TODO Should we complain?
+ }
+
+ this.param = kgp;
+ }
+ }
+
+ public AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ SecureRandom random = param.Random;
+ Gost3410Parameters gost3410Params = param.Parameters;
+
+ BigInteger q = gost3410Params.Q, x;
+
+ int minWeight = 64;
+ for (;;)
+ {
+ x = new BigInteger(256, random);
+
+ if (x.SignValue < 1 || x.CompareTo(q) >= 0)
+ continue;
+
+ if (WNafUtilities.GetNafWeight(x) < minWeight)
+ continue;
+
+ break;
+ }
+
+ BigInteger p = gost3410Params.P;
+ BigInteger a = gost3410Params.A;
+
+ // calculate the public key.
+ BigInteger y = a.ModPow(x, p);
+
+ if (param.PublicKeyParamSet != null)
+ {
+ return new AsymmetricCipherKeyPair(
+ new Gost3410PublicKeyParameters(y, param.PublicKeyParamSet),
+ new Gost3410PrivateKeyParameters(x, param.PublicKeyParamSet));
+ }
+
+ return new AsymmetricCipherKeyPair(
+ new Gost3410PublicKeyParameters(y, gost3410Params),
+ new Gost3410PrivateKeyParameters(x, gost3410Params));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/GOST3410ParametersGenerator.cs b/bc-sharp-crypto/src/crypto/generators/GOST3410ParametersGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..52a9f5a82daf6cc606a81af1f99a45a9fddeeb07
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/GOST3410ParametersGenerator.cs
@@ -0,0 +1,530 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * generate suitable parameters for GOST3410.
+ */
+ public class Gost3410ParametersGenerator
+ {
+ private int size;
+ private int typeproc;
+ private SecureRandom init_random;
+
+ /**
+ * initialise the key generator.
+ *
+ * @param size size of the key
+ * @param typeProcedure type procedure A,B = 1; A',B' - else
+ * @param random random byte source.
+ */
+ public void Init(
+ int size,
+ int typeProcedure,
+ SecureRandom random)
+ {
+ this.size = size;
+ this.typeproc = typeProcedure;
+ this.init_random = random;
+ }
+
+ //Procedure A
+ private int procedure_A(int x0, int c, BigInteger[] pq, int size)
+ {
+ //Verify and perform condition: 065536)
+ {
+ x0 = init_random.NextInt()/32768;
+ }
+
+ while((c<0 || c>65536) || (c/2==0))
+ {
+ c = init_random.NextInt()/32768 + 1;
+ }
+
+ BigInteger C = BigInteger.ValueOf(c);
+ BigInteger constA16 = BigInteger.ValueOf(19381);
+
+ //step1
+ BigInteger[] y = new BigInteger[1]; // begin length = 1
+ y[0] = BigInteger.ValueOf(x0);
+
+ //step 2
+ int[] t = new int[1]; // t - orders; begin length = 1
+ t[0] = size;
+ int s = 0;
+ for (int i=0; t[i]>=17; i++)
+ {
+ // extension array t
+ int[] tmp_t = new int[t.Length + 1]; ///////////////
+ Array.Copy(t,0,tmp_t,0,t.Length); // extension
+ t = new int[tmp_t.Length]; // array t
+ Array.Copy(tmp_t, 0, t, 0, tmp_t.Length); ///////////////
+
+ t[i+1] = t[i]/2;
+ s = i+1;
+ }
+
+ //step3
+ BigInteger[] p = new BigInteger[s+1];
+ p[s] = new BigInteger("8003",16); //set min prime number length 16 bit
+
+ int m = s-1; //step4
+
+ for (int i=0; i t[m])
+ {
+ goto step6; //step 12
+ }
+
+ p[m] = NByLastP.Add(BigInteger.One);
+
+ //step13
+ if (BigInteger.Two.ModPow(NByLastP, p[m]).CompareTo(BigInteger.One) == 0
+ && BigInteger.Two.ModPow(N, p[m]).CompareTo(BigInteger.One) != 0)
+ {
+ break;
+ }
+
+ N = N.Add(BigInteger.Two);
+ }
+
+ if (--m < 0)
+ {
+ pq[0] = p[0];
+ pq[1] = p[1];
+ return y[0].IntValue; //return for procedure B step 2
+ }
+
+ break; //step 14
+ }
+ }
+ return y[0].IntValue;
+ }
+
+ //Procedure A'
+ private long procedure_Aa(long x0, long c, BigInteger[] pq, int size)
+ {
+ //Verify and perform condition: 04294967296L)
+ {
+ x0 = init_random.NextInt()*2;
+ }
+
+ while((c<0 || c>4294967296L) || (c/2==0))
+ {
+ c = init_random.NextInt()*2+1;
+ }
+
+ BigInteger C = BigInteger.ValueOf(c);
+ BigInteger constA32 = BigInteger.ValueOf(97781173);
+
+ //step1
+ BigInteger[] y = new BigInteger[1]; // begin length = 1
+ y[0] = BigInteger.ValueOf(x0);
+
+ //step 2
+ int[] t = new int[1]; // t - orders; begin length = 1
+ t[0] = size;
+ int s = 0;
+ for (int i=0; t[i]>=33; i++)
+ {
+ // extension array t
+ int[] tmp_t = new int[t.Length + 1]; ///////////////
+ Array.Copy(t,0,tmp_t,0,t.Length); // extension
+ t = new int[tmp_t.Length]; // array t
+ Array.Copy(tmp_t, 0, t, 0, tmp_t.Length); ///////////////
+
+ t[i+1] = t[i]/2;
+ s = i+1;
+ }
+
+ //step3
+ BigInteger[] p = new BigInteger[s+1];
+ p[s] = new BigInteger("8000000B",16); //set min prime number length 32 bit
+
+ int m = s-1; //step4
+
+ for (int i=0; i t[m])
+ {
+ goto step6; //step 12
+ }
+
+ p[m] = NByLastP.Add(BigInteger.One);
+
+ //step13
+ if (BigInteger.Two.ModPow(NByLastP, p[m]).CompareTo(BigInteger.One) == 0
+ && BigInteger.Two.ModPow(N, p[m]).CompareTo(BigInteger.One) != 0)
+ {
+ break;
+ }
+
+ N = N.Add(BigInteger.Two);
+ }
+
+ if (--m < 0)
+ {
+ pq[0] = p[0];
+ pq[1] = p[1];
+ return y[0].LongValue; //return for procedure B' step 2
+ }
+
+ break; //step 14
+ }
+ }
+ return y[0].LongValue;
+ }
+
+ //Procedure B
+ private void procedure_B(int x0, int c, BigInteger[] pq)
+ {
+ //Verify and perform condition: 065536)
+ {
+ x0 = init_random.NextInt()/32768;
+ }
+
+ while((c<0 || c>65536) || (c/2==0))
+ {
+ c = init_random.NextInt()/32768 + 1;
+ }
+
+ BigInteger [] qp = new BigInteger[2];
+ BigInteger q = null, Q = null, p = null;
+ BigInteger C = BigInteger.ValueOf(c);
+ BigInteger constA16 = BigInteger.ValueOf(19381);
+
+ //step1
+ x0 = procedure_A(x0, c, qp, 256);
+ q = qp[0];
+
+ //step2
+ x0 = procedure_A(x0, c, qp, 512);
+ Q = qp[0];
+
+ BigInteger[] y = new BigInteger[65];
+ y[0] = BigInteger.ValueOf(x0);
+
+ const int tp = 1024;
+
+ BigInteger qQ = q.Multiply(Q);
+
+step3:
+ for(;;)
+ {
+ //step 3
+ for (int j=0; j<64; j++)
+ {
+ y[j+1] = (y[j].Multiply(constA16).Add(C)).Mod(BigInteger.Two.Pow(16));
+ }
+
+ //step 4
+ BigInteger Y = BigInteger.Zero;
+
+ for (int j=0; j<64; j++)
+ {
+ Y = Y.Add(y[j].ShiftLeft(16*j));
+ }
+
+ y[0] = y[64]; //step 5
+
+ //step 6
+ BigInteger N = BigInteger.One.ShiftLeft(tp-1).Divide(qQ).Add(
+ Y.ShiftLeft(tp-1).Divide(qQ.ShiftLeft(1024)));
+
+ if (N.TestBit(0))
+ {
+ N = N.Add(BigInteger.One);
+ }
+
+ //step 7
+
+ for(;;)
+ {
+ //step 11
+ BigInteger qQN = qQ.Multiply(N);
+
+ if (qQN.BitLength > tp)
+ {
+ goto step3; //step 9
+ }
+
+ p = qQN.Add(BigInteger.One);
+
+ //step10
+ if (BigInteger.Two.ModPow(qQN, p).CompareTo(BigInteger.One) == 0
+ && BigInteger.Two.ModPow(q.Multiply(N), p).CompareTo(BigInteger.One) != 0)
+ {
+ pq[0] = p;
+ pq[1] = q;
+ return;
+ }
+
+ N = N.Add(BigInteger.Two);
+ }
+ }
+ }
+
+ //Procedure B'
+ private void procedure_Bb(long x0, long c, BigInteger[] pq)
+ {
+ //Verify and perform condition: 04294967296L)
+ {
+ x0 = init_random.NextInt()*2;
+ }
+
+ while((c<0 || c>4294967296L) || (c/2==0))
+ {
+ c = init_random.NextInt()*2+1;
+ }
+
+ BigInteger [] qp = new BigInteger[2];
+ BigInteger q = null, Q = null, p = null;
+ BigInteger C = BigInteger.ValueOf(c);
+ BigInteger constA32 = BigInteger.ValueOf(97781173);
+
+ //step1
+ x0 = procedure_Aa(x0, c, qp, 256);
+ q = qp[0];
+
+ //step2
+ x0 = procedure_Aa(x0, c, qp, 512);
+ Q = qp[0];
+
+ BigInteger[] y = new BigInteger[33];
+ y[0] = BigInteger.ValueOf(x0);
+
+ const int tp = 1024;
+
+ BigInteger qQ = q.Multiply(Q);
+
+step3:
+ for(;;)
+ {
+ //step 3
+ for (int j=0; j<32; j++)
+ {
+ y[j+1] = (y[j].Multiply(constA32).Add(C)).Mod(BigInteger.Two.Pow(32));
+ }
+
+ //step 4
+ BigInteger Y = BigInteger.Zero;
+ for (int j=0; j<32; j++)
+ {
+ Y = Y.Add(y[j].ShiftLeft(32*j));
+ }
+
+ y[0] = y[32]; //step 5
+
+ //step 6
+ BigInteger N = BigInteger.One.ShiftLeft(tp-1).Divide(qQ).Add(
+ Y.ShiftLeft(tp-1).Divide(qQ.ShiftLeft(1024)));
+
+ if (N.TestBit(0))
+ {
+ N = N.Add(BigInteger.One);
+ }
+
+ //step 7
+
+ for(;;)
+ {
+ //step 11
+ BigInteger qQN = qQ.Multiply(N);
+
+ if (qQN.BitLength > tp)
+ {
+ goto step3; //step 9
+ }
+
+ p = qQN.Add(BigInteger.One);
+
+ //step10
+ if (BigInteger.Two.ModPow(qQN, p).CompareTo(BigInteger.One) == 0
+ && BigInteger.Two.ModPow(q.Multiply(N), p).CompareTo(BigInteger.One) != 0)
+ {
+ pq[0] = p;
+ pq[1] = q;
+ return;
+ }
+
+ N = N.Add(BigInteger.Two);
+ }
+ }
+ }
+
+
+ /**
+ * Procedure C
+ * procedure generates the a value from the given p,q,
+ * returning the a value.
+ */
+ private BigInteger procedure_C(BigInteger p, BigInteger q)
+ {
+ BigInteger pSub1 = p.Subtract(BigInteger.One);
+ BigInteger pSub1Divq = pSub1.Divide(q);
+
+ for(;;)
+ {
+ BigInteger d = new BigInteger(p.BitLength, init_random);
+
+ // 1 < d < p-1
+ if (d.CompareTo(BigInteger.One) > 0 && d.CompareTo(pSub1) < 0)
+ {
+ BigInteger a = d.ModPow(pSub1Divq, p);
+
+ if (a.CompareTo(BigInteger.One) != 0)
+ {
+ return a;
+ }
+ }
+ }
+ }
+
+ /**
+ * which generates the p , q and a values from the given parameters,
+ * returning the Gost3410Parameters object.
+ */
+ public Gost3410Parameters GenerateParameters()
+ {
+ BigInteger [] pq = new BigInteger[2];
+ BigInteger q = null, p = null, a = null;
+
+ int x0, c;
+ long x0L, cL;
+
+ if (typeproc==1)
+ {
+ x0 = init_random.NextInt();
+ c = init_random.NextInt();
+
+ switch(size)
+ {
+ case 512:
+ procedure_A(x0, c, pq, 512);
+ break;
+ case 1024:
+ procedure_B(x0, c, pq);
+ break;
+ default:
+ throw new ArgumentException("Ooops! key size 512 or 1024 bit.");
+ }
+ p = pq[0]; q = pq[1];
+ a = procedure_C(p, q);
+ //System.out.println("p:"+p.toString(16)+"\n"+"q:"+q.toString(16)+"\n"+"a:"+a.toString(16));
+ //System.out.println("p:"+p+"\n"+"q:"+q+"\n"+"a:"+a);
+ return new Gost3410Parameters(p, q, a, new Gost3410ValidationParameters(x0, c));
+ }
+ else
+ {
+ x0L = init_random.NextLong();
+ cL = init_random.NextLong();
+
+ switch(size)
+ {
+ case 512:
+ procedure_Aa(x0L, cL, pq, 512);
+ break;
+ case 1024:
+ procedure_Bb(x0L, cL, pq);
+ break;
+ default:
+ throw new InvalidOperationException("Ooops! key size 512 or 1024 bit.");
+ }
+ p = pq[0]; q = pq[1];
+ a = procedure_C(p, q);
+ //System.out.println("p:"+p.toString(16)+"\n"+"q:"+q.toString(16)+"\n"+"a:"+a.toString(16));
+ //System.out.println("p:"+p+"\n"+"q:"+q+"\n"+"a:"+a);
+ return new Gost3410Parameters(p, q, a, new Gost3410ValidationParameters(x0L, cL));
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/HKDFBytesGenerator.cs b/bc-sharp-crypto/src/crypto/generators/HKDFBytesGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c2e667c9554ee99ab20e5ff69c77127342f5a106
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/HKDFBytesGenerator.cs
@@ -0,0 +1,153 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * HMAC-based Extract-and-Expand Key Derivation Function (HKDF) implemented
+ * according to IETF RFC 5869, May 2010 as specified by H. Krawczyk, IBM
+ * Research & P. Eronen, Nokia. It uses a HMac internally to compute de OKM
+ * (output keying material) and is likely to have better security properties
+ * than KDF's based on just a hash function.
+ */
+ public class HkdfBytesGenerator
+ : IDerivationFunction
+ {
+ private HMac hMacHash;
+ private int hashLen;
+
+ private byte[] info;
+ private byte[] currentT;
+
+ private int generatedBytes;
+
+ /**
+ * Creates a HKDFBytesGenerator based on the given hash function.
+ *
+ * @param hash the digest to be used as the source of generatedBytes bytes
+ */
+ public HkdfBytesGenerator(IDigest hash)
+ {
+ this.hMacHash = new HMac(hash);
+ this.hashLen = hash.GetDigestSize();
+ }
+
+ public virtual void Init(IDerivationParameters parameters)
+ {
+ if (!(parameters is HkdfParameters))
+ throw new ArgumentException("HKDF parameters required for HkdfBytesGenerator", "parameters");
+
+ HkdfParameters hkdfParameters = (HkdfParameters)parameters;
+ if (hkdfParameters.SkipExtract)
+ {
+ // use IKM directly as PRK
+ hMacHash.Init(new KeyParameter(hkdfParameters.GetIkm()));
+ }
+ else
+ {
+ hMacHash.Init(Extract(hkdfParameters.GetSalt(), hkdfParameters.GetIkm()));
+ }
+
+ info = hkdfParameters.GetInfo();
+
+ generatedBytes = 0;
+ currentT = new byte[hashLen];
+ }
+
+ /**
+ * Performs the extract part of the key derivation function.
+ *
+ * @param salt the salt to use
+ * @param ikm the input keying material
+ * @return the PRK as KeyParameter
+ */
+ private KeyParameter Extract(byte[] salt, byte[] ikm)
+ {
+ hMacHash.Init(new KeyParameter(ikm));
+ if (salt == null)
+ {
+ // TODO check if hashLen is indeed same as HMAC size
+ hMacHash.Init(new KeyParameter(new byte[hashLen]));
+ }
+ else
+ {
+ hMacHash.Init(new KeyParameter(salt));
+ }
+
+ hMacHash.BlockUpdate(ikm, 0, ikm.Length);
+
+ byte[] prk = new byte[hashLen];
+ hMacHash.DoFinal(prk, 0);
+ return new KeyParameter(prk);
+ }
+
+ /**
+ * Performs the expand part of the key derivation function, using currentT
+ * as input and output buffer.
+ *
+ * @throws DataLengthException if the total number of bytes generated is larger than the one
+ * specified by RFC 5869 (255 * HashLen)
+ */
+ private void ExpandNext()
+ {
+ int n = generatedBytes / hashLen + 1;
+ if (n >= 256)
+ {
+ throw new DataLengthException(
+ "HKDF cannot generate more than 255 blocks of HashLen size");
+ }
+ // special case for T(0): T(0) is empty, so no update
+ if (generatedBytes != 0)
+ {
+ hMacHash.BlockUpdate(currentT, 0, hashLen);
+ }
+ hMacHash.BlockUpdate(info, 0, info.Length);
+ hMacHash.Update((byte)n);
+ hMacHash.DoFinal(currentT, 0);
+ }
+
+ public virtual IDigest Digest
+ {
+ get { return hMacHash.GetUnderlyingDigest(); }
+ }
+
+ public virtual int GenerateBytes(byte[] output, int outOff, int len)
+ {
+ if (generatedBytes + len > 255 * hashLen)
+ {
+ throw new DataLengthException(
+ "HKDF may only be used for 255 * HashLen bytes of output");
+ }
+
+ if (generatedBytes % hashLen == 0)
+ {
+ ExpandNext();
+ }
+
+ // copy what is left in the currentT (1..hash
+ int toGenerate = len;
+ int posInT = generatedBytes % hashLen;
+ int leftInT = hashLen - generatedBytes % hashLen;
+ int toCopy = System.Math.Min(leftInT, toGenerate);
+ Array.Copy(currentT, posInT, output, outOff, toCopy);
+ generatedBytes += toCopy;
+ toGenerate -= toCopy;
+ outOff += toCopy;
+
+ while (toGenerate > 0)
+ {
+ ExpandNext();
+ toCopy = System.Math.Min(hashLen, toGenerate);
+ Array.Copy(currentT, 0, output, outOff, toCopy);
+ generatedBytes += toCopy;
+ toGenerate -= toCopy;
+ outOff += toCopy;
+ }
+
+ return len;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/Kdf1BytesGenerator.cs b/bc-sharp-crypto/src/crypto/generators/Kdf1BytesGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0ddf6c166f78a19d240bc450824d6d1e143fb8ac
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/Kdf1BytesGenerator.cs
@@ -0,0 +1,26 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * KFD2 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+ *
+ * This implementation is based on IEEE P1363/ISO 18033.
+ */
+ public class Kdf1BytesGenerator
+ : BaseKdfBytesGenerator
+ {
+ /**
+ * Construct a KDF1 byte generator.
+ *
+ * @param digest the digest to be used as the source of derived keys.
+ */
+ public Kdf1BytesGenerator(IDigest digest)
+ : base(0, digest)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/Kdf2BytesGenerator.cs b/bc-sharp-crypto/src/crypto/generators/Kdf2BytesGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8a6821980607a6f27eeb2b3c3710870d06dae6b1
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/Kdf2BytesGenerator.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * KDF2 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+ *
+ * This implementation is based on IEEE P1363/ISO 18033.
+ */
+ public class Kdf2BytesGenerator
+ : BaseKdfBytesGenerator
+ {
+ /**
+ * Construct a KDF2 bytes generator. Generates key material
+ * according to IEEE P1363 or ISO 18033 depending on the initialisation.
+ *
+ * @param digest the digest to be used as the source of derived keys.
+ */
+ public Kdf2BytesGenerator(IDigest digest)
+ : base(1, digest)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/Mgf1BytesGenerator.cs b/bc-sharp-crypto/src/crypto/generators/Mgf1BytesGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..23a3aca25d7a4508816002924384a44a93c1d322
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/Mgf1BytesGenerator.cs
@@ -0,0 +1,117 @@
+using System;
+//using Org.BouncyCastle.Math;
+//using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generator for MGF1 as defined in Pkcs 1v2
+ */
+ public class Mgf1BytesGenerator : IDerivationFunction
+ {
+ private IDigest digest;
+ private byte[] seed;
+ private int hLen;
+
+ /**
+ * @param digest the digest to be used as the source of Generated bytes
+ */
+ public Mgf1BytesGenerator(
+ IDigest digest)
+ {
+ this.digest = digest;
+ this.hLen = digest.GetDigestSize();
+ }
+
+ public void Init(
+ IDerivationParameters parameters)
+ {
+ if (!(typeof(MgfParameters).IsInstanceOfType(parameters)))
+ {
+ throw new ArgumentException("MGF parameters required for MGF1Generator");
+ }
+
+ MgfParameters p = (MgfParameters)parameters;
+
+ seed = p.GetSeed();
+ }
+
+ /**
+ * return the underlying digest.
+ */
+ public IDigest Digest
+ {
+ get
+ {
+ return digest;
+ }
+ }
+
+ /**
+ * int to octet string.
+ */
+ private void ItoOSP(
+ int i,
+ byte[] sp)
+ {
+ sp[0] = (byte)((uint) i >> 24);
+ sp[1] = (byte)((uint) i >> 16);
+ sp[2] = (byte)((uint) i >> 8);
+ sp[3] = (byte)((uint) i >> 0);
+ }
+
+ /**
+ * fill len bytes of the output buffer with bytes Generated from
+ * the derivation function.
+ *
+ * @throws DataLengthException if the out buffer is too small.
+ */
+ public int GenerateBytes(
+ byte[] output,
+ int outOff,
+ int length)
+ {
+ if ((output.Length - length) < outOff)
+ {
+ throw new DataLengthException("output buffer too small");
+ }
+
+ byte[] hashBuf = new byte[hLen];
+ byte[] C = new byte[4];
+ int counter = 0;
+
+ digest.Reset();
+
+ if (length > hLen)
+ {
+ do
+ {
+ ItoOSP(counter, C);
+
+ digest.BlockUpdate(seed, 0, seed.Length);
+ digest.BlockUpdate(C, 0, C.Length);
+ digest.DoFinal(hashBuf, 0);
+
+ Array.Copy(hashBuf, 0, output, outOff + counter * hLen, hLen);
+ }
+ while (++counter < (length / hLen));
+ }
+
+ if ((counter * hLen) < length)
+ {
+ ItoOSP(counter, C);
+
+ digest.BlockUpdate(seed, 0, seed.Length);
+ digest.BlockUpdate(C, 0, C.Length);
+ digest.DoFinal(hashBuf, 0);
+
+ Array.Copy(hashBuf, 0, output, outOff + counter * hLen, length - (counter * hLen));
+ }
+
+ return length;
+ }
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/NaccacheSternKeyPairGenerator.cs b/bc-sharp-crypto/src/crypto/generators/NaccacheSternKeyPairGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..618ca9a1cc2fc4a69b85b8d9a689e5a17a6bacf5
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/NaccacheSternKeyPairGenerator.cs
@@ -0,0 +1,268 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Key generation parameters for NaccacheStern cipher. For details on this cipher, please see
+ *
+ * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+ */
+ public class NaccacheSternKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private static readonly int[] smallPrimes =
+ {
+ 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
+ 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149,
+ 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233,
+ 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331,
+ 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431,
+ 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523,
+ 541, 547, 557
+ };
+
+ private NaccacheSternKeyGenerationParameters param;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator#init(org.bouncycastle.crypto.KeyGenerationParameters)
+ */
+ public void Init(KeyGenerationParameters parameters)
+ {
+ this.param = (NaccacheSternKeyGenerationParameters)parameters;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator#generateKeyPair()
+ */
+ public AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ int strength = param.Strength;
+ SecureRandom rand = param.Random;
+ int certainty = param.Certainty;
+
+ IList smallPrimes = findFirstPrimes(param.CountSmallPrimes);
+
+ smallPrimes = permuteList(smallPrimes, rand);
+
+ BigInteger u = BigInteger.One;
+ BigInteger v = BigInteger.One;
+
+ for (int i = 0; i < smallPrimes.Count / 2; i++)
+ {
+ u = u.Multiply((BigInteger)smallPrimes[i]);
+ }
+ for (int i = smallPrimes.Count / 2; i < smallPrimes.Count; i++)
+ {
+ v = v.Multiply((BigInteger)smallPrimes[i]);
+ }
+
+ BigInteger sigma = u.Multiply(v);
+
+ // n = (2 a u _p + 1 ) ( 2 b v _q + 1)
+ // -> |n| = strength
+ // |2| = 1 in bits
+ // -> |a| * |b| = |n| - |u| - |v| - |_p| - |_q| - |2| -|2|
+ // remainingStrength = strength - sigma.bitLength() - _p.bitLength() -
+ // _q.bitLength() - 1 -1
+ int remainingStrength = strength - sigma.BitLength - 48;
+ BigInteger a = generatePrime(remainingStrength / 2 + 1, certainty, rand);
+ BigInteger b = generatePrime(remainingStrength / 2 + 1, certainty, rand);
+
+ BigInteger _p;
+ BigInteger _q;
+ BigInteger p;
+ BigInteger q;
+
+ long tries = 0;
+
+ BigInteger _2au = a.Multiply(u).ShiftLeft(1);
+ BigInteger _2bv = b.Multiply(v).ShiftLeft(1);
+
+ for (;;)
+ {
+ tries++;
+
+ _p = generatePrime(24, certainty, rand);
+
+ p = _p.Multiply(_2au).Add(BigInteger.One);
+
+ if (!p.IsProbablePrime(certainty, true))
+ continue;
+
+ for (;;)
+ {
+ _q = generatePrime(24, certainty, rand);
+
+ if (_p.Equals(_q))
+ continue;
+
+ q = _q.Multiply(_2bv).Add(BigInteger.One);
+
+ if (q.IsProbablePrime(certainty, true))
+ break;
+ }
+
+ if (!sigma.Gcd(_p.Multiply(_q)).Equals(BigInteger.One))
+ {
+ //Console.WriteLine("sigma.gcd(_p.mult(_q)) != 1!\n _p: " + _p +"\n _q: "+ _q );
+ continue;
+ }
+
+ if (p.Multiply(q).BitLength < strength)
+ {
+ continue;
+ }
+ break;
+ }
+
+ BigInteger n = p.Multiply(q);
+ BigInteger phi_n = p.Subtract(BigInteger.One).Multiply(q.Subtract(BigInteger.One));
+ BigInteger g;
+ tries = 0;
+
+ for (;;)
+ {
+ // TODO After the first loop, just regenerate one randomly-selected gPart each time?
+ IList gParts = Platform.CreateArrayList();
+ for (int ind = 0; ind != smallPrimes.Count; ind++)
+ {
+ BigInteger i = (BigInteger)smallPrimes[ind];
+ BigInteger e = phi_n.Divide(i);
+
+ for (;;)
+ {
+ tries++;
+
+ g = generatePrime(strength, certainty, rand);
+
+ if (!g.ModPow(e, n).Equals(BigInteger.One))
+ {
+ gParts.Add(g);
+ break;
+ }
+ }
+ }
+ g = BigInteger.One;
+ for (int i = 0; i < smallPrimes.Count; i++)
+ {
+ BigInteger gPart = (BigInteger) gParts[i];
+ BigInteger smallPrime = (BigInteger) smallPrimes[i];
+ g = g.Multiply(gPart.ModPow(sigma.Divide(smallPrime), n)).Mod(n);
+ }
+
+ // make sure that g is not divisible by p_i or q_i
+ bool divisible = false;
+ for (int i = 0; i < smallPrimes.Count; i++)
+ {
+ if (g.ModPow(phi_n.Divide((BigInteger)smallPrimes[i]), n).Equals(BigInteger.One))
+ {
+ divisible = true;
+ break;
+ }
+ }
+
+ if (divisible)
+ {
+ continue;
+ }
+
+ // make sure that g has order > phi_n/4
+
+ //if (g.ModPow(phi_n.Divide(BigInteger.ValueOf(4)), n).Equals(BigInteger.One))
+ if (g.ModPow(phi_n.ShiftRight(2), n).Equals(BigInteger.One))
+ {
+ continue;
+ }
+
+ if (g.ModPow(phi_n.Divide(_p), n).Equals(BigInteger.One))
+ {
+ continue;
+ }
+ if (g.ModPow(phi_n.Divide(_q), n).Equals(BigInteger.One))
+ {
+ continue;
+ }
+ if (g.ModPow(phi_n.Divide(a), n).Equals(BigInteger.One))
+ {
+ continue;
+ }
+ if (g.ModPow(phi_n.Divide(b), n).Equals(BigInteger.One))
+ {
+ continue;
+ }
+ break;
+ }
+
+ return new AsymmetricCipherKeyPair(new NaccacheSternKeyParameters(false, g, n, sigma.BitLength),
+ new NaccacheSternPrivateKeyParameters(g, n, sigma.BitLength, smallPrimes, phi_n));
+ }
+
+ private static BigInteger generatePrime(
+ int bitLength,
+ int certainty,
+ SecureRandom rand)
+ {
+ return new BigInteger(bitLength, certainty, rand);
+ }
+
+ /**
+ * Generates a permuted ArrayList from the original one. The original List
+ * is not modified
+ *
+ * @param arr
+ * the ArrayList to be permuted
+ * @param rand
+ * the source of Randomness for permutation
+ * @return a new IList with the permuted elements.
+ */
+ private static IList permuteList(
+ IList arr,
+ SecureRandom rand)
+ {
+ // TODO Create a utility method for generating permutation of first 'n' integers
+
+ IList retval = Platform.CreateArrayList(arr.Count);
+
+ foreach (object element in arr)
+ {
+ int index = rand.Next(retval.Count + 1);
+ retval.Insert(index, element);
+ }
+
+ return retval;
+ }
+
+ /**
+ * Finds the first 'count' primes starting with 3
+ *
+ * @param count
+ * the number of primes to find
+ * @return a vector containing the found primes as Integer
+ */
+ private static IList findFirstPrimes(
+ int count)
+ {
+ IList primes = Platform.CreateArrayList(count);
+
+ for (int i = 0; i != count; i++)
+ {
+ primes.Add(BigInteger.ValueOf(smallPrimes[i]));
+ }
+
+ return primes;
+ }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/OpenBsdBCrypt.cs b/bc-sharp-crypto/src/crypto/generators/OpenBsdBCrypt.cs
new file mode 100644
index 0000000000000000000000000000000000000000..85c34d76920969c07ba73547ba228ed4affdf912
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/OpenBsdBCrypt.cs
@@ -0,0 +1,270 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Password hashing scheme BCrypt,
+ * designed by Niels Provos and David Mazières, using the
+ * String format and the Base64 encoding
+ * of the reference implementation on OpenBSD
+ */
+ public class OpenBsdBCrypt
+ {
+ private static readonly byte[] EncodingTable = // the Bcrypts encoding table for OpenBSD
+ {
+ (byte)'.', (byte)'/', (byte)'A', (byte)'B', (byte)'C', (byte)'D',
+ (byte)'E', (byte)'F', (byte)'G', (byte)'H', (byte)'I', (byte)'J',
+ (byte)'K', (byte)'L', (byte)'M', (byte)'N', (byte)'O', (byte)'P',
+ (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', (byte)'V',
+ (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', (byte)'a', (byte)'b',
+ (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', (byte)'h',
+ (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+ (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t',
+ (byte)'u', (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5',
+ (byte)'6', (byte)'7', (byte)'8', (byte)'9'
+ };
+
+ /*
+ * set up the decoding table.
+ */
+ private static readonly byte[] DecodingTable = new byte[128];
+ private static readonly string Version = "2a"; // previous version was not UTF-8
+
+ static OpenBsdBCrypt()
+ {
+ for (int i = 0; i < DecodingTable.Length; i++)
+ {
+ DecodingTable[i] = (byte)0xff;
+ }
+
+ for (int i = 0; i < EncodingTable.Length; i++)
+ {
+ DecodingTable[EncodingTable[i]] = (byte)i;
+ }
+ }
+
+ public OpenBsdBCrypt()
+ {
+ }
+
+ /**
+ * Creates a 60 character Bcrypt String, including
+ * version, cost factor, salt and hash, separated by '$'
+ *
+ * @param cost the cost factor, treated as an exponent of 2
+ * @param salt a 16 byte salt
+ * @param password the password
+ * @return a 60 character Bcrypt String
+ */
+ private static string CreateBcryptString(byte[] password, byte[] salt, int cost)
+ {
+ StringBuilder sb = new StringBuilder(60);
+ sb.Append('$');
+ sb.Append(Version);
+ sb.Append('$');
+ sb.Append(cost < 10 ? ("0" + cost) : cost.ToString());
+ sb.Append('$');
+ sb.Append(EncodeData(salt));
+
+ byte[] key = BCrypt.Generate(password, salt, cost);
+
+ sb.Append(EncodeData(key));
+
+ return sb.ToString();
+ }
+
+ /**
+ * Creates a 60 character Bcrypt String, including
+ * version, cost factor, salt and hash, separated by '$'
+ *
+ * @param cost the cost factor, treated as an exponent of 2
+ * @param salt a 16 byte salt
+ * @param password the password
+ * @return a 60 character Bcrypt String
+ */
+ public static string Generate(char[] password, byte[] salt, int cost)
+ {
+ if (password == null)
+ throw new ArgumentNullException("password");
+ if (salt == null)
+ throw new ArgumentNullException("salt");
+ if (salt.Length != 16)
+ throw new DataLengthException("16 byte salt required: " + salt.Length);
+
+ if (cost < 4 || cost > 31) // Minimum rounds: 16, maximum 2^31
+ throw new ArgumentException("Invalid cost factor.", "cost");
+
+ byte[] psw = Strings.ToUtf8ByteArray(password);
+
+ // 0 termination:
+
+ byte[] tmp = new byte[psw.Length >= 72 ? 72 : psw.Length + 1];
+ int copyLen = System.Math.Min(psw.Length, tmp.Length);
+ Array.Copy(psw, 0, tmp, 0, copyLen);
+
+ Array.Clear(psw, 0, psw.Length);
+
+ string rv = CreateBcryptString(tmp, salt, cost);
+
+ Array.Clear(tmp, 0, tmp.Length);
+
+ return rv;
+ }
+
+ /**
+ * Checks if a password corresponds to a 60 character Bcrypt String
+ *
+ * @param bcryptString a 60 character Bcrypt String, including
+ * version, cost factor, salt and hash,
+ * separated by '$'
+ * @param password the password as an array of chars
+ * @return true if the password corresponds to the
+ * Bcrypt String, otherwise false
+ */
+ public static bool CheckPassword(string bcryptString, char[] password)
+ {
+ // validate bcryptString:
+ if (bcryptString.Length != 60)
+ throw new DataLengthException("Bcrypt String length: " + bcryptString.Length + ", 60 required.");
+ if (bcryptString[0] != '$' || bcryptString[3] != '$' || bcryptString[6] != '$')
+ throw new ArgumentException("Invalid Bcrypt String format.", "bcryptString");
+ if (!bcryptString.Substring(1, 2).Equals(Version))
+ throw new ArgumentException("Wrong Bcrypt version, 2a expected.", "bcryptString");
+
+ int cost = 0;
+ try
+ {
+ cost = Int32.Parse(bcryptString.Substring(4, 2));
+ }
+ catch (Exception nfe)
+ {
+ throw new ArgumentException("Invalid cost factor: " + bcryptString.Substring(4, 2), "bcryptString");
+ }
+ if (cost < 4 || cost > 31)
+ throw new ArgumentException("Invalid cost factor: " + cost + ", 4 < cost < 31 expected.");
+
+ // check password:
+ if (password == null)
+ throw new ArgumentNullException("Missing password.");
+
+ int start = bcryptString.LastIndexOf('$') + 1, end = bcryptString.Length - 31;
+ byte[] salt = DecodeSaltString(bcryptString.Substring(start, end - start));
+
+ string newBcryptString = Generate(password, salt, cost);
+
+ return bcryptString.Equals(newBcryptString);
+ }
+
+ /*
+ * encode the input data producing a Bcrypt base 64 string.
+ *
+ * @param a byte representation of the salt or the password
+ * @return the Bcrypt base64 string
+ */
+ private static string EncodeData(byte[] data)
+ {
+ if (data.Length != 24 && data.Length != 16) // 192 bit key or 128 bit salt expected
+ throw new DataLengthException("Invalid length: " + data.Length + ", 24 for key or 16 for salt expected");
+
+ bool salt = false;
+ if (data.Length == 16)//salt
+ {
+ salt = true;
+ byte[] tmp = new byte[18];// zero padding
+ Array.Copy(data, 0, tmp, 0, data.Length);
+ data = tmp;
+ }
+ else // key
+ {
+ data[data.Length - 1] = (byte)0;
+ }
+
+ MemoryStream mOut = new MemoryStream();
+ int len = data.Length;
+
+ uint a1, a2, a3;
+ int i;
+ for (i = 0; i < len; i += 3)
+ {
+ a1 = data[i];
+ a2 = data[i + 1];
+ a3 = data[i + 2];
+
+ mOut.WriteByte(EncodingTable[(a1 >> 2) & 0x3f]);
+ mOut.WriteByte(EncodingTable[((a1 << 4) | (a2 >> 4)) & 0x3f]);
+ mOut.WriteByte(EncodingTable[((a2 << 2) | (a3 >> 6)) & 0x3f]);
+ mOut.WriteByte(EncodingTable[a3 & 0x3f]);
+ }
+
+ string result = Strings.FromByteArray(mOut.ToArray());
+ int resultLen = salt
+ ? 22 // truncate padding
+ : result.Length - 1;
+
+ return result.Substring(0, resultLen);
+ }
+
+
+ /*
+ * decodes the bcrypt base 64 encoded SaltString
+ *
+ * @param a 22 character Bcrypt base 64 encoded String
+ * @return the 16 byte salt
+ * @exception DataLengthException if the length
+ * of parameter is not 22
+ * @exception InvalidArgumentException if the parameter
+ * contains a value other than from Bcrypts base 64 encoding table
+ */
+ private static byte[] DecodeSaltString(string saltString)
+ {
+ char[] saltChars = saltString.ToCharArray();
+
+ MemoryStream mOut = new MemoryStream(16);
+ byte b1, b2, b3, b4;
+
+ if (saltChars.Length != 22)// bcrypt salt must be 22 (16 bytes)
+ throw new DataLengthException("Invalid base64 salt length: " + saltChars.Length + " , 22 required.");
+
+ // check string for invalid characters:
+ for (int i = 0; i < saltChars.Length; i++)
+ {
+ int value = saltChars[i];
+ if (value > 122 || value < 46 || (value > 57 && value < 65))
+ throw new ArgumentException("Salt string contains invalid character: " + value, "saltString");
+ }
+
+ // Padding: add two '\u0000'
+ char[] tmp = new char[22 + 2];
+ Array.Copy(saltChars, 0, tmp, 0, saltChars.Length);
+ saltChars = tmp;
+
+ int len = saltChars.Length;
+
+ for (int i = 0; i < len; i += 4)
+ {
+ b1 = DecodingTable[saltChars[i]];
+ b2 = DecodingTable[saltChars[i + 1]];
+ b3 = DecodingTable[saltChars[i + 2]];
+ b4 = DecodingTable[saltChars[i + 3]];
+
+ mOut.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
+ mOut.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
+ mOut.WriteByte((byte)((b3 << 6) | b4));
+ }
+
+ byte[] saltBytes = mOut.ToArray();
+
+ // truncate:
+ byte[] tmpSalt = new byte[16];
+ Array.Copy(saltBytes, 0, tmpSalt, 0, tmpSalt.Length);
+ saltBytes = tmpSalt;
+
+ return saltBytes;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/OpenSSLPBEParametersGenerator.cs b/bc-sharp-crypto/src/crypto/generators/OpenSSLPBEParametersGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8da5d3ad1ce078f1ff5e0df0f7e49f37a136d75e
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/OpenSSLPBEParametersGenerator.cs
@@ -0,0 +1,167 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generator for PBE derived keys and ivs as usd by OpenSSL.
+ *
+ * The scheme is a simple extension of PKCS 5 V2.0 Scheme 1 using MD5 with an
+ * iteration count of 1.
+ *
+ */
+ public class OpenSslPbeParametersGenerator
+ : PbeParametersGenerator
+ {
+ private readonly IDigest digest = new MD5Digest();
+
+ /**
+ * Construct a OpenSSL Parameters generator.
+ */
+ public OpenSslPbeParametersGenerator()
+ {
+ }
+
+ public override void Init(
+ byte[] password,
+ byte[] salt,
+ int iterationCount)
+ {
+ // Ignore the provided iterationCount
+ base.Init(password, salt, 1);
+ }
+
+ /**
+ * Initialise - note the iteration count for this algorithm is fixed at 1.
+ *
+ * @param password password to use.
+ * @param salt salt to use.
+ */
+ public virtual void Init(
+ byte[] password,
+ byte[] salt)
+ {
+ base.Init(password, salt, 1);
+ }
+
+ /**
+ * the derived key function, the ith hash of the password and the salt.
+ */
+ private byte[] GenerateDerivedKey(
+ int bytesNeeded)
+ {
+ byte[] buf = new byte[digest.GetDigestSize()];
+ byte[] key = new byte[bytesNeeded];
+ int offset = 0;
+
+ for (;;)
+ {
+ digest.BlockUpdate(mPassword, 0, mPassword.Length);
+ digest.BlockUpdate(mSalt, 0, mSalt.Length);
+
+ digest.DoFinal(buf, 0);
+
+ int len = (bytesNeeded > buf.Length) ? buf.Length : bytesNeeded;
+ Array.Copy(buf, 0, key, offset, len);
+ offset += len;
+
+ // check if we need any more
+ bytesNeeded -= len;
+ if (bytesNeeded == 0)
+ {
+ break;
+ }
+
+ // do another round
+ digest.Reset();
+ digest.BlockUpdate(buf, 0, buf.Length);
+ }
+
+ return key;
+ }
+
+ /**
+ * Generate a key parameter derived from the password, salt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception ArgumentException if the key length larger than the base hash size.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize)
+ {
+ return GenerateDerivedMacParameters(keySize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize)
+ {
+ keySize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize);
+
+ return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the password, salt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ * @exception ArgumentException if keySize + ivSize is larger than the base hash size.
+ */
+ [Obsolete("Use version with 'algorithm' parameter")]
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize = keySize / 8;
+ ivSize = ivSize / 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize + ivSize);
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize + ivSize);
+ KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+
+ return new ParametersWithIV(key, dKey, keySize, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the password,
+ * salt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception ArgumentException if the key length larger than the base hash size.
+ */
+ public override ICipherParameters GenerateDerivedMacParameters(
+ int keySize)
+ {
+ keySize = keySize / 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs b/bc-sharp-crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..85543a0380b6e1fc32ccdb4b61dd0ee7476e276f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs
@@ -0,0 +1,243 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generator for Pbe derived keys and ivs as defined by Pkcs 12 V1.0.
+ *
+ * The document this implementation is based on can be found at
+ *
+ * RSA's Pkcs12 Page
+ *
+ */
+ public class Pkcs12ParametersGenerator
+ : PbeParametersGenerator
+ {
+ public const int KeyMaterial = 1;
+ public const int IVMaterial = 2;
+ public const int MacMaterial = 3;
+
+ private readonly IDigest digest;
+
+ private readonly int u;
+ private readonly int v;
+
+ /**
+ * Construct a Pkcs 12 Parameters generator.
+ *
+ * @param digest the digest to be used as the source of derived keys.
+ * @exception ArgumentException if an unknown digest is passed in.
+ */
+ public Pkcs12ParametersGenerator(
+ IDigest digest)
+ {
+ this.digest = digest;
+
+ u = digest.GetDigestSize();
+ v = digest.GetByteLength();
+ }
+
+ /**
+ * add a + b + 1, returning the result in a. The a value is treated
+ * as a BigInteger of length (b.Length * 8) bits. The result is
+ * modulo 2^b.Length in case of overflow.
+ */
+ private void Adjust(
+ byte[] a,
+ int aOff,
+ byte[] b)
+ {
+ int x = (b[b.Length - 1] & 0xff) + (a[aOff + b.Length - 1] & 0xff) + 1;
+
+ a[aOff + b.Length - 1] = (byte)x;
+ x = (int) ((uint) x >> 8);
+
+ for (int i = b.Length - 2; i >= 0; i--)
+ {
+ x += (b[i] & 0xff) + (a[aOff + i] & 0xff);
+ a[aOff + i] = (byte)x;
+ x = (int) ((uint) x >> 8);
+ }
+ }
+
+ /**
+ * generation of a derived key ala Pkcs12 V1.0.
+ */
+ private byte[] GenerateDerivedKey(
+ int idByte,
+ int n)
+ {
+ byte[] D = new byte[v];
+ byte[] dKey = new byte[n];
+
+ for (int i = 0; i != D.Length; i++)
+ {
+ D[i] = (byte)idByte;
+ }
+
+ byte[] S;
+
+ if ((mSalt != null) && (mSalt.Length != 0))
+ {
+ S = new byte[v * ((mSalt.Length + v - 1) / v)];
+
+ for (int i = 0; i != S.Length; i++)
+ {
+ S[i] = mSalt[i % mSalt.Length];
+ }
+ }
+ else
+ {
+ S = new byte[0];
+ }
+
+ byte[] P;
+
+ if ((mPassword != null) && (mPassword.Length != 0))
+ {
+ P = new byte[v * ((mPassword.Length + v - 1) / v)];
+
+ for (int i = 0; i != P.Length; i++)
+ {
+ P[i] = mPassword[i % mPassword.Length];
+ }
+ }
+ else
+ {
+ P = new byte[0];
+ }
+
+ byte[] I = new byte[S.Length + P.Length];
+
+ Array.Copy(S, 0, I, 0, S.Length);
+ Array.Copy(P, 0, I, S.Length, P.Length);
+
+ byte[] B = new byte[v];
+ int c = (n + u - 1) / u;
+ byte[] A = new byte[u];
+
+ for (int i = 1; i <= c; i++)
+ {
+ digest.BlockUpdate(D, 0, D.Length);
+ digest.BlockUpdate(I, 0, I.Length);
+ digest.DoFinal(A, 0);
+
+ for (int j = 1; j != mIterationCount; j++)
+ {
+ digest.BlockUpdate(A, 0, A.Length);
+ digest.DoFinal(A, 0);
+ }
+
+ for (int j = 0; j != B.Length; j++)
+ {
+ B[j] = A[j % A.Length];
+ }
+
+ for (int j = 0; j != I.Length / v; j++)
+ {
+ Adjust(I, j * v, B);
+ }
+
+ if (i == c)
+ {
+ Array.Copy(A, 0, dKey, (i - 1) * u, dKey.Length - ((i - 1) * u));
+ }
+ else
+ {
+ Array.Copy(A, 0, dKey, (i - 1) * u, A.Length);
+ }
+ }
+
+ return dKey;
+ }
+
+ /**
+ * Generate a key parameter derived from the password, salt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize)
+ {
+ keySize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize)
+ {
+ keySize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
+
+ return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the password, salt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ */
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
+
+ byte[] iv = GenerateDerivedKey(IVMaterial, ivSize);
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), iv, 0, ivSize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
+ KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+
+ byte[] iv = GenerateDerivedKey(IVMaterial, ivSize);
+
+ return new ParametersWithIV(key, iv, 0, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the password,
+ * salt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ public override ICipherParameters GenerateDerivedMacParameters(
+ int keySize)
+ {
+ keySize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(MacMaterial, keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs b/bc-sharp-crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9b39a5f422db12fd0c8e13cb5550ffa6eff65044
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs
@@ -0,0 +1,160 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generator for Pbe derived keys and ivs as defined by Pkcs 5 V2.0 Scheme 1.
+ * Note this generator is limited to the size of the hash produced by the
+ * digest used to drive it.
+ *
+ * The document this implementation is based on can be found at
+ *
+ * RSA's Pkcs5 Page
+ *
+ */
+ public class Pkcs5S1ParametersGenerator
+ : PbeParametersGenerator
+ {
+ private readonly IDigest digest;
+
+ /**
+ * Construct a Pkcs 5 Scheme 1 Parameters generator.
+ *
+ * @param digest the digest to be used as the source of derived keys.
+ */
+ public Pkcs5S1ParametersGenerator(
+ IDigest digest)
+ {
+ this.digest = digest;
+ }
+
+ /**
+ * the derived key function, the ith hash of the mPassword and the mSalt.
+ */
+ private byte[] GenerateDerivedKey()
+ {
+ byte[] digestBytes = new byte[digest.GetDigestSize()];
+
+ digest.BlockUpdate(mPassword, 0, mPassword.Length);
+ digest.BlockUpdate(mSalt, 0, mSalt.Length);
+
+ digest.DoFinal(digestBytes, 0);
+ for (int i = 1; i < mIterationCount; i++)
+ {
+ digest.BlockUpdate(digestBytes, 0, digestBytes.Length);
+ digest.DoFinal(digestBytes, 0);
+ }
+
+ return digestBytes;
+ }
+
+ /**
+ * Generate a key parameter derived from the mPassword, mSalt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception ArgumentException if the key length larger than the base hash size.
+ */
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize)
+ {
+ return GenerateDerivedMacParameters(keySize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize)
+ {
+ keySize /= 8;
+
+ if (keySize > digest.GetDigestSize())
+ {
+ throw new ArgumentException(
+ "Can't Generate a derived key " + keySize + " bytes long.");
+ }
+
+ byte[] dKey = GenerateDerivedKey();
+
+ return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the mPassword, mSalt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ * @exception ArgumentException if keySize + ivSize is larger than the base hash size.
+ */
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ if ((keySize + ivSize) > digest.GetDigestSize())
+ {
+ throw new ArgumentException(
+ "Can't Generate a derived key " + (keySize + ivSize) + " bytes long.");
+ }
+
+ byte[] dKey = GenerateDerivedKey();
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ if ((keySize + ivSize) > digest.GetDigestSize())
+ {
+ throw new ArgumentException(
+ "Can't Generate a derived key " + (keySize + ivSize) + " bytes long.");
+ }
+
+ byte[] dKey = GenerateDerivedKey();
+ KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+
+ return new ParametersWithIV(key, dKey, keySize, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the mPassword,
+ * mSalt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception ArgumentException if the key length larger than the base hash size.
+ */
+ public override ICipherParameters GenerateDerivedMacParameters(
+ int keySize)
+ {
+ keySize /= 8;
+
+ if (keySize > digest.GetDigestSize())
+ {
+ throw new ArgumentException(
+ "Can't Generate a derived key " + keySize + " bytes long.");
+ }
+
+ byte[] dKey = GenerateDerivedKey();
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs b/bc-sharp-crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0b0caa05716576c6dac946b688a323808eeef4e1
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs
@@ -0,0 +1,178 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generator for Pbe derived keys and ivs as defined by Pkcs 5 V2.0 Scheme 2.
+ * This generator uses a SHA-1 HMac as the calculation function.
+ *
+ * The document this implementation is based on can be found at
+ *
+ * RSA's Pkcs5 Page
+ */
+ public class Pkcs5S2ParametersGenerator
+ : PbeParametersGenerator
+ {
+ private readonly IMac hMac;
+ private readonly byte[] state;
+
+ /**
+ * construct a Pkcs5 Scheme 2 Parameters generator.
+ */
+ public Pkcs5S2ParametersGenerator()
+ : this(new Sha1Digest())
+ {
+ }
+
+ public Pkcs5S2ParametersGenerator(IDigest digest)
+ {
+ this.hMac = new HMac(digest);
+ this.state = new byte[hMac.GetMacSize()];
+ }
+
+ private void F(
+ byte[] S,
+ int c,
+ byte[] iBuf,
+ byte[] outBytes,
+ int outOff)
+ {
+ if (c == 0)
+ throw new ArgumentException("iteration count must be at least 1.");
+
+ if (S != null)
+ {
+ hMac.BlockUpdate(S, 0, S.Length);
+ }
+
+ hMac.BlockUpdate(iBuf, 0, iBuf.Length);
+ hMac.DoFinal(state, 0);
+
+ Array.Copy(state, 0, outBytes, outOff, state.Length);
+
+ for (int count = 1; count < c; ++count)
+ {
+ hMac.BlockUpdate(state, 0, state.Length);
+ hMac.DoFinal(state, 0);
+
+ for (int j = 0; j < state.Length; ++j)
+ {
+ outBytes[outOff + j] ^= state[j];
+ }
+ }
+ }
+
+ private byte[] GenerateDerivedKey(
+ int dkLen)
+ {
+ int hLen = hMac.GetMacSize();
+ int l = (dkLen + hLen - 1) / hLen;
+ byte[] iBuf = new byte[4];
+ byte[] outBytes = new byte[l * hLen];
+ int outPos = 0;
+
+ ICipherParameters param = new KeyParameter(mPassword);
+
+ hMac.Init(param);
+
+ for (int i = 1; i <= l; i++)
+ {
+ // Increment the value in 'iBuf'
+ int pos = 3;
+ while (++iBuf[pos] == 0)
+ {
+ --pos;
+ }
+
+ F(mSalt, mIterationCount, iBuf, outBytes, outPos);
+ outPos += hLen;
+ }
+
+ return outBytes;
+ }
+
+ /**
+ * Generate a key parameter derived from the password, salt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize)
+ {
+ return GenerateDerivedMacParameters(keySize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize)
+ {
+ keySize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize);
+
+ return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the password, salt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ */
+ public override ICipherParameters GenerateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize + ivSize);
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+ }
+
+ public override ICipherParameters GenerateDerivedParameters(
+ string algorithm,
+ int keySize,
+ int ivSize)
+ {
+ keySize /= 8;
+ ivSize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize + ivSize);
+ KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+
+ return new ParametersWithIV(key, dKey, keySize, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the password,
+ * salt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ public override ICipherParameters GenerateDerivedMacParameters(
+ int keySize)
+ {
+ keySize /= 8;
+
+ byte[] dKey = GenerateDerivedKey(keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/Poly1305KeyGenerator.cs b/bc-sharp-crypto/src/crypto/generators/Poly1305KeyGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cdb24bfa0157126286e0692fd94e33e268ca9fa7
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/Poly1305KeyGenerator.cs
@@ -0,0 +1,116 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ ///
+ /// Generates keys for the Poly1305 MAC.
+ ///
+ ///
+ /// Poly1305 keys are 256 bit keys consisting of a 128 bit secret key used for the underlying block
+ /// cipher followed by a 128 bit {@code r} value used for the polynomial portion of the Mac.
+ /// The {@code r} value has a specific format with some bits required to be cleared, resulting in an
+ /// effective 106 bit key.
+ /// A separately generated 256 bit key can be modified to fit the Poly1305 key format by using the
+ /// {@link #clamp(byte[])} method to clear the required bits.
+ ///
+ ///
+ public class Poly1305KeyGenerator
+ : CipherKeyGenerator
+ {
+ private const byte R_MASK_LOW_2 = (byte)0xFC;
+ private const byte R_MASK_HIGH_4 = (byte)0x0F;
+
+ ///
+ /// Initialises the key generator.
+ ///
+ ///
+ /// Poly1305 keys are always 256 bits, so the key length in the provided parameters is ignored.
+ ///
+ protected override void engineInit(KeyGenerationParameters param)
+ {
+ // Poly1305 keys are always 256 bits
+ this.random = param.Random;
+ this.strength = 32;
+ }
+
+ ///
+ /// Generates a 256 bit key in the format required for Poly1305 - e.g.
+ /// k[0] ... k[15], r[0] ... r[15]
with the required bits in r
cleared
+ /// as per .
+ ///
+ protected override byte[] engineGenerateKey()
+ {
+ byte[] key = base.engineGenerateKey();
+ Clamp(key);
+ return key;
+ }
+
+ ///
+ /// Modifies an existing 32 byte key value to comply with the requirements of the Poly1305 key by
+ /// clearing required bits in the r
(second 16 bytes) portion of the key.
+ /// Specifically:
+ ///
+ /// r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15})
+ /// r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252})
+ ///
+ ///
+ /// a 32 byte key value k[0] ... k[15], r[0] ... r[15]
+ public static void Clamp(byte[] key)
+ {
+ /*
+ * Key is k[0] ... k[15], r[0] ... r[15] as per poly1305_aes_clamp in ref impl.
+ */
+ if (key.Length != 32)
+ throw new ArgumentException("Poly1305 key must be 256 bits.");
+
+ /*
+ * r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15})
+ */
+ key[3] &= R_MASK_HIGH_4;
+ key[7] &= R_MASK_HIGH_4;
+ key[11] &= R_MASK_HIGH_4;
+ key[15] &= R_MASK_HIGH_4;
+
+ /*
+ * r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252}).
+ */
+ key[4] &= R_MASK_LOW_2;
+ key[8] &= R_MASK_LOW_2;
+ key[12] &= R_MASK_LOW_2;
+ }
+
+ ///
+ /// Checks a 32 byte key for compliance with the Poly1305 key requirements, e.g.
+ /// k[0] ... k[15], r[0] ... r[15]
with the required bits in r
cleared
+ /// as per .
+ ///
+ /// Key.
+ /// if the key is of the wrong length, or has invalid bits set
+ /// in the r
portion of the key.
+ public static void CheckKey(byte[] key)
+ {
+ if (key.Length != 32)
+ throw new ArgumentException("Poly1305 key must be 256 bits.");
+
+ CheckMask(key[3], R_MASK_HIGH_4);
+ CheckMask(key[7], R_MASK_HIGH_4);
+ CheckMask(key[11], R_MASK_HIGH_4);
+ CheckMask(key[15], R_MASK_HIGH_4);
+
+ CheckMask(key[4], R_MASK_LOW_2);
+ CheckMask(key[8], R_MASK_LOW_2);
+ CheckMask(key[12], R_MASK_LOW_2);
+ }
+
+ private static void CheckMask(byte b, byte mask)
+ {
+ if ((b & (~mask)) != 0)
+ throw new ArgumentException("Invalid format for r portion of Poly1305 key.");
+ }
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/crypto/generators/RSABlindingFactorGenerator.cs b/bc-sharp-crypto/src/crypto/generators/RSABlindingFactorGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e2f63facec987998377cf614dbc1959a5d679185
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/RSABlindingFactorGenerator.cs
@@ -0,0 +1,69 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * Generate a random factor suitable for use with RSA blind signatures
+ * as outlined in Chaum's blinding and unblinding as outlined in
+ * "Handbook of Applied Cryptography", page 475.
+ */
+ public class RsaBlindingFactorGenerator
+ {
+ private RsaKeyParameters key;
+ private SecureRandom random;
+
+ /**
+ * Initialise the factor generator
+ *
+ * @param param the necessary RSA key parameters.
+ */
+ public void Init(
+ ICipherParameters param)
+ {
+ if (param is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ key = (RsaKeyParameters)rParam.Parameters;
+ random = rParam.Random;
+ }
+ else
+ {
+ key = (RsaKeyParameters)param;
+ random = new SecureRandom();
+ }
+
+ if (key.IsPrivate)
+ throw new ArgumentException("generator requires RSA public key");
+ }
+
+ /**
+ * Generate a suitable blind factor for the public key the generator was initialised with.
+ *
+ * @return a random blind factor
+ */
+ public BigInteger GenerateBlindingFactor()
+ {
+ if (key == null)
+ throw new InvalidOperationException("generator not initialised");
+
+ BigInteger m = key.Modulus;
+ int length = m.BitLength - 1; // must be less than m.BitLength
+ BigInteger factor;
+ BigInteger gcd;
+
+ do
+ {
+ factor = new BigInteger(length, random);
+ gcd = factor.Gcd(m);
+ }
+ while (factor.SignValue == 0 || factor.Equals(BigInteger.One) || !gcd.Equals(BigInteger.One));
+
+ return factor;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/RsaKeyPairGenerator.cs b/bc-sharp-crypto/src/crypto/generators/RsaKeyPairGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4499765500e19f91652eddca57848e13b77b9cbf
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/RsaKeyPairGenerator.cs
@@ -0,0 +1,163 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ /**
+ * an RSA key pair generator.
+ */
+ public class RsaKeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private static readonly int[] SPECIAL_E_VALUES = new int[]{ 3, 5, 17, 257, 65537 };
+ private static readonly int SPECIAL_E_HIGHEST = SPECIAL_E_VALUES[SPECIAL_E_VALUES.Length - 1];
+ private static readonly int SPECIAL_E_BITS = BigInteger.ValueOf(SPECIAL_E_HIGHEST).BitLength;
+
+ protected static readonly BigInteger One = BigInteger.One;
+ protected static readonly BigInteger DefaultPublicExponent = BigInteger.ValueOf(0x10001);
+ protected const int DefaultTests = 100;
+
+ protected RsaKeyGenerationParameters parameters;
+
+ public virtual void Init(
+ KeyGenerationParameters parameters)
+ {
+ if (parameters is RsaKeyGenerationParameters)
+ {
+ this.parameters = (RsaKeyGenerationParameters)parameters;
+ }
+ else
+ {
+ this.parameters = new RsaKeyGenerationParameters(
+ DefaultPublicExponent, parameters.Random, parameters.Strength, DefaultTests);
+ }
+ }
+
+ public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ for (;;)
+ {
+ //
+ // p and q values should have a length of half the strength in bits
+ //
+ int strength = parameters.Strength;
+ int pBitlength = (strength + 1) / 2;
+ int qBitlength = strength - pBitlength;
+ int mindiffbits = strength / 3;
+ int minWeight = strength >> 2;
+
+ BigInteger e = parameters.PublicExponent;
+
+ // TODO Consider generating safe primes for p, q (see DHParametersHelper.generateSafePrimes)
+ // (then p-1 and q-1 will not consist of only small factors - see "Pollard's algorithm")
+
+ BigInteger p = ChooseRandomPrime(pBitlength, e);
+ BigInteger q, n;
+
+ //
+ // generate a modulus of the required length
+ //
+ for (;;)
+ {
+ q = ChooseRandomPrime(qBitlength, e);
+
+ // p and q should not be too close together (or equal!)
+ BigInteger diff = q.Subtract(p).Abs();
+ if (diff.BitLength < mindiffbits)
+ continue;
+
+ //
+ // calculate the modulus
+ //
+ n = p.Multiply(q);
+
+ if (n.BitLength != strength)
+ {
+ //
+ // if we get here our primes aren't big enough, make the largest
+ // of the two p and try again
+ //
+ p = p.Max(q);
+ continue;
+ }
+
+ /*
+ * Require a minimum weight of the NAF representation, since low-weight composites may
+ * be weak against a version of the number-field-sieve for factoring.
+ *
+ * See "The number field sieve for integers of low weight", Oliver Schirokauer.
+ */
+ if (WNafUtilities.GetNafWeight(n) < minWeight)
+ {
+ p = ChooseRandomPrime(pBitlength, e);
+ continue;
+ }
+
+ break;
+ }
+
+ if (p.CompareTo(q) < 0)
+ {
+ BigInteger tmp = p;
+ p = q;
+ q = tmp;
+ }
+
+ BigInteger pSub1 = p.Subtract(One);
+ BigInteger qSub1 = q.Subtract(One);
+ //BigInteger phi = pSub1.Multiply(qSub1);
+ BigInteger gcd = pSub1.Gcd(qSub1);
+ BigInteger lcm = pSub1.Divide(gcd).Multiply(qSub1);
+
+ //
+ // calculate the private exponent
+ //
+ BigInteger d = e.ModInverse(lcm);
+
+ if (d.BitLength <= qBitlength)
+ continue;
+
+ //
+ // calculate the CRT factors
+ //
+ BigInteger dP = d.Remainder(pSub1);
+ BigInteger dQ = d.Remainder(qSub1);
+ BigInteger qInv = q.ModInverse(p);
+
+ return new AsymmetricCipherKeyPair(
+ new RsaKeyParameters(false, n, e),
+ new RsaPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
+ }
+ }
+
+ /// Choose a random prime value for use with RSA
+ /// the bit-length of the returned prime
+ /// the RSA public exponent
+ /// a prime p, with (p-1) relatively prime to e
+ protected virtual BigInteger ChooseRandomPrime(int bitlength, BigInteger e)
+ {
+ bool eIsKnownOddPrime = (e.BitLength <= SPECIAL_E_BITS) && Arrays.Contains(SPECIAL_E_VALUES, e.IntValue);
+
+ for (;;)
+ {
+ BigInteger p = new BigInteger(bitlength, 1, parameters.Random);
+
+ if (p.Mod(e).Equals(One))
+ continue;
+
+ if (!p.IsProbablePrime(parameters.Certainty, true))
+ continue;
+
+ if (!eIsKnownOddPrime && !e.Gcd(p.Subtract(One)).Equals(One))
+ continue;
+
+ return p;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/generators/SCrypt.cs b/bc-sharp-crypto/src/crypto/generators/SCrypt.cs
new file mode 100644
index 0000000000000000000000000000000000000000..efa74d735086291e6b8fe466d24cbd60f302cd57
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/generators/SCrypt.cs
@@ -0,0 +1,140 @@
+using System;
+using System.Threading;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class SCrypt
+ {
+ // TODO Validate arguments
+ public static byte[] Generate(byte[] P, byte[] S, int N, int r, int p, int dkLen)
+ {
+ return MFcrypt(P, S, N, r, p, dkLen);
+ }
+
+ private static byte[] MFcrypt(byte[] P, byte[] S, int N, int r, int p, int dkLen)
+ {
+ int MFLenBytes = r * 128;
+ byte[] bytes = SingleIterationPBKDF2(P, S, p * MFLenBytes);
+
+ uint[] B = null;
+
+ try
+ {
+ int BLen = bytes.Length >> 2;
+ B = new uint[BLen];
+
+ Pack.LE_To_UInt32(bytes, 0, B);
+
+ int MFLenWords = MFLenBytes >> 2;
+ for (int BOff = 0; BOff < BLen; BOff += MFLenWords)
+ {
+ // TODO These can be done in parallel threads
+ SMix(B, BOff, N, r);
+ }
+
+ Pack.UInt32_To_LE(B, bytes, 0);
+
+ return SingleIterationPBKDF2(P, bytes, dkLen);
+ }
+ finally
+ {
+ ClearAll(bytes, B);
+ }
+ }
+
+ private static byte[] SingleIterationPBKDF2(byte[] P, byte[] S, int dkLen)
+ {
+ PbeParametersGenerator pGen = new Pkcs5S2ParametersGenerator(new Sha256Digest());
+ pGen.Init(P, S, 1);
+ KeyParameter key = (KeyParameter)pGen.GenerateDerivedMacParameters(dkLen * 8);
+ return key.GetKey();
+ }
+
+ private static void SMix(uint[] B, int BOff, int N, int r)
+ {
+ int BCount = r * 32;
+
+ uint[] blockX1 = new uint[16];
+ uint[] blockX2 = new uint[16];
+ uint[] blockY = new uint[BCount];
+
+ uint[] X = new uint[BCount];
+ uint[][] V = new uint[N][];
+
+ try
+ {
+ Array.Copy(B, BOff, X, 0, BCount);
+
+ for (int i = 0; i < N; ++i)
+ {
+ V[i] = (uint[])X.Clone();
+ BlockMix(X, blockX1, blockX2, blockY, r);
+ }
+
+ uint mask = (uint)N - 1;
+ for (int i = 0; i < N; ++i)
+ {
+ uint j = X[BCount - 16] & mask;
+ Xor(X, V[j], 0, X);
+ BlockMix(X, blockX1, blockX2, blockY, r);
+ }
+
+ Array.Copy(X, 0, B, BOff, BCount);
+ }
+ finally
+ {
+ ClearAll(V);
+ ClearAll(X, blockX1, blockX2, blockY);
+ }
+ }
+
+ private static void BlockMix(uint[] B, uint[] X1, uint[] X2, uint[] Y, int r)
+ {
+ Array.Copy(B, B.Length - 16, X1, 0, 16);
+
+ int BOff = 0, YOff = 0, halfLen = B.Length >> 1;
+
+ for (int i = 2 * r; i > 0; --i)
+ {
+ Xor(X1, B, BOff, X2);
+
+ Salsa20Engine.SalsaCore(8, X2, X1);
+ Array.Copy(X1, 0, Y, YOff, 16);
+
+ YOff = halfLen + BOff - YOff;
+ BOff += 16;
+ }
+
+ Array.Copy(Y, 0, B, 0, Y.Length);
+ }
+
+ private static void Xor(uint[] a, uint[] b, int bOff, uint[] output)
+ {
+ for (int i = output.Length - 1; i >= 0; --i)
+ {
+ output[i] = a[i] ^ b[bOff + i];
+ }
+ }
+
+ private static void Clear(Array array)
+ {
+ if (array != null)
+ {
+ Array.Clear(array, 0, array.Length);
+ }
+ }
+
+ private static void ClearAll(params Array[] arrays)
+ {
+ foreach (Array array in arrays)
+ {
+ Clear(array);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/io/CipherStream.cs b/bc-sharp-crypto/src/crypto/io/CipherStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b5e68307584a5d7303ee0500784e6b5fe28f1c8e
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/io/CipherStream.cs
@@ -0,0 +1,252 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.IO
+{
+ public class CipherStream
+ : Stream
+ {
+ internal Stream stream;
+ internal IBufferedCipher inCipher, outCipher;
+ private byte[] mInBuf;
+ private int mInPos;
+ private bool inStreamEnded;
+
+ public CipherStream(
+ Stream stream,
+ IBufferedCipher readCipher,
+ IBufferedCipher writeCipher)
+ {
+ this.stream = stream;
+
+ if (readCipher != null)
+ {
+ this.inCipher = readCipher;
+ mInBuf = null;
+ }
+
+ if (writeCipher != null)
+ {
+ this.outCipher = writeCipher;
+ }
+ }
+
+ public IBufferedCipher ReadCipher
+ {
+ get { return inCipher; }
+ }
+
+ public IBufferedCipher WriteCipher
+ {
+ get { return outCipher; }
+ }
+
+ public override int ReadByte()
+ {
+ if (inCipher == null)
+ return stream.ReadByte();
+
+ if (mInBuf == null || mInPos >= mInBuf.Length)
+ {
+ if (!FillInBuf())
+ return -1;
+ }
+
+ return mInBuf[mInPos++];
+ }
+
+ public override int Read(
+ byte[] buffer,
+ int offset,
+ int count)
+ {
+ if (inCipher == null)
+ return stream.Read(buffer, offset, count);
+
+ int num = 0;
+ while (num < count)
+ {
+ if (mInBuf == null || mInPos >= mInBuf.Length)
+ {
+ if (!FillInBuf())
+ break;
+ }
+
+ int numToCopy = System.Math.Min(count - num, mInBuf.Length - mInPos);
+ Array.Copy(mInBuf, mInPos, buffer, offset + num, numToCopy);
+ mInPos += numToCopy;
+ num += numToCopy;
+ }
+
+ return num;
+ }
+
+ private bool FillInBuf()
+ {
+ if (inStreamEnded)
+ return false;
+
+ mInPos = 0;
+
+ do
+ {
+ mInBuf = ReadAndProcessBlock();
+ }
+ while (!inStreamEnded && mInBuf == null);
+
+ return mInBuf != null;
+ }
+
+ private byte[] ReadAndProcessBlock()
+ {
+ int blockSize = inCipher.GetBlockSize();
+ int readSize = (blockSize == 0) ? 256 : blockSize;
+
+ byte[] block = new byte[readSize];
+ int numRead = 0;
+ do
+ {
+ int count = stream.Read(block, numRead, block.Length - numRead);
+ if (count < 1)
+ {
+ inStreamEnded = true;
+ break;
+ }
+ numRead += count;
+ }
+ while (numRead < block.Length);
+
+ Debug.Assert(inStreamEnded || numRead == block.Length);
+
+ byte[] bytes = inStreamEnded
+ ? inCipher.DoFinal(block, 0, numRead)
+ : inCipher.ProcessBytes(block);
+
+ if (bytes != null && bytes.Length == 0)
+ {
+ bytes = null;
+ }
+
+ return bytes;
+ }
+
+ public override void Write(
+ byte[] buffer,
+ int offset,
+ int count)
+ {
+ Debug.Assert(buffer != null);
+ Debug.Assert(0 <= offset && offset <= buffer.Length);
+ Debug.Assert(count >= 0);
+
+ int end = offset + count;
+
+ Debug.Assert(0 <= end && end <= buffer.Length);
+
+ if (outCipher == null)
+ {
+ stream.Write(buffer, offset, count);
+ return;
+ }
+
+ byte[] data = outCipher.ProcessBytes(buffer, offset, count);
+ if (data != null)
+ {
+ stream.Write(data, 0, data.Length);
+ }
+ }
+
+ public override void WriteByte(
+ byte b)
+ {
+ if (outCipher == null)
+ {
+ stream.WriteByte(b);
+ return;
+ }
+
+ byte[] data = outCipher.ProcessByte(b);
+ if (data != null)
+ {
+ stream.Write(data, 0, data.Length);
+ }
+ }
+
+ public override bool CanRead
+ {
+ get { return stream.CanRead && (inCipher != null); }
+ }
+
+ public override bool CanWrite
+ {
+ get { return stream.CanWrite && (outCipher != null); }
+ }
+
+ public override bool CanSeek
+ {
+ get { return false; }
+ }
+
+ public sealed override long Length
+ {
+ get { throw new NotSupportedException(); }
+ }
+
+ public sealed override long Position
+ {
+ get { throw new NotSupportedException(); }
+ set { throw new NotSupportedException(); }
+ }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (outCipher != null)
+ {
+ byte[] data = outCipher.DoFinal();
+ stream.Write(data, 0, data.Length);
+ stream.Flush();
+ }
+ Platform.Dispose(stream);
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ if (outCipher != null)
+ {
+ byte[] data = outCipher.DoFinal();
+ stream.Write(data, 0, data.Length);
+ stream.Flush();
+ }
+ Platform.Dispose(stream);
+ base.Close();
+ }
+#endif
+
+ public override void Flush()
+ {
+ // Note: outCipher.DoFinal is only called during Close()
+ stream.Flush();
+ }
+
+ public sealed override long Seek(
+ long offset,
+ SeekOrigin origin)
+ {
+ throw new NotSupportedException();
+ }
+
+ public sealed override void SetLength(
+ long length)
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/io/DigestStream.cs b/bc-sharp-crypto/src/crypto/io/DigestStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..dce8757929b729e8150637d41178a4b99e8c8339
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/io/DigestStream.cs
@@ -0,0 +1,151 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.IO
+{
+ public class DigestStream
+ : Stream
+ {
+ protected readonly Stream stream;
+ protected readonly IDigest inDigest;
+ protected readonly IDigest outDigest;
+
+ public DigestStream(
+ Stream stream,
+ IDigest readDigest,
+ IDigest writeDigest)
+ {
+ this.stream = stream;
+ this.inDigest = readDigest;
+ this.outDigest = writeDigest;
+ }
+
+ public virtual IDigest ReadDigest()
+ {
+ return inDigest;
+ }
+
+ public virtual IDigest WriteDigest()
+ {
+ return outDigest;
+ }
+
+ public override int Read(
+ byte[] buffer,
+ int offset,
+ int count)
+ {
+ int n = stream.Read(buffer, offset, count);
+ if (inDigest != null)
+ {
+ if (n > 0)
+ {
+ inDigest.BlockUpdate(buffer, offset, n);
+ }
+ }
+ return n;
+ }
+
+ public override int ReadByte()
+ {
+ int b = stream.ReadByte();
+ if (inDigest != null)
+ {
+ if (b >= 0)
+ {
+ inDigest.Update((byte)b);
+ }
+ }
+ return b;
+ }
+
+ public override void Write(
+ byte[] buffer,
+ int offset,
+ int count)
+ {
+ if (outDigest != null)
+ {
+ if (count > 0)
+ {
+ outDigest.BlockUpdate(buffer, offset, count);
+ }
+ }
+ stream.Write(buffer, offset, count);
+ }
+
+ public override void WriteByte(
+ byte b)
+ {
+ if (outDigest != null)
+ {
+ outDigest.Update(b);
+ }
+ stream.WriteByte(b);
+ }
+
+ public override bool CanRead
+ {
+ get { return stream.CanRead; }
+ }
+
+ public override bool CanWrite
+ {
+ get { return stream.CanWrite; }
+ }
+
+ public override bool CanSeek
+ {
+ get { return stream.CanSeek; }
+ }
+
+ public override long Length
+ {
+ get { return stream.Length; }
+ }
+
+ public override long Position
+ {
+ get { return stream.Position; }
+ set { stream.Position = value; }
+ }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Platform.Dispose(stream);
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ Platform.Dispose(stream);
+ base.Close();
+ }
+#endif
+
+ public override void Flush()
+ {
+ stream.Flush();
+ }
+
+ public override long Seek(
+ long offset,
+ SeekOrigin origin)
+ {
+ return stream.Seek(offset, origin);
+ }
+
+ public override void SetLength(
+ long length)
+ {
+ stream.SetLength(length);
+ }
+ }
+}
+
diff --git a/bc-sharp-crypto/src/crypto/io/MacStream.cs b/bc-sharp-crypto/src/crypto/io/MacStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d9b8323b54a81e93e489d9313e8d22538109e4b6
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/io/MacStream.cs
@@ -0,0 +1,150 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.IO
+{
+ public class MacStream
+ : Stream
+ {
+ protected readonly Stream stream;
+ protected readonly IMac inMac;
+ protected readonly IMac outMac;
+
+ public MacStream(
+ Stream stream,
+ IMac readMac,
+ IMac writeMac)
+ {
+ this.stream = stream;
+ this.inMac = readMac;
+ this.outMac = writeMac;
+ }
+
+ public virtual IMac ReadMac()
+ {
+ return inMac;
+ }
+
+ public virtual IMac WriteMac()
+ {
+ return outMac;
+ }
+
+ public override int Read(
+ byte[] buffer,
+ int offset,
+ int count)
+ {
+ int n = stream.Read(buffer, offset, count);
+ if (inMac != null)
+ {
+ if (n > 0)
+ {
+ inMac.BlockUpdate(buffer, offset, n);
+ }
+ }
+ return n;
+ }
+
+ public override int ReadByte()
+ {
+ int b = stream.ReadByte();
+ if (inMac != null)
+ {
+ if (b >= 0)
+ {
+ inMac.Update((byte)b);
+ }
+ }
+ return b;
+ }
+
+ public override void Write(
+ byte[] buffer,
+ int offset,
+ int count)
+ {
+ if (outMac != null)
+ {
+ if (count > 0)
+ {
+ outMac.BlockUpdate(buffer, offset, count);
+ }
+ }
+ stream.Write(buffer, offset, count);
+ }
+
+ public override void WriteByte(byte b)
+ {
+ if (outMac != null)
+ {
+ outMac.Update(b);
+ }
+ stream.WriteByte(b);
+ }
+
+ public override bool CanRead
+ {
+ get { return stream.CanRead; }
+ }
+
+ public override bool CanWrite
+ {
+ get { return stream.CanWrite; }
+ }
+
+ public override bool CanSeek
+ {
+ get { return stream.CanSeek; }
+ }
+
+ public override long Length
+ {
+ get { return stream.Length; }
+ }
+
+ public override long Position
+ {
+ get { return stream.Position; }
+ set { stream.Position = value; }
+ }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Platform.Dispose(stream);
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ Platform.Dispose(stream);
+ base.Close();
+ }
+#endif
+
+ public override void Flush()
+ {
+ stream.Flush();
+ }
+
+ public override long Seek(
+ long offset,
+ SeekOrigin origin)
+ {
+ return stream.Seek(offset,origin);
+ }
+
+ public override void SetLength(
+ long length)
+ {
+ stream.SetLength(length);
+ }
+ }
+}
+
diff --git a/bc-sharp-crypto/src/crypto/io/SignerStream.cs b/bc-sharp-crypto/src/crypto/io/SignerStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1e37c8d34e8677bee40fa3d2d1f0c523919c527a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/io/SignerStream.cs
@@ -0,0 +1,151 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.IO
+{
+ public class SignerStream
+ : Stream
+ {
+ protected readonly Stream stream;
+ protected readonly ISigner inSigner;
+ protected readonly ISigner outSigner;
+
+ public SignerStream(
+ Stream stream,
+ ISigner readSigner,
+ ISigner writeSigner)
+ {
+ this.stream = stream;
+ this.inSigner = readSigner;
+ this.outSigner = writeSigner;
+ }
+
+ public virtual ISigner ReadSigner()
+ {
+ return inSigner;
+ }
+
+ public virtual ISigner WriteSigner()
+ {
+ return outSigner;
+ }
+
+ public override int Read(
+ byte[] buffer,
+ int offset,
+ int count)
+ {
+ int n = stream.Read(buffer, offset, count);
+ if (inSigner != null)
+ {
+ if (n > 0)
+ {
+ inSigner.BlockUpdate(buffer, offset, n);
+ }
+ }
+ return n;
+ }
+
+ public override int ReadByte()
+ {
+ int b = stream.ReadByte();
+ if (inSigner != null)
+ {
+ if (b >= 0)
+ {
+ inSigner.Update((byte)b);
+ }
+ }
+ return b;
+ }
+
+ public override void Write(
+ byte[] buffer,
+ int offset,
+ int count)
+ {
+ if (outSigner != null)
+ {
+ if (count > 0)
+ {
+ outSigner.BlockUpdate(buffer, offset, count);
+ }
+ }
+ stream.Write(buffer, offset, count);
+ }
+
+ public override void WriteByte(
+ byte b)
+ {
+ if (outSigner != null)
+ {
+ outSigner.Update(b);
+ }
+ stream.WriteByte(b);
+ }
+
+ public override bool CanRead
+ {
+ get { return stream.CanRead; }
+ }
+
+ public override bool CanWrite
+ {
+ get { return stream.CanWrite; }
+ }
+
+ public override bool CanSeek
+ {
+ get { return stream.CanSeek; }
+ }
+
+ public override long Length
+ {
+ get { return stream.Length; }
+ }
+
+ public override long Position
+ {
+ get { return stream.Position; }
+ set { stream.Position = value; }
+ }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Platform.Dispose(stream);
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ Platform.Dispose(stream);
+ base.Close();
+ }
+#endif
+
+ public override void Flush()
+ {
+ stream.Flush();
+ }
+
+ public override long Seek(
+ long offset,
+ SeekOrigin origin)
+ {
+ return stream.Seek(offset, origin);
+ }
+
+ public override void SetLength(
+ long length)
+ {
+ stream.SetLength(length);
+ }
+ }
+}
+
diff --git a/bc-sharp-crypto/src/crypto/macs/CMac.cs b/bc-sharp-crypto/src/crypto/macs/CMac.cs
new file mode 100644
index 0000000000000000000000000000000000000000..682c12bacde5ca316f089c3a5fd1c331c4dd01fe
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/macs/CMac.cs
@@ -0,0 +1,257 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+ /**
+ * CMAC - as specified at www.nuee.nagoya-u.ac.jp/labs/tiwata/omac/omac.html
+ *
+ * CMAC is analogous to OMAC1 - see also en.wikipedia.org/wiki/CMAC
+ *
+ * CMAC is a NIST recomendation - see
+ * csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38B.pdf
+ *
+ * CMAC/OMAC1 is a blockcipher-based message authentication code designed and
+ * analyzed by Tetsu Iwata and Kaoru Kurosawa.
+ *
+ * CMAC/OMAC1 is a simple variant of the CBC MAC (Cipher Block Chaining Message
+ * Authentication Code). OMAC stands for One-Key CBC MAC.
+ *
+ * It supports 128- or 64-bits block ciphers, with any key size, and returns
+ * a MAC with dimension less or equal to the block size of the underlying
+ * cipher.
+ *
+ */
+ public class CMac
+ : IMac
+ {
+ private const byte CONSTANT_128 = (byte)0x87;
+ private const byte CONSTANT_64 = (byte)0x1b;
+
+ private byte[] ZEROES;
+
+ private byte[] mac;
+
+ private byte[] buf;
+ private int bufOff;
+ private IBlockCipher cipher;
+
+ private int macSize;
+
+ private byte[] L, Lu, Lu2;
+
+ /**
+ * create a standard MAC based on a CBC block cipher (64 or 128 bit block).
+ * This will produce an authentication code the length of the block size
+ * of the cipher.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ */
+ public CMac(
+ IBlockCipher cipher)
+ : this(cipher, cipher.GetBlockSize() * 8)
+ {
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8 and @lt;= 128.
+ */
+ public CMac(
+ IBlockCipher cipher,
+ int macSizeInBits)
+ {
+ if ((macSizeInBits % 8) != 0)
+ throw new ArgumentException("MAC size must be multiple of 8");
+
+ if (macSizeInBits > (cipher.GetBlockSize() * 8))
+ {
+ throw new ArgumentException(
+ "MAC size must be less or equal to "
+ + (cipher.GetBlockSize() * 8));
+ }
+
+ if (cipher.GetBlockSize() != 8 && cipher.GetBlockSize() != 16)
+ {
+ throw new ArgumentException(
+ "Block size must be either 64 or 128 bits");
+ }
+
+ this.cipher = new CbcBlockCipher(cipher);
+ this.macSize = macSizeInBits / 8;
+
+ mac = new byte[cipher.GetBlockSize()];
+
+ buf = new byte[cipher.GetBlockSize()];
+
+ ZEROES = new byte[cipher.GetBlockSize()];
+
+ bufOff = 0;
+ }
+
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName; }
+ }
+
+ private static int ShiftLeft(byte[] block, byte[] output)
+ {
+ int i = block.Length;
+ uint bit = 0;
+ while (--i >= 0)
+ {
+ uint b = block[i];
+ output[i] = (byte)((b << 1) | bit);
+ bit = (b >> 7) & 1;
+ }
+ return (int)bit;
+ }
+
+ private static byte[] DoubleLu(byte[] input)
+ {
+ byte[] ret = new byte[input.Length];
+ int carry = ShiftLeft(input, ret);
+ int xor = input.Length == 16 ? CONSTANT_128 : CONSTANT_64;
+
+ /*
+ * NOTE: This construction is an attempt at a constant-time implementation.
+ */
+ ret[input.Length - 1] ^= (byte)(xor >> ((1 - carry) << 3));
+
+ return ret;
+ }
+
+ public void Init(
+ ICipherParameters parameters)
+ {
+ if (parameters is KeyParameter)
+ {
+ cipher.Init(true, parameters);
+
+ //initializes the L, Lu, Lu2 numbers
+ L = new byte[ZEROES.Length];
+ cipher.ProcessBlock(ZEROES, 0, L, 0);
+ Lu = DoubleLu(L);
+ Lu2 = DoubleLu(Lu);
+ }
+ else if (parameters != null)
+ {
+ // CMAC mode does not permit IV to underlying CBC mode
+ throw new ArgumentException("CMac mode only permits key to be set.", "parameters");
+ }
+
+ Reset();
+ }
+
+ public int GetMacSize()
+ {
+ return macSize;
+ }
+
+ public void Update(
+ byte input)
+ {
+ if (bufOff == buf.Length)
+ {
+ cipher.ProcessBlock(buf, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ buf[bufOff++] = input;
+ }
+
+ public void BlockUpdate(
+ byte[] inBytes,
+ int inOff,
+ int len)
+ {
+ if (len < 0)
+ throw new ArgumentException("Can't have a negative input length!");
+
+ int blockSize = cipher.GetBlockSize();
+ int gapLen = blockSize - bufOff;
+
+ if (len > gapLen)
+ {
+ Array.Copy(inBytes, inOff, buf, bufOff, gapLen);
+
+ cipher.ProcessBlock(buf, 0, mac, 0);
+
+ bufOff = 0;
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > blockSize)
+ {
+ cipher.ProcessBlock(inBytes, inOff, mac, 0);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ Array.Copy(inBytes, inOff, buf, bufOff, len);
+
+ bufOff += len;
+ }
+
+ public int DoFinal(
+ byte[] outBytes,
+ int outOff)
+ {
+ int blockSize = cipher.GetBlockSize();
+
+ byte[] lu;
+ if (bufOff == blockSize)
+ {
+ lu = Lu;
+ }
+ else
+ {
+ new ISO7816d4Padding().AddPadding(buf, bufOff);
+ lu = Lu2;
+ }
+
+ for (int i = 0; i < mac.Length; i++)
+ {
+ buf[i] ^= lu[i];
+ }
+
+ cipher.ProcessBlock(buf, 0, mac, 0);
+
+ Array.Copy(mac, 0, outBytes, outOff, macSize);
+
+ Reset();
+
+ return macSize;
+ }
+
+ /**
+ * Reset the mac generator.
+ */
+ public void Reset()
+ {
+ /*
+ * clean the buffer.
+ */
+ Array.Clear(buf, 0, buf.Length);
+ bufOff = 0;
+
+ /*
+ * Reset the underlying cipher.
+ */
+ cipher.Reset();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/macs/CbcBlockCipherMac.cs b/bc-sharp-crypto/src/crypto/macs/CbcBlockCipherMac.cs
new file mode 100644
index 0000000000000000000000000000000000000000..146e16aa830d1a758e53baf0736ab151421258b1
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/macs/CbcBlockCipherMac.cs
@@ -0,0 +1,209 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+ /**
+ * standard CBC Block Cipher MAC - if no padding is specified the default of
+ * pad of zeroes is used.
+ */
+ public class CbcBlockCipherMac
+ : IMac
+ {
+ private byte[] buf;
+ private int bufOff;
+ private IBlockCipher cipher;
+ private IBlockCipherPadding padding;
+ private int macSize;
+
+ /**
+ * create a standard MAC based on a CBC block cipher. This will produce an
+ * authentication code half the length of the block size of the cipher.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ */
+ public CbcBlockCipherMac(
+ IBlockCipher cipher)
+ : this(cipher, (cipher.GetBlockSize() * 8) / 2, null)
+ {
+ }
+
+ /**
+ * create a standard MAC based on a CBC block cipher. This will produce an
+ * authentication code half the length of the block size of the cipher.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param padding the padding to be used to complete the last block.
+ */
+ public CbcBlockCipherMac(
+ IBlockCipher cipher,
+ IBlockCipherPadding padding)
+ : this(cipher, (cipher.GetBlockSize() * 8) / 2, padding)
+ {
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits. This class uses CBC mode as the basis for the
+ * MAC generation.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ */
+ public CbcBlockCipherMac(
+ IBlockCipher cipher,
+ int macSizeInBits)
+ : this(cipher, macSizeInBits, null)
+ {
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits. This class uses CBC mode as the basis for the
+ * MAC generation.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ * @param padding the padding to be used to complete the last block.
+ */
+ public CbcBlockCipherMac(
+ IBlockCipher cipher,
+ int macSizeInBits,
+ IBlockCipherPadding padding)
+ {
+ if ((macSizeInBits % 8) != 0)
+ throw new ArgumentException("MAC size must be multiple of 8");
+
+ this.cipher = new CbcBlockCipher(cipher);
+ this.padding = padding;
+ this.macSize = macSizeInBits / 8;
+
+ buf = new byte[cipher.GetBlockSize()];
+ bufOff = 0;
+ }
+
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName; }
+ }
+
+ public void Init(
+ ICipherParameters parameters)
+ {
+ Reset();
+
+ cipher.Init(true, parameters);
+ }
+
+ public int GetMacSize()
+ {
+ return macSize;
+ }
+
+ public void Update(
+ byte input)
+ {
+ if (bufOff == buf.Length)
+ {
+ cipher.ProcessBlock(buf, 0, buf, 0);
+ bufOff = 0;
+ }
+
+ buf[bufOff++] = input;
+ }
+
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int len)
+ {
+ if (len < 0)
+ throw new ArgumentException("Can't have a negative input length!");
+
+ int blockSize = cipher.GetBlockSize();
+ int gapLen = blockSize - bufOff;
+
+ if (len > gapLen)
+ {
+ Array.Copy(input, inOff, buf, bufOff, gapLen);
+
+ cipher.ProcessBlock(buf, 0, buf, 0);
+
+ bufOff = 0;
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > blockSize)
+ {
+ cipher.ProcessBlock(input, inOff, buf, 0);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ Array.Copy(input, inOff, buf, bufOff, len);
+
+ bufOff += len;
+ }
+
+ public int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ int blockSize = cipher.GetBlockSize();
+
+ if (padding == null)
+ {
+ // pad with zeroes
+ while (bufOff < blockSize)
+ {
+ buf[bufOff++] = 0;
+ }
+ }
+ else
+ {
+ if (bufOff == blockSize)
+ {
+ cipher.ProcessBlock(buf, 0, buf, 0);
+ bufOff = 0;
+ }
+
+ padding.AddPadding(buf, bufOff);
+ }
+
+ cipher.ProcessBlock(buf, 0, buf, 0);
+
+ Array.Copy(buf, 0, output, outOff, macSize);
+
+ Reset();
+
+ return macSize;
+ }
+
+ /**
+ * Reset the mac generator.
+ */
+ public void Reset()
+ {
+ // Clear the buffer.
+ Array.Clear(buf, 0, buf.Length);
+ bufOff = 0;
+
+ // Reset the underlying cipher.
+ cipher.Reset();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/macs/CfbBlockCipherMac.cs b/bc-sharp-crypto/src/crypto/macs/CfbBlockCipherMac.cs
new file mode 100644
index 0000000000000000000000000000000000000000..364cf849911d3c8eb92b02ffe51e04d098f0e7ec
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/macs/CfbBlockCipherMac.cs
@@ -0,0 +1,368 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+ /**
+ * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
+ */
+ class MacCFBBlockCipher
+ : IBlockCipher
+ {
+ private byte[] IV;
+ private byte[] cfbV;
+ private byte[] cfbOutV;
+
+ private readonly int blockSize;
+ private readonly IBlockCipher cipher;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of the
+ * feedback mode.
+ * @param blockSize the block size in bits (note: a multiple of 8)
+ */
+ public MacCFBBlockCipher(
+ IBlockCipher cipher,
+ int bitBlockSize)
+ {
+ this.cipher = cipher;
+ this.blockSize = bitBlockSize / 8;
+
+ this.IV = new byte[cipher.GetBlockSize()];
+ this.cfbV = new byte[cipher.GetBlockSize()];
+ this.cfbOutV = new byte[cipher.GetBlockSize()];
+ }
+
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ * An IV which is too short is handled in FIPS compliant fashion.
+ *
+ * @param param the key and other data required by the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)parameters;
+ byte[] iv = ivParam.GetIV();
+
+ if (iv.Length < IV.Length)
+ {
+ Array.Copy(iv, 0, IV, IV.Length - iv.Length, iv.Length);
+ }
+ else
+ {
+ Array.Copy(iv, 0, IV, 0, IV.Length);
+ }
+
+ parameters = ivParam.Parameters;
+ }
+
+ Reset();
+
+ cipher.Init(true, parameters);
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/CFB"
+ * and the block size in bits.
+ */
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/CFB" + (blockSize * 8); }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return true; }
+ }
+
+ /**
+ * return the block size we are operating at.
+ *
+ * @return the block size we are operating at (in bytes).
+ */
+ public int GetBlockSize()
+ {
+ 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)
+ {
+ if ((inOff + blockSize) > input.Length)
+ throw new DataLengthException("input buffer too short");
+
+ if ((outOff + blockSize) > outBytes.Length)
+ throw new DataLengthException("output buffer too short");
+
+ cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
+
+ //
+ // XOR the cfbV with the plaintext producing the cipher text
+ //
+ for (int i = 0; i < blockSize; i++)
+ {
+ outBytes[outOff + i] = (byte)(cfbOutV[i] ^ input[inOff + i]);
+ }
+
+ //
+ // change over the input block.
+ //
+ Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize);
+ Array.Copy(outBytes, outOff, cfbV, cfbV.Length - blockSize, blockSize);
+
+ return blockSize;
+ }
+
+ /**
+ * reset the chaining vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void Reset()
+ {
+ IV.CopyTo(cfbV, 0);
+
+ cipher.Reset();
+ }
+
+ public void GetMacBlock(
+ byte[] mac)
+ {
+ cipher.ProcessBlock(cfbV, 0, mac, 0);
+ }
+ }
+
+ public class CfbBlockCipherMac
+ : IMac
+ {
+ private byte[] mac;
+ private byte[] Buffer;
+ private int bufOff;
+ private MacCFBBlockCipher cipher;
+ private IBlockCipherPadding padding;
+ private int macSize;
+
+ /**
+ * create a standard MAC based on a CFB block cipher. This will produce an
+ * authentication code half the length of the block size of the cipher, with
+ * the CFB mode set to 8 bits.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ */
+ public CfbBlockCipherMac(
+ IBlockCipher cipher)
+ : this(cipher, 8, (cipher.GetBlockSize() * 8) / 2, null)
+ {
+ }
+
+ /**
+ * create a standard MAC based on a CFB block cipher. This will produce an
+ * authentication code half the length of the block size of the cipher, with
+ * the CFB mode set to 8 bits.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param padding the padding to be used.
+ */
+ public CfbBlockCipherMac(
+ IBlockCipher cipher,
+ IBlockCipherPadding padding)
+ : this(cipher, 8, (cipher.GetBlockSize() * 8) / 2, padding)
+ {
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits. This class uses CFB mode as the basis for the
+ * MAC generation.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param cfbBitSize the size of an output block produced by the CFB mode.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ */
+ public CfbBlockCipherMac(
+ IBlockCipher cipher,
+ int cfbBitSize,
+ int macSizeInBits)
+ : this(cipher, cfbBitSize, macSizeInBits, null)
+ {
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits. This class uses CFB mode as the basis for the
+ * MAC generation.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param cfbBitSize the size of an output block produced by the CFB mode.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ * @param padding a padding to be used.
+ */
+ public CfbBlockCipherMac(
+ IBlockCipher cipher,
+ int cfbBitSize,
+ int macSizeInBits,
+ IBlockCipherPadding padding)
+ {
+ if ((macSizeInBits % 8) != 0)
+ throw new ArgumentException("MAC size must be multiple of 8");
+
+ mac = new byte[cipher.GetBlockSize()];
+
+ this.cipher = new MacCFBBlockCipher(cipher, cfbBitSize);
+ this.padding = padding;
+ this.macSize = macSizeInBits / 8;
+
+ Buffer = new byte[this.cipher.GetBlockSize()];
+ bufOff = 0;
+ }
+
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName; }
+ }
+
+ public void Init(
+ ICipherParameters parameters)
+ {
+ Reset();
+
+ cipher.Init(true, parameters);
+ }
+
+ public int GetMacSize()
+ {
+ return macSize;
+ }
+
+ public void Update(
+ byte input)
+ {
+ if (bufOff == Buffer.Length)
+ {
+ cipher.ProcessBlock(Buffer, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ Buffer[bufOff++] = input;
+ }
+
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int len)
+ {
+ if (len < 0)
+ throw new ArgumentException("Can't have a negative input length!");
+
+ int blockSize = cipher.GetBlockSize();
+ int resultLen = 0;
+ int gapLen = blockSize - bufOff;
+
+ if (len > gapLen)
+ {
+ Array.Copy(input, inOff, Buffer, bufOff, gapLen);
+
+ resultLen += cipher.ProcessBlock(Buffer, 0, mac, 0);
+
+ bufOff = 0;
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > blockSize)
+ {
+ resultLen += cipher.ProcessBlock(input, inOff, mac, 0);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ Array.Copy(input, inOff, Buffer, bufOff, len);
+
+ bufOff += len;
+ }
+
+ public int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ int blockSize = cipher.GetBlockSize();
+
+ // pad with zeroes
+ if (this.padding == null)
+ {
+ while (bufOff < blockSize)
+ {
+ Buffer[bufOff++] = 0;
+ }
+ }
+ else
+ {
+ padding.AddPadding(Buffer, bufOff);
+ }
+
+ cipher.ProcessBlock(Buffer, 0, mac, 0);
+
+ cipher.GetMacBlock(mac);
+
+ Array.Copy(mac, 0, output, outOff, macSize);
+
+ Reset();
+
+ return macSize;
+ }
+
+ /**
+ * Reset the mac generator.
+ */
+ public void Reset()
+ {
+ // Clear the buffer.
+ Array.Clear(Buffer, 0, Buffer.Length);
+ bufOff = 0;
+
+ // Reset the underlying cipher.
+ cipher.Reset();
+ }
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/macs/DSTU7564Mac.cs b/bc-sharp-crypto/src/crypto/macs/DSTU7564Mac.cs
new file mode 100644
index 0000000000000000000000000000000000000000..36e86418a2c4de449efe3c3dfd6ada00f4eaa968
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/macs/DSTU7564Mac.cs
@@ -0,0 +1,143 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+ ///
+ /// Implementation of DSTU7564 mac mode
+ ///
+ public class Dstu7564Mac
+ : IMac
+ {
+ private Dstu7564Digest engine;
+ private int macSize;
+
+ private ulong inputLength;
+
+ byte[] paddedKey;
+ byte[] invertedKey;
+
+ public string AlgorithmName
+ {
+ get { return "DSTU7564Mac"; }
+ }
+
+ public Dstu7564Mac(int macSizeBits)
+ {
+ engine = new Dstu7564Digest(macSizeBits);
+ macSize = macSizeBits / 8;
+ }
+
+ public void Init(ICipherParameters parameters)
+ {
+ if (parameters is KeyParameter)
+ {
+ byte[] key = ((KeyParameter)parameters).GetKey();
+
+ invertedKey = new byte[key.Length];
+
+ paddedKey = PadKey(key);
+
+ for (int byteIndex = 0; byteIndex < invertedKey.Length; byteIndex++)
+ {
+ invertedKey[byteIndex] = (byte)(key[byteIndex] ^ (byte)0xFF);
+ }
+ }
+ else
+ {
+ throw new ArgumentException("Bad parameter passed");
+ }
+
+ engine.BlockUpdate(paddedKey, 0, paddedKey.Length);
+ }
+
+ public int GetMacSize()
+ {
+ return macSize;
+ }
+
+ public void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ Check.DataLength(input, inOff, len, "Input buffer too short");
+
+ if (paddedKey == null)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ engine.BlockUpdate(input, inOff, len);
+ inputLength += (ulong)len;
+ }
+
+ public void Update(byte input)
+ {
+ engine.Update(input);
+ inputLength++;
+ }
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ Check.OutputLength(output, outOff, macSize, "Output buffer too short");
+
+ if (paddedKey == null)
+ throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+ Pad();
+
+ engine.BlockUpdate(invertedKey, 0, invertedKey.Length);
+
+ inputLength = 0;
+
+ return engine.DoFinal(output, outOff);
+ }
+
+ public void Reset()
+ {
+ inputLength = 0;
+ engine.Reset();
+ if (paddedKey != null)
+ {
+ engine.BlockUpdate(paddedKey, 0, paddedKey.Length);
+ }
+ }
+
+ private void Pad()
+ {
+ int extra = engine.GetByteLength() - (int)(inputLength % (ulong)engine.GetByteLength());
+ if (extra < 13) // terminator byte + 96 bits of length
+ {
+ extra += engine.GetByteLength();
+ }
+
+ byte[] padded = new byte[extra];
+
+ padded[0] = (byte)0x80; // Defined in standard;
+
+ // Defined in standard;
+ Pack.UInt64_To_LE(inputLength * 8, padded, padded.Length - 12);
+
+ engine.BlockUpdate(padded, 0, padded.Length);
+ }
+
+ private byte[] PadKey(byte[] input)
+ {
+ int paddedLen = ((input.Length + engine.GetByteLength() - 1) / engine.GetByteLength()) * engine.GetByteLength();
+
+ int extra = engine.GetByteLength() - (int)(input.Length % engine.GetByteLength());
+ if (extra < 13) // terminator byte + 96 bits of length
+ {
+ paddedLen += engine.GetByteLength();
+ }
+
+ byte[] padded = new byte[paddedLen];
+
+ Array.Copy(input, 0, padded, 0, input.Length);
+
+ padded[input.Length] = (byte)0x80; // Defined in standard;
+ Pack.UInt32_To_LE((uint)(input.Length * 8), padded, padded.Length - 12); // Defined in standard;
+
+ return padded;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/macs/DSTU7624Mac.cs b/bc-sharp-crypto/src/crypto/macs/DSTU7624Mac.cs
new file mode 100644
index 0000000000000000000000000000000000000000..953d8164f4affdc4ebd71b93d2ab067bca42a217
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/macs/DSTU7624Mac.cs
@@ -0,0 +1,160 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+ /**
+ * implementation of DSTU 7624 MAC
+ */
+ public class Dstu7624Mac : IMac
+ {
+ private int macSize;
+
+ private Dstu7624Engine engine;
+ private int blockSize;
+
+ private byte[] c, cTemp, kDelta;
+ private byte[] buf;
+ private int bufOff;
+
+ public Dstu7624Mac(int blockSizeBits, int q)
+ {
+ engine = new Dstu7624Engine(blockSizeBits);
+
+ blockSize = blockSizeBits / 8;
+
+ macSize = q / 8;
+
+ c = new byte[blockSize];
+
+ cTemp = new byte[blockSize];
+
+ kDelta = new byte[blockSize];
+ buf = new byte[blockSize];
+ }
+
+ public void Init(ICipherParameters parameters)
+ {
+ if (parameters is KeyParameter)
+ {
+ engine.Init(true, (KeyParameter)parameters);
+
+ engine.ProcessBlock(kDelta, 0, kDelta, 0);
+ }
+ else
+ {
+ throw new ArgumentException("invalid parameter passed to Dstu7624Mac init - "
+ + Platform.GetTypeName(parameters));
+ }
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Dstu7624Mac"; }
+ }
+
+ public int GetMacSize()
+ {
+ return macSize;
+ }
+
+ public void Update(byte input)
+ {
+ if (bufOff == buf.Length)
+ {
+ processBlock(buf, 0);
+ bufOff = 0;
+ }
+
+ buf[bufOff++] = input;
+ }
+
+ public void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ if (len < 0)
+ {
+ throw new ArgumentException(
+ "Can't have a negative input length!");
+ }
+
+ int blockSize = engine.GetBlockSize();
+ int gapLen = blockSize - bufOff;
+
+ if (len > gapLen)
+ {
+ Array.Copy(input, inOff, buf, bufOff, gapLen);
+
+ processBlock(buf, 0);
+
+ bufOff = 0;
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > blockSize)
+ {
+ processBlock(input, inOff);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ Array.Copy(input, inOff, buf, bufOff, len);
+
+ bufOff += len;
+ }
+
+ private void processBlock(byte[] input, int inOff)
+ {
+ Xor(c, 0, input, inOff, cTemp);
+
+ engine.ProcessBlock(cTemp, 0, c, 0);
+ }
+
+ private void Xor(byte[] c, int cOff, byte[] input, int inOff, byte[] xorResult)
+ {
+ for (int byteIndex = 0; byteIndex < blockSize; byteIndex++)
+ {
+ xorResult[byteIndex] = (byte)(c[byteIndex + cOff] ^ input[byteIndex + inOff]);
+ }
+ }
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ if (bufOff % buf.Length != 0)
+ {
+ throw new DataLengthException("Input must be a multiple of blocksize");
+ }
+
+ //Last block
+ Xor(c, 0, buf, 0, cTemp);
+ Xor(cTemp, 0, kDelta, 0, c);
+ engine.ProcessBlock(c, 0, c, 0);
+
+ if (macSize + outOff > output.Length)
+ {
+ throw new DataLengthException("Output buffer too short");
+ }
+
+ Array.Copy(c, 0, output, outOff, macSize);
+
+ return macSize;
+ }
+
+ public void Reset()
+ {
+ Arrays.Fill(c, (byte)0x00);
+ Arrays.Fill(cTemp, (byte)0x00);
+ Arrays.Fill(kDelta, (byte)0x00);
+ Arrays.Fill(buf, (byte)0x00);
+ engine.Reset();
+ engine.ProcessBlock(kDelta, 0, kDelta, 0);
+ bufOff = 0;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/macs/GMac.cs b/bc-sharp-crypto/src/crypto/macs/GMac.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f2c3990c641847eeca1fabeb58cd6d42f0998753
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/macs/GMac.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+ ///
+ /// The GMAC specialisation of Galois/Counter mode (GCM) detailed in NIST Special Publication
+ /// 800-38D.
+ ///
+ ///
+ /// GMac is an invocation of the GCM mode where no data is encrypted (i.e. all input data to the Mac
+ /// is processed as additional authenticated data with the underlying GCM block cipher).
+ ///
+ public class GMac
+ : IMac
+ {
+ private readonly GcmBlockCipher cipher;
+ private readonly int macSizeBits;
+
+ ///
+ /// Creates a GMAC based on the operation of a block cipher in GCM mode.
+ ///
+ ///
+ /// This will produce an authentication code the length of the block size of the cipher.
+ ///
+ /// the cipher to be used in GCM mode to generate the MAC.
+ public GMac(GcmBlockCipher cipher)
+ : this(cipher, 128)
+ {
+ }
+
+ ///
+ /// Creates a GMAC based on the operation of a 128 bit block cipher in GCM mode.
+ ///
+ ///
+ /// This will produce an authentication code the length of the block size of the cipher.
+ ///
+ /// the cipher to be used in GCM mode to generate the MAC.
+ /// the mac size to generate, in bits. Must be a multiple of 8, between 32 and 128 (inclusive).
+ /// Sizes less than 96 are not recommended, but are supported for specialized applications.
+ public GMac(GcmBlockCipher cipher, int macSizeBits)
+ {
+ this.cipher = cipher;
+ this.macSizeBits = macSizeBits;
+ }
+
+ ///
+ /// Initialises the GMAC - requires a
+ /// providing a and a nonce.
+ ///
+ public void Init(ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV param = (ParametersWithIV)parameters;
+
+ byte[] iv = param.GetIV();
+ KeyParameter keyParam = (KeyParameter)param.Parameters;
+
+ // GCM is always operated in encrypt mode to calculate MAC
+ cipher.Init(true, new AeadParameters(keyParam, macSizeBits, iv));
+ }
+ else
+ {
+ throw new ArgumentException("GMAC requires ParametersWithIV");
+ }
+ }
+
+ public string AlgorithmName
+ {
+ get { return cipher.GetUnderlyingCipher().AlgorithmName + "-GMAC"; }
+ }
+
+ public int GetMacSize()
+ {
+ return macSizeBits / 8;
+ }
+
+ public void Update(byte input)
+ {
+ cipher.ProcessAadByte(input);
+ }
+
+ public void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ cipher.ProcessAadBytes(input, inOff, len);
+ }
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ try
+ {
+ return cipher.DoFinal(output, outOff);
+ }
+ catch (InvalidCipherTextException e)
+ {
+ // Impossible in encrypt mode
+ throw new InvalidOperationException(e.ToString());
+ }
+ }
+
+ public void Reset()
+ {
+ cipher.Reset();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/macs/GOST28147Mac.cs b/bc-sharp-crypto/src/crypto/macs/GOST28147Mac.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cc6b723d66e619dff91194ad703818cbb8672820
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/macs/GOST28147Mac.cs
@@ -0,0 +1,297 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+ /**
+ * implementation of GOST 28147-89 MAC
+ */
+ public class Gost28147Mac : IMac
+ {
+ private const int blockSize = 8;
+ private const int macSize = 4;
+ private int bufOff;
+ private byte[] buf;
+ private byte[] mac;
+ private bool firstStep = true;
+ private int[] workingKey;
+
+ //
+ // This is default S-box - E_A.
+ private byte[] S =
+ {
+ 0x9,0x6,0x3,0x2,0x8,0xB,0x1,0x7,0xA,0x4,0xE,0xF,0xC,0x0,0xD,0x5,
+ 0x3,0x7,0xE,0x9,0x8,0xA,0xF,0x0,0x5,0x2,0x6,0xC,0xB,0x4,0xD,0x1,
+ 0xE,0x4,0x6,0x2,0xB,0x3,0xD,0x8,0xC,0xF,0x5,0xA,0x0,0x7,0x1,0x9,
+ 0xE,0x7,0xA,0xC,0xD,0x1,0x3,0x9,0x0,0x2,0xB,0x4,0xF,0x8,0x5,0x6,
+ 0xB,0x5,0x1,0x9,0x8,0xD,0xF,0x0,0xE,0x4,0x2,0x3,0xC,0x7,0xA,0x6,
+ 0x3,0xA,0xD,0xC,0x1,0x2,0x0,0xB,0x7,0x5,0x9,0x4,0x8,0xF,0xE,0x6,
+ 0x1,0xD,0x2,0x9,0x7,0xA,0x6,0x0,0x8,0xC,0x4,0x5,0xF,0x3,0xB,0xE,
+ 0xB,0xA,0xF,0x5,0x0,0xC,0xE,0x8,0x6,0x2,0x3,0x9,0x1,0x7,0xD,0x4
+ };
+
+ public Gost28147Mac()
+ {
+ mac = new byte[blockSize];
+ buf = new byte[blockSize];
+ bufOff = 0;
+ }
+
+ private static int[] generateWorkingKey(
+ byte[] userKey)
+ {
+ 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++)
+ {
+ key[i] = bytesToint(userKey,i*4);
+ }
+
+ return key;
+ }
+
+ public void Init(
+ ICipherParameters parameters)
+ {
+ Reset();
+ buf = new byte[blockSize];
+ if (parameters is ParametersWithSBox)
+ {
+ ParametersWithSBox param = (ParametersWithSBox)parameters;
+
+ //
+ // Set the S-Box
+ //
+ param.GetSBox().CopyTo(this.S, 0);
+
+ //
+ // set key if there is one
+ //
+ if (param.Parameters != null)
+ {
+ workingKey = generateWorkingKey(((KeyParameter)param.Parameters).GetKey());
+ }
+ }
+ else if (parameters is KeyParameter)
+ {
+ workingKey = generateWorkingKey(((KeyParameter)parameters).GetKey());
+ }
+ else
+ {
+ throw new ArgumentException("invalid parameter passed to Gost28147 init - "
+ + Platform.GetTypeName(parameters));
+ }
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Gost28147Mac"; }
+ }
+
+ public int GetMacSize()
+ {
+ return macSize;
+ }
+
+ private int gost28147_mainStep(int n1, int key)
+ {
+ int cm = (key + n1); // CM1
+
+ // S-box replacing
+
+ int om = S[ 0 + ((cm >> (0 * 4)) & 0xF)] << (0 * 4);
+ om += S[ 16 + ((cm >> (1 * 4)) & 0xF)] << (1 * 4);
+ om += S[ 32 + ((cm >> (2 * 4)) & 0xF)] << (2 * 4);
+ om += S[ 48 + ((cm >> (3 * 4)) & 0xF)] << (3 * 4);
+ om += S[ 64 + ((cm >> (4 * 4)) & 0xF)] << (4 * 4);
+ om += S[ 80 + ((cm >> (5 * 4)) & 0xF)] << (5 * 4);
+ om += S[ 96 + ((cm >> (6 * 4)) & 0xF)] << (6 * 4);
+ om += S[112 + ((cm >> (7 * 4)) & 0xF)] << (7 * 4);
+
+// return om << 11 | om >>> (32-11); // 11-leftshift
+ int omLeft = om << 11;
+ int omRight = (int)(((uint) om) >> (32 - 11)); // Note: Casts required to get unsigned bit rotation
+
+ return omLeft | omRight;
+ }
+
+ private void gost28147MacFunc(
+ int[] workingKey,
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ int N1, N2, tmp; //tmp -> for saving N1
+ N1 = bytesToint(input, inOff);
+ N2 = bytesToint(input, inOff + 4);
+
+ for (int k = 0; k < 2; k++) // 1-16 steps
+ {
+ for (int j = 0; j < 8; j++)
+ {
+ tmp = N1;
+ N1 = N2 ^ gost28147_mainStep(N1, workingKey[j]); // CM2
+ N2 = tmp;
+ }
+ }
+
+ intTobytes(N1, output, outOff);
+ intTobytes(N2, output, outOff + 4);
+ }
+
+ //array of bytes to type int
+ private static int bytesToint(
+ byte[] input,
+ int inOff)
+ {
+ return (int)((input[inOff + 3] << 24) & 0xff000000) + ((input[inOff + 2] << 16) & 0xff0000)
+ + ((input[inOff + 1] << 8) & 0xff00) + (input[inOff] & 0xff);
+ }
+
+ //int to array of bytes
+ private static void intTobytes(
+ int num,
+ byte[] output,
+ int outOff)
+ {
+ output[outOff + 3] = (byte)(num >> 24);
+ output[outOff + 2] = (byte)(num >> 16);
+ output[outOff + 1] = (byte)(num >> 8);
+ output[outOff] = (byte)num;
+ }
+
+ private static byte[] CM5func(
+ byte[] buf,
+ int bufOff,
+ byte[] mac)
+ {
+ byte[] sum = new byte[buf.Length - bufOff];
+
+ Array.Copy(buf, bufOff, sum, 0, mac.Length);
+
+ for (int i = 0; i != mac.Length; i++)
+ {
+ sum[i] = (byte)(sum[i] ^ mac[i]);
+ }
+
+ return sum;
+ }
+
+ public void Update(
+ byte input)
+ {
+ if (bufOff == buf.Length)
+ {
+ byte[] sumbuf = new byte[buf.Length];
+ Array.Copy(buf, 0, sumbuf, 0, mac.Length);
+
+ if (firstStep)
+ {
+ firstStep = false;
+ }
+ else
+ {
+ sumbuf = CM5func(buf, 0, mac);
+ }
+
+ gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ buf[bufOff++] = input;
+ }
+
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int len)
+ {
+ if (len < 0)
+ throw new ArgumentException("Can't have a negative input length!");
+
+ int gapLen = blockSize - bufOff;
+
+ if (len > gapLen)
+ {
+ Array.Copy(input, inOff, buf, bufOff, gapLen);
+
+ byte[] sumbuf = new byte[buf.Length];
+ Array.Copy(buf, 0, sumbuf, 0, mac.Length);
+
+ if (firstStep)
+ {
+ firstStep = false;
+ }
+ else
+ {
+ sumbuf = CM5func(buf, 0, mac);
+ }
+
+ gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
+
+ bufOff = 0;
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > blockSize)
+ {
+ sumbuf = CM5func(input, inOff, mac);
+ gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ Array.Copy(input, inOff, buf, bufOff, len);
+
+ bufOff += len;
+ }
+
+ public int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ //padding with zero
+ while (bufOff < blockSize)
+ {
+ buf[bufOff++] = 0;
+ }
+
+ byte[] sumbuf = new byte[buf.Length];
+ Array.Copy(buf, 0, sumbuf, 0, mac.Length);
+
+ if (firstStep)
+ {
+ firstStep = false;
+ }
+ else
+ {
+ sumbuf = CM5func(buf, 0, mac);
+ }
+
+ gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
+
+ Array.Copy(mac, (mac.Length/2)-macSize, output, outOff, macSize);
+
+ Reset();
+
+ return macSize;
+ }
+
+ public void Reset()
+ {
+ // Clear the buffer.
+ Array.Clear(buf, 0, buf.Length);
+ bufOff = 0;
+
+ firstStep = true;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/macs/HMac.cs b/bc-sharp-crypto/src/crypto/macs/HMac.cs
new file mode 100644
index 0000000000000000000000000000000000000000..460f3c5a0b9a9dcb21ac4173ca62c81f788b911f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/macs/HMac.cs
@@ -0,0 +1,154 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+ /**
+ * HMAC implementation based on RFC2104
+ *
+ * H(K XOR opad, H(K XOR ipad, text))
+ */
+ public class HMac
+ : IMac
+ {
+ private const byte IPAD = (byte)0x36;
+ private const byte OPAD = (byte)0x5C;
+
+ private readonly IDigest digest;
+ private readonly int digestSize;
+ private readonly int blockLength;
+ private IMemoable ipadState;
+ private IMemoable opadState;
+
+ private readonly byte[] inputPad;
+ private readonly byte[] outputBuf;
+
+ public HMac(IDigest digest)
+ {
+ this.digest = digest;
+ this.digestSize = digest.GetDigestSize();
+ this.blockLength = digest.GetByteLength();
+ this.inputPad = new byte[blockLength];
+ this.outputBuf = new byte[blockLength + digestSize];
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return digest.AlgorithmName + "/HMAC"; }
+ }
+
+ public virtual IDigest GetUnderlyingDigest()
+ {
+ return digest;
+ }
+
+ public virtual void Init(ICipherParameters parameters)
+ {
+ digest.Reset();
+
+ byte[] key = ((KeyParameter)parameters).GetKey();
+ int keyLength = key.Length;
+
+ if (keyLength > blockLength)
+ {
+ digest.BlockUpdate(key, 0, keyLength);
+ digest.DoFinal(inputPad, 0);
+
+ keyLength = digestSize;
+ }
+ else
+ {
+ Array.Copy(key, 0, inputPad, 0, keyLength);
+ }
+
+ Array.Clear(inputPad, keyLength, blockLength - keyLength);
+ Array.Copy(inputPad, 0, outputBuf, 0, blockLength);
+
+ XorPad(inputPad, blockLength, IPAD);
+ XorPad(outputBuf, blockLength, OPAD);
+
+ if (digest is IMemoable)
+ {
+ opadState = ((IMemoable)digest).Copy();
+
+ ((IDigest)opadState).BlockUpdate(outputBuf, 0, blockLength);
+ }
+
+ digest.BlockUpdate(inputPad, 0, inputPad.Length);
+
+ if (digest is IMemoable)
+ {
+ ipadState = ((IMemoable)digest).Copy();
+ }
+ }
+
+ public virtual int GetMacSize()
+ {
+ return digestSize;
+ }
+
+ public virtual void Update(byte input)
+ {
+ digest.Update(input);
+ }
+
+ public virtual void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ digest.BlockUpdate(input, inOff, len);
+ }
+
+ public virtual int DoFinal(byte[] output, int outOff)
+ {
+ digest.DoFinal(outputBuf, blockLength);
+
+ if (opadState != null)
+ {
+ ((IMemoable)digest).Reset(opadState);
+ digest.BlockUpdate(outputBuf, blockLength, digest.GetDigestSize());
+ }
+ else
+ {
+ digest.BlockUpdate(outputBuf, 0, outputBuf.Length);
+ }
+
+ int len = digest.DoFinal(output, outOff);
+
+ Array.Clear(outputBuf, blockLength, digestSize);
+
+ if (ipadState != null)
+ {
+ ((IMemoable)digest).Reset(ipadState);
+ }
+ else
+ {
+ digest.BlockUpdate(inputPad, 0, inputPad.Length);
+ }
+
+ return len;
+ }
+
+ /**
+ * Reset the mac generator.
+ */
+ public virtual void Reset()
+ {
+ // Reset underlying digest
+ digest.Reset();
+
+ // Initialise the digest
+ digest.BlockUpdate(inputPad, 0, inputPad.Length);
+ }
+
+ private static void XorPad(byte[] pad, int len, byte n)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ pad[i] ^= n;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/macs/ISO9797Alg3Mac.cs b/bc-sharp-crypto/src/crypto/macs/ISO9797Alg3Mac.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6fee619c1c65415a489d136f4c77431d0a3c6198
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/macs/ISO9797Alg3Mac.cs
@@ -0,0 +1,275 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+ /**
+ * DES based CBC Block Cipher MAC according to ISO9797, algorithm 3 (ANSI X9.19 Retail MAC)
+ *
+ * This could as well be derived from CBCBlockCipherMac, but then the property mac in the base
+ * class must be changed to protected
+ */
+ public class ISO9797Alg3Mac : IMac
+ {
+ private byte[] mac;
+ private byte[] buf;
+ private int bufOff;
+ private IBlockCipher cipher;
+ private IBlockCipherPadding padding;
+ private int macSize;
+ private KeyParameter lastKey2;
+ private KeyParameter lastKey3;
+
+ /**
+ * create a Retail-MAC based on a CBC block cipher. This will produce an
+ * authentication code of the length of the block size of the cipher.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation. This must
+ * be DESEngine.
+ */
+ public ISO9797Alg3Mac(
+ IBlockCipher cipher)
+ : this(cipher, cipher.GetBlockSize() * 8, null)
+ {
+ }
+
+ /**
+ * create a Retail-MAC based on a CBC block cipher. This will produce an
+ * authentication code of the length of the block size of the cipher.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param padding the padding to be used to complete the last block.
+ */
+ public ISO9797Alg3Mac(
+ IBlockCipher cipher,
+ IBlockCipherPadding padding)
+ : this(cipher, cipher.GetBlockSize() * 8, padding)
+ {
+ }
+
+ /**
+ * create a Retail-MAC based on a block cipher with the size of the
+ * MAC been given in bits. This class uses single DES CBC mode as the basis for the
+ * MAC generation.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ */
+ public ISO9797Alg3Mac(
+ IBlockCipher cipher,
+ int macSizeInBits)
+ : this(cipher, macSizeInBits, null)
+ {
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits. This class uses single DES CBC mode as the basis for the
+ * MAC generation. The final block is decrypted and then encrypted using the
+ * middle and right part of the key.
+ *
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ * @param padding the padding to be used to complete the last block.
+ */
+ public ISO9797Alg3Mac(
+ IBlockCipher cipher,
+ int macSizeInBits,
+ IBlockCipherPadding padding)
+ {
+ if ((macSizeInBits % 8) != 0)
+ throw new ArgumentException("MAC size must be multiple of 8");
+
+ if (!(cipher is DesEngine))
+ throw new ArgumentException("cipher must be instance of DesEngine");
+
+ this.cipher = new CbcBlockCipher(cipher);
+ this.padding = padding;
+ this.macSize = macSizeInBits / 8;
+
+ mac = new byte[cipher.GetBlockSize()];
+ buf = new byte[cipher.GetBlockSize()];
+ bufOff = 0;
+ }
+
+ public string AlgorithmName
+ {
+ get { return "ISO9797Alg3"; }
+ }
+
+ public void Init(
+ ICipherParameters parameters)
+ {
+ Reset();
+
+ if (!(parameters is KeyParameter || parameters is ParametersWithIV))
+ throw new ArgumentException("parameters must be an instance of KeyParameter or ParametersWithIV");
+
+ // KeyParameter must contain a double or triple length DES key,
+ // however the underlying cipher is a single DES. The middle and
+ // right key are used only in the final step.
+
+ KeyParameter kp;
+ if (parameters is KeyParameter)
+ {
+ kp = (KeyParameter)parameters;
+ }
+ else
+ {
+ kp = (KeyParameter)((ParametersWithIV)parameters).Parameters;
+ }
+
+ KeyParameter key1;
+ byte[] keyvalue = kp.GetKey();
+
+ if (keyvalue.Length == 16)
+ { // Double length DES key
+ key1 = new KeyParameter(keyvalue, 0, 8);
+ this.lastKey2 = new KeyParameter(keyvalue, 8, 8);
+ this.lastKey3 = key1;
+ }
+ else if (keyvalue.Length == 24)
+ { // Triple length DES key
+ key1 = new KeyParameter(keyvalue, 0, 8);
+ this.lastKey2 = new KeyParameter(keyvalue, 8, 8);
+ this.lastKey3 = new KeyParameter(keyvalue, 16, 8);
+ }
+ else
+ {
+ throw new ArgumentException("Key must be either 112 or 168 bit long");
+ }
+
+ if (parameters is ParametersWithIV)
+ {
+ cipher.Init(true, new ParametersWithIV(key1, ((ParametersWithIV)parameters).GetIV()));
+ }
+ else
+ {
+ cipher.Init(true, key1);
+ }
+ }
+
+ public int GetMacSize()
+ {
+ return macSize;
+ }
+
+ public void Update(
+ byte input)
+ {
+ if (bufOff == buf.Length)
+ {
+ cipher.ProcessBlock(buf, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ buf[bufOff++] = input;
+ }
+
+ public void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int len)
+ {
+ if (len < 0)
+ throw new ArgumentException("Can't have a negative input length!");
+
+ int blockSize = cipher.GetBlockSize();
+ int resultLen = 0;
+ int gapLen = blockSize - bufOff;
+
+ if (len > gapLen)
+ {
+ Array.Copy(input, inOff, buf, bufOff, gapLen);
+
+ resultLen += cipher.ProcessBlock(buf, 0, mac, 0);
+
+ bufOff = 0;
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > blockSize)
+ {
+ resultLen += cipher.ProcessBlock(input, inOff, mac, 0);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ Array.Copy(input, inOff, buf, bufOff, len);
+
+ bufOff += len;
+ }
+
+ public int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ int blockSize = cipher.GetBlockSize();
+
+ if (padding == null)
+ {
+ // pad with zeroes
+ while (bufOff < blockSize)
+ {
+ buf[bufOff++] = 0;
+ }
+ }
+ else
+ {
+ if (bufOff == blockSize)
+ {
+ cipher.ProcessBlock(buf, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ padding.AddPadding(buf, bufOff);
+ }
+
+ cipher.ProcessBlock(buf, 0, mac, 0);
+
+ // Added to code from base class
+ DesEngine deseng = new DesEngine();
+
+ deseng.Init(false, this.lastKey2);
+ deseng.ProcessBlock(mac, 0, mac, 0);
+
+ deseng.Init(true, this.lastKey3);
+ deseng.ProcessBlock(mac, 0, mac, 0);
+ // ****
+
+ Array.Copy(mac, 0, output, outOff, macSize);
+
+ Reset();
+
+ return macSize;
+ }
+
+ /**
+ * Reset the mac generator.
+ */
+ public void Reset()
+ {
+ Array.Clear(buf, 0, buf.Length);
+ bufOff = 0;
+
+ // reset the underlying cipher.
+ cipher.Reset();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/macs/Poly1305.cs b/bc-sharp-crypto/src/crypto/macs/Poly1305.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c0a660facf4e7439174eb2e6501444110a506b53
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/macs/Poly1305.cs
@@ -0,0 +1,293 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+
+ ///
+ /// Poly1305 message authentication code, designed by D. J. Bernstein.
+ ///
+ ///
+ /// Poly1305 computes a 128-bit (16 bytes) authenticator, using a 128 bit nonce and a 256 bit key
+ /// consisting of a 128 bit key applied to an underlying cipher, and a 128 bit key (with 106
+ /// effective key bits) used in the authenticator.
+ ///
+ /// The polynomial calculation in this implementation is adapted from the public domain poly1305-donna-unrolled C implementation
+ /// by Andrew M (@floodyberry).
+ ///
+ ///
+ public class Poly1305
+ : IMac
+ {
+ private const int BlockSize = 16;
+
+ private readonly IBlockCipher cipher;
+
+ private readonly byte[] singleByte = new byte[1];
+
+ // Initialised state
+
+ /** Polynomial key */
+ private uint r0, r1, r2, r3, r4;
+
+ /** Precomputed 5 * r[1..4] */
+ private uint s1, s2, s3, s4;
+
+ /** Encrypted nonce */
+ private uint k0, k1, k2, k3;
+
+ // Accumulating state
+
+ /** Current block of buffered input */
+ private byte[] currentBlock = new byte[BlockSize];
+
+ /** Current offset in input buffer */
+ private int currentBlockOffset = 0;
+
+ /** Polynomial accumulator */
+ private uint h0, h1, h2, h3, h4;
+
+ /**
+ * Constructs a Poly1305 MAC, where the key passed to init() will be used directly.
+ */
+ public Poly1305()
+ {
+ this.cipher = null;
+ }
+
+ /**
+ * Constructs a Poly1305 MAC, using a 128 bit block cipher.
+ */
+ public Poly1305(IBlockCipher cipher)
+ {
+ if (cipher.GetBlockSize() != BlockSize)
+ {
+ throw new ArgumentException("Poly1305 requires a 128 bit block cipher.");
+ }
+ this.cipher = cipher;
+ }
+
+ ///
+ /// Initialises the Poly1305 MAC.
+ ///
+ /// a {@link ParametersWithIV} containing a 128 bit nonce and a {@link KeyParameter} with
+ /// a 256 bit key complying to the {@link Poly1305KeyGenerator Poly1305 key format}.
+ public void Init(ICipherParameters parameters)
+ {
+ byte[] nonce = null;
+
+ if (cipher != null)
+ {
+ if (!(parameters is ParametersWithIV))
+ throw new ArgumentException("Poly1305 requires an IV when used with a block cipher.", "parameters");
+
+ ParametersWithIV ivParams = (ParametersWithIV)parameters;
+ nonce = ivParams.GetIV();
+ parameters = ivParams.Parameters;
+ }
+
+ if (!(parameters is KeyParameter))
+ throw new ArgumentException("Poly1305 requires a key.");
+
+ KeyParameter keyParams = (KeyParameter)parameters;
+
+ SetKey(keyParams.GetKey(), nonce);
+
+ Reset();
+ }
+
+ private void SetKey(byte[] key, byte[] nonce)
+ {
+ if (key.Length != 32)
+ throw new ArgumentException("Poly1305 key must be 256 bits.");
+
+ if (cipher != null && (nonce == null || nonce.Length != BlockSize))
+ throw new ArgumentException("Poly1305 requires a 128 bit IV.");
+
+ // Extract r portion of key (and "clamp" the values)
+ uint t0 = Pack.LE_To_UInt32(key, 0);
+ uint t1 = Pack.LE_To_UInt32(key, 4);
+ uint t2 = Pack.LE_To_UInt32(key, 8);
+ uint t3 = Pack.LE_To_UInt32(key, 12);
+
+ // NOTE: The masks perform the key "clamping" implicitly
+ r0 = t0 & 0x03FFFFFFU;
+ r1 = ((t0 >> 26) | (t1 << 6)) & 0x03FFFF03U;
+ r2 = ((t1 >> 20) | (t2 << 12)) & 0x03FFC0FFU;
+ r3 = ((t2 >> 14) | (t3 << 18)) & 0x03F03FFFU;
+ r4 = (t3 >> 8) & 0x000FFFFFU;
+
+ // Precompute multipliers
+ s1 = r1 * 5;
+ s2 = r2 * 5;
+ s3 = r3 * 5;
+ s4 = r4 * 5;
+
+ byte[] kBytes;
+ int kOff;
+
+ if (cipher == null)
+ {
+ kBytes = key;
+ kOff = BlockSize;
+ }
+ else
+ {
+ // Compute encrypted nonce
+ kBytes = new byte[BlockSize];
+ kOff = 0;
+
+ cipher.Init(true, new KeyParameter(key, BlockSize, BlockSize));
+ cipher.ProcessBlock(nonce, 0, kBytes, 0);
+ }
+
+ k0 = Pack.LE_To_UInt32(kBytes, kOff + 0);
+ k1 = Pack.LE_To_UInt32(kBytes, kOff + 4);
+ k2 = Pack.LE_To_UInt32(kBytes, kOff + 8);
+ k3 = Pack.LE_To_UInt32(kBytes, kOff + 12);
+ }
+
+ public string AlgorithmName
+ {
+ get { return cipher == null ? "Poly1305" : "Poly1305-" + cipher.AlgorithmName; }
+ }
+
+ public int GetMacSize()
+ {
+ return BlockSize;
+ }
+
+ public void Update(byte input)
+ {
+ singleByte[0] = input;
+ BlockUpdate(singleByte, 0, 1);
+ }
+
+ public void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ int copied = 0;
+ while (len > copied)
+ {
+ if (currentBlockOffset == BlockSize)
+ {
+ ProcessBlock();
+ currentBlockOffset = 0;
+ }
+
+ int toCopy = System.Math.Min((len - copied), BlockSize - currentBlockOffset);
+ Array.Copy(input, copied + inOff, currentBlock, currentBlockOffset, toCopy);
+ copied += toCopy;
+ currentBlockOffset += toCopy;
+ }
+
+ }
+
+ private void ProcessBlock()
+ {
+ if (currentBlockOffset < BlockSize)
+ {
+ currentBlock[currentBlockOffset] = 1;
+ for (int i = currentBlockOffset + 1; i < BlockSize; i++)
+ {
+ currentBlock[i] = 0;
+ }
+ }
+
+ ulong t0 = Pack.LE_To_UInt32(currentBlock, 0);
+ ulong t1 = Pack.LE_To_UInt32(currentBlock, 4);
+ ulong t2 = Pack.LE_To_UInt32(currentBlock, 8);
+ ulong t3 = Pack.LE_To_UInt32(currentBlock, 12);
+
+ h0 += (uint)(t0 & 0x3ffffffU);
+ h1 += (uint)((((t1 << 32) | t0) >> 26) & 0x3ffffff);
+ h2 += (uint)((((t2 << 32) | t1) >> 20) & 0x3ffffff);
+ h3 += (uint)((((t3 << 32) | t2) >> 14) & 0x3ffffff);
+ h4 += (uint)(t3 >> 8);
+
+ if (currentBlockOffset == BlockSize)
+ {
+ h4 += (1 << 24);
+ }
+
+ ulong tp0 = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1);
+ ulong tp1 = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2);
+ ulong tp2 = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3);
+ ulong tp3 = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4);
+ ulong tp4 = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0);
+
+ h0 = (uint)tp0 & 0x3ffffff; tp1 += (tp0 >> 26);
+ h1 = (uint)tp1 & 0x3ffffff; tp2 += (tp1 >> 26);
+ h2 = (uint)tp2 & 0x3ffffff; tp3 += (tp2 >> 26);
+ h3 = (uint)tp3 & 0x3ffffff; tp4 += (tp3 >> 26);
+ h4 = (uint)tp4 & 0x3ffffff;
+ h0 += (uint)(tp4 >> 26) * 5;
+ h1 += (h0 >> 26); h0 &= 0x3ffffff;
+ }
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ Check.DataLength(output, outOff, BlockSize, "Output buffer is too short.");
+
+ if (currentBlockOffset > 0)
+ {
+ // Process padded block
+ ProcessBlock();
+ }
+
+ h1 += (h0 >> 26); h0 &= 0x3ffffff;
+ h2 += (h1 >> 26); h1 &= 0x3ffffff;
+ h3 += (h2 >> 26); h2 &= 0x3ffffff;
+ h4 += (h3 >> 26); h3 &= 0x3ffffff;
+ h0 += (h4 >> 26) * 5; h4 &= 0x3ffffff;
+ h1 += (h0 >> 26); h0 &= 0x3ffffff;
+
+ uint g0, g1, g2, g3, g4, b;
+ g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff;
+ g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff;
+ g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff;
+ g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff;
+ g4 = h4 + b - (1 << 26);
+
+ b = (g4 >> 31) - 1;
+ uint nb = ~b;
+ h0 = (h0 & nb) | (g0 & b);
+ h1 = (h1 & nb) | (g1 & b);
+ h2 = (h2 & nb) | (g2 & b);
+ h3 = (h3 & nb) | (g3 & b);
+ h4 = (h4 & nb) | (g4 & b);
+
+ ulong f0, f1, f2, f3;
+ f0 = ((h0 ) | (h1 << 26)) + (ulong)k0;
+ f1 = ((h1 >> 6 ) | (h2 << 20)) + (ulong)k1;
+ f2 = ((h2 >> 12) | (h3 << 14)) + (ulong)k2;
+ f3 = ((h3 >> 18) | (h4 << 8 )) + (ulong)k3;
+
+ Pack.UInt32_To_LE((uint)f0, output, outOff);
+ f1 += (f0 >> 32);
+ Pack.UInt32_To_LE((uint)f1, output, outOff + 4);
+ f2 += (f1 >> 32);
+ Pack.UInt32_To_LE((uint)f2, output, outOff + 8);
+ f3 += (f2 >> 32);
+ Pack.UInt32_To_LE((uint)f3, output, outOff + 12);
+
+ Reset();
+ return BlockSize;
+ }
+
+ public void Reset()
+ {
+ currentBlockOffset = 0;
+
+ h0 = h1 = h2 = h3 = h4 = 0;
+ }
+
+ private static ulong mul32x32_64(uint i1, uint i2)
+ {
+ return ((ulong)i1) * i2;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/macs/SipHash.cs b/bc-sharp-crypto/src/crypto/macs/SipHash.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e1a19fa5bb9e6379fb2df6cc606632370ece6983
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/macs/SipHash.cs
@@ -0,0 +1,199 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+ ///
+ /// Implementation of SipHash as specified in "SipHash: a fast short-input PRF", by Jean-Philippe
+ /// Aumasson and Daniel J. Bernstein (https://131002.net/siphash/siphash.pdf).
+ ///
+ ///
+ /// "SipHash is a family of PRFs SipHash-c-d where the integer parameters c and d are the number of
+ /// compression rounds and the number of finalization rounds. A compression round is identical to a
+ /// finalization round and this round function is called SipRound. Given a 128-bit key k and a
+ /// (possibly empty) byte string m, SipHash-c-d returns a 64-bit value..."
+ ///
+ public class SipHash
+ : IMac
+ {
+ protected readonly int c, d;
+
+ protected long k0, k1;
+ protected long v0, v1, v2, v3;
+
+ protected long m = 0;
+ protected int wordPos = 0;
+ protected int wordCount = 0;
+
+ /// SipHash-2-4
+ public SipHash()
+ : this(2, 4)
+ {
+ }
+
+ /// SipHash-c-d
+ /// the number of compression rounds
+ /// the number of finalization rounds
+ public SipHash(int c, int d)
+ {
+ this.c = c;
+ this.d = d;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "SipHash-" + c + "-" + d; }
+ }
+
+ public virtual int GetMacSize()
+ {
+ return 8;
+ }
+
+ public virtual void Init(ICipherParameters parameters)
+ {
+ KeyParameter keyParameter = parameters as KeyParameter;
+ if (keyParameter == null)
+ throw new ArgumentException("must be an instance of KeyParameter", "parameters");
+ byte[] key = keyParameter.GetKey();
+ if (key.Length != 16)
+ throw new ArgumentException("must be a 128-bit key", "parameters");
+
+ this.k0 = (long)Pack.LE_To_UInt64(key, 0);
+ this.k1 = (long)Pack.LE_To_UInt64(key, 8);
+
+ Reset();
+ }
+
+ public virtual void Update(byte input)
+ {
+ m = (long)(((ulong)m >> 8) | ((ulong)input << 56));
+
+ if (++wordPos == 8)
+ {
+ ProcessMessageWord();
+ wordPos = 0;
+ }
+ }
+
+ public virtual void BlockUpdate(byte[] input, int offset, int length)
+ {
+ int i = 0, fullWords = length & ~7;
+ if (wordPos == 0)
+ {
+ for (; i < fullWords; i += 8)
+ {
+ m = (long)Pack.LE_To_UInt64(input, offset + i);
+ ProcessMessageWord();
+ }
+ for (; i < length; ++i)
+ {
+ m = (long)(((ulong)m >> 8) | ((ulong)input[offset + i] << 56));
+ }
+ wordPos = length - fullWords;
+ }
+ else
+ {
+ int bits = wordPos << 3;
+ for (; i < fullWords; i += 8)
+ {
+ ulong n = Pack.LE_To_UInt64(input, offset + i);
+ m = (long)((n << bits) | ((ulong)m >> -bits));
+ ProcessMessageWord();
+ m = (long)n;
+ }
+ for (; i < length; ++i)
+ {
+ m = (long)(((ulong)m >> 8) | ((ulong)input[offset + i] << 56));
+
+ if (++wordPos == 8)
+ {
+ ProcessMessageWord();
+ wordPos = 0;
+ }
+ }
+ }
+ }
+
+ public virtual long DoFinal()
+ {
+ // NOTE: 2 distinct shifts to avoid "64-bit shift" when wordPos == 0
+ m = (long)((ulong)m >> ((7 - wordPos) << 3));
+ m = (long)((ulong)m >> 8);
+ m = (long)((ulong)m | ((ulong)((wordCount << 3) + wordPos) << 56));
+
+ ProcessMessageWord();
+
+ v2 ^= 0xffL;
+
+ ApplySipRounds(d);
+
+ long result = v0 ^ v1 ^ v2 ^ v3;
+
+ Reset();
+
+ return result;
+ }
+
+ public virtual int DoFinal(byte[] output, int outOff)
+ {
+ long result = DoFinal();
+ Pack.UInt64_To_LE((ulong)result, output, outOff);
+ return 8;
+ }
+
+ public virtual void Reset()
+ {
+ v0 = k0 ^ 0x736f6d6570736575L;
+ v1 = k1 ^ 0x646f72616e646f6dL;
+ v2 = k0 ^ 0x6c7967656e657261L;
+ v3 = k1 ^ 0x7465646279746573L;
+
+ m = 0;
+ wordPos = 0;
+ wordCount = 0;
+ }
+
+ protected virtual void ProcessMessageWord()
+ {
+ ++wordCount;
+ v3 ^= m;
+ ApplySipRounds(c);
+ v0 ^= m;
+ }
+
+ protected virtual void ApplySipRounds(int n)
+ {
+ long r0 = v0, r1 = v1, r2 = v2, r3 = v3;
+
+ for (int r = 0; r < n; ++r)
+ {
+ r0 += r1;
+ r2 += r3;
+ r1 = RotateLeft(r1, 13);
+ r3 = RotateLeft(r3, 16);
+ r1 ^= r0;
+ r3 ^= r2;
+ r0 = RotateLeft(r0, 32);
+ r2 += r1;
+ r0 += r3;
+ r1 = RotateLeft(r1, 17);
+ r3 = RotateLeft(r3, 21);
+ r1 ^= r2;
+ r3 ^= r0;
+ r2 = RotateLeft(r2, 32);
+ }
+
+ v0 = r0; v1 = r1; v2 = r2; v3 = r3;
+ }
+
+ protected static long RotateLeft(long x, int n)
+ {
+ ulong ux = (ulong)x;
+ ux = (ux << n) | (ux >> -n);
+ return (long)ux;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/macs/SkeinMac.cs b/bc-sharp-crypto/src/crypto/macs/SkeinMac.cs
new file mode 100644
index 0000000000000000000000000000000000000000..07eff24f47bc69552df219ac14dbbc3d9e3aeebc
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/macs/SkeinMac.cs
@@ -0,0 +1,118 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+
+ ///
+ /// Implementation of the Skein parameterised MAC function in 256, 512 and 1024 bit block sizes,
+ /// based on the Threefish tweakable block cipher.
+ ///
+ ///
+ /// This is the 1.3 version of Skein defined in the Skein hash function submission to the NIST SHA-3
+ /// competition in October 2010.
+ ///
+ /// Skein was designed by Niels Ferguson - Stefan Lucks - Bruce Schneier - Doug Whiting - Mihir
+ /// Bellare - Tadayoshi Kohno - Jon Callas - Jesse Walker.
+ ///
+ ///
+ ///
+ public class SkeinMac
+ : IMac
+ {
+ ///
+ /// 256 bit block size - Skein-256
+ ///
+ public const int SKEIN_256 = SkeinEngine.SKEIN_256;
+ ///
+ /// 512 bit block size - Skein-512
+ ///
+ public const int SKEIN_512 = SkeinEngine.SKEIN_512;
+ ///
+ /// 1024 bit block size - Skein-1024
+ ///
+ public const int SKEIN_1024 = SkeinEngine.SKEIN_1024;
+
+ private readonly SkeinEngine engine;
+
+ ///
+ /// Constructs a Skein MAC with an internal state size and output size.
+ ///
+ /// the internal state size in bits - one of or
+ /// .
+ /// the output/MAC size to produce in bits, which must be an integral number of
+ /// bytes.
+ public SkeinMac(int stateSizeBits, int digestSizeBits)
+ {
+ this.engine = new SkeinEngine(stateSizeBits, digestSizeBits);
+ }
+
+ public SkeinMac(SkeinMac mac)
+ {
+ this.engine = new SkeinEngine(mac.engine);
+ }
+
+ public string AlgorithmName
+ {
+ get { return "Skein-MAC-" + (engine.BlockSize * 8) + "-" + (engine.OutputSize * 8); }
+ }
+
+ ///
+ /// Optionally initialises the Skein digest with the provided parameters.
+ ///
+ /// See for details on the parameterisation of the Skein hash function.
+ /// the parameters to apply to this engine, or null
to use no parameters.
+ public void Init(ICipherParameters parameters)
+ {
+ SkeinParameters skeinParameters;
+ if (parameters is SkeinParameters)
+ {
+ skeinParameters = (SkeinParameters)parameters;
+ }
+ else if (parameters is KeyParameter)
+ {
+ skeinParameters = new SkeinParameters.Builder().SetKey(((KeyParameter)parameters).GetKey()).Build();
+ }
+ else
+ {
+ throw new ArgumentException("Invalid parameter passed to Skein MAC init - "
+ + Platform.GetTypeName(parameters));
+ }
+ if (skeinParameters.GetKey() == null)
+ {
+ throw new ArgumentException("Skein MAC requires a key parameter.");
+ }
+ engine.Init(skeinParameters);
+ }
+
+ public int GetMacSize()
+ {
+ return engine.OutputSize;
+ }
+
+ public void Reset()
+ {
+ engine.Reset();
+ }
+
+ public void Update(byte inByte)
+ {
+ engine.Update(inByte);
+ }
+
+ public void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ engine.Update(input, inOff, len);
+ }
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ return engine.DoFinal(output, outOff);
+ }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/macs/VMPCMac.cs b/bc-sharp-crypto/src/crypto/macs/VMPCMac.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6f2da075ceb33c633bfdc613a366dc29723a13ed
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/macs/VMPCMac.cs
@@ -0,0 +1,173 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+ public class VmpcMac
+ : IMac
+ {
+ private byte g;
+
+ private byte n = 0;
+ private byte[] P = null;
+ private byte s = 0;
+
+ private byte[] T;
+ private byte[] workingIV;
+
+ private byte[] workingKey;
+
+ private byte x1, x2, x3, x4;
+
+ public virtual int DoFinal(byte[] output, int outOff)
+ {
+ // Execute the Post-Processing Phase
+ for (int r = 1; r < 25; r++)
+ {
+ s = P[(s + P[n & 0xff]) & 0xff];
+
+ x4 = P[(x4 + x3 + r) & 0xff];
+ x3 = P[(x3 + x2 + r) & 0xff];
+ x2 = P[(x2 + x1 + r) & 0xff];
+ x1 = P[(x1 + s + r) & 0xff];
+ T[g & 0x1f] = (byte) (T[g & 0x1f] ^ x1);
+ T[(g + 1) & 0x1f] = (byte) (T[(g + 1) & 0x1f] ^ x2);
+ T[(g + 2) & 0x1f] = (byte) (T[(g + 2) & 0x1f] ^ x3);
+ T[(g + 3) & 0x1f] = (byte) (T[(g + 3) & 0x1f] ^ x4);
+ g = (byte) ((g + 4) & 0x1f);
+
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte) ((n + 1) & 0xff);
+ }
+
+ // Input T to the IV-phase of the VMPC KSA
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + T[m & 0x1f]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+
+ // Store 20 new outputs of the VMPC Stream Cipher input table M
+ byte[] M = new byte[20];
+ for (int i = 0; i < 20; i++)
+ {
+ s = P[(s + P[i & 0xff]) & 0xff];
+ M[i] = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+
+ byte temp = P[i & 0xff];
+ P[i & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+
+ Array.Copy(M, 0, output, outOff, M.Length);
+ Reset();
+
+ return M.Length;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "VMPC-MAC"; }
+ }
+
+ public virtual int GetMacSize()
+ {
+ return 20;
+ }
+
+ public virtual void Init(ICipherParameters parameters)
+ {
+ if (!(parameters is ParametersWithIV))
+ throw new ArgumentException("VMPC-MAC Init parameters must include an IV", "parameters");
+
+ ParametersWithIV ivParams = (ParametersWithIV) parameters;
+ KeyParameter key = (KeyParameter) ivParams.Parameters;
+
+ if (!(ivParams.Parameters is KeyParameter))
+ throw new ArgumentException("VMPC-MAC Init parameters must include a key", "parameters");
+
+ this.workingIV = ivParams.GetIV();
+
+ if (workingIV == null || workingIV.Length < 1 || workingIV.Length > 768)
+ throw new ArgumentException("VMPC-MAC requires 1 to 768 bytes of IV", "parameters");
+
+ this.workingKey = key.GetKey();
+
+ Reset();
+
+ }
+
+ private void initKey(byte[] keyBytes, byte[] ivBytes)
+ {
+ s = 0;
+ P = new byte[256];
+ for (int i = 0; i < 256; i++)
+ {
+ P[i] = (byte) i;
+ }
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+ for (int m = 0; m < 768; m++)
+ {
+ s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.Length]) & 0xff];
+ byte temp = P[m & 0xff];
+ P[m & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ }
+ n = 0;
+ }
+
+ public virtual void Reset()
+ {
+ initKey(this.workingKey, this.workingIV);
+ g = x1 = x2 = x3 = x4 = n = 0;
+ T = new byte[32];
+ for (int i = 0; i < 32; i++)
+ {
+ T[i] = 0;
+ }
+ }
+
+ public virtual void Update(byte input)
+ {
+ s = P[(s + P[n & 0xff]) & 0xff];
+ byte c = (byte) (input ^ P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff]);
+
+ x4 = P[(x4 + x3) & 0xff];
+ x3 = P[(x3 + x2) & 0xff];
+ x2 = P[(x2 + x1) & 0xff];
+ x1 = P[(x1 + s + c) & 0xff];
+ T[g & 0x1f] = (byte) (T[g & 0x1f] ^ x1);
+ T[(g + 1) & 0x1f] = (byte) (T[(g + 1) & 0x1f] ^ x2);
+ T[(g + 2) & 0x1f] = (byte) (T[(g + 2) & 0x1f] ^ x3);
+ T[(g + 3) & 0x1f] = (byte) (T[(g + 3) & 0x1f] ^ x4);
+ g = (byte) ((g + 4) & 0x1f);
+
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte) ((n + 1) & 0xff);
+ }
+
+ public virtual void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ if ((inOff + len) > input.Length)
+ throw new DataLengthException("input buffer too short");
+
+ for (int i = 0; i < len; i++)
+ {
+ Update(input[inOff + i]);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/CbcBlockCipher.cs b/bc-sharp-crypto/src/crypto/modes/CbcBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9345fd8c29887ec6c4f4f0792f166e2b3e76a227
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/CbcBlockCipher.cs
@@ -0,0 +1,241 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ /**
+ * implements Cipher-Block-Chaining (CBC) mode on top of a simple cipher.
+ */
+ public class CbcBlockCipher
+ : IBlockCipher
+ {
+ private byte[] IV, cbcV, cbcNextV;
+ private int blockSize;
+ private IBlockCipher cipher;
+ private bool encrypting;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of chaining.
+ */
+ public CbcBlockCipher(
+ IBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ this.blockSize = cipher.GetBlockSize();
+
+ this.IV = new byte[blockSize];
+ this.cbcV = new byte[blockSize];
+ this.cbcNextV = new byte[blockSize];
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param param the key and other data required by the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ bool oldEncrypting = this.encrypting;
+
+ this.encrypting = forEncryption;
+
+ if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)parameters;
+ 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);
+
+ parameters = ivParam.Parameters;
+ }
+
+ Reset();
+
+ // if null it's an IV changed only.
+ if (parameters != null)
+ {
+ cipher.Init(encrypting, parameters);
+ }
+ else if (oldEncrypting != encrypting)
+ {
+ throw new ArgumentException("cannot change encrypting state without providing key.");
+ }
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/CBC".
+ */
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/CBC"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return false; }
+ }
+
+ /**
+ * return the block size of the underlying cipher.
+ *
+ * @return the block size of the underlying cipher.
+ */
+ public int GetBlockSize()
+ {
+ 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)
+ {
+ return (encrypting)
+ ? EncryptBlock(input, inOff, output, outOff)
+ : DecryptBlock(input, inOff, output, outOff);
+ }
+
+ /**
+ * reset the chaining vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void Reset()
+ {
+ Array.Copy(IV, 0, cbcV, 0, IV.Length);
+ Array.Clear(cbcNextV, 0, cbcNextV.Length);
+
+ 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 ((inOff + blockSize) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ /*
+ * XOR the cbcV and the input,
+ * then encrypt the cbcV
+ */
+ for (int i = 0; i < blockSize; i++)
+ {
+ cbcV[i] ^= input[inOff + i];
+ }
+
+ 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)
+ {
+ if ((inOff + blockSize) > input.Length)
+ {
+ throw new DataLengthException("input 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;
+ cbcV = cbcNextV;
+ cbcNextV = tmp;
+
+ return length;
+ }
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/CcmBlockCipher.cs b/bc-sharp-crypto/src/crypto/modes/CcmBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4de40d58e1cd17716ec179e764a1b525217c9837
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/CcmBlockCipher.cs
@@ -0,0 +1,449 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ /**
+ * Implements the Counter with Cipher Block Chaining mode (CCM) detailed in
+ * NIST Special Publication 800-38C.
+ *
+ * Note : this mode is a packet mode - it needs all the data up front.
+ *
+ */
+ public class CcmBlockCipher
+ : IAeadBlockCipher
+ {
+ private static readonly int BlockSize = 16;
+
+ private readonly IBlockCipher cipher;
+ private readonly byte[] macBlock;
+ private bool forEncryption;
+ private byte[] nonce;
+ private byte[] initialAssociatedText;
+ private int macSize;
+ private ICipherParameters keyParam;
+ private readonly MemoryStream associatedText = new MemoryStream();
+ private readonly MemoryStream data = new MemoryStream();
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used.
+ */
+ public CcmBlockCipher(
+ IBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ this.macBlock = new byte[BlockSize];
+
+ if (cipher.GetBlockSize() != BlockSize)
+ throw new ArgumentException("cipher required with a block size of " + BlockSize + ".");
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public virtual IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+
+ ICipherParameters cipherParameters;
+ if (parameters is AeadParameters)
+ {
+ AeadParameters param = (AeadParameters) parameters;
+
+ nonce = param.GetNonce();
+ initialAssociatedText = param.GetAssociatedText();
+ macSize = param.MacSize / 8;
+ cipherParameters = param.Key;
+ }
+ else if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV param = (ParametersWithIV) parameters;
+
+ nonce = param.GetIV();
+ initialAssociatedText = null;
+ macSize = macBlock.Length / 2;
+ cipherParameters = param.Parameters;
+ }
+ else
+ {
+ throw new ArgumentException("invalid parameters passed to CCM");
+ }
+
+ // NOTE: Very basic support for key re-use, but no performance gain from it
+ if (cipherParameters != null)
+ {
+ keyParam = cipherParameters;
+ }
+
+ if (nonce == null || nonce.Length < 7 || nonce.Length > 13)
+ {
+ throw new ArgumentException("nonce must have length from 7 to 13 octets");
+ }
+
+ Reset();
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/CCM"; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return cipher.GetBlockSize();
+ }
+
+ public virtual void ProcessAadByte(byte input)
+ {
+ associatedText.WriteByte(input);
+ }
+
+ public virtual void ProcessAadBytes(byte[] inBytes, int inOff, int len)
+ {
+ // TODO: Process AAD online
+ associatedText.Write(inBytes, inOff, len);
+ }
+
+ public virtual int ProcessByte(
+ byte input,
+ byte[] outBytes,
+ int outOff)
+ {
+ data.WriteByte(input);
+
+ return 0;
+ }
+
+ public virtual int ProcessBytes(
+ byte[] inBytes,
+ int inOff,
+ int inLen,
+ byte[] outBytes,
+ int outOff)
+ {
+ Check.DataLength(inBytes, inOff, inLen, "Input buffer too short");
+
+ data.Write(inBytes, inOff, inLen);
+
+ return 0;
+ }
+
+ public virtual int DoFinal(
+ byte[] outBytes,
+ int outOff)
+ {
+#if PORTABLE
+ byte[] input = data.ToArray();
+ int inLen = input.Length;
+#else
+ byte[] input = data.GetBuffer();
+ int inLen = (int)data.Position;
+#endif
+
+ int len = ProcessPacket(input, 0, inLen, outBytes, outOff);
+
+ Reset();
+
+ return len;
+ }
+
+ public virtual void Reset()
+ {
+ cipher.Reset();
+ associatedText.SetLength(0);
+ data.SetLength(0);
+ }
+
+ /**
+ * Returns a byte array containing the mac calculated as part of the
+ * last encrypt or decrypt operation.
+ *
+ * @return the last mac calculated.
+ */
+ public virtual byte[] GetMac()
+ {
+ return Arrays.CopyOfRange(macBlock, 0, macSize);
+ }
+
+ public virtual int GetUpdateOutputSize(
+ int len)
+ {
+ return 0;
+ }
+
+ public virtual int GetOutputSize(
+ int len)
+ {
+ int totalData = (int)data.Length + len;
+
+ if (forEncryption)
+ {
+ return totalData + macSize;
+ }
+
+ return totalData < macSize ? 0 : totalData - macSize;
+ }
+
+ /**
+ * Process a packet of data for either CCM decryption or encryption.
+ *
+ * @param in data for processing.
+ * @param inOff offset at which data starts in the input array.
+ * @param inLen length of the data in the input array.
+ * @return a byte array containing the processed input..
+ * @throws IllegalStateException if the cipher is not appropriately set up.
+ * @throws InvalidCipherTextException if the input data is truncated or the mac check fails.
+ */
+ public virtual byte[] ProcessPacket(byte[] input, int inOff, int inLen)
+ {
+ byte[] output;
+
+ if (forEncryption)
+ {
+ output = new byte[inLen + macSize];
+ }
+ else
+ {
+ if (inLen < macSize)
+ throw new InvalidCipherTextException("data too short");
+
+ output = new byte[inLen - macSize];
+ }
+
+ ProcessPacket(input, inOff, inLen, output, 0);
+
+ return output;
+ }
+
+ /**
+ * Process a packet of data for either CCM decryption or encryption.
+ *
+ * @param in data for processing.
+ * @param inOff offset at which data starts in the input array.
+ * @param inLen length of the data in the input array.
+ * @param output output array.
+ * @param outOff offset into output array to start putting processed bytes.
+ * @return the number of bytes added to output.
+ * @throws IllegalStateException if the cipher is not appropriately set up.
+ * @throws InvalidCipherTextException if the input data is truncated or the mac check fails.
+ * @throws DataLengthException if output buffer too short.
+ */
+ public virtual int ProcessPacket(byte[] input, int inOff, int inLen, byte[] output, int outOff)
+ {
+ // TODO: handle null keyParam (e.g. via RepeatedKeySpec)
+ // Need to keep the CTR and CBC Mac parts around and reset
+ if (keyParam == null)
+ throw new InvalidOperationException("CCM cipher unitialized.");
+
+ int n = nonce.Length;
+ int q = 15 - n;
+ if (q < 4)
+ {
+ int limitLen = 1 << (8 * q);
+ if (inLen >= limitLen)
+ throw new InvalidOperationException("CCM packet too large for choice of q.");
+ }
+
+ byte[] iv = new byte[BlockSize];
+ iv[0] = (byte)((q - 1) & 0x7);
+ nonce.CopyTo(iv, 1);
+
+ IBlockCipher ctrCipher = new SicBlockCipher(cipher);
+ ctrCipher.Init(forEncryption, new ParametersWithIV(keyParam, iv));
+
+ int outputLen;
+ int inIndex = inOff;
+ int outIndex = outOff;
+
+ if (forEncryption)
+ {
+ outputLen = inLen + macSize;
+ Check.OutputLength(output, outOff, outputLen, "Output buffer too short.");
+
+ CalculateMac(input, inOff, inLen, macBlock);
+
+ byte[] encMac = new byte[BlockSize];
+ ctrCipher.ProcessBlock(macBlock, 0, encMac, 0); // S0
+
+ while (inIndex < (inOff + inLen - BlockSize)) // S1...
+ {
+ ctrCipher.ProcessBlock(input, inIndex, output, outIndex);
+ outIndex += BlockSize;
+ inIndex += BlockSize;
+ }
+
+ byte[] block = new byte[BlockSize];
+
+ Array.Copy(input, inIndex, block, 0, inLen + inOff - inIndex);
+
+ ctrCipher.ProcessBlock(block, 0, block, 0);
+
+ Array.Copy(block, 0, output, outIndex, inLen + inOff - inIndex);
+
+ Array.Copy(encMac, 0, output, outOff + inLen, macSize);
+ }
+ else
+ {
+ if (inLen < macSize)
+ throw new InvalidCipherTextException("data too short");
+
+ outputLen = inLen - macSize;
+ Check.OutputLength(output, outOff, outputLen, "Output buffer too short.");
+
+ Array.Copy(input, inOff + outputLen, macBlock, 0, macSize);
+
+ ctrCipher.ProcessBlock(macBlock, 0, macBlock, 0);
+
+ for (int i = macSize; i != macBlock.Length; i++)
+ {
+ macBlock[i] = 0;
+ }
+
+ while (inIndex < (inOff + outputLen - BlockSize))
+ {
+ ctrCipher.ProcessBlock(input, inIndex, output, outIndex);
+ outIndex += BlockSize;
+ inIndex += BlockSize;
+ }
+
+ byte[] block = new byte[BlockSize];
+
+ Array.Copy(input, inIndex, block, 0, outputLen - (inIndex - inOff));
+
+ ctrCipher.ProcessBlock(block, 0, block, 0);
+
+ Array.Copy(block, 0, output, outIndex, outputLen - (inIndex - inOff));
+
+ byte[] calculatedMacBlock = new byte[BlockSize];
+
+ CalculateMac(output, outOff, outputLen, calculatedMacBlock);
+
+ if (!Arrays.ConstantTimeAreEqual(macBlock, calculatedMacBlock))
+ throw new InvalidCipherTextException("mac check in CCM failed");
+ }
+
+ return outputLen;
+ }
+
+ private int CalculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
+ {
+ IMac cMac = new CbcBlockCipherMac(cipher, macSize * 8);
+
+ cMac.Init(keyParam);
+
+ //
+ // build b0
+ //
+ byte[] b0 = new byte[16];
+
+ if (HasAssociatedText())
+ {
+ b0[0] |= 0x40;
+ }
+
+ b0[0] |= (byte)((((cMac.GetMacSize() - 2) / 2) & 0x7) << 3);
+
+ b0[0] |= (byte)(((15 - nonce.Length) - 1) & 0x7);
+
+ Array.Copy(nonce, 0, b0, 1, nonce.Length);
+
+ int q = dataLen;
+ int count = 1;
+ while (q > 0)
+ {
+ b0[b0.Length - count] = (byte)(q & 0xff);
+ q >>= 8;
+ count++;
+ }
+
+ cMac.BlockUpdate(b0, 0, b0.Length);
+
+ //
+ // process associated text
+ //
+ if (HasAssociatedText())
+ {
+ int extra;
+
+ int textLength = GetAssociatedTextLength();
+ if (textLength < ((1 << 16) - (1 << 8)))
+ {
+ cMac.Update((byte)(textLength >> 8));
+ cMac.Update((byte)textLength);
+
+ extra = 2;
+ }
+ else // can't go any higher than 2^32
+ {
+ cMac.Update((byte)0xff);
+ cMac.Update((byte)0xfe);
+ cMac.Update((byte)(textLength >> 24));
+ cMac.Update((byte)(textLength >> 16));
+ cMac.Update((byte)(textLength >> 8));
+ cMac.Update((byte)textLength);
+
+ extra = 6;
+ }
+
+ if (initialAssociatedText != null)
+ {
+ cMac.BlockUpdate(initialAssociatedText, 0, initialAssociatedText.Length);
+ }
+ if (associatedText.Position > 0)
+ {
+#if PORTABLE
+ byte[] input = associatedText.ToArray();
+ int len = input.Length;
+#else
+ byte[] input = associatedText.GetBuffer();
+ int len = (int)associatedText.Position;
+#endif
+
+ cMac.BlockUpdate(input, 0, len);
+ }
+
+ extra = (extra + textLength) % 16;
+ if (extra != 0)
+ {
+ for (int i = extra; i < 16; ++i)
+ {
+ cMac.Update((byte)0x00);
+ }
+ }
+ }
+
+ //
+ // add the text
+ //
+ cMac.BlockUpdate(data, dataOff, dataLen);
+
+ return cMac.DoFinal(macBlock, 0);
+ }
+
+ private int GetAssociatedTextLength()
+ {
+ return (int)associatedText.Length + ((initialAssociatedText == null) ? 0 : initialAssociatedText.Length);
+ }
+
+ private bool HasAssociatedText()
+ {
+ return GetAssociatedTextLength() > 0;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/CfbBlockCipher.cs b/bc-sharp-crypto/src/crypto/modes/CfbBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..433716535d77eb1b2e2354b1664be2116954968f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/CfbBlockCipher.cs
@@ -0,0 +1,224 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ /**
+ * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
+ */
+ public class CfbBlockCipher
+ : IBlockCipher
+ {
+ private byte[] IV;
+ private byte[] cfbV;
+ private byte[] cfbOutV;
+ private bool encrypting;
+
+ private readonly int blockSize;
+ private readonly IBlockCipher cipher;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of the
+ * feedback mode.
+ * @param blockSize the block size in bits (note: a multiple of 8)
+ */
+ public CfbBlockCipher(
+ IBlockCipher cipher,
+ int bitBlockSize)
+ {
+ this.cipher = cipher;
+ this.blockSize = bitBlockSize / 8;
+ this.IV = new byte[cipher.GetBlockSize()];
+ this.cfbV = new byte[cipher.GetBlockSize()];
+ this.cfbOutV = new byte[cipher.GetBlockSize()];
+ }
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ * An IV which is too short is handled in FIPS compliant fashion.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param param the key and other data required by the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.encrypting = forEncryption;
+ if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV) parameters;
+ byte[] iv = ivParam.GetIV();
+ int diff = IV.Length - iv.Length;
+ Array.Copy(iv, 0, IV, diff, iv.Length);
+ Array.Clear(IV, 0, diff);
+
+ parameters = ivParam.Parameters;
+ }
+ Reset();
+
+ // if it's null, key is to be reused.
+ if (parameters != null)
+ {
+ cipher.Init(true, parameters);
+ }
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/CFB"
+ * and the block size in bits.
+ */
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/CFB" + (blockSize * 8); }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return true; }
+ }
+
+ /**
+ * return the block size we are operating at.
+ *
+ * @return the block size we are operating at (in bytes).
+ */
+ public int GetBlockSize()
+ {
+ 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)
+ {
+ return (encrypting)
+ ? EncryptBlock(input, inOff, output, outOff)
+ : DecryptBlock(input, inOff, output, outOff);
+ }
+
+ /**
+ * 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 ((inOff + blockSize) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+ if ((outOff + blockSize) > outBytes.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+ cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
+ //
+ // XOR the cfbV with the plaintext producing the ciphertext
+ //
+ for (int i = 0; i < blockSize; i++)
+ {
+ outBytes[outOff + i] = (byte)(cfbOutV[i] ^ input[inOff + i]);
+ }
+ //
+ // change over the input block.
+ //
+ Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize);
+ 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)
+ {
+ if ((inOff + blockSize) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+ if ((outOff + blockSize) > outBytes.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+ cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
+ //
+ // change over the input block.
+ //
+ Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize);
+ Array.Copy(input, inOff, cfbV, cfbV.Length - blockSize, blockSize);
+ //
+ // XOR the cfbV with the ciphertext producing the plaintext
+ //
+ for (int i = 0; i < blockSize; i++)
+ {
+ outBytes[outOff + i] = (byte)(cfbOutV[i] ^ input[inOff + i]);
+ }
+ return blockSize;
+ }
+ /**
+ * reset the chaining vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void Reset()
+ {
+ Array.Copy(IV, 0, cfbV, 0, IV.Length);
+ cipher.Reset();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/CtsBlockCipher.cs b/bc-sharp-crypto/src/crypto/modes/CtsBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ff37844ab8f642334b668096bb5ed66c01d814e5
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/CtsBlockCipher.cs
@@ -0,0 +1,253 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ /**
+ * A Cipher Text Stealing (CTS) mode cipher. CTS allows block ciphers to
+ * be used to produce cipher text which is the same outLength as the plain text.
+ */
+ public class CtsBlockCipher
+ : BufferedBlockCipher
+ {
+ private readonly int blockSize;
+
+ /**
+ * Create a buffered block cipher that uses Cipher Text Stealing
+ *
+ * @param cipher the underlying block cipher this buffering object wraps.
+ */
+ public CtsBlockCipher(
+ IBlockCipher cipher)
+ {
+ // TODO Should this test for acceptable ones instead?
+ if (cipher is OfbBlockCipher || cipher is CfbBlockCipher)
+ throw new ArgumentException("CtsBlockCipher can only accept ECB, or CBC ciphers");
+
+ this.cipher = cipher;
+
+ blockSize = cipher.GetBlockSize();
+
+ buf = new byte[blockSize * 2];
+ bufOff = 0;
+ }
+
+ /**
+ * return the size of the output buffer required for an update of 'length' bytes.
+ *
+ * @param length the outLength of the input.
+ * @return the space required to accommodate a call to update
+ * with length bytes of input.
+ */
+ public override int GetUpdateOutputSize(
+ int length)
+ {
+ int total = length + bufOff;
+ int leftOver = total % buf.Length;
+
+ if (leftOver == 0)
+ {
+ return total - buf.Length;
+ }
+
+ return total - leftOver;
+ }
+
+ /**
+ * return the size of the output buffer required for an update plus a
+ * doFinal with an input of length bytes.
+ *
+ * @param length the outLength of the input.
+ * @return the space required to accommodate a call to update and doFinal
+ * with length bytes of input.
+ */
+ public override int GetOutputSize(
+ int length)
+ {
+ return length + bufOff;
+ }
+
+ /**
+ * process a single byte, producing an output block if necessary.
+ *
+ * @param in the input byte.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ */
+ public override int ProcessByte(
+ byte input,
+ byte[] output,
+ int outOff)
+ {
+ int resultLen = 0;
+
+ if (bufOff == buf.Length)
+ {
+ resultLen = cipher.ProcessBlock(buf, 0, output, outOff);
+ Debug.Assert(resultLen == blockSize);
+
+ Array.Copy(buf, blockSize, buf, 0, blockSize);
+ bufOff = blockSize;
+ }
+
+ buf[bufOff++] = input;
+
+ return resultLen;
+ }
+
+ /**
+ * process an array of bytes, producing output if necessary.
+ *
+ * @param in the input byte array.
+ * @param inOff the offset at which the input data starts.
+ * @param length the number of bytes to be copied out of the input array.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ */
+ public override int ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] output,
+ int outOff)
+ {
+ if (length < 0)
+ {
+ throw new ArgumentException("Can't have a negative input outLength!");
+ }
+
+ int blockSize = GetBlockSize();
+ int outLength = GetUpdateOutputSize(length);
+
+ if (outLength > 0)
+ {
+ if ((outOff + outLength) > output.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+ }
+
+ int resultLen = 0;
+ int gapLen = buf.Length - bufOff;
+
+ if (length > gapLen)
+ {
+ Array.Copy(input, inOff, buf, bufOff, gapLen);
+
+ resultLen += cipher.ProcessBlock(buf, 0, output, outOff);
+ Array.Copy(buf, blockSize, buf, 0, blockSize);
+
+ bufOff = blockSize;
+
+ length -= gapLen;
+ inOff += gapLen;
+
+ while (length > blockSize)
+ {
+ Array.Copy(input, inOff, buf, bufOff, blockSize);
+ resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen);
+ Array.Copy(buf, blockSize, buf, 0, blockSize);
+
+ length -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ Array.Copy(input, inOff, buf, bufOff, length);
+
+ bufOff += length;
+
+ return resultLen;
+ }
+
+ /**
+ * Process the last block in the buffer.
+ *
+ * @param out the array the block currently being held is copied into.
+ * @param outOff the offset at which the copying starts.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there is insufficient space in out for
+ * the output.
+ * @exception InvalidOperationException if the underlying cipher is not
+ * initialised.
+ * @exception InvalidCipherTextException if cipher text decrypts wrongly (in
+ * case the exception will never Get thrown).
+ */
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ if (bufOff + outOff > output.Length)
+ {
+ throw new DataLengthException("output buffer too small in doFinal");
+ }
+
+ int blockSize = cipher.GetBlockSize();
+ int length = bufOff - blockSize;
+ byte[] block = new byte[blockSize];
+
+ if (forEncryption)
+ {
+ cipher.ProcessBlock(buf, 0, block, 0);
+
+ if (bufOff < blockSize)
+ {
+ throw new DataLengthException("need at least one block of input for CTS");
+ }
+
+ for (int i = bufOff; i != buf.Length; i++)
+ {
+ buf[i] = block[i - blockSize];
+ }
+
+ for (int i = blockSize; i != bufOff; i++)
+ {
+ buf[i] ^= block[i - blockSize];
+ }
+
+ IBlockCipher c = (cipher is CbcBlockCipher)
+ ? ((CbcBlockCipher)cipher).GetUnderlyingCipher()
+ : cipher;
+
+ c.ProcessBlock(buf, blockSize, output, outOff);
+
+ Array.Copy(block, 0, output, outOff + blockSize, length);
+ }
+ else
+ {
+ byte[] lastBlock = new byte[blockSize];
+
+ IBlockCipher c = (cipher is CbcBlockCipher)
+ ? ((CbcBlockCipher)cipher).GetUnderlyingCipher()
+ : cipher;
+
+ c.ProcessBlock(buf, 0, block, 0);
+
+ for (int i = blockSize; i != bufOff; i++)
+ {
+ lastBlock[i - blockSize] = (byte)(block[i - blockSize] ^ buf[i]);
+ }
+
+ Array.Copy(buf, blockSize, block, 0, length);
+
+ cipher.ProcessBlock(block, 0, output, outOff);
+ Array.Copy(lastBlock, 0, output, outOff + blockSize, length);
+ }
+
+ int offset = bufOff;
+
+ Reset();
+
+ return offset;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/EAXBlockCipher.cs b/bc-sharp-crypto/src/crypto/modes/EAXBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..624f385b5ee0812a091fd075df3604fdd1a4955c
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/EAXBlockCipher.cs
@@ -0,0 +1,379 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ /**
+ * A Two-Pass Authenticated-Encryption Scheme Optimized for Simplicity and
+ * Efficiency - by M. Bellare, P. Rogaway, D. Wagner.
+ *
+ * http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
+ *
+ * EAX is an AEAD scheme based on CTR and OMAC1/CMAC, that uses a single block
+ * cipher to encrypt and authenticate data. It's on-line (the length of a
+ * message isn't needed to begin processing it), has good performances, it's
+ * simple and provably secure (provided the underlying block cipher is secure).
+ *
+ * Of course, this implementations is NOT thread-safe.
+ */
+ public class EaxBlockCipher
+ : IAeadBlockCipher
+ {
+ private enum Tag : byte { N, H, C };
+
+ private SicBlockCipher cipher;
+
+ private bool forEncryption;
+
+ private int blockSize;
+
+ private IMac mac;
+
+ private byte[] nonceMac;
+ private byte[] associatedTextMac;
+ private byte[] macBlock;
+
+ private int macSize;
+ private byte[] bufBlock;
+ private int bufOff;
+
+ private bool cipherInitialized;
+ private byte[] initialAssociatedText;
+
+ /**
+ * Constructor that accepts an instance of a block cipher engine.
+ *
+ * @param cipher the engine to use
+ */
+ public EaxBlockCipher(
+ IBlockCipher cipher)
+ {
+ blockSize = cipher.GetBlockSize();
+ mac = new CMac(cipher);
+ macBlock = new byte[blockSize];
+ associatedTextMac = new byte[mac.GetMacSize()];
+ nonceMac = new byte[mac.GetMacSize()];
+ this.cipher = new SicBlockCipher(cipher);
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return cipher.GetUnderlyingCipher().AlgorithmName + "/EAX"; }
+ }
+
+ public virtual IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return cipher.GetBlockSize();
+ }
+
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+
+ byte[] nonce;
+ ICipherParameters keyParam;
+
+ if (parameters is AeadParameters)
+ {
+ AeadParameters param = (AeadParameters) parameters;
+
+ nonce = param.GetNonce();
+ initialAssociatedText = param.GetAssociatedText();
+ macSize = param.MacSize / 8;
+ keyParam = param.Key;
+ }
+ else if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV param = (ParametersWithIV) parameters;
+
+ nonce = param.GetIV();
+ initialAssociatedText = null;
+ macSize = mac.GetMacSize() / 2;
+ keyParam = param.Parameters;
+ }
+ else
+ {
+ throw new ArgumentException("invalid parameters passed to EAX");
+ }
+
+ bufBlock = new byte[forEncryption ? blockSize : (blockSize + macSize)];
+
+ byte[] tag = new byte[blockSize];
+
+ // Key reuse implemented in CBC mode of underlying CMac
+ mac.Init(keyParam);
+
+ tag[blockSize - 1] = (byte)Tag.N;
+ mac.BlockUpdate(tag, 0, blockSize);
+ mac.BlockUpdate(nonce, 0, nonce.Length);
+ mac.DoFinal(nonceMac, 0);
+
+ // Same BlockCipher underlies this and the mac, so reuse last key on cipher
+ cipher.Init(true, new ParametersWithIV(null, nonceMac));
+
+ Reset();
+ }
+
+ private void InitCipher()
+ {
+ if (cipherInitialized)
+ {
+ return;
+ }
+
+ cipherInitialized = true;
+
+ mac.DoFinal(associatedTextMac, 0);
+
+ byte[] tag = new byte[blockSize];
+ tag[blockSize - 1] = (byte)Tag.C;
+ mac.BlockUpdate(tag, 0, blockSize);
+ }
+
+ private void CalculateMac()
+ {
+ byte[] outC = new byte[blockSize];
+ mac.DoFinal(outC, 0);
+
+ for (int i = 0; i < macBlock.Length; i++)
+ {
+ macBlock[i] = (byte)(nonceMac[i] ^ associatedTextMac[i] ^ outC[i]);
+ }
+ }
+
+ public virtual void Reset()
+ {
+ Reset(true);
+ }
+
+ private void Reset(
+ bool clearMac)
+ {
+ cipher.Reset(); // TODO Redundant since the mac will reset it?
+ mac.Reset();
+
+ bufOff = 0;
+ Array.Clear(bufBlock, 0, bufBlock.Length);
+
+ if (clearMac)
+ {
+ Array.Clear(macBlock, 0, macBlock.Length);
+ }
+
+ byte[] tag = new byte[blockSize];
+ tag[blockSize - 1] = (byte)Tag.H;
+ mac.BlockUpdate(tag, 0, blockSize);
+
+ cipherInitialized = false;
+
+ if (initialAssociatedText != null)
+ {
+ ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
+ }
+ }
+
+ public virtual void ProcessAadByte(byte input)
+ {
+ if (cipherInitialized)
+ {
+ throw new InvalidOperationException("AAD data cannot be added after encryption/decryption processing has begun.");
+ }
+ mac.Update(input);
+ }
+
+ public virtual void ProcessAadBytes(byte[] inBytes, int inOff, int len)
+ {
+ if (cipherInitialized)
+ {
+ throw new InvalidOperationException("AAD data cannot be added after encryption/decryption processing has begun.");
+ }
+ mac.BlockUpdate(inBytes, inOff, len);
+ }
+
+ public virtual int ProcessByte(
+ byte input,
+ byte[] outBytes,
+ int outOff)
+ {
+ InitCipher();
+
+ return Process(input, outBytes, outOff);
+ }
+
+ public virtual int ProcessBytes(
+ byte[] inBytes,
+ int inOff,
+ int len,
+ byte[] outBytes,
+ int outOff)
+ {
+ InitCipher();
+
+ int resultLen = 0;
+
+ for (int i = 0; i != len; i++)
+ {
+ resultLen += Process(inBytes[inOff + i], outBytes, outOff + resultLen);
+ }
+
+ return resultLen;
+ }
+
+ public virtual int DoFinal(
+ byte[] outBytes,
+ int outOff)
+ {
+ InitCipher();
+
+ int extra = bufOff;
+ byte[] tmp = new byte[bufBlock.Length];
+
+ bufOff = 0;
+
+ if (forEncryption)
+ {
+ Check.OutputLength(outBytes, outOff, extra + macSize, "Output buffer too short");
+
+ cipher.ProcessBlock(bufBlock, 0, tmp, 0);
+
+ Array.Copy(tmp, 0, outBytes, outOff, extra);
+
+ mac.BlockUpdate(tmp, 0, extra);
+
+ CalculateMac();
+
+ Array.Copy(macBlock, 0, outBytes, outOff + extra, macSize);
+
+ Reset(false);
+
+ return extra + macSize;
+ }
+ else
+ {
+ if (extra < macSize)
+ throw new InvalidCipherTextException("data too short");
+
+ Check.OutputLength(outBytes, outOff, extra - macSize, "Output buffer too short");
+
+ if (extra > macSize)
+ {
+ mac.BlockUpdate(bufBlock, 0, extra - macSize);
+
+ cipher.ProcessBlock(bufBlock, 0, tmp, 0);
+
+ Array.Copy(tmp, 0, outBytes, outOff, extra - macSize);
+ }
+
+ CalculateMac();
+
+ if (!VerifyMac(bufBlock, extra - macSize))
+ throw new InvalidCipherTextException("mac check in EAX failed");
+
+ Reset(false);
+
+ return extra - macSize;
+ }
+ }
+
+ public virtual byte[] GetMac()
+ {
+ byte[] mac = new byte[macSize];
+
+ Array.Copy(macBlock, 0, mac, 0, macSize);
+
+ return mac;
+ }
+
+ public virtual int GetUpdateOutputSize(
+ int len)
+ {
+ int totalData = len + bufOff;
+ if (!forEncryption)
+ {
+ if (totalData < macSize)
+ {
+ return 0;
+ }
+ totalData -= macSize;
+ }
+ return totalData - totalData % blockSize;
+ }
+
+ public virtual int GetOutputSize(
+ int len)
+ {
+ int totalData = len + bufOff;
+
+ if (forEncryption)
+ {
+ return totalData + macSize;
+ }
+
+ return totalData < macSize ? 0 : totalData - macSize;
+ }
+
+ private int Process(
+ byte b,
+ byte[] outBytes,
+ int outOff)
+ {
+ bufBlock[bufOff++] = b;
+
+ if (bufOff == bufBlock.Length)
+ {
+ Check.OutputLength(outBytes, outOff, blockSize, "Output buffer is too short");
+
+ // TODO Could move the ProcessByte(s) calls to here
+// InitCipher();
+
+ int size;
+
+ if (forEncryption)
+ {
+ size = cipher.ProcessBlock(bufBlock, 0, outBytes, outOff);
+
+ mac.BlockUpdate(outBytes, outOff, blockSize);
+ }
+ else
+ {
+ mac.BlockUpdate(bufBlock, 0, blockSize);
+
+ size = cipher.ProcessBlock(bufBlock, 0, outBytes, outOff);
+ }
+
+ bufOff = 0;
+ if (!forEncryption)
+ {
+ Array.Copy(bufBlock, blockSize, bufBlock, 0, macSize);
+ bufOff = macSize;
+ }
+
+ return size;
+ }
+
+ return 0;
+ }
+
+ private bool VerifyMac(byte[] mac, int off)
+ {
+ int nonEqual = 0;
+
+ for (int i = 0; i < macSize; i++)
+ {
+ nonEqual |= (macBlock[i] ^ mac[off + i]);
+ }
+
+ return nonEqual == 0;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/GCMBlockCipher.cs b/bc-sharp-crypto/src/crypto/modes/GCMBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a6cd00401fe2523f49930980df007fe22ba46f53
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/GCMBlockCipher.cs
@@ -0,0 +1,594 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Modes.Gcm;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ ///
+ /// Implements the Galois/Counter mode (GCM) detailed in
+ /// NIST Special Publication 800-38D.
+ ///
+ public class GcmBlockCipher
+ : IAeadBlockCipher
+ {
+ private const int BlockSize = 16;
+
+ private readonly IBlockCipher cipher;
+ private readonly IGcmMultiplier multiplier;
+ private IGcmExponentiator exp;
+
+ // These fields are set by Init and not modified by processing
+ private bool forEncryption;
+ private bool initialised;
+ private int macSize;
+ private byte[] lastKey;
+ private byte[] nonce;
+ private byte[] initialAssociatedText;
+ private byte[] H;
+ private byte[] J0;
+
+ // These fields are modified during processing
+ private byte[] bufBlock;
+ private byte[] macBlock;
+ private byte[] S, S_at, S_atPre;
+ private byte[] counter;
+ private uint blocksRemaining;
+ private int bufOff;
+ private ulong totalLength;
+ private byte[] atBlock;
+ private int atBlockPos;
+ private ulong atLength;
+ private ulong atLengthPre;
+
+ public GcmBlockCipher(
+ IBlockCipher c)
+ : this(c, null)
+ {
+ }
+
+ public GcmBlockCipher(
+ IBlockCipher c,
+ IGcmMultiplier m)
+ {
+ if (c.GetBlockSize() != BlockSize)
+ throw new ArgumentException("cipher required with a block size of " + BlockSize + ".");
+
+ if (m == null)
+ {
+ // TODO Consider a static property specifying default multiplier
+ m = new Tables8kGcmMultiplier();
+ }
+
+ this.cipher = c;
+ this.multiplier = m;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/GCM"; }
+ }
+
+ public IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BlockSize;
+ }
+
+ ///
+ /// MAC sizes from 32 bits to 128 bits (must be a multiple of 8) are supported. The default is 128 bits.
+ /// Sizes less than 96 are not recommended, but are supported for specialized applications.
+ ///
+ public virtual void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+ this.macBlock = null;
+ this.initialised = true;
+
+ KeyParameter keyParam;
+ byte[] newNonce = null;
+
+ if (parameters is AeadParameters)
+ {
+ AeadParameters param = (AeadParameters)parameters;
+
+ newNonce = param.GetNonce();
+ initialAssociatedText = param.GetAssociatedText();
+
+ int macSizeBits = param.MacSize;
+ if (macSizeBits < 32 || macSizeBits > 128 || macSizeBits % 8 != 0)
+ {
+ throw new ArgumentException("Invalid value for MAC size: " + macSizeBits);
+ }
+
+ macSize = macSizeBits / 8;
+ keyParam = param.Key;
+ }
+ else if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV param = (ParametersWithIV)parameters;
+
+ newNonce = param.GetIV();
+ initialAssociatedText = null;
+ macSize = 16;
+ keyParam = (KeyParameter)param.Parameters;
+ }
+ else
+ {
+ throw new ArgumentException("invalid parameters passed to GCM");
+ }
+
+ int bufLength = forEncryption ? BlockSize : (BlockSize + macSize);
+ this.bufBlock = new byte[bufLength];
+
+ if (newNonce == null || newNonce.Length < 1)
+ {
+ throw new ArgumentException("IV must be at least 1 byte");
+ }
+
+ if (forEncryption)
+ {
+ if (nonce != null && Arrays.AreEqual(nonce, newNonce))
+ {
+ if (keyParam == null)
+ {
+ throw new ArgumentException("cannot reuse nonce for GCM encryption");
+ }
+ if (lastKey != null && Arrays.AreEqual(lastKey, keyParam.GetKey()))
+ {
+ throw new ArgumentException("cannot reuse nonce for GCM encryption");
+ }
+ }
+ }
+
+ nonce = newNonce;
+ if (keyParam != null)
+ {
+ lastKey = keyParam.GetKey();
+ }
+
+ // TODO Restrict macSize to 16 if nonce length not 12?
+
+ // Cipher always used in forward mode
+ // if keyParam is null we're reusing the last key.
+ if (keyParam != null)
+ {
+ cipher.Init(true, keyParam);
+
+ this.H = new byte[BlockSize];
+ cipher.ProcessBlock(H, 0, H, 0);
+
+ // if keyParam is null we're reusing the last key and the multiplier doesn't need re-init
+ multiplier.Init(H);
+ exp = null;
+ }
+ else if (this.H == null)
+ {
+ throw new ArgumentException("Key must be specified in initial init");
+ }
+
+ this.J0 = new byte[BlockSize];
+
+ if (nonce.Length == 12)
+ {
+ Array.Copy(nonce, 0, J0, 0, nonce.Length);
+ this.J0[BlockSize - 1] = 0x01;
+ }
+ else
+ {
+ gHASH(J0, nonce, nonce.Length);
+ byte[] X = new byte[BlockSize];
+ Pack.UInt64_To_BE((ulong)nonce.Length * 8UL, X, 8);
+ gHASHBlock(J0, X);
+ }
+
+ this.S = new byte[BlockSize];
+ this.S_at = new byte[BlockSize];
+ this.S_atPre = new byte[BlockSize];
+ this.atBlock = new byte[BlockSize];
+ this.atBlockPos = 0;
+ this.atLength = 0;
+ this.atLengthPre = 0;
+ this.counter = Arrays.Clone(J0);
+ this.blocksRemaining = uint.MaxValue - 1; // page 8, len(P) <= 2^39 - 256, 1 block used by tag
+ this.bufOff = 0;
+ this.totalLength = 0;
+
+ if (initialAssociatedText != null)
+ {
+ ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
+ }
+ }
+
+ public virtual byte[] GetMac()
+ {
+ return macBlock == null
+ ? new byte[macSize]
+ : Arrays.Clone(macBlock);
+ }
+
+ public virtual int GetOutputSize(
+ int len)
+ {
+ int totalData = len + bufOff;
+
+ if (forEncryption)
+ {
+ return totalData + macSize;
+ }
+
+ return totalData < macSize ? 0 : totalData - macSize;
+ }
+
+ public virtual int GetUpdateOutputSize(
+ int len)
+ {
+ int totalData = len + bufOff;
+ if (!forEncryption)
+ {
+ if (totalData < macSize)
+ {
+ return 0;
+ }
+ totalData -= macSize;
+ }
+ return totalData - totalData % BlockSize;
+ }
+
+ public virtual void ProcessAadByte(byte input)
+ {
+ CheckStatus();
+
+ atBlock[atBlockPos] = input;
+ if (++atBlockPos == BlockSize)
+ {
+ // Hash each block as it fills
+ gHASHBlock(S_at, atBlock);
+ atBlockPos = 0;
+ atLength += BlockSize;
+ }
+ }
+
+ public virtual void ProcessAadBytes(byte[] inBytes, int inOff, int len)
+ {
+ CheckStatus();
+
+ for (int i = 0; i < len; ++i)
+ {
+ atBlock[atBlockPos] = inBytes[inOff + i];
+ if (++atBlockPos == BlockSize)
+ {
+ // Hash each block as it fills
+ gHASHBlock(S_at, atBlock);
+ atBlockPos = 0;
+ atLength += BlockSize;
+ }
+ }
+ }
+
+ private void InitCipher()
+ {
+ if (atLength > 0)
+ {
+ Array.Copy(S_at, 0, S_atPre, 0, BlockSize);
+ atLengthPre = atLength;
+ }
+
+ // Finish hash for partial AAD block
+ if (atBlockPos > 0)
+ {
+ gHASHPartial(S_atPre, atBlock, 0, atBlockPos);
+ atLengthPre += (uint)atBlockPos;
+ }
+
+ if (atLengthPre > 0)
+ {
+ Array.Copy(S_atPre, 0, S, 0, BlockSize);
+ }
+ }
+
+ public virtual int ProcessByte(
+ byte input,
+ byte[] output,
+ int outOff)
+ {
+ CheckStatus();
+
+ bufBlock[bufOff] = input;
+ if (++bufOff == bufBlock.Length)
+ {
+ OutputBlock(output, outOff);
+ return BlockSize;
+ }
+ return 0;
+ }
+
+ public virtual int ProcessBytes(
+ byte[] input,
+ int inOff,
+ int len,
+ byte[] output,
+ int outOff)
+ {
+ CheckStatus();
+
+ if (input.Length < (inOff + len))
+ throw new DataLengthException("Input buffer too short");
+
+ int resultLen = 0;
+
+ for (int i = 0; i < len; ++i)
+ {
+ bufBlock[bufOff] = input[inOff + i];
+ if (++bufOff == bufBlock.Length)
+ {
+ OutputBlock(output, outOff + resultLen);
+ resultLen += BlockSize;
+ }
+ }
+
+ return resultLen;
+ }
+
+ private void OutputBlock(byte[] output, int offset)
+ {
+ Check.OutputLength(output, offset, BlockSize, "Output buffer too short");
+ if (totalLength == 0)
+ {
+ InitCipher();
+ }
+ gCTRBlock(bufBlock, output, offset);
+ if (forEncryption)
+ {
+ bufOff = 0;
+ }
+ else
+ {
+ Array.Copy(bufBlock, BlockSize, bufBlock, 0, macSize);
+ bufOff = macSize;
+ }
+ }
+
+ public int DoFinal(byte[] output, int outOff)
+ {
+ CheckStatus();
+
+ if (totalLength == 0)
+ {
+ InitCipher();
+ }
+
+ int extra = bufOff;
+
+ if (forEncryption)
+ {
+ Check.OutputLength(output, outOff, extra + macSize, "Output buffer too short");
+ }
+ else
+ {
+ if (extra < macSize)
+ throw new InvalidCipherTextException("data too short");
+
+ extra -= macSize;
+
+ Check.OutputLength(output, outOff, extra, "Output buffer too short");
+ }
+
+ if (extra > 0)
+ {
+ gCTRPartial(bufBlock, 0, extra, output, outOff);
+ }
+
+ atLength += (uint)atBlockPos;
+
+ if (atLength > atLengthPre)
+ {
+ /*
+ * Some AAD was sent after the cipher started. We determine the difference b/w the hash value
+ * we actually used when the cipher started (S_atPre) and the final hash value calculated (S_at).
+ * Then we carry this difference forward by multiplying by H^c, where c is the number of (full or
+ * partial) cipher-text blocks produced, and adjust the current hash.
+ */
+
+ // Finish hash for partial AAD block
+ if (atBlockPos > 0)
+ {
+ gHASHPartial(S_at, atBlock, 0, atBlockPos);
+ }
+
+ // Find the difference between the AAD hashes
+ if (atLengthPre > 0)
+ {
+ GcmUtilities.Xor(S_at, S_atPre);
+ }
+
+ // Number of cipher-text blocks produced
+ long c = (long)(((totalLength * 8) + 127) >> 7);
+
+ // Calculate the adjustment factor
+ byte[] H_c = new byte[16];
+ if (exp == null)
+ {
+ exp = new Tables1kGcmExponentiator();
+ exp.Init(H);
+ }
+ exp.ExponentiateX(c, H_c);
+
+ // Carry the difference forward
+ GcmUtilities.Multiply(S_at, H_c);
+
+ // Adjust the current hash
+ GcmUtilities.Xor(S, S_at);
+ }
+
+ // Final gHASH
+ byte[] X = new byte[BlockSize];
+ Pack.UInt64_To_BE(atLength * 8UL, X, 0);
+ Pack.UInt64_To_BE(totalLength * 8UL, X, 8);
+
+ gHASHBlock(S, X);
+
+ // T = MSBt(GCTRk(J0,S))
+ byte[] tag = new byte[BlockSize];
+ cipher.ProcessBlock(J0, 0, tag, 0);
+ GcmUtilities.Xor(tag, S);
+
+ int resultLen = extra;
+
+ // We place into macBlock our calculated value for T
+ this.macBlock = new byte[macSize];
+ Array.Copy(tag, 0, macBlock, 0, macSize);
+
+ if (forEncryption)
+ {
+ // Append T to the message
+ Array.Copy(macBlock, 0, output, outOff + bufOff, macSize);
+ resultLen += macSize;
+ }
+ else
+ {
+ // Retrieve the T value from the message and compare to calculated one
+ byte[] msgMac = new byte[macSize];
+ Array.Copy(bufBlock, extra, msgMac, 0, macSize);
+ if (!Arrays.ConstantTimeAreEqual(this.macBlock, msgMac))
+ throw new InvalidCipherTextException("mac check in GCM failed");
+ }
+
+ Reset(false);
+
+ return resultLen;
+ }
+
+ public virtual void Reset()
+ {
+ Reset(true);
+ }
+
+ private void Reset(
+ bool clearMac)
+ {
+ cipher.Reset();
+
+ // note: we do not reset the nonce.
+
+ S = new byte[BlockSize];
+ S_at = new byte[BlockSize];
+ S_atPre = new byte[BlockSize];
+ atBlock = new byte[BlockSize];
+ atBlockPos = 0;
+ atLength = 0;
+ atLengthPre = 0;
+ counter = Arrays.Clone(J0);
+ blocksRemaining = uint.MaxValue - 1;
+ bufOff = 0;
+ totalLength = 0;
+
+ if (bufBlock != null)
+ {
+ Arrays.Fill(bufBlock, 0);
+ }
+
+ if (clearMac)
+ {
+ macBlock = null;
+ }
+
+ if (forEncryption)
+ {
+ initialised = false;
+ }
+ else
+ {
+ if (initialAssociatedText != null)
+ {
+ ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
+ }
+ }
+ }
+
+ private void gCTRBlock(byte[] block, byte[] output, int outOff)
+ {
+ byte[] tmp = GetNextCounterBlock();
+
+ GcmUtilities.Xor(tmp, block);
+ Array.Copy(tmp, 0, output, outOff, BlockSize);
+
+ gHASHBlock(S, forEncryption ? tmp : block);
+
+ totalLength += BlockSize;
+ }
+
+ private void gCTRPartial(byte[] buf, int off, int len, byte[] output, int outOff)
+ {
+ byte[] tmp = GetNextCounterBlock();
+
+ GcmUtilities.Xor(tmp, buf, off, len);
+ Array.Copy(tmp, 0, output, outOff, len);
+
+ gHASHPartial(S, forEncryption ? tmp : buf, 0, len);
+
+ totalLength += (uint)len;
+ }
+
+ private void gHASH(byte[] Y, byte[] b, int len)
+ {
+ for (int pos = 0; pos < len; pos += BlockSize)
+ {
+ int num = System.Math.Min(len - pos, BlockSize);
+ gHASHPartial(Y, b, pos, num);
+ }
+ }
+
+ private void gHASHBlock(byte[] Y, byte[] b)
+ {
+ GcmUtilities.Xor(Y, b);
+ multiplier.MultiplyH(Y);
+ }
+
+ private void gHASHPartial(byte[] Y, byte[] b, int off, int len)
+ {
+ GcmUtilities.Xor(Y, b, off, len);
+ multiplier.MultiplyH(Y);
+ }
+
+ private byte[] GetNextCounterBlock()
+ {
+ if (blocksRemaining == 0)
+ throw new InvalidOperationException("Attempt to process too many blocks");
+
+ blocksRemaining--;
+
+ uint c = 1;
+ c += counter[15]; counter[15] = (byte)c; c >>= 8;
+ c += counter[14]; counter[14] = (byte)c; c >>= 8;
+ c += counter[13]; counter[13] = (byte)c; c >>= 8;
+ c += counter[12]; counter[12] = (byte)c;
+
+ byte[] tmp = new byte[BlockSize];
+ // TODO Sure would be nice if ciphers could operate on int[]
+ cipher.ProcessBlock(counter, 0, tmp, 0);
+ return tmp;
+ }
+
+ private void CheckStatus()
+ {
+ if (!initialised)
+ {
+ if (forEncryption)
+ {
+ throw new InvalidOperationException("GCM cipher cannot be reused for encryption");
+ }
+ throw new InvalidOperationException("GCM cipher needs to be initialised");
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/GOFBBlockCipher.cs b/bc-sharp-crypto/src/crypto/modes/GOFBBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..436b58a1d289978bbbecc69fe087438c6139d714
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/GOFBBlockCipher.cs
@@ -0,0 +1,234 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ /**
+ * implements the GOST 28147 OFB counter mode (GCTR).
+ */
+ public class GOfbBlockCipher
+ : IBlockCipher
+ {
+ private byte[] IV;
+ private byte[] ofbV;
+ private byte[] ofbOutV;
+
+ private readonly int blockSize;
+ private readonly IBlockCipher cipher;
+
+ bool firstStep = true;
+ int N3;
+ int N4;
+ const int C1 = 16843012; //00000001000000010000000100000100
+ const int C2 = 16843009; //00000001000000010000000100000001
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of the
+ * counter mode (must have a 64 bit block size).
+ */
+ public GOfbBlockCipher(
+ IBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ this.blockSize = cipher.GetBlockSize();
+
+ if (blockSize != 8)
+ {
+ throw new ArgumentException("GCTR only for 64 bit block ciphers");
+ }
+
+ this.IV = new byte[cipher.GetBlockSize()];
+ this.ofbV = new byte[cipher.GetBlockSize()];
+ this.ofbOutV = new byte[cipher.GetBlockSize()];
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ * An IV which is too short is handled in FIPS compliant fashion.
+ *
+ * @param encrypting if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param parameters the key and other data required by the cipher.
+ * @exception ArgumentException if the parameters argument is inappropriate.
+ */
+ public void Init(
+ bool forEncryption, //ignored by this CTR mode
+ ICipherParameters parameters)
+ {
+ firstStep = true;
+ N3 = 0;
+ N4 = 0;
+
+ if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)parameters;
+ byte[] iv = ivParam.GetIV();
+
+ if (iv.Length < IV.Length)
+ {
+ // prepend the supplied IV with zeros (per FIPS PUB 81)
+ Array.Copy(iv, 0, IV, IV.Length - iv.Length, iv.Length);
+ for (int i = 0; i < IV.Length - iv.Length; i++)
+ {
+ IV[i] = 0;
+ }
+ }
+ else
+ {
+ Array.Copy(iv, 0, IV, 0, IV.Length);
+ }
+
+ parameters = ivParam.Parameters;
+ }
+
+ Reset();
+
+ // if it's null, key is to be reused.
+ if (parameters != null)
+ {
+ cipher.Init(true, parameters);
+ }
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/GCTR"
+ * and the block size in bits
+ */
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/GCTR"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return true; }
+ }
+
+ /**
+ * return the block size we are operating at (in bytes).
+ *
+ * @return the block size we are operating at (in bytes).
+ */
+ public int GetBlockSize()
+ {
+ 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)
+ {
+ if ((inOff + blockSize) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > output.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (firstStep)
+ {
+ firstStep = false;
+ cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
+ N3 = bytesToint(ofbOutV, 0);
+ N4 = bytesToint(ofbOutV, 4);
+ }
+ N3 += C2;
+ N4 += C1;
+ if (N4 < C1) // addition is mod (2**32 - 1)
+ {
+ if (N4 > 0)
+ {
+ N4++;
+ }
+ }
+ intTobytes(N3, ofbV, 0);
+ intTobytes(N4, ofbV, 4);
+
+ cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
+
+ //
+ // XOR the ofbV with the plaintext producing the cipher text (and
+ // the next input block).
+ //
+ for (int i = 0; i < blockSize; i++)
+ {
+ output[outOff + i] = (byte)(ofbOutV[i] ^ input[inOff + 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;
+ }
+
+ /**
+ * reset the feedback vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void Reset()
+ {
+ Array.Copy(IV, 0, ofbV, 0, IV.Length);
+
+ 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/bc-sharp-crypto/src/crypto/modes/IAeadBlockCipher.cs b/bc-sharp-crypto/src/crypto/modes/IAeadBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..52c4ff42832db5fb70ee0b000a1be9ba18390c4e
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/IAeadBlockCipher.cs
@@ -0,0 +1,105 @@
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ ///
+ /// A block cipher mode that includes authenticated encryption with a streaming mode
+ /// and optional associated data.
+ ///
+ public interface IAeadBlockCipher
+ {
+ /// The name of the algorithm this cipher implements.
+ string AlgorithmName { get; }
+
+ /// The block cipher underlying this algorithm.
+ IBlockCipher GetUnderlyingCipher();
+
+ /// Initialise the cipher.
+ /// Parameter can either be an AeadParameters or a ParametersWithIV object.
+ /// Initialise for encryption if true, for decryption if false.
+ /// The key or other data required by the cipher.
+ void Init(bool forEncryption, ICipherParameters parameters);
+
+ /// The block size for this cipher, in bytes.
+ int GetBlockSize();
+
+ /// Add a single byte to the associated data check.
+ /// If the implementation supports it, this will be an online operation and will not retain the associated data.
+ /// The byte to be processed.
+ void ProcessAadByte(byte input);
+
+ /// Add a sequence of bytes to the associated data check.
+ /// If the implementation supports it, this will be an online operation and will not retain the associated data.
+ /// The input byte array.
+ /// The offset into the input array where the data to be processed starts.
+ /// The number of bytes to be processed.
+ void ProcessAadBytes(byte[] inBytes, int inOff, int len);
+
+ /**
+ * Encrypt/decrypt a single byte.
+ *
+ * @param input the byte to be processed.
+ * @param outBytes the output buffer the processed byte goes into.
+ * @param outOff the offset into the output byte array the processed data starts at.
+ * @return the number of bytes written to out.
+ * @exception DataLengthException if the output buffer is too small.
+ */
+ int ProcessByte(byte input, byte[] outBytes, int outOff);
+
+ /**
+ * Process a block of bytes from in putting the result into out.
+ *
+ * @param inBytes the input byte array.
+ * @param inOff the offset into the in array where the data to be processed starts.
+ * @param len the number of bytes to be processed.
+ * @param outBytes the output buffer the processed bytes go into.
+ * @param outOff the offset into the output byte array the processed data starts at.
+ * @return the number of bytes written to out.
+ * @exception DataLengthException if the output buffer is too small.
+ */
+ int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff);
+
+ /**
+ * Finish the operation either appending or verifying the MAC at the end of the data.
+ *
+ * @param outBytes space for any resulting output data.
+ * @param outOff offset into out to start copying the data at.
+ * @return number of bytes written into out.
+ * @throws InvalidOperationException if the cipher is in an inappropriate state.
+ * @throws InvalidCipherTextException if the MAC fails to match.
+ */
+ int DoFinal(byte[] outBytes, int outOff);
+
+ /**
+ * Return the value of the MAC associated with the last stream processed.
+ *
+ * @return MAC for plaintext data.
+ */
+ byte[] GetMac();
+
+ /**
+ * Return the size of the output buffer required for a ProcessBytes
+ * an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to ProcessBytes
+ * with len bytes of input.
+ */
+ int GetUpdateOutputSize(int len);
+
+ /**
+ * Return the size of the output buffer required for a ProcessBytes plus a
+ * DoFinal with an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to ProcessBytes and DoFinal
+ * with len bytes of input.
+ */
+ int GetOutputSize(int len);
+
+ ///
+ /// Reset the cipher to the same state as it was after the last init (if there was one).
+ ///
+ void Reset();
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/KCcmBlockCipher.cs b/bc-sharp-crypto/src/crypto/modes/KCcmBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4f78214522445d9ac748016c9bc3075ebb0de830
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/KCcmBlockCipher.cs
@@ -0,0 +1,490 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ public class KCcmBlockCipher: IAeadBlockCipher
+ {
+ private static readonly int BYTES_IN_INT = 4;
+ private static readonly int BITS_IN_BYTE = 8;
+
+ private static readonly int MAX_MAC_BIT_LENGTH = 512;
+ private static readonly int MIN_MAC_BIT_LENGTH = 64;
+
+ private IBlockCipher engine;
+
+ private int macSize;
+ private bool forEncryption;
+
+ private byte[] initialAssociatedText;
+ private byte[] mac;
+ private byte[] macBlock;
+
+ private byte[] nonce;
+
+ private byte[] G1;
+ private byte[] buffer;
+
+ private byte[] s;
+ private byte[] counter;
+
+ private readonly MemoryStream associatedText = new MemoryStream();
+ private readonly MemoryStream data = new MemoryStream();
+
+ /*
+ *
+ *
+ */
+ private int Nb_ = 4;
+
+ private void setNb(int Nb)
+ {
+ if (Nb == 4 || Nb == 6 || Nb == 8)
+ {
+ Nb_ = Nb;
+ }
+ else
+ {
+ throw new ArgumentException("Nb = 4 is recommended by DSTU7624 but can be changed to only 6 or 8 in this implementation");
+ }
+ }
+
+ ///
+ /// Base constructor. Nb value is set to 4.
+ ///
+ /// base cipher to use under CCM.
+ public KCcmBlockCipher(IBlockCipher engine): this(engine, 4)
+ {
+ }
+
+ ///
+ /// Constructor allowing Nb configuration.
+ ///
+ /// Nb is a parameter specified in CCM mode of DSTU7624 standard.
+ /// This parameter specifies maximum possible length of input.It should
+ /// be calculated as follows: Nb = 1 / 8 * (-3 + log[2]Nmax) + 1,
+ /// where Nmax - length of input message in bits.For practical reasons
+ /// Nmax usually less than 4Gb, e.g. for Nmax = 2^32 - 1, Nb = 4.
+ ///
+ /// base cipher to use under CCM.
+ /// Nb value to use.
+ public KCcmBlockCipher(IBlockCipher engine, int Nb)
+ {
+ this.engine = engine;
+ this.macSize = engine.GetBlockSize();
+ this.nonce = new byte[engine.GetBlockSize()];
+ this.initialAssociatedText = new byte[engine.GetBlockSize()];
+ this.mac = new byte[engine.GetBlockSize()];
+ this.macBlock = new byte[engine.GetBlockSize()];
+ this.G1 = new byte[engine.GetBlockSize()];
+ this.buffer = new byte[engine.GetBlockSize()];
+ this.s = new byte[engine.GetBlockSize()];
+ this.counter = new byte[engine.GetBlockSize()];
+ setNb(Nb);
+ }
+
+ public virtual void Init(bool forEncryption, ICipherParameters parameters)
+ {
+
+ ICipherParameters cipherParameters;
+ if (parameters is AeadParameters)
+ {
+
+ AeadParameters param = (AeadParameters)parameters;
+
+ if (param.MacSize > MAX_MAC_BIT_LENGTH || param.MacSize < MIN_MAC_BIT_LENGTH || param.MacSize % 8 != 0)
+ {
+ throw new ArgumentException("Invalid mac size specified");
+ }
+
+ nonce = param.GetNonce();
+ macSize = param.MacSize / BITS_IN_BYTE;
+ initialAssociatedText = param.GetAssociatedText();
+ cipherParameters = param.Key;
+ }
+ else if (parameters is ParametersWithIV)
+ {
+ nonce = ((ParametersWithIV)parameters).GetIV();
+ macSize = engine.GetBlockSize(); // use default blockSize for MAC if it is not specified
+ initialAssociatedText = null;
+ cipherParameters = ((ParametersWithIV)parameters).Parameters;
+ }
+ else
+ {
+ throw new ArgumentException("Invalid parameters specified");
+ }
+
+ this.mac = new byte[macSize];
+ this.forEncryption = forEncryption;
+ engine.Init(true, cipherParameters);
+
+ counter[0] = 0x01; // defined in standard
+
+ if (initialAssociatedText != null)
+ {
+ ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
+ }
+ }
+
+ public virtual String AlgorithmName
+ {
+ get
+ {
+ return engine.AlgorithmName + "/KCCM";
+ }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return engine.GetBlockSize();
+ }
+
+ public virtual IBlockCipher GetUnderlyingCipher()
+ {
+ return engine;
+ }
+
+ public virtual void ProcessAadByte(byte input)
+ {
+ associatedText.WriteByte(input);
+ }
+
+ public virtual void ProcessAadBytes(byte[] input, int inOff, int len)
+ {
+ associatedText.Write(input, inOff, len);
+ }
+
+ private void ProcessAAD(byte[] assocText, int assocOff, int assocLen, int dataLen)
+ {
+ if (assocLen - assocOff < engine.GetBlockSize())
+ {
+ throw new ArgumentException("authText buffer too short");
+ }
+ if (assocLen % engine.GetBlockSize() != 0)
+ {
+ throw new ArgumentException("padding not supported");
+ }
+
+ Array.Copy(nonce, 0, G1, 0, nonce.Length - Nb_ - 1);
+
+ intToBytes(dataLen, buffer, 0); // for G1
+
+ Array.Copy(buffer, 0, G1, nonce.Length - Nb_ - 1, BYTES_IN_INT);
+
+ G1[G1.Length - 1] = getFlag(true, macSize);
+
+ engine.ProcessBlock(G1, 0, macBlock, 0);
+
+ intToBytes(assocLen, buffer, 0); // for G2
+
+ if (assocLen <= engine.GetBlockSize() - Nb_)
+ {
+ for (int byteIndex = 0; byteIndex < assocLen; byteIndex++)
+ {
+ buffer[byteIndex + Nb_] ^= assocText[assocOff + byteIndex];
+ }
+
+ for (int byteIndex = 0; byteIndex < engine.GetBlockSize(); byteIndex++)
+ {
+ macBlock[byteIndex] ^= buffer[byteIndex];
+ }
+
+ engine.ProcessBlock(macBlock, 0, macBlock, 0);
+
+ return;
+ }
+
+ for (int byteIndex = 0; byteIndex < engine.GetBlockSize(); byteIndex++)
+ {
+ macBlock[byteIndex] ^= buffer[byteIndex];
+ }
+
+ engine.ProcessBlock(macBlock, 0, macBlock, 0);
+
+ int authLen = assocLen;
+ while (authLen != 0)
+ {
+ for (int byteIndex = 0; byteIndex < engine.GetBlockSize(); byteIndex++)
+ {
+ macBlock[byteIndex] ^= assocText[byteIndex + assocOff];
+ }
+
+ engine.ProcessBlock(macBlock, 0, macBlock, 0);
+
+ assocOff += engine.GetBlockSize();
+ authLen -= engine.GetBlockSize();
+ }
+ }
+
+ public virtual int ProcessByte(byte input, byte[] output, int outOff)
+ {
+ data.WriteByte(input);
+
+ return 0;
+ }
+
+ public virtual int ProcessBytes(byte[] input, int inOff, int inLen, byte[] output, int outOff)
+ {
+ Check.DataLength(input, inOff, inLen, "input buffer too short");
+
+ data.Write(input, inOff, inLen);
+
+ return 0;
+ }
+
+ public int ProcessPacket(byte[] input, int inOff, int len, byte[] output, int outOff)
+ {
+ Check.DataLength(input, inOff, len, "input buffer too short");
+ Check.OutputLength(output, outOff, len, "output buffer too short");
+
+ if (associatedText.Length > 0)
+ {
+#if PORTABLE
+ byte[] aad = associatedText.ToArray();
+ int aadLen = aad.Length;
+#else
+ byte[] aad = associatedText.GetBuffer();
+ int aadLen = (int)associatedText.Length;
+#endif
+
+ int dataLen = forEncryption ? (int)data.Length : ((int)data.Length - macSize);
+
+ ProcessAAD(aad, 0, aadLen, dataLen);
+ }
+
+ if (forEncryption)
+ {
+ Check.DataLength(len % engine.GetBlockSize() != 0, "partial blocks not supported");
+
+ CalculateMac(input, inOff, len);
+ engine.ProcessBlock(nonce, 0, s, 0);
+
+ int totalLength = len;
+ while (totalLength > 0)
+ {
+ ProcessBlock(input, inOff, len, output, outOff);
+ totalLength -= engine.GetBlockSize();
+ inOff += engine.GetBlockSize();
+ outOff += engine.GetBlockSize();
+ }
+
+ for (int byteIndex = 0; byteIndex inOff)
+ {
+ for (int byteIndex = 0; byteIndex 0)
+ {
+ for (int byteIndex = 0; byteIndex < engine.GetBlockSize(); byteIndex++)
+ {
+ macBlock[byteIndex] ^= authText[authOff + byteIndex];
+ }
+
+ engine.ProcessBlock(macBlock, 0, macBlock, 0);
+
+ totalLen -= engine.GetBlockSize();
+ authOff += engine.GetBlockSize();
+ }
+ }
+
+ public virtual int DoFinal(byte[] output, int outOff)
+ {
+#if PORTABLE
+ byte[] buf = data.ToArray();
+ int bufLen = buf.Length;
+#else
+ byte[] buf = data.GetBuffer();
+ int bufLen = (int)data.Length;
+#endif
+
+ int len = ProcessPacket(buf, 0, bufLen, output, outOff);
+
+ Reset();
+
+ return len;
+ }
+
+ public virtual byte[] GetMac()
+ {
+ return Arrays.Clone(mac);
+ }
+
+ public virtual int GetUpdateOutputSize(int len)
+ {
+ return len;
+ }
+
+ public virtual int GetOutputSize(int len)
+ {
+ return len + macSize;
+ }
+
+ public virtual void Reset()
+ {
+ Arrays.Fill(G1, (byte)0);
+ Arrays.Fill(buffer, (byte)0);
+ Arrays.Fill(counter, (byte)0);
+ Arrays.Fill(macBlock, (byte)0);
+
+ counter[0] = 0x01;
+ data.SetLength(0);
+ associatedText.SetLength(0);
+
+ if (initialAssociatedText != null)
+ {
+ ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
+ }
+ }
+
+ 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;
+ }
+
+ private byte getFlag(bool authTextPresents, int macSize)
+ {
+ StringBuilder flagByte = new StringBuilder();
+
+ if (authTextPresents)
+ {
+ flagByte.Append("1");
+ }
+ else
+ {
+ flagByte.Append("0");
+ }
+
+
+ switch (macSize)
+ {
+ case 8:
+ flagByte.Append("010"); // binary 2
+ break;
+ case 16:
+ flagByte.Append("011"); // binary 3
+ break;
+ case 32:
+ flagByte.Append("100"); // binary 4
+ break;
+ case 48:
+ flagByte.Append("101"); // binary 5
+ break;
+ case 64:
+ flagByte.Append("110"); // binary 6
+ break;
+ }
+
+ String binaryNb = Convert.ToString(Nb_ - 1, 2);
+ while (binaryNb.Length < 4)
+ {
+ binaryNb = new StringBuilder(binaryNb).Insert(0, "0").ToString();
+ }
+
+ flagByte.Append(binaryNb);
+
+ return (byte)Convert.ToInt32(flagByte.ToString(), 2);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/KCtrBlockCipher.cs b/bc-sharp-crypto/src/crypto/modes/KCtrBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ff0249a6c073ca6df5628140032d930e9d0fe840
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/KCtrBlockCipher.cs
@@ -0,0 +1,235 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ /**
+ * Implements a Gamming or Counter (CTR) mode on top of a DSTU 7624 block cipher.
+ */
+ public class KCtrBlockCipher : IStreamCipher, IBlockCipher
+ {
+ private byte[] IV;
+ private byte[] ofbV;
+ private byte[] ofbOutV;
+ private bool initialised;
+
+ private int byteCount;
+
+ private readonly int blockSize;
+ private readonly IBlockCipher cipher;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of the
+ * feedback mode.
+ */
+ public KCtrBlockCipher(IBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ this.IV = new byte[cipher.GetBlockSize()];
+ this.blockSize = cipher.GetBlockSize();
+
+ this.ofbV = new byte[cipher.GetBlockSize()];
+ this.ofbOutV = new byte[cipher.GetBlockSize()];
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ * An IV which is too short is handled in FIPS compliant fashion.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param param the key and other data required by the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.initialised = true;
+ if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)parameters;
+ byte[] iv = ivParam.GetIV();
+ int diff = IV.Length - iv.Length;
+
+ Array.Clear(IV, 0, IV.Length);
+ Array.Copy(iv, 0, IV, diff, iv.Length);
+
+ parameters = ivParam.Parameters;
+ }
+ else
+ {
+ throw new ArgumentException("Invalid parameter passed");
+ }
+
+ // if it's null, key is to be reused.
+ if (parameters != null)
+ {
+ cipher.Init(true, parameters);
+ }
+
+ Reset();
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/KCTR"
+ * and the block size in bits.
+ */
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/KCTR"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return true; }
+ }
+
+ /**
+ * return the block size we are operating at.
+ *
+ * @return the block size we are operating at (in bytes).
+ */
+ public int GetBlockSize()
+ {
+ return cipher.GetBlockSize();
+ }
+
+ public byte ReturnByte(byte input)
+ {
+ return CalculateByte(input);
+ }
+
+ 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");
+ }
+
+ int inStart = inOff;
+ int inEnd = inOff + len;
+ int outStart = outOff;
+
+ while (inStartRFC 7253 on The OCB
+ * Authenticated-Encryption Algorithm, licensed per:
+ *
+ * License for
+ * Open-Source Software Implementations of OCB (Jan 9, 2013) - 'License 1'
+ * Under this license, you are authorized to make, use, and distribute open-source software
+ * implementations of OCB. This license terminates for you if you sue someone over their open-source
+ * software implementation of OCB claiming that you have a patent covering their implementation.
+ *
+ * This is a non-binding summary of a legal document (the link above). The parameters of the license
+ * are specified in the license document and that document is controlling.
+ */
+ public class OcbBlockCipher
+ : IAeadBlockCipher
+ {
+ private const int BLOCK_SIZE = 16;
+
+ private readonly IBlockCipher hashCipher;
+ private readonly IBlockCipher mainCipher;
+
+ /*
+ * CONFIGURATION
+ */
+ private bool forEncryption;
+ private int macSize;
+ private byte[] initialAssociatedText;
+
+ /*
+ * KEY-DEPENDENT
+ */
+ // NOTE: elements are lazily calculated
+ private IList L;
+ private byte[] L_Asterisk, L_Dollar;
+
+ /*
+ * NONCE-DEPENDENT
+ */
+ private byte[] KtopInput = null;
+ private byte[] Stretch = new byte[24];
+ private byte[] OffsetMAIN_0 = new byte[16];
+
+ /*
+ * PER-ENCRYPTION/DECRYPTION
+ */
+ private byte[] hashBlock, mainBlock;
+ private int hashBlockPos, mainBlockPos;
+ private long hashBlockCount, mainBlockCount;
+ private byte[] OffsetHASH;
+ private byte[] Sum;
+ private byte[] OffsetMAIN = new byte[16];
+ private byte[] Checksum;
+
+ // NOTE: The MAC value is preserved after doFinal
+ private byte[] macBlock;
+
+ public OcbBlockCipher(IBlockCipher hashCipher, IBlockCipher mainCipher)
+ {
+ if (hashCipher == null)
+ throw new ArgumentNullException("hashCipher");
+ if (hashCipher.GetBlockSize() != BLOCK_SIZE)
+ throw new ArgumentException("must have a block size of " + BLOCK_SIZE, "hashCipher");
+ if (mainCipher == null)
+ throw new ArgumentNullException("mainCipher");
+ if (mainCipher.GetBlockSize() != BLOCK_SIZE)
+ throw new ArgumentException("must have a block size of " + BLOCK_SIZE, "mainCipher");
+
+ if (!hashCipher.AlgorithmName.Equals(mainCipher.AlgorithmName))
+ throw new ArgumentException("'hashCipher' and 'mainCipher' must be the same algorithm");
+
+ this.hashCipher = hashCipher;
+ this.mainCipher = mainCipher;
+ }
+
+ public virtual IBlockCipher GetUnderlyingCipher()
+ {
+ return mainCipher;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return mainCipher.AlgorithmName + "/OCB"; }
+ }
+
+ public virtual void Init(bool forEncryption, ICipherParameters parameters)
+ {
+ bool oldForEncryption = this.forEncryption;
+ this.forEncryption = forEncryption;
+ this.macBlock = null;
+
+ KeyParameter keyParameter;
+
+ byte[] N;
+ if (parameters is AeadParameters)
+ {
+ AeadParameters aeadParameters = (AeadParameters) parameters;
+
+ N = aeadParameters.GetNonce();
+ initialAssociatedText = aeadParameters.GetAssociatedText();
+
+ int macSizeBits = aeadParameters.MacSize;
+ if (macSizeBits < 64 || macSizeBits > 128 || macSizeBits % 8 != 0)
+ throw new ArgumentException("Invalid value for MAC size: " + macSizeBits);
+
+ macSize = macSizeBits / 8;
+ keyParameter = aeadParameters.Key;
+ }
+ else if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV parametersWithIV = (ParametersWithIV) parameters;
+
+ N = parametersWithIV.GetIV();
+ initialAssociatedText = null;
+ macSize = 16;
+ keyParameter = (KeyParameter) parametersWithIV.Parameters;
+ }
+ else
+ {
+ throw new ArgumentException("invalid parameters passed to OCB");
+ }
+
+ this.hashBlock = new byte[16];
+ this.mainBlock = new byte[forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize)];
+
+ if (N == null)
+ {
+ N = new byte[0];
+ }
+
+ if (N.Length > 15)
+ {
+ throw new ArgumentException("IV must be no more than 15 bytes");
+ }
+
+ /*
+ * KEY-DEPENDENT INITIALISATION
+ */
+
+ if (keyParameter != null)
+ {
+ // hashCipher always used in forward mode
+ hashCipher.Init(true, keyParameter);
+ mainCipher.Init(forEncryption, keyParameter);
+ KtopInput = null;
+ }
+ else if (oldForEncryption != forEncryption)
+ {
+ throw new ArgumentException("cannot change encrypting state without providing key.");
+ }
+
+ this.L_Asterisk = new byte[16];
+ hashCipher.ProcessBlock(L_Asterisk, 0, L_Asterisk, 0);
+
+ this.L_Dollar = OCB_double(L_Asterisk);
+
+ this.L = Platform.CreateArrayList();
+ this.L.Add(OCB_double(L_Dollar));
+
+ /*
+ * NONCE-DEPENDENT AND PER-ENCRYPTION/DECRYPTION INITIALISATION
+ */
+
+ int bottom = ProcessNonce(N);
+
+ int bits = bottom % 8, bytes = bottom / 8;
+ if (bits == 0)
+ {
+ Array.Copy(Stretch, bytes, OffsetMAIN_0, 0, 16);
+ }
+ else
+ {
+ for (int i = 0; i < 16; ++i)
+ {
+ uint b1 = Stretch[bytes];
+ uint b2 = Stretch[++bytes];
+ this.OffsetMAIN_0[i] = (byte) ((b1 << bits) | (b2 >> (8 - bits)));
+ }
+ }
+
+ this.hashBlockPos = 0;
+ this.mainBlockPos = 0;
+
+ this.hashBlockCount = 0;
+ this.mainBlockCount = 0;
+
+ this.OffsetHASH = new byte[16];
+ this.Sum = new byte[16];
+ Array.Copy(OffsetMAIN_0, 0, OffsetMAIN, 0, 16);
+ this.Checksum = new byte[16];
+
+ if (initialAssociatedText != null)
+ {
+ ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
+ }
+ }
+
+ protected virtual int ProcessNonce(byte[] N)
+ {
+ byte[] nonce = new byte[16];
+ Array.Copy(N, 0, nonce, nonce.Length - N.Length, N.Length);
+ nonce[0] = (byte)(macSize << 4);
+ nonce[15 - N.Length] |= 1;
+
+ int bottom = nonce[15] & 0x3F;
+ nonce[15] &= 0xC0;
+
+ /*
+ * When used with incrementing nonces, the cipher is only applied once every 64 inits.
+ */
+ if (KtopInput == null || !Arrays.AreEqual(nonce, KtopInput))
+ {
+ byte[] Ktop = new byte[16];
+ KtopInput = nonce;
+ hashCipher.ProcessBlock(KtopInput, 0, Ktop, 0);
+ Array.Copy(Ktop, 0, Stretch, 0, 16);
+ for (int i = 0; i < 8; ++i)
+ {
+ Stretch[16 + i] = (byte)(Ktop[i] ^ Ktop[i + 1]);
+ }
+ }
+
+ return bottom;
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public virtual byte[] GetMac()
+ {
+ return macBlock == null
+ ? new byte[macSize]
+ : Arrays.Clone(macBlock);
+ }
+
+ public virtual int GetOutputSize(int len)
+ {
+ int totalData = len + mainBlockPos;
+ if (forEncryption)
+ {
+ return totalData + macSize;
+ }
+ return totalData < macSize ? 0 : totalData - macSize;
+ }
+
+ public virtual int GetUpdateOutputSize(int len)
+ {
+ int totalData = len + mainBlockPos;
+ if (!forEncryption)
+ {
+ if (totalData < macSize)
+ {
+ return 0;
+ }
+ totalData -= macSize;
+ }
+ return totalData - totalData % BLOCK_SIZE;
+ }
+
+ public virtual void ProcessAadByte(byte input)
+ {
+ hashBlock[hashBlockPos] = input;
+ if (++hashBlockPos == hashBlock.Length)
+ {
+ ProcessHashBlock();
+ }
+ }
+
+ public virtual void ProcessAadBytes(byte[] input, int off, int len)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ hashBlock[hashBlockPos] = input[off + i];
+ if (++hashBlockPos == hashBlock.Length)
+ {
+ ProcessHashBlock();
+ }
+ }
+ }
+
+ public virtual int ProcessByte(byte input, byte[] output, int outOff)
+ {
+ mainBlock[mainBlockPos] = input;
+ if (++mainBlockPos == mainBlock.Length)
+ {
+ ProcessMainBlock(output, outOff);
+ return BLOCK_SIZE;
+ }
+ return 0;
+ }
+
+ public virtual int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+ {
+ int resultLen = 0;
+
+ for (int i = 0; i < len; ++i)
+ {
+ mainBlock[mainBlockPos] = input[inOff + i];
+ if (++mainBlockPos == mainBlock.Length)
+ {
+ ProcessMainBlock(output, outOff + resultLen);
+ resultLen += BLOCK_SIZE;
+ }
+ }
+
+ return resultLen;
+ }
+
+ public virtual int DoFinal(byte[] output, int outOff)
+ {
+ /*
+ * For decryption, get the tag from the end of the message
+ */
+ byte[] tag = null;
+ if (!forEncryption) {
+ if (mainBlockPos < macSize)
+ throw new InvalidCipherTextException("data too short");
+
+ mainBlockPos -= macSize;
+ tag = new byte[macSize];
+ Array.Copy(mainBlock, mainBlockPos, tag, 0, macSize);
+ }
+
+ /*
+ * HASH: Process any final partial block; compute final hash value
+ */
+ if (hashBlockPos > 0)
+ {
+ OCB_extend(hashBlock, hashBlockPos);
+ UpdateHASH(L_Asterisk);
+ }
+
+ /*
+ * OCB-ENCRYPT/OCB-DECRYPT: Process any final partial block
+ */
+ if (mainBlockPos > 0)
+ {
+ if (forEncryption)
+ {
+ OCB_extend(mainBlock, mainBlockPos);
+ Xor(Checksum, mainBlock);
+ }
+
+ Xor(OffsetMAIN, L_Asterisk);
+
+ byte[] Pad = new byte[16];
+ hashCipher.ProcessBlock(OffsetMAIN, 0, Pad, 0);
+
+ Xor(mainBlock, Pad);
+
+ Check.OutputLength(output, outOff, mainBlockPos, "Output buffer too short");
+ Array.Copy(mainBlock, 0, output, outOff, mainBlockPos);
+
+ if (!forEncryption)
+ {
+ OCB_extend(mainBlock, mainBlockPos);
+ Xor(Checksum, mainBlock);
+ }
+ }
+
+ /*
+ * OCB-ENCRYPT/OCB-DECRYPT: Compute raw tag
+ */
+ Xor(Checksum, OffsetMAIN);
+ Xor(Checksum, L_Dollar);
+ hashCipher.ProcessBlock(Checksum, 0, Checksum, 0);
+ Xor(Checksum, Sum);
+
+ this.macBlock = new byte[macSize];
+ Array.Copy(Checksum, 0, macBlock, 0, macSize);
+
+ /*
+ * Validate or append tag and reset this cipher for the next run
+ */
+ int resultLen = mainBlockPos;
+
+ if (forEncryption)
+ {
+ Check.OutputLength(output, outOff, resultLen + macSize, "Output buffer too short");
+
+ // Append tag to the message
+ Array.Copy(macBlock, 0, output, outOff + resultLen, macSize);
+ resultLen += macSize;
+ }
+ else
+ {
+ // Compare the tag from the message with the calculated one
+ if (!Arrays.ConstantTimeAreEqual(macBlock, tag))
+ throw new InvalidCipherTextException("mac check in OCB failed");
+ }
+
+ Reset(false);
+
+ return resultLen;
+ }
+
+ public virtual void Reset()
+ {
+ Reset(true);
+ }
+
+ protected virtual void Clear(byte[] bs)
+ {
+ if (bs != null)
+ {
+ Array.Clear(bs, 0, bs.Length);
+ }
+ }
+
+ protected virtual byte[] GetLSub(int n)
+ {
+ while (n >= L.Count)
+ {
+ L.Add(OCB_double((byte[]) L[L.Count - 1]));
+ }
+ return (byte[])L[n];
+ }
+
+ protected virtual void ProcessHashBlock()
+ {
+ /*
+ * HASH: Process any whole blocks
+ */
+ UpdateHASH(GetLSub(OCB_ntz(++hashBlockCount)));
+ hashBlockPos = 0;
+ }
+
+ protected virtual void ProcessMainBlock(byte[] output, int outOff)
+ {
+ Check.DataLength(output, outOff, BLOCK_SIZE, "Output buffer too short");
+
+ /*
+ * OCB-ENCRYPT/OCB-DECRYPT: Process any whole blocks
+ */
+
+ if (forEncryption)
+ {
+ Xor(Checksum, mainBlock);
+ mainBlockPos = 0;
+ }
+
+ Xor(OffsetMAIN, GetLSub(OCB_ntz(++mainBlockCount)));
+
+ Xor(mainBlock, OffsetMAIN);
+ mainCipher.ProcessBlock(mainBlock, 0, mainBlock, 0);
+ Xor(mainBlock, OffsetMAIN);
+
+ Array.Copy(mainBlock, 0, output, outOff, 16);
+
+ if (!forEncryption)
+ {
+ Xor(Checksum, mainBlock);
+ Array.Copy(mainBlock, BLOCK_SIZE, mainBlock, 0, macSize);
+ mainBlockPos = macSize;
+ }
+ }
+
+ protected virtual void Reset(bool clearMac)
+ {
+ hashCipher.Reset();
+ mainCipher.Reset();
+
+ Clear(hashBlock);
+ Clear(mainBlock);
+
+ hashBlockPos = 0;
+ mainBlockPos = 0;
+
+ hashBlockCount = 0;
+ mainBlockCount = 0;
+
+ Clear(OffsetHASH);
+ Clear(Sum);
+ Array.Copy(OffsetMAIN_0, 0, OffsetMAIN, 0, 16);
+ Clear(Checksum);
+
+ if (clearMac)
+ {
+ macBlock = null;
+ }
+
+ if (initialAssociatedText != null)
+ {
+ ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
+ }
+ }
+
+ protected virtual void UpdateHASH(byte[] LSub)
+ {
+ Xor(OffsetHASH, LSub);
+ Xor(hashBlock, OffsetHASH);
+ hashCipher.ProcessBlock(hashBlock, 0, hashBlock, 0);
+ Xor(Sum, hashBlock);
+ }
+
+ protected static byte[] OCB_double(byte[] block)
+ {
+ byte[] result = new byte[16];
+ int carry = ShiftLeft(block, result);
+
+ /*
+ * NOTE: This construction is an attempt at a constant-time implementation.
+ */
+ result[15] ^= (byte)(0x87 >> ((1 - carry) << 3));
+
+ return result;
+ }
+
+ protected static void OCB_extend(byte[] block, int pos)
+ {
+ block[pos] = (byte) 0x80;
+ while (++pos < 16)
+ {
+ block[pos] = 0;
+ }
+ }
+
+ protected static int OCB_ntz(long x)
+ {
+ if (x == 0)
+ {
+ return 64;
+ }
+
+ int n = 0;
+ ulong ux = (ulong)x;
+ while ((ux & 1UL) == 0UL)
+ {
+ ++n;
+ ux >>= 1;
+ }
+ return n;
+ }
+
+ protected static int ShiftLeft(byte[] block, byte[] output)
+ {
+ int i = 16;
+ uint bit = 0;
+ while (--i >= 0)
+ {
+ uint b = block[i];
+ output[i] = (byte) ((b << 1) | bit);
+ bit = (b >> 7) & 1;
+ }
+ return (int)bit;
+ }
+
+ protected static void Xor(byte[] block, byte[] val)
+ {
+ for (int i = 15; i >= 0; --i)
+ {
+ block[i] ^= val[i];
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/OfbBlockCipher.cs b/bc-sharp-crypto/src/crypto/modes/OfbBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a99f8c5d77da94999a3522b67cc31cff75e4df7d
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/OfbBlockCipher.cs
@@ -0,0 +1,182 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ /**
+ * implements a Output-FeedBack (OFB) mode on top of a simple cipher.
+ */
+ public class OfbBlockCipher
+ : IBlockCipher
+ {
+ private byte[] IV;
+ private byte[] ofbV;
+ private byte[] ofbOutV;
+
+ private readonly int blockSize;
+ private readonly IBlockCipher cipher;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of the
+ * feedback mode.
+ * @param blockSize the block size in bits (note: a multiple of 8)
+ */
+ public OfbBlockCipher(
+ IBlockCipher cipher,
+ int blockSize)
+ {
+ this.cipher = cipher;
+ this.blockSize = blockSize / 8;
+
+ this.IV = new byte[cipher.GetBlockSize()];
+ this.ofbV = new byte[cipher.GetBlockSize()];
+ this.ofbOutV = new byte[cipher.GetBlockSize()];
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ * An IV which is too short is handled in FIPS compliant fashion.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param param the key and other data required by the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption, //ignored by this OFB mode
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)parameters;
+ byte[] iv = ivParam.GetIV();
+
+ if (iv.Length < IV.Length)
+ {
+ // prepend the supplied IV with zeros (per FIPS PUB 81)
+ Array.Copy(iv, 0, IV, IV.Length - iv.Length, iv.Length);
+ for (int i = 0; i < IV.Length - iv.Length; i++)
+ {
+ IV[i] = 0;
+ }
+ }
+ else
+ {
+ Array.Copy(iv, 0, IV, 0, IV.Length);
+ }
+
+ parameters = ivParam.Parameters;
+ }
+
+ Reset();
+
+ // if it's null, key is to be reused.
+ if (parameters != null)
+ {
+ cipher.Init(true, parameters);
+ }
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/OFB"
+ * and the block size in bits
+ */
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/OFB" + (blockSize * 8); }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return true; }
+ }
+
+ /**
+ * return the block size we are operating at (in bytes).
+ *
+ * @return the block size we are operating at (in bytes).
+ */
+ public int GetBlockSize()
+ {
+ 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)
+ {
+ if ((inOff + blockSize) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > output.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
+
+ //
+ // XOR the ofbV with the plaintext producing the cipher text (and
+ // the next input block).
+ //
+ for (int i = 0; i < blockSize; i++)
+ {
+ output[outOff + i] = (byte)(ofbOutV[i] ^ input[inOff + 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;
+ }
+
+ /**
+ * reset the feedback vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void Reset()
+ {
+ Array.Copy(IV, 0, ofbV, 0, IV.Length);
+
+ cipher.Reset();
+ }
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs b/bc-sharp-crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..038ca783df2adcb8beec6dc890dc9bb43502856c
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs
@@ -0,0 +1,337 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ /**
+ * Implements OpenPGP's rather strange version of Cipher-FeedBack (CFB) mode
+ * on top of a simple cipher. This class assumes the IV has been prepended
+ * to the data stream already, and just accomodates the reset after
+ * (blockSize + 2) bytes have been read.
+ *
+ * For further info see RFC 2440 .
+ *
+ */
+ public class OpenPgpCfbBlockCipher
+ : IBlockCipher
+ {
+ private byte[] IV;
+ private byte[] FR;
+ private byte[] FRE;
+
+ private readonly IBlockCipher cipher;
+ private readonly int blockSize;
+
+ private int count;
+ private bool forEncryption;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of the
+ * feedback mode.
+ */
+ public OpenPgpCfbBlockCipher(
+ IBlockCipher cipher)
+ {
+ this.cipher = cipher;
+
+ this.blockSize = cipher.GetBlockSize();
+ this.IV = new byte[blockSize];
+ this.FR = new byte[blockSize];
+ this.FRE = new byte[blockSize];
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/PGPCFB"
+ * and the block size in bits.
+ */
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/OpenPGPCFB"; }
+ }
+
+ public bool IsPartialBlockOkay
+ {
+ get { return true; }
+ }
+
+ /**
+ * return the block size we are operating at.
+ *
+ * @return the block size we are operating at (in bytes).
+ */
+ public int GetBlockSize()
+ {
+ 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)
+ {
+ return (forEncryption) ? EncryptBlock(input, inOff, output, outOff) : DecryptBlock(input, inOff, output, outOff);
+ }
+
+ /**
+ * reset the chaining vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void Reset()
+ {
+ count = 0;
+
+ Array.Copy(IV, 0, FR, 0, FR.Length);
+
+ cipher.Reset();
+ }
+
+ /**
+ * Initialise the cipher and, possibly, the initialisation vector (IV).
+ * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+ * An IV which is too short is handled in FIPS compliant fashion.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param parameters the key and other data required by the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+
+ if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)parameters;
+ byte[] iv = ivParam.GetIV();
+
+ if (iv.Length < IV.Length)
+ {
+ // prepend the supplied IV with zeros (per FIPS PUB 81)
+ Array.Copy(iv, 0, IV, IV.Length - iv.Length, iv.Length);
+ for (int i = 0; i < IV.Length - iv.Length; i++)
+ {
+ IV[i] = 0;
+ }
+ }
+ else
+ {
+ Array.Copy(iv, 0, IV, 0, IV.Length);
+ }
+
+ parameters = ivParam.Parameters;
+ }
+
+ Reset();
+
+ cipher.Init(true, parameters);
+ }
+
+ /**
+ * Encrypt one byte of data according to CFB mode.
+ * @param data the byte to encrypt
+ * @param blockOff offset in the current block
+ * @returns the encrypted byte
+ */
+ private byte EncryptByte(byte data, int blockOff)
+ {
+ 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 ((inOff + blockSize) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > outBytes.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (count > blockSize)
+ {
+ FR[blockSize - 2] = outBytes[outOff] = EncryptByte(input[inOff], blockSize - 2);
+ FR[blockSize - 1] = outBytes[outOff + 1] = EncryptByte(input[inOff + 1], blockSize - 1);
+
+ cipher.ProcessBlock(FR, 0, FRE, 0);
+
+ for (int n = 2; n < blockSize; n++)
+ {
+ FR[n - 2] = outBytes[outOff + n] = EncryptByte(input[inOff + n], n - 2);
+ }
+ }
+ else if (count == 0)
+ {
+ cipher.ProcessBlock(FR, 0, FRE, 0);
+
+ for (int n = 0; n < blockSize; n++)
+ {
+ FR[n] = outBytes[outOff + n] = EncryptByte(input[inOff + n], n);
+ }
+
+ count += blockSize;
+ }
+ else if (count == blockSize)
+ {
+ cipher.ProcessBlock(FR, 0, FRE, 0);
+
+ outBytes[outOff] = EncryptByte(input[inOff], 0);
+ outBytes[outOff + 1] = EncryptByte(input[inOff + 1], 1);
+
+ //
+ // do reset
+ //
+ Array.Copy(FR, 2, FR, 0, blockSize - 2);
+ Array.Copy(outBytes, outOff, FR, blockSize - 2, 2);
+
+ cipher.ProcessBlock(FR, 0, FRE, 0);
+
+ for (int n = 2; n < blockSize; n++)
+ {
+ FR[n - 2] = outBytes[outOff + n] = EncryptByte(input[inOff + n], n - 2);
+ }
+
+ count += blockSize;
+ }
+
+ 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)
+ {
+ if ((inOff + blockSize) > input.Length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + blockSize) > outBytes.Length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (count > blockSize)
+ {
+ byte inVal = input[inOff];
+ FR[blockSize - 2] = inVal;
+ outBytes[outOff] = EncryptByte(inVal, blockSize - 2);
+
+ inVal = input[inOff + 1];
+ FR[blockSize - 1] = inVal;
+ outBytes[outOff + 1] = EncryptByte(inVal, blockSize - 1);
+
+ cipher.ProcessBlock(FR, 0, FRE, 0);
+
+ for (int n = 2; n < blockSize; n++)
+ {
+ inVal = input[inOff + n];
+ FR[n - 2] = inVal;
+ outBytes[outOff + n] = EncryptByte(inVal, n - 2);
+ }
+ }
+ else if (count == 0)
+ {
+ cipher.ProcessBlock(FR, 0, FRE, 0);
+
+ for (int n = 0; n < blockSize; n++)
+ {
+ FR[n] = input[inOff + n];
+ outBytes[n] = EncryptByte(input[inOff + n], n);
+ }
+
+ count += blockSize;
+ }
+ else if (count == blockSize)
+ {
+ cipher.ProcessBlock(FR, 0, FRE, 0);
+
+ byte inVal1 = input[inOff];
+ byte inVal2 = input[inOff + 1];
+ outBytes[outOff ] = EncryptByte(inVal1, 0);
+ outBytes[outOff + 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[inOff + n];
+ FR[n - 2] = inVal;
+ outBytes[outOff + n] = EncryptByte(inVal, n - 2);
+ }
+
+ count += blockSize;
+ }
+
+ return blockSize;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/SicBlockCipher.cs b/bc-sharp-crypto/src/crypto/modes/SicBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0bea4a455b588880f6bdbcbbfa2879cc90aed5ef
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/SicBlockCipher.cs
@@ -0,0 +1,120 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+ /**
+ * Implements the Segmented Integer Counter (SIC) mode on top of a simple
+ * block cipher.
+ */
+ public class SicBlockCipher
+ : IBlockCipher
+ {
+ private readonly IBlockCipher cipher;
+ private readonly int blockSize;
+ private readonly byte[] counter;
+ private readonly byte[] counterOut;
+ private byte[] IV;
+
+ /**
+ * Basic constructor.
+ *
+ * @param c the block cipher to be used.
+ */
+ public SicBlockCipher(IBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ this.blockSize = cipher.GetBlockSize();
+ this.counter = new byte[blockSize];
+ this.counterOut = new byte[blockSize];
+ this.IV = new byte[blockSize];
+ }
+
+ /**
+ * return the underlying block cipher that we are wrapping.
+ *
+ * @return the underlying block cipher that we are wrapping.
+ */
+ public virtual IBlockCipher GetUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ public virtual void Init(
+ bool forEncryption, //ignored by this CTR mode
+ ICipherParameters parameters)
+ {
+ ParametersWithIV ivParam = parameters as ParametersWithIV;
+ if (ivParam == null)
+ throw new ArgumentException("CTR/SIC mode requires ParametersWithIV", "parameters");
+
+ this.IV = Arrays.Clone(ivParam.GetIV());
+
+ if (blockSize < IV.Length)
+ throw new ArgumentException("CTR/SIC mode requires IV no greater than: " + blockSize + " bytes.");
+
+ int maxCounterSize = System.Math.Min(8, blockSize / 2);
+ if (blockSize - IV.Length > maxCounterSize)
+ throw new ArgumentException("CTR/SIC mode requires IV of at least: " + (blockSize - maxCounterSize) + " bytes.");
+
+ // if null it's an IV changed only.
+ if (ivParam.Parameters != null)
+ {
+ cipher.Init(true, ivParam.Parameters);
+ }
+
+ Reset();
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return cipher.AlgorithmName + "/SIC"; }
+ }
+
+ public virtual bool IsPartialBlockOkay
+ {
+ get { return true; }
+ }
+
+ public virtual int GetBlockSize()
+ {
+ return cipher.GetBlockSize();
+ }
+
+ public virtual int ProcessBlock(
+ byte[] input,
+ int inOff,
+ byte[] output,
+ int outOff)
+ {
+ 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[outOff + i] = (byte)(counterOut[i] ^ input[inOff + i]);
+ }
+
+ // Increment the counter
+ int j = counter.Length;
+ while (--j >= 0 && ++counter[j] == 0)
+ {
+ }
+
+ return counter.Length;
+ }
+
+ public virtual void Reset()
+ {
+ Arrays.Fill(counter, (byte)0);
+ Array.Copy(IV, 0, counter, 0, IV.Length);
+ cipher.Reset();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/gcm/BasicGcmExponentiator.cs b/bc-sharp-crypto/src/crypto/modes/gcm/BasicGcmExponentiator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5660a1f841f10923eb784e5618a3231bb9e676c3
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/gcm/BasicGcmExponentiator.cs
@@ -0,0 +1,40 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+ public class BasicGcmExponentiator
+ : IGcmExponentiator
+ {
+ private uint[] x;
+
+ public void Init(byte[] x)
+ {
+ this.x = GcmUtilities.AsUints(x);
+ }
+
+ public void ExponentiateX(long pow, byte[] output)
+ {
+ // Initial value is little-endian 1
+ uint[] y = GcmUtilities.OneAsUints();
+
+ if (pow > 0)
+ {
+ uint[] powX = Arrays.Clone(x);
+ do
+ {
+ if ((pow & 1L) != 0)
+ {
+ GcmUtilities.Multiply(y, powX);
+ }
+ GcmUtilities.Multiply(powX, powX);
+ pow >>= 1;
+ }
+ while (pow > 0);
+ }
+
+ GcmUtilities.AsBytes(y, output);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/gcm/BasicGcmMultiplier.cs b/bc-sharp-crypto/src/crypto/modes/gcm/BasicGcmMultiplier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..eb89383fb6fef884029c13ae02ac5c1db1a5cb77
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/gcm/BasicGcmMultiplier.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+ public class BasicGcmMultiplier
+ : IGcmMultiplier
+ {
+ private uint[] H;
+
+ public void Init(byte[] H)
+ {
+ this.H = GcmUtilities.AsUints(H);
+ }
+
+ public void MultiplyH(byte[] x)
+ {
+ uint[] t = GcmUtilities.AsUints(x);
+ GcmUtilities.Multiply(t, H);
+ GcmUtilities.AsBytes(t, x);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/gcm/GcmUtilities.cs b/bc-sharp-crypto/src/crypto/modes/gcm/GcmUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d8ab2ca73a3aa64783397afe64a44f3c65e5137d
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/gcm/GcmUtilities.cs
@@ -0,0 +1,319 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+ internal abstract class GcmUtilities
+ {
+ private const uint E1 = 0xe1000000;
+ private const ulong E1L = (ulong)E1 << 32;
+
+ private static uint[] GenerateLookup()
+ {
+ uint[] lookup = new uint[256];
+
+ for (int c = 0; c < 256; ++c)
+ {
+ uint v = 0;
+ for (int i = 7; i >= 0; --i)
+ {
+ if ((c & (1 << i)) != 0)
+ {
+ v ^= (E1 >> (7 - i));
+ }
+ }
+ lookup[c] = v;
+ }
+
+ return lookup;
+ }
+
+ private static readonly uint[] LOOKUP = GenerateLookup();
+
+ internal static byte[] OneAsBytes()
+ {
+ byte[] tmp = new byte[16];
+ tmp[0] = 0x80;
+ return tmp;
+ }
+
+ internal static uint[] OneAsUints()
+ {
+ uint[] tmp = new uint[4];
+ tmp[0] = 0x80000000;
+ return tmp;
+ }
+
+ internal static ulong[] OneAsUlongs()
+ {
+ ulong[] tmp = new ulong[2];
+ tmp[0] = 1UL << 63;
+ return tmp;
+ }
+
+ internal static byte[] AsBytes(uint[] x)
+ {
+ return Pack.UInt32_To_BE(x);
+ }
+
+ internal static void AsBytes(uint[] x, byte[] z)
+ {
+ Pack.UInt32_To_BE(x, z, 0);
+ }
+
+ internal static byte[] AsBytes(ulong[] x)
+ {
+ byte[] z = new byte[16];
+ Pack.UInt64_To_BE(x, z, 0);
+ return z;
+ }
+
+ internal static void AsBytes(ulong[] x, byte[] z)
+ {
+ Pack.UInt64_To_BE(x, z, 0);
+ }
+
+ internal static uint[] AsUints(byte[] bs)
+ {
+ uint[] output = new uint[4];
+ Pack.BE_To_UInt32(bs, 0, output);
+ return output;
+ }
+
+ internal static void AsUints(byte[] bs, uint[] output)
+ {
+ Pack.BE_To_UInt32(bs, 0, output);
+ }
+
+ internal static ulong[] AsUlongs(byte[] x)
+ {
+ ulong[] z = new ulong[2];
+ Pack.BE_To_UInt64(x, 0, z);
+ return z;
+ }
+
+ public static void AsUlongs(byte[] x, ulong[] z)
+ {
+ Pack.BE_To_UInt64(x, 0, z);
+ }
+
+ internal static void Multiply(byte[] x, byte[] y)
+ {
+ uint[] t1 = GcmUtilities.AsUints(x);
+ uint[] t2 = GcmUtilities.AsUints(y);
+ GcmUtilities.Multiply(t1, t2);
+ GcmUtilities.AsBytes(t1, x);
+ }
+
+ internal static void Multiply(uint[] x, uint[] y)
+ {
+ uint r00 = x[0], r01 = x[1], r02 = x[2], r03 = x[3];
+ uint r10 = 0, r11 = 0, r12 = 0, r13 = 0;
+
+ for (int i = 0; i < 4; ++i)
+ {
+ int bits = (int)y[i];
+ for (int j = 0; j < 32; ++j)
+ {
+ uint m1 = (uint)(bits >> 31); bits <<= 1;
+ r10 ^= (r00 & m1);
+ r11 ^= (r01 & m1);
+ r12 ^= (r02 & m1);
+ r13 ^= (r03 & m1);
+
+ uint m2 = (uint)((int)(r03 << 31) >> 8);
+ r03 = (r03 >> 1) | (r02 << 31);
+ r02 = (r02 >> 1) | (r01 << 31);
+ r01 = (r01 >> 1) | (r00 << 31);
+ r00 = (r00 >> 1) ^ (m2 & E1);
+ }
+ }
+
+ x[0] = r10;
+ x[1] = r11;
+ x[2] = r12;
+ x[3] = r13;
+ }
+
+ internal static void Multiply(ulong[] x, ulong[] y)
+ {
+ ulong r00 = x[0], r01 = x[1], r10 = 0, r11 = 0;
+
+ for (int i = 0; i < 2; ++i)
+ {
+ long bits = (long)y[i];
+ for (int j = 0; j < 64; ++j)
+ {
+ ulong m1 = (ulong)(bits >> 63); bits <<= 1;
+ r10 ^= (r00 & m1);
+ r11 ^= (r01 & m1);
+
+ ulong m2 = (ulong)((long)(r01 << 63) >> 8);
+ r01 = (r01 >> 1) | (r00 << 63);
+ r00 = (r00 >> 1) ^ (m2 & E1L);
+ }
+ }
+
+ x[0] = r10;
+ x[1] = r11;
+ }
+
+ // P is the value with only bit i=1 set
+ internal static void MultiplyP(uint[] x)
+ {
+ uint m = (uint)((int)ShiftRight(x) >> 8);
+ x[0] ^= (m & E1);
+ }
+
+ internal static void MultiplyP(uint[] x, uint[] z)
+ {
+ uint m = (uint)((int)ShiftRight(x, z) >> 8);
+ z[0] ^= (m & E1);
+ }
+
+ internal static void MultiplyP8(uint[] x)
+ {
+// for (int i = 8; i != 0; --i)
+// {
+// MultiplyP(x);
+// }
+
+ uint c = ShiftRightN(x, 8);
+ x[0] ^= LOOKUP[c >> 24];
+ }
+
+ internal static void MultiplyP8(uint[] x, uint[] y)
+ {
+ uint c = ShiftRightN(x, 8, y);
+ y[0] ^= LOOKUP[c >> 24];
+ }
+
+ internal static uint ShiftRight(uint[] x)
+ {
+ uint b = x[0];
+ x[0] = b >> 1;
+ uint c = b << 31;
+ b = x[1];
+ x[1] = (b >> 1) | c;
+ c = b << 31;
+ b = x[2];
+ x[2] = (b >> 1) | c;
+ c = b << 31;
+ b = x[3];
+ x[3] = (b >> 1) | c;
+ return b << 31;
+ }
+
+ internal static uint ShiftRight(uint[] x, uint[] z)
+ {
+ uint b = x[0];
+ z[0] = b >> 1;
+ uint c = b << 31;
+ b = x[1];
+ z[1] = (b >> 1) | c;
+ c = b << 31;
+ b = x[2];
+ z[2] = (b >> 1) | c;
+ c = b << 31;
+ b = x[3];
+ z[3] = (b >> 1) | c;
+ return b << 31;
+ }
+
+ internal static uint ShiftRightN(uint[] x, int n)
+ {
+ uint b = x[0]; int nInv = 32 - n;
+ x[0] = b >> n;
+ uint c = b << nInv;
+ b = x[1];
+ x[1] = (b >> n) | c;
+ c = b << nInv;
+ b = x[2];
+ x[2] = (b >> n) | c;
+ c = b << nInv;
+ b = x[3];
+ x[3] = (b >> n) | c;
+ return b << nInv;
+ }
+
+ internal static uint ShiftRightN(uint[] x, int n, uint[] z)
+ {
+ uint b = x[0]; int nInv = 32 - n;
+ z[0] = b >> n;
+ uint c = b << nInv;
+ b = x[1];
+ z[1] = (b >> n) | c;
+ c = b << nInv;
+ b = x[2];
+ z[2] = (b >> n) | c;
+ c = b << nInv;
+ b = x[3];
+ z[3] = (b >> n) | c;
+ return b << nInv;
+ }
+
+ internal static void Xor(byte[] x, byte[] y)
+ {
+ int i = 0;
+ do
+ {
+ x[i] ^= y[i]; ++i;
+ x[i] ^= y[i]; ++i;
+ x[i] ^= y[i]; ++i;
+ x[i] ^= y[i]; ++i;
+ }
+ while (i < 16);
+ }
+
+ internal static void Xor(byte[] x, byte[] y, int yOff, int yLen)
+ {
+ while (--yLen >= 0)
+ {
+ x[yLen] ^= y[yOff + yLen];
+ }
+ }
+
+ internal static void Xor(byte[] x, byte[] y, byte[] z)
+ {
+ int i = 0;
+ do
+ {
+ z[i] = (byte)(x[i] ^ y[i]); ++i;
+ z[i] = (byte)(x[i] ^ y[i]); ++i;
+ z[i] = (byte)(x[i] ^ y[i]); ++i;
+ z[i] = (byte)(x[i] ^ y[i]); ++i;
+ }
+ while (i < 16);
+ }
+
+ internal static void Xor(uint[] x, uint[] y)
+ {
+ x[0] ^= y[0];
+ x[1] ^= y[1];
+ x[2] ^= y[2];
+ x[3] ^= y[3];
+ }
+
+ internal static void Xor(uint[] x, uint[] y, uint[] z)
+ {
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
+ z[2] = x[2] ^ y[2];
+ z[3] = x[3] ^ y[3];
+ }
+
+ internal static void Xor(ulong[] x, ulong[] y)
+ {
+ x[0] ^= y[0];
+ x[1] ^= y[1];
+ }
+
+ internal static void Xor(ulong[] x, ulong[] y, ulong[] z)
+ {
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/gcm/IGcmExponentiator.cs b/bc-sharp-crypto/src/crypto/modes/gcm/IGcmExponentiator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5b4ce9d7a38aaf78d481374e32157750f7fa8bbf
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/gcm/IGcmExponentiator.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+ public interface IGcmExponentiator
+ {
+ void Init(byte[] x);
+ void ExponentiateX(long pow, byte[] output);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/gcm/IGcmMultiplier.cs b/bc-sharp-crypto/src/crypto/modes/gcm/IGcmMultiplier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ec7b906ee9ea131587e85f6228d27dfa2618017f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/gcm/IGcmMultiplier.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+ public interface IGcmMultiplier
+ {
+ void Init(byte[] H);
+ void MultiplyH(byte[] x);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/gcm/Tables1kGcmExponentiator.cs b/bc-sharp-crypto/src/crypto/modes/gcm/Tables1kGcmExponentiator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e649d6770c8e93c16ecbeafe3b3b86e8ca8e83d7
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/gcm/Tables1kGcmExponentiator.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+ public class Tables1kGcmExponentiator
+ : IGcmExponentiator
+ {
+ // A lookup table of the power-of-two powers of 'x'
+ // - lookupPowX2[i] = x^(2^i)
+ private IList lookupPowX2;
+
+ public void Init(byte[] x)
+ {
+ uint[] y = GcmUtilities.AsUints(x);
+ if (lookupPowX2 != null && Arrays.AreEqual(y, (uint[])lookupPowX2[0]))
+ return;
+
+ lookupPowX2 = Platform.CreateArrayList(8);
+ lookupPowX2.Add(y);
+ }
+
+ public void ExponentiateX(long pow, byte[] output)
+ {
+ uint[] y = GcmUtilities.OneAsUints();
+ int bit = 0;
+ while (pow > 0)
+ {
+ if ((pow & 1L) != 0)
+ {
+ EnsureAvailable(bit);
+ GcmUtilities.Multiply(y, (uint[])lookupPowX2[bit]);
+ }
+ ++bit;
+ pow >>= 1;
+ }
+
+ GcmUtilities.AsBytes(y, output);
+ }
+
+ private void EnsureAvailable(int bit)
+ {
+ int count = lookupPowX2.Count;
+ if (count <= bit)
+ {
+ uint[] tmp = (uint[])lookupPowX2[count - 1];
+ do
+ {
+ tmp = Arrays.Clone(tmp);
+ GcmUtilities.Multiply(tmp, tmp);
+ lookupPowX2.Add(tmp);
+ }
+ while (++count <= bit);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/gcm/Tables64kGcmMultiplier.cs b/bc-sharp-crypto/src/crypto/modes/gcm/Tables64kGcmMultiplier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..707b0be2e8651bc8e8f3b4526f858b8d6e71d87c
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/gcm/Tables64kGcmMultiplier.cs
@@ -0,0 +1,77 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+ public class Tables64kGcmMultiplier
+ : IGcmMultiplier
+ {
+ private byte[] H;
+ private uint[][][] M;
+
+ public void Init(byte[] H)
+ {
+ if (M == null)
+ {
+ M = new uint[16][][];
+ }
+ else if (Arrays.AreEqual(this.H, H))
+ {
+ return;
+ }
+
+ this.H = Arrays.Clone(H);
+
+ M[0] = new uint[256][];
+ M[0][0] = new uint[4];
+ M[0][128] = GcmUtilities.AsUints(H);
+ for (int j = 64; j >= 1; j >>= 1)
+ {
+ uint[] tmp = (uint[])M[0][j + j].Clone();
+ GcmUtilities.MultiplyP(tmp);
+ M[0][j] = tmp;
+ }
+ for (int i = 0; ; )
+ {
+ for (int j = 2; j < 256; j += j)
+ {
+ for (int k = 1; k < j; ++k)
+ {
+ uint[] tmp = (uint[])M[i][j].Clone();
+ GcmUtilities.Xor(tmp, M[i][k]);
+ M[i][j + k] = tmp;
+ }
+ }
+
+ if (++i == 16) return;
+
+ M[i] = new uint[256][];
+ M[i][0] = new uint[4];
+ for (int j = 128; j > 0; j >>= 1)
+ {
+ uint[] tmp = (uint[])M[i - 1][j].Clone();
+ GcmUtilities.MultiplyP8(tmp);
+ M[i][j] = tmp;
+ }
+ }
+ }
+
+ public void MultiplyH(byte[] x)
+ {
+ uint[] z = new uint[4];
+ for (int i = 0; i != 16; ++i)
+ {
+ //GcmUtilities.Xor(z, M[i][x[i]]);
+ uint[] m = M[i][x[i]];
+ z[0] ^= m[0];
+ z[1] ^= m[1];
+ z[2] ^= m[2];
+ z[3] ^= m[3];
+ }
+
+ Pack.UInt32_To_BE(z, x, 0);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/modes/gcm/Tables8kGcmMultiplier.cs b/bc-sharp-crypto/src/crypto/modes/gcm/Tables8kGcmMultiplier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5f3d6c86ceb93632863ff871fe057708befbcbd7
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/modes/gcm/Tables8kGcmMultiplier.cs
@@ -0,0 +1,103 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+ public class Tables8kGcmMultiplier
+ : IGcmMultiplier
+ {
+ private byte[] H;
+ private uint[][][] M;
+
+ public void Init(byte[] H)
+ {
+ if (M == null)
+ {
+ M = new uint[32][][];
+ }
+ else if (Arrays.AreEqual(this.H, H))
+ {
+ return;
+ }
+
+ this.H = Arrays.Clone(H);
+
+ M[0] = new uint[16][];
+ M[1] = new uint[16][];
+ M[0][0] = new uint[4];
+ M[1][0] = new uint[4];
+ M[1][8] = GcmUtilities.AsUints(H);
+
+ for (int j = 4; j >= 1; j >>= 1)
+ {
+ uint[] tmp = (uint[])M[1][j + j].Clone();
+ GcmUtilities.MultiplyP(tmp);
+ M[1][j] = tmp;
+ }
+
+ {
+ uint[] tmp = (uint[])M[1][1].Clone();
+ GcmUtilities.MultiplyP(tmp);
+ M[0][8] = tmp;
+ }
+
+ for (int j = 4; j >= 1; j >>= 1)
+ {
+ uint[] tmp = (uint[])M[0][j + j].Clone();
+ GcmUtilities.MultiplyP(tmp);
+ M[0][j] = tmp;
+ }
+
+ for (int i = 0; ; )
+ {
+ for (int j = 2; j < 16; j += j)
+ {
+ for (int k = 1; k < j; ++k)
+ {
+ uint[] tmp = (uint[])M[i][j].Clone();
+ GcmUtilities.Xor(tmp, M[i][k]);
+ M[i][j + k] = tmp;
+ }
+ }
+
+ if (++i == 32) return;
+
+ if (i > 1)
+ {
+ M[i] = new uint[16][];
+ M[i][0] = new uint[4];
+ for (int j = 8; j > 0; j >>= 1)
+ {
+ uint[] tmp = (uint[])M[i - 2][j].Clone();
+ GcmUtilities.MultiplyP8(tmp);
+ M[i][j] = tmp;
+ }
+ }
+ }
+ }
+
+ public void MultiplyH(byte[] x)
+ {
+ uint[] z = new uint[4];
+ for (int i = 15; i >= 0; --i)
+ {
+ //GcmUtilities.Xor(z, M[i + i][x[i] & 0x0f]);
+ uint[] m = M[i + i][x[i] & 0x0f];
+ z[0] ^= m[0];
+ z[1] ^= m[1];
+ z[2] ^= m[2];
+ z[3] ^= m[3];
+ //GcmUtilities.Xor(z, M[i + i + 1][(x[i] & 0xf0) >> 4]);
+ m = M[i + i + 1][(x[i] & 0xf0) >> 4];
+ z[0] ^= m[0];
+ z[1] ^= m[1];
+ z[2] ^= m[2];
+ z[3] ^= m[3];
+ }
+
+ Pack.UInt32_To_BE(z, x, 0);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/operators/Asn1Signature.cs b/bc-sharp-crypto/src/crypto/operators/Asn1Signature.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e023c1d1816c2719709663638216a6d7e622f363
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/operators/Asn1Signature.cs
@@ -0,0 +1,555 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Crypto.Operators
+{
+ internal class X509Utilities
+ {
+ private static readonly Asn1Null derNull = DerNull.Instance;
+
+ private static readonly IDictionary algorithms = Platform.CreateHashtable();
+ private static readonly IDictionary exParams = Platform.CreateHashtable();
+ private static readonly ISet noParams = new HashSet();
+
+ static X509Utilities()
+ {
+ algorithms.Add("MD2WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+ algorithms.Add("MD2WITHRSA", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+ algorithms.Add("MD5WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+ algorithms.Add("MD5WITHRSA", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSA", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+ algorithms.Add("SHA224WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+ algorithms.Add("SHA224WITHRSA", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+ algorithms.Add("SHA256WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+ algorithms.Add("SHA256WITHRSA", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+ algorithms.Add("SHA384WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+ algorithms.Add("SHA384WITHRSA", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+ algorithms.Add("SHA512WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+ algorithms.Add("SHA512WITHRSA", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA224WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA256WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA384WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA512WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+ algorithms.Add("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+ algorithms.Add("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+ algorithms.Add("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+ algorithms.Add("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+ algorithms.Add("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+ algorithms.Add("SHA1WITHDSA", X9ObjectIdentifiers.IdDsaWithSha1);
+ algorithms.Add("DSAWITHSHA1", X9ObjectIdentifiers.IdDsaWithSha1);
+ algorithms.Add("SHA224WITHDSA", NistObjectIdentifiers.DsaWithSha224);
+ algorithms.Add("SHA256WITHDSA", NistObjectIdentifiers.DsaWithSha256);
+ algorithms.Add("SHA384WITHDSA", NistObjectIdentifiers.DsaWithSha384);
+ algorithms.Add("SHA512WITHDSA", NistObjectIdentifiers.DsaWithSha512);
+ algorithms.Add("SHA1WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha1);
+ algorithms.Add("ECDSAWITHSHA1", X9ObjectIdentifiers.ECDsaWithSha1);
+ algorithms.Add("SHA224WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha224);
+ algorithms.Add("SHA256WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha256);
+ algorithms.Add("SHA384WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha384);
+ algorithms.Add("SHA512WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha512);
+ algorithms.Add("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ algorithms.Add("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ algorithms.Add("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+ algorithms.Add("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+ algorithms.Add("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha1);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha224);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha256);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha384);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha512);
+ noParams.Add(X9ObjectIdentifiers.IdDsaWithSha1);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha224);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha256);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha384);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha512);
+
+ //
+ // RFC 4491
+ //
+ noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+ //
+ // explicit params
+ //
+ AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+ exParams.Add("SHA1WITHRSAANDMGF1", CreatePssParams(sha1AlgId, 20));
+
+ AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha224, DerNull.Instance);
+ exParams.Add("SHA224WITHRSAANDMGF1", CreatePssParams(sha224AlgId, 28));
+
+ AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha256, DerNull.Instance);
+ exParams.Add("SHA256WITHRSAANDMGF1", CreatePssParams(sha256AlgId, 32));
+
+ AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha384, DerNull.Instance);
+ exParams.Add("SHA384WITHRSAANDMGF1", CreatePssParams(sha384AlgId, 48));
+
+ AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha512, DerNull.Instance);
+ exParams.Add("SHA512WITHRSAANDMGF1", CreatePssParams(sha512AlgId, 64));
+ }
+
+ /**
+ * Return the digest algorithm using one of the standard JCA string
+ * representations rather than the algorithm identifier (if possible).
+ */
+ private static string GetDigestAlgName(
+ DerObjectIdentifier digestAlgOID)
+ {
+ if (PkcsObjectIdentifiers.MD5.Equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OiwObjectIdentifiers.IdSha1.Equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ else if (NistObjectIdentifiers.IdSha224.Equals(digestAlgOID))
+ {
+ return "SHA224";
+ }
+ else if (NistObjectIdentifiers.IdSha256.Equals(digestAlgOID))
+ {
+ return "SHA256";
+ }
+ else if (NistObjectIdentifiers.IdSha384.Equals(digestAlgOID))
+ {
+ return "SHA384";
+ }
+ else if (NistObjectIdentifiers.IdSha512.Equals(digestAlgOID))
+ {
+ return "SHA512";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD128.Equals(digestAlgOID))
+ {
+ return "RIPEMD128";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD160.Equals(digestAlgOID))
+ {
+ return "RIPEMD160";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD256.Equals(digestAlgOID))
+ {
+ return "RIPEMD256";
+ }
+ else if (CryptoProObjectIdentifiers.GostR3411.Equals(digestAlgOID))
+ {
+ return "GOST3411";
+ }
+ else
+ {
+ return digestAlgOID.Id;
+ }
+ }
+
+ internal static string GetSignatureName(AlgorithmIdentifier sigAlgId)
+ {
+ Asn1Encodable parameters = sigAlgId.Parameters;
+
+ if (parameters != null && !derNull.Equals(parameters))
+ {
+ if (sigAlgId.Algorithm.Equals(PkcsObjectIdentifiers.IdRsassaPss))
+ {
+ RsassaPssParameters rsaParams = RsassaPssParameters.GetInstance(parameters);
+
+ return GetDigestAlgName(rsaParams.HashAlgorithm.Algorithm) + "withRSAandMGF1";
+ }
+ if (sigAlgId.Algorithm.Equals(X9ObjectIdentifiers.ECDsaWithSha2))
+ {
+ Asn1Sequence ecDsaParams = Asn1Sequence.GetInstance(parameters);
+
+ return GetDigestAlgName((DerObjectIdentifier)ecDsaParams[0]) + "withECDSA";
+ }
+ }
+
+ return sigAlgId.Algorithm.Id;
+ }
+
+ private static RsassaPssParameters CreatePssParams(
+ AlgorithmIdentifier hashAlgId,
+ int saltSize)
+ {
+ return new RsassaPssParameters(
+ hashAlgId,
+ new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, hashAlgId),
+ new DerInteger(saltSize),
+ new DerInteger(1));
+ }
+
+ internal static DerObjectIdentifier GetAlgorithmOid(
+ string algorithmName)
+ {
+ algorithmName = Platform.ToUpperInvariant(algorithmName);
+
+ if (algorithms.Contains(algorithmName))
+ {
+ return (DerObjectIdentifier) algorithms[algorithmName];
+ }
+
+ return new DerObjectIdentifier(algorithmName);
+ }
+
+ internal static AlgorithmIdentifier GetSigAlgID(
+ DerObjectIdentifier sigOid,
+ string algorithmName)
+ {
+ if (noParams.Contains(sigOid))
+ {
+ return new AlgorithmIdentifier(sigOid);
+ }
+
+ algorithmName = Platform.ToUpperInvariant(algorithmName);
+
+ if (exParams.Contains(algorithmName))
+ {
+ return new AlgorithmIdentifier(sigOid, (Asn1Encodable) exParams[algorithmName]);
+ }
+
+ return new AlgorithmIdentifier(sigOid, DerNull.Instance);
+ }
+
+ internal static IEnumerable GetAlgNames()
+ {
+ return new EnumerableProxy(algorithms.Keys);
+ }
+ }
+
+ internal class SignerBucket
+ : Stream
+ {
+ protected readonly ISigner signer;
+
+ public SignerBucket(
+ ISigner signer)
+ {
+ this.signer = signer;
+ }
+
+ public override int Read(
+ byte[] buffer,
+ int offset,
+ int count)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override int ReadByte()
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override void Write(
+ byte[] buffer,
+ int offset,
+ int count)
+ {
+ if (count > 0)
+ {
+ signer.BlockUpdate(buffer, offset, count);
+ }
+ }
+
+ public override void WriteByte(
+ byte b)
+ {
+ signer.Update(b);
+ }
+
+ public override bool CanRead
+ {
+ get { return false; }
+ }
+
+ public override bool CanWrite
+ {
+ get { return true; }
+ }
+
+ public override bool CanSeek
+ {
+ get { return false; }
+ }
+
+ public override long Length
+ {
+ get { return 0; }
+ }
+
+ public override long Position
+ {
+ get { throw new NotImplementedException (); }
+ set { throw new NotImplementedException (); }
+ }
+
+ public override void Flush()
+ {
+ }
+
+ public override long Seek(
+ long offset,
+ SeekOrigin origin)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public override void SetLength(
+ long length)
+ {
+ throw new NotImplementedException ();
+ }
+ }
+
+ ///
+ /// Calculator factory class for signature generation in ASN.1 based profiles that use an AlgorithmIdentifier to preserve
+ /// signature algorithm details.
+ ///
+ public class Asn1SignatureFactory: ISignatureFactory
+ {
+ private readonly AlgorithmIdentifier algID;
+ private readonly string algorithm;
+ private readonly AsymmetricKeyParameter privateKey;
+ private readonly SecureRandom random;
+
+ ///
+ /// Base constructor.
+ ///
+ /// The name of the signature algorithm to use.
+ /// The private key to be used in the signing operation.
+ public Asn1SignatureFactory (string algorithm, AsymmetricKeyParameter privateKey): this(algorithm, privateKey, null)
+ {
+ }
+
+ ///
+ /// Constructor which also specifies a source of randomness to be used if one is required.
+ ///
+ /// The name of the signature algorithm to use.
+ /// The private key to be used in the signing operation.
+ /// The source of randomness to be used in signature calculation.
+ public Asn1SignatureFactory (string algorithm, AsymmetricKeyParameter privateKey, SecureRandom random)
+ {
+ DerObjectIdentifier sigOid = X509Utilities.GetAlgorithmOid (algorithm);
+
+ this.algorithm = algorithm;
+ this.privateKey = privateKey;
+ this.random = random;
+ this.algID = X509Utilities.GetSigAlgID (sigOid, algorithm);
+ }
+
+ public Object AlgorithmDetails
+ {
+ get { return this.algID; }
+ }
+
+ public IStreamCalculator CreateCalculator()
+ {
+ ISigner sig = SignerUtilities.GetSigner(algorithm);
+
+ if (random != null)
+ {
+ sig.Init(true, new ParametersWithRandom(privateKey, random));
+ }
+ else
+ {
+ sig.Init(true, privateKey);
+ }
+
+ return new SigCalculator(sig);
+ }
+
+ ///
+ /// Allows enumeration of the signature names supported by the verifier provider.
+ ///
+ public static IEnumerable SignatureAlgNames
+ {
+ get { return X509Utilities.GetAlgNames(); }
+ }
+ }
+
+ internal class SigCalculator : IStreamCalculator
+ {
+ private readonly ISigner sig;
+ private readonly Stream stream;
+
+ internal SigCalculator(ISigner sig)
+ {
+ this.sig = sig;
+ this.stream = new SignerBucket(sig);
+ }
+
+ public Stream Stream
+ {
+ get { return stream; }
+ }
+
+ public object GetResult()
+ {
+ return new SigResult(sig);
+ }
+ }
+
+ internal class SigResult : IBlockResult
+ {
+ private readonly ISigner sig;
+
+ internal SigResult(ISigner sig)
+ {
+ this.sig = sig;
+ }
+
+ public byte[] Collect()
+ {
+ return sig.GenerateSignature();
+ }
+
+ public int Collect(byte[] destination, int offset)
+ {
+ byte[] signature = Collect();
+
+ Array.Copy(signature, 0, destination, offset, signature.Length);
+
+ return signature.Length;
+ }
+ }
+
+ ///
+ /// Verifier class for signature verification in ASN.1 based profiles that use an AlgorithmIdentifier to preserve
+ /// signature algorithm details.
+ ///
+ public class Asn1VerifierFactory: IVerifierFactory
+ {
+ private readonly AlgorithmIdentifier algID;
+ private readonly AsymmetricKeyParameter publicKey;
+
+ ///
+ /// Base constructor.
+ ///
+ /// The name of the signature algorithm to use.
+ /// The public key to be used in the verification operation.
+ public Asn1VerifierFactory (String algorithm, AsymmetricKeyParameter publicKey)
+ {
+ DerObjectIdentifier sigOid = X509Utilities.GetAlgorithmOid (algorithm);
+
+ this.publicKey = publicKey;
+ this.algID = X509Utilities.GetSigAlgID (sigOid, algorithm);
+ }
+
+ public Asn1VerifierFactory (AlgorithmIdentifier algorithm, AsymmetricKeyParameter publicKey)
+ {
+ this.publicKey = publicKey;
+ this.algID = algorithm;
+ }
+
+ public Object AlgorithmDetails
+ {
+ get { return this.algID; }
+ }
+
+ public IStreamCalculator CreateCalculator()
+ {
+ ISigner sig = SignerUtilities.GetSigner(X509Utilities.GetSignatureName(algID));
+
+ sig.Init(false, publicKey);
+
+ return new VerifierCalculator(sig);
+ }
+ }
+
+ internal class VerifierCalculator : IStreamCalculator
+ {
+ private readonly ISigner sig;
+ private readonly Stream stream;
+
+ internal VerifierCalculator(ISigner sig)
+ {
+ this.sig = sig;
+ this.stream = new SignerBucket(sig);
+ }
+
+ public Stream Stream
+ {
+ get { return stream; }
+ }
+
+ public object GetResult()
+ {
+ return new VerifierResult(sig);
+ }
+ }
+
+ internal class VerifierResult : IVerifier
+ {
+ private readonly ISigner sig;
+
+ internal VerifierResult(ISigner sig)
+ {
+ this.sig = sig;
+ }
+
+ public bool IsVerified(byte[] signature)
+ {
+ return sig.VerifySignature(signature);
+ }
+
+ public bool IsVerified(byte[] signature, int off, int length)
+ {
+ byte[] sigBytes = new byte[length];
+
+ Array.Copy(signature, 0, sigBytes, off, sigBytes.Length);
+
+ return sig.VerifySignature(signature);
+ }
+ }
+
+ ///
+ /// Provider class which supports dynamic creation of signature verifiers.
+ ///
+ public class Asn1VerifierFactoryProvider: IVerifierFactoryProvider
+ {
+ private readonly AsymmetricKeyParameter publicKey;
+
+ ///
+ /// Base constructor - specify the public key to be used in verification.
+ ///
+ /// The public key to be used in creating verifiers provided by this object.
+ public Asn1VerifierFactoryProvider(AsymmetricKeyParameter publicKey)
+ {
+ this.publicKey = publicKey;
+ }
+
+ public IVerifierFactory CreateVerifierFactory(Object algorithmDetails)
+ {
+ return new Asn1VerifierFactory ((AlgorithmIdentifier)algorithmDetails, publicKey);
+ }
+
+ ///
+ /// Allows enumeration of the signature names supported by the verifier provider.
+ ///
+ public IEnumerable SignatureAlgNames
+ {
+ get { return X509Utilities.GetAlgNames(); }
+ }
+ }
+}
+
diff --git a/bc-sharp-crypto/src/crypto/paddings/BlockCipherPadding.cs b/bc-sharp-crypto/src/crypto/paddings/BlockCipherPadding.cs
new file mode 100644
index 0000000000000000000000000000000000000000..33a5f9f0f11ee2019bbf9fdb81d952d9f6f1867b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/paddings/BlockCipherPadding.cs
@@ -0,0 +1,43 @@
+using System;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+ /**
+ * Block cipher padders are expected to conform to this interface
+ */
+ public interface IBlockCipherPadding
+ {
+ /**
+ * Initialise the padder.
+ *
+ * @param param parameters, if any required.
+ */
+ void Init(SecureRandom random);
+ //throws ArgumentException;
+
+ /**
+ * Return the name of the algorithm the cipher implements.
+ *
+ * @return the name of the algorithm the cipher implements.
+ */
+ string PaddingName { get; }
+
+ /**
+ * add the pad bytes to the passed in block, returning the
+ * number of bytes added.
+ */
+ int AddPadding(byte[] input, int inOff);
+
+ /**
+ * return the number of pad bytes present in the block.
+ * @exception InvalidCipherTextException if the padding is badly formed
+ * or invalid.
+ */
+ int PadCount(byte[] input);
+ //throws InvalidCipherTextException;
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/paddings/ISO10126d2Padding.cs b/bc-sharp-crypto/src/crypto/paddings/ISO10126d2Padding.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e132a62dd06525b7e6e788b0f2c6e7f64c1a255e
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/paddings/ISO10126d2Padding.cs
@@ -0,0 +1,76 @@
+using System;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+
+ /**
+ * A padder that adds ISO10126-2 padding to a block.
+ */
+ public class ISO10126d2Padding: IBlockCipherPadding
+ {
+ private SecureRandom random;
+
+ /**
+ * Initialise the padder.
+ *
+ * @param random a SecureRandom if available.
+ */
+ public void Init(
+ SecureRandom random)
+ //throws ArgumentException
+ {
+ this.random = (random != null) ? random : new SecureRandom();
+ }
+
+ /**
+ * Return the name of the algorithm the cipher implements.
+ *
+ * @return the name of the algorithm the cipher implements.
+ */
+ public string PaddingName
+ {
+ get { return "ISO10126-2"; }
+ }
+
+ /**
+ * add the pad bytes to the passed in block, returning the
+ * number of bytes added.
+ */
+ public int AddPadding(
+ byte[] input,
+ int inOff)
+ {
+ byte code = (byte)(input.Length - inOff);
+
+ while (inOff < (input.Length - 1))
+ {
+ input[inOff] = (byte)random.NextInt();
+ inOff++;
+ }
+
+ input[inOff] = code;
+
+ return code;
+ }
+
+ /**
+ * return the number of pad bytes present in the block.
+ */
+ public int PadCount(byte[] input)
+ //throws InvalidCipherTextException
+ {
+ int count = input[input.Length - 1] & 0xff;
+
+ if (count > input.Length)
+ {
+ throw new InvalidCipherTextException("pad block corrupted");
+ }
+
+ return count;
+ }
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/paddings/ISO7816d4Padding.cs b/bc-sharp-crypto/src/crypto/paddings/ISO7816d4Padding.cs
new file mode 100644
index 0000000000000000000000000000000000000000..016b25a819ba82c9a88aff3dc703c40dab3f0065
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/paddings/ISO7816d4Padding.cs
@@ -0,0 +1,79 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+ /**
+ * A padder that adds the padding according to the scheme referenced in
+ * ISO 7814-4 - scheme 2 from ISO 9797-1. The first byte is 0x80, rest is 0x00
+ */
+ public class ISO7816d4Padding
+ : IBlockCipherPadding
+ {
+ /**
+ * Initialise the padder.
+ *
+ * @param random - a SecureRandom if available.
+ */
+ public void Init(
+ SecureRandom random)
+ {
+ // nothing to do.
+ }
+
+ /**
+ * Return the name of the algorithm the padder implements.
+ *
+ * @return the name of the algorithm the padder implements.
+ */
+ public string PaddingName
+ {
+ get { return "ISO7816-4"; }
+ }
+
+ /**
+ * add the pad bytes to the passed in block, returning the
+ * number of bytes added.
+ */
+ public int AddPadding(
+ byte[] input,
+ int inOff)
+ {
+ int added = (input.Length - inOff);
+
+ input[inOff]= (byte) 0x80;
+ inOff ++;
+
+ while (inOff < input.Length)
+ {
+ input[inOff] = (byte) 0;
+ inOff++;
+ }
+
+ return added;
+ }
+
+ /**
+ * return the number of pad bytes present in the block.
+ */
+ public int PadCount(
+ byte[] input)
+ {
+ int count = input.Length - 1;
+
+ while (count > 0 && input[count] == 0)
+ {
+ count--;
+ }
+
+ if (input[count] != (byte)0x80)
+ {
+ throw new InvalidCipherTextException("pad block corrupted");
+ }
+
+ return input.Length - count;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs b/bc-sharp-crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5d2f8cf151075f8f54aed7d602974973da65c4f1
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs
@@ -0,0 +1,285 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+ /**
+ * A wrapper class that allows block ciphers to be used to process data in
+ * a piecemeal fashion with padding. The PaddedBufferedBlockCipher
+ * outputs a block only when the buffer is full and more data is being added,
+ * or on a doFinal (unless the current block in the buffer is a pad block).
+ * The default padding mechanism used is the one outlined in Pkcs5/Pkcs7.
+ */
+ public class PaddedBufferedBlockCipher
+ : BufferedBlockCipher
+ {
+ private readonly IBlockCipherPadding padding;
+
+ /**
+ * Create a buffered block cipher with the desired padding.
+ *
+ * @param cipher the underlying block cipher this buffering object wraps.
+ * @param padding the padding type.
+ */
+ public PaddedBufferedBlockCipher(
+ IBlockCipher cipher,
+ IBlockCipherPadding padding)
+ {
+ this.cipher = cipher;
+ this.padding = padding;
+
+ buf = new byte[cipher.GetBlockSize()];
+ bufOff = 0;
+ }
+
+ /**
+ * Create a buffered block cipher Pkcs7 padding
+ *
+ * @param cipher the underlying block cipher this buffering object wraps.
+ */
+ public PaddedBufferedBlockCipher(
+ IBlockCipher cipher)
+ : this(cipher, new Pkcs7Padding()) { }
+
+ /**
+ * initialise the cipher.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param param the key and other data required by the cipher.
+ * @exception ArgumentException if the parameters argument is
+ * inappropriate.
+ */
+ public override void Init(
+ bool forEncryption,
+ ICipherParameters parameters)
+ {
+ this.forEncryption = forEncryption;
+
+ SecureRandom initRandom = null;
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom p = (ParametersWithRandom)parameters;
+ initRandom = p.Random;
+ parameters = p.Parameters;
+ }
+
+ Reset();
+ padding.Init(initRandom);
+ cipher.Init(forEncryption, parameters);
+ }
+
+ /**
+ * return the minimum size of the output buffer required for an update
+ * plus a doFinal with an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update and doFinal
+ * with len bytes of input.
+ */
+ public override int GetOutputSize(
+ int length)
+ {
+ int total = length + bufOff;
+ int leftOver = total % buf.Length;
+
+ if (leftOver == 0)
+ {
+ if (forEncryption)
+ {
+ return total + buf.Length;
+ }
+
+ return total;
+ }
+
+ return total - leftOver + buf.Length;
+ }
+
+ /**
+ * return the size of the output buffer required for an update
+ * an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update
+ * with len bytes of input.
+ */
+ public override int GetUpdateOutputSize(
+ int length)
+ {
+ int total = length + bufOff;
+ int leftOver = total % buf.Length;
+
+ if (leftOver == 0)
+ {
+ return total - buf.Length;
+ }
+
+ return total - leftOver;
+ }
+
+ /**
+ * process a single byte, producing an output block if necessary.
+ *
+ * @param in the input byte.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ */
+ public override int ProcessByte(
+ byte input,
+ byte[] output,
+ int outOff)
+ {
+ int resultLen = 0;
+
+ if (bufOff == buf.Length)
+ {
+ resultLen = cipher.ProcessBlock(buf, 0, output, outOff);
+ bufOff = 0;
+ }
+
+ buf[bufOff++] = input;
+
+ return resultLen;
+ }
+
+ /**
+ * process an array of bytes, producing output if necessary.
+ *
+ * @param in the input byte array.
+ * @param inOff the offset at which the input data starts.
+ * @param len the number of bytes to be copied out of the input array.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception InvalidOperationException if the cipher isn't initialised.
+ */
+ public override int ProcessBytes(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] output,
+ int outOff)
+ {
+ if (length < 0)
+ {
+ throw new ArgumentException("Can't have a negative input length!");
+ }
+
+ int blockSize = GetBlockSize();
+ int outLength = GetUpdateOutputSize(length);
+
+ if (outLength > 0)
+ {
+ Check.OutputLength(output, outOff, outLength, "output buffer too short");
+ }
+
+ int resultLen = 0;
+ int gapLen = buf.Length - bufOff;
+
+ if (length > gapLen)
+ {
+ Array.Copy(input, inOff, buf, bufOff, gapLen);
+
+ resultLen += cipher.ProcessBlock(buf, 0, output, outOff);
+
+ bufOff = 0;
+ length -= gapLen;
+ inOff += gapLen;
+
+ while (length > buf.Length)
+ {
+ resultLen += cipher.ProcessBlock(input, inOff, output, outOff + resultLen);
+
+ length -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ Array.Copy(input, inOff, buf, bufOff, length);
+
+ bufOff += length;
+
+ return resultLen;
+ }
+
+ /**
+ * Process the last block in the buffer. If the buffer is currently
+ * full and padding needs to be added a call to doFinal will produce
+ * 2 * GetBlockSize() bytes.
+ *
+ * @param out the array the block currently being held is copied into.
+ * @param outOff the offset at which the copying starts.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there is insufficient space in out for
+ * the output or we are decrypting and the input is not block size aligned.
+ * @exception InvalidOperationException if the underlying cipher is not
+ * initialised.
+ * @exception InvalidCipherTextException if padding is expected and not found.
+ */
+ public override int DoFinal(
+ byte[] output,
+ int outOff)
+ {
+ int blockSize = cipher.GetBlockSize();
+ int resultLen = 0;
+
+ if (forEncryption)
+ {
+ if (bufOff == blockSize)
+ {
+ if ((outOff + 2 * blockSize) > output.Length)
+ {
+ Reset();
+
+ throw new OutputLengthException("output buffer too short");
+ }
+
+ resultLen = cipher.ProcessBlock(buf, 0, output, outOff);
+ bufOff = 0;
+ }
+
+ padding.AddPadding(buf, bufOff);
+
+ resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen);
+
+ Reset();
+ }
+ else
+ {
+ if (bufOff == blockSize)
+ {
+ resultLen = cipher.ProcessBlock(buf, 0, buf, 0);
+ bufOff = 0;
+ }
+ else
+ {
+ Reset();
+
+ throw new DataLengthException("last block incomplete in decryption");
+ }
+
+ try
+ {
+ resultLen -= padding.PadCount(buf);
+
+ Array.Copy(buf, 0, output, outOff, resultLen);
+ }
+ finally
+ {
+ Reset();
+ }
+ }
+
+ return resultLen;
+ }
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/paddings/Pkcs7Padding.cs b/bc-sharp-crypto/src/crypto/paddings/Pkcs7Padding.cs
new file mode 100644
index 0000000000000000000000000000000000000000..11585647a729c2da1cd3d3b845fa09c8071a8a2f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/paddings/Pkcs7Padding.cs
@@ -0,0 +1,76 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+ /**
+ * A padder that adds Pkcs7/Pkcs5 padding to a block.
+ */
+ public class Pkcs7Padding
+ : IBlockCipherPadding
+ {
+ /**
+ * Initialise the padder.
+ *
+ * @param random - a SecureRandom if available.
+ */
+ public void Init(
+ SecureRandom random)
+ {
+ // nothing to do.
+ }
+
+ /**
+ * Return the name of the algorithm the cipher implements.
+ *
+ * @return the name of the algorithm the cipher implements.
+ */
+ public string PaddingName
+ {
+ get { return "PKCS7"; }
+ }
+
+ /**
+ * add the pad bytes to the passed in block, returning the
+ * number of bytes added.
+ */
+ public int AddPadding(
+ byte[] input,
+ int inOff)
+ {
+ byte code = (byte)(input.Length - inOff);
+
+ while (inOff < input.Length)
+ {
+ input[inOff] = code;
+ inOff++;
+ }
+
+ return code;
+ }
+
+ /**
+ * return the number of pad bytes present in the block.
+ */
+ public int PadCount(
+ byte[] input)
+ {
+ byte countAsByte = input[input.Length - 1];
+ int count = countAsByte;
+
+ if (count < 1 || count > input.Length)
+ throw new InvalidCipherTextException("pad block corrupted");
+
+ for (int i = 2; i <= count; i++)
+ {
+ if (input[input.Length - i] != countAsByte)
+ throw new InvalidCipherTextException("pad block corrupted");
+ }
+
+ return count;
+ }
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/paddings/TbcPadding.cs b/bc-sharp-crypto/src/crypto/paddings/TbcPadding.cs
new file mode 100644
index 0000000000000000000000000000000000000000..74b64e8e1b01dd4b51eb46a369133e3b9360c881
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/paddings/TbcPadding.cs
@@ -0,0 +1,79 @@
+using System;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+
+ /// A padder that adds Trailing-Bit-Compliment padding to a block.
+ ///
+ /// This padding pads the block out compliment of the last bit
+ /// of the plain text.
+ ///
+ ///
+ public class TbcPadding
+ : IBlockCipherPadding
+ {
+ /// Return the name of the algorithm the cipher implements.
+ /// the name of the algorithm the cipher implements.
+ ///
+ public string PaddingName
+ {
+ get { return "TBC"; }
+ }
+
+ /// Initialise the padder.
+ /// - a SecureRandom if available.
+ ///
+ public virtual void Init(SecureRandom random)
+ {
+ // nothing to do.
+ }
+
+ /// add the pad bytes to the passed in block, returning the
+ /// number of bytes added.
+ ///
+ /// Note: this assumes that the last block of plain text is always
+ /// passed to it inside in. i.e. if inOff is zero, indicating the
+ /// entire block is to be overwritten with padding the value of in
+ /// should be the same as the last block of plain text.
+ ///
+ ///
+ public virtual int AddPadding(byte[] input, int inOff)
+ {
+ int count = input.Length - inOff;
+ byte code;
+
+ if (inOff > 0)
+ {
+ code = (byte)((input[inOff - 1] & 0x01) == 0?0xff:0x00);
+ }
+ else
+ {
+ code = (byte)((input[input.Length - 1] & 0x01) == 0?0xff:0x00);
+ }
+
+ while (inOff < input.Length)
+ {
+ input[inOff] = code;
+ inOff++;
+ }
+
+ return count;
+ }
+
+ /// return the number of pad bytes present in the block.
+ public virtual int PadCount(byte[] input)
+ {
+ byte code = input[input.Length - 1];
+
+ int index = input.Length - 1;
+ while (index > 0 && input[index - 1] == code)
+ {
+ index--;
+ }
+
+ return input.Length - index;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/paddings/X923Padding.cs b/bc-sharp-crypto/src/crypto/paddings/X923Padding.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cc1b52b3ec2d2d58eb6ca3be138ff2a7dc017281
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/paddings/X923Padding.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+ /**
+ * A padder that adds X9.23 padding to a block - if a SecureRandom is
+ * passed in random padding is assumed, otherwise padding with zeros is used.
+ */
+ public class X923Padding
+ : IBlockCipherPadding
+ {
+ private SecureRandom random;
+
+ /**
+ * Initialise the padder.
+ *
+ * @param random a SecureRandom if one is available.
+ */
+ public void Init(
+ SecureRandom random)
+ {
+ this.random = random;
+ }
+
+ /**
+ * Return the name of the algorithm the cipher implements.
+ *
+ * @return the name of the algorithm the cipher implements.
+ */
+ public string PaddingName
+ {
+ get { return "X9.23"; }
+ }
+
+ /**
+ * add the pad bytes to the passed in block, returning the
+ * number of bytes added.
+ */
+ public int AddPadding(
+ byte[] input,
+ int inOff)
+ {
+ byte code = (byte)(input.Length - inOff);
+
+ while (inOff < input.Length - 1)
+ {
+ if (random == null)
+ {
+ input[inOff] = 0;
+ }
+ else
+ {
+ input[inOff] = (byte)random.NextInt();
+ }
+ inOff++;
+ }
+
+ input[inOff] = code;
+
+ return code;
+ }
+
+ /**
+ * return the number of pad bytes present in the block.
+ */
+ public int PadCount(
+ byte[] input)
+ {
+ int count = input[input.Length - 1] & 0xff;
+
+ if (count > input.Length)
+ {
+ throw new InvalidCipherTextException("pad block corrupted");
+ }
+
+ return count;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/paddings/ZeroBytePadding.cs b/bc-sharp-crypto/src/crypto/paddings/ZeroBytePadding.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0d55ca4c299a2afb49d213d6f417e79a01cf6999
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/paddings/ZeroBytePadding.cs
@@ -0,0 +1,68 @@
+using System;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+
+ /// A padder that adds Null byte padding to a block.
+ public class ZeroBytePadding : IBlockCipherPadding
+ {
+ /// Return the name of the algorithm the cipher implements.
+ ///
+ ///
+ /// the name of the algorithm the cipher implements.
+ ///
+ public string PaddingName
+ {
+ get { return "ZeroBytePadding"; }
+ }
+
+ /// Initialise the padder.
+ ///
+ ///
+ /// - a SecureRandom if available.
+ ///
+ public void Init(SecureRandom random)
+ {
+ // nothing to do.
+ }
+
+ /// add the pad bytes to the passed in block, returning the
+ /// number of bytes added.
+ ///
+ public int AddPadding(
+ byte[] input,
+ int inOff)
+ {
+ int added = (input.Length - inOff);
+
+ while (inOff < input.Length)
+ {
+ input[inOff] = (byte) 0;
+ inOff++;
+ }
+
+ return added;
+ }
+
+ /// return the number of pad bytes present in the block.
+ public int PadCount(
+ byte[] input)
+ {
+ int count = input.Length;
+
+ while (count > 0)
+ {
+ if (input[count - 1] != 0)
+ {
+ break;
+ }
+
+ count--;
+ }
+
+ return input.Length - count;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/AEADParameters.cs b/bc-sharp-crypto/src/crypto/parameters/AEADParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..825d6b7f2bec37430218c6545b8f0caaefaf6e26
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/AEADParameters.cs
@@ -0,0 +1,65 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class AeadParameters
+ : ICipherParameters
+ {
+ private readonly byte[] associatedText;
+ private readonly byte[] nonce;
+ private readonly KeyParameter key;
+ private readonly int macSize;
+
+ /**
+ * Base constructor.
+ *
+ * @param key key to be used by underlying cipher
+ * @param macSize macSize in bits
+ * @param nonce nonce to be used
+ */
+ public AeadParameters(KeyParameter key, int macSize, byte[] nonce)
+ : this(key, macSize, nonce, null)
+ {
+ }
+
+ /**
+ * Base constructor.
+ *
+ * @param key key to be used by underlying cipher
+ * @param macSize macSize in bits
+ * @param nonce nonce to be used
+ * @param associatedText associated text, if any
+ */
+ public AeadParameters(
+ KeyParameter key,
+ int macSize,
+ byte[] nonce,
+ byte[] associatedText)
+ {
+ this.key = key;
+ this.nonce = nonce;
+ this.macSize = macSize;
+ this.associatedText = associatedText;
+ }
+
+ public virtual KeyParameter Key
+ {
+ get { return key; }
+ }
+
+ public virtual int MacSize
+ {
+ get { return macSize; }
+ }
+
+ public virtual byte[] GetAssociatedText()
+ {
+ return associatedText;
+ }
+
+ public virtual byte[] GetNonce()
+ {
+ return nonce;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/CcmParameters.cs b/bc-sharp-crypto/src/crypto/parameters/CcmParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d4459081c7751b2aeb70538dd56a4d11b743fca1
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/CcmParameters.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ [Obsolete("Use AeadParameters")]
+ public class CcmParameters
+ : AeadParameters
+ {
+ /**
+ * Base constructor.
+ *
+ * @param key key to be used by underlying cipher
+ * @param macSize macSize in bits
+ * @param nonce nonce to be used
+ * @param associatedText associated text, if any
+ */
+ public CcmParameters(
+ KeyParameter key,
+ int macSize,
+ byte[] nonce,
+ byte[] associatedText)
+ : base(key, macSize, nonce, associatedText)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/DHKeyGenerationParameters.cs b/bc-sharp-crypto/src/crypto/parameters/DHKeyGenerationParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ab3e18f091d18e57238fd731fc60aa66ae7b0c5d
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/DHKeyGenerationParameters.cs
@@ -0,0 +1,31 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DHKeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ private readonly DHParameters parameters;
+
+ public DHKeyGenerationParameters(
+ SecureRandom random,
+ DHParameters parameters)
+ : base(random, GetStrength(parameters))
+ {
+ this.parameters = parameters;
+ }
+
+ public DHParameters Parameters
+ {
+ get { return parameters; }
+ }
+
+ internal static int GetStrength(
+ DHParameters parameters)
+ {
+ return parameters.L != 0 ? parameters.L : parameters.P.BitLength;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/DHKeyParameters.cs b/bc-sharp-crypto/src/crypto/parameters/DHKeyParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1a5c1386f5d3705e08206bc2716f55447f403995
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/DHKeyParameters.cs
@@ -0,0 +1,76 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DHKeyParameters
+ : AsymmetricKeyParameter
+ {
+ private readonly DHParameters parameters;
+ private readonly DerObjectIdentifier algorithmOid;
+
+ protected DHKeyParameters(
+ bool isPrivate,
+ DHParameters parameters)
+ : this(isPrivate, parameters, PkcsObjectIdentifiers.DhKeyAgreement)
+ {
+ }
+
+ protected DHKeyParameters(
+ bool isPrivate,
+ DHParameters parameters,
+ DerObjectIdentifier algorithmOid)
+ : base(isPrivate)
+ {
+ // TODO Should we allow parameters to be null?
+ this.parameters = parameters;
+ this.algorithmOid = algorithmOid;
+ }
+
+ public DHParameters Parameters
+ {
+ get { return parameters; }
+ }
+
+ public DerObjectIdentifier AlgorithmOid
+ {
+ get { return algorithmOid; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DHKeyParameters other = obj as DHKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ DHKeyParameters other)
+ {
+ return Platform.Equals(parameters, other.parameters)
+ && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ int hc = base.GetHashCode();
+
+ if (parameters != null)
+ {
+ hc ^= parameters.GetHashCode();
+ }
+
+ return hc;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/DHParameters.cs b/bc-sharp-crypto/src/crypto/parameters/DHParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bdea12432694081abac516a7777ddfab23754d36
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/DHParameters.cs
@@ -0,0 +1,185 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DHParameters
+ : ICipherParameters
+ {
+ private const int DefaultMinimumLength = 160;
+
+ private readonly BigInteger p, g, q, j;
+ private readonly int m, l;
+ private readonly DHValidationParameters validation;
+
+ private static int GetDefaultMParam(
+ int lParam)
+ {
+ if (lParam == 0)
+ return DefaultMinimumLength;
+
+ return System.Math.Min(lParam, DefaultMinimumLength);
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g)
+ : this(p, g, null, 0)
+ {
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q)
+ : this(p, g, q, 0)
+ {
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q,
+ int l)
+ : this(p, g, q, GetDefaultMParam(l), l, null, null)
+ {
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q,
+ int m,
+ int l)
+ : this(p, g, q, m, l, null, null)
+ {
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q,
+ BigInteger j,
+ DHValidationParameters validation)
+ : this(p, g, q, DefaultMinimumLength, 0, j, validation)
+ {
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q,
+ int m,
+ int l,
+ BigInteger j,
+ DHValidationParameters validation)
+ {
+ if (p == null)
+ throw new ArgumentNullException("p");
+ if (g == null)
+ throw new ArgumentNullException("g");
+ if (!p.TestBit(0))
+ throw new ArgumentException("field must be an odd prime", "p");
+ if (g.CompareTo(BigInteger.Two) < 0
+ || g.CompareTo(p.Subtract(BigInteger.Two)) > 0)
+ throw new ArgumentException("generator must in the range [2, p - 2]", "g");
+ if (q != null && q.BitLength >= p.BitLength)
+ throw new ArgumentException("q too big to be a factor of (p-1)", "q");
+ if (m >= p.BitLength)
+ throw new ArgumentException("m value must be < bitlength of p", "m");
+ if (l != 0)
+ {
+ // TODO Check this against the Java version, which has 'l > p.BitLength' here
+ if (l >= p.BitLength)
+ throw new ArgumentException("when l value specified, it must be less than bitlength(p)", "l");
+ if (l < m)
+ throw new ArgumentException("when l value specified, it may not be less than m value", "l");
+ }
+ if (j != null && j.CompareTo(BigInteger.Two) < 0)
+ throw new ArgumentException("subgroup factor must be >= 2", "j");
+
+ // TODO If q, j both provided, validate p = jq + 1 ?
+
+ this.p = p;
+ this.g = g;
+ this.q = q;
+ this.m = m;
+ this.l = l;
+ this.j = j;
+ this.validation = validation;
+ }
+
+ public BigInteger P
+ {
+ get { return p; }
+ }
+
+ public BigInteger G
+ {
+ get { return g; }
+ }
+
+ public BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public BigInteger J
+ {
+ get { return j; }
+ }
+
+ /// The minimum bitlength of the private value.
+ public int M
+ {
+ get { return m; }
+ }
+
+ /// The bitlength of the private value.
+ public int L
+ {
+ get { return l; }
+ }
+
+ public DHValidationParameters ValidationParameters
+ {
+ get { return validation; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DHParameters other = obj as DHParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected virtual bool Equals(
+ DHParameters other)
+ {
+ return p.Equals(other.p)
+ && g.Equals(other.g)
+ && Platform.Equals(q, other.q);
+ }
+
+ public override int GetHashCode()
+ {
+ int hc = p.GetHashCode() ^ g.GetHashCode();
+
+ if (q != null)
+ {
+ hc ^= q.GetHashCode();
+ }
+
+ return hc;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/DHPrivateKeyParameters.cs b/bc-sharp-crypto/src/crypto/parameters/DHPrivateKeyParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fc724df810e30b37f2206306e7fde039a582b7a8
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/DHPrivateKeyParameters.cs
@@ -0,0 +1,60 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DHPrivateKeyParameters
+ : DHKeyParameters
+ {
+ private readonly BigInteger x;
+
+ public DHPrivateKeyParameters(
+ BigInteger x,
+ DHParameters parameters)
+ : base(true, parameters)
+ {
+ this.x = x;
+ }
+
+ public DHPrivateKeyParameters(
+ BigInteger x,
+ DHParameters parameters,
+ DerObjectIdentifier algorithmOid)
+ : base(true, parameters, algorithmOid)
+ {
+ this.x = x;
+ }
+
+ public BigInteger X
+ {
+ get { return x; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DHPrivateKeyParameters other = obj as DHPrivateKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ DHPrivateKeyParameters other)
+ {
+ return x.Equals(other.x) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return x.GetHashCode() ^ base.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/DHPublicKeyParameters.cs b/bc-sharp-crypto/src/crypto/parameters/DHPublicKeyParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e7aeeff19dd19440205121b0b798fe2bee62ec61
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/DHPublicKeyParameters.cs
@@ -0,0 +1,79 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DHPublicKeyParameters
+ : DHKeyParameters
+ {
+ private static BigInteger Validate(BigInteger y, DHParameters dhParams)
+ {
+ if (y == null)
+ throw new ArgumentNullException("y");
+
+ // TLS check
+ if (y.CompareTo(BigInteger.Two) < 0 || y.CompareTo(dhParams.P.Subtract(BigInteger.Two)) > 0)
+ throw new ArgumentException("invalid DH public key", "y");
+
+ // we can't validate without Q.
+ if (dhParams.Q != null
+ && !y.ModPow(dhParams.Q, dhParams.P).Equals(BigInteger.One))
+ {
+ throw new ArgumentException("y value does not appear to be in correct group", "y");
+ }
+
+ return y;
+ }
+
+ private readonly BigInteger y;
+
+ public DHPublicKeyParameters(
+ BigInteger y,
+ DHParameters parameters)
+ : base(false, parameters)
+ {
+ this.y = Validate(y, parameters);
+ }
+
+ public DHPublicKeyParameters(
+ BigInteger y,
+ DHParameters parameters,
+ DerObjectIdentifier algorithmOid)
+ : base(false, parameters, algorithmOid)
+ {
+ this.y = Validate(y, parameters);
+ }
+
+ public virtual BigInteger Y
+ {
+ get { return y; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DHPublicKeyParameters other = obj as DHPublicKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ DHPublicKeyParameters other)
+ {
+ return y.Equals(other.y) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ base.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/DHValidationParameters.cs b/bc-sharp-crypto/src/crypto/parameters/DHValidationParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..50c0739faf93f232f8a47c4344f4fc3614988330
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/DHValidationParameters.cs
@@ -0,0 +1,59 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DHValidationParameters
+ {
+ private readonly byte[] seed;
+ private readonly int counter;
+
+ public DHValidationParameters(
+ byte[] seed,
+ int counter)
+ {
+ if (seed == null)
+ throw new ArgumentNullException("seed");
+
+ this.seed = (byte[]) seed.Clone();
+ this.counter = counter;
+ }
+
+ public byte[] GetSeed()
+ {
+ return (byte[]) seed.Clone();
+ }
+
+ public int Counter
+ {
+ get { return counter; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DHValidationParameters other = obj as DHValidationParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ DHValidationParameters other)
+ {
+ return counter == other.counter
+ && Arrays.AreEqual(this.seed, other.seed);
+ }
+
+ public override int GetHashCode()
+ {
+ return counter.GetHashCode() ^ Arrays.GetHashCode(seed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/DSAParameterGenerationParameters.cs b/bc-sharp-crypto/src/crypto/parameters/DSAParameterGenerationParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7427574c8bbc5ca33d2afa5544d37db3153a9f56
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/DSAParameterGenerationParameters.cs
@@ -0,0 +1,74 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DsaParameterGenerationParameters
+ {
+ public const int DigitalSignatureUsage = 1;
+ public const int KeyEstablishmentUsage = 2;
+
+ private readonly int l;
+ private readonly int n;
+ private readonly int certainty;
+ private readonly SecureRandom random;
+ private readonly int usageIndex;
+
+ /**
+ * Construct without a usage index, this will do a random construction of G.
+ *
+ * @param L desired length of prime P in bits (the effective key size).
+ * @param N desired length of prime Q in bits.
+ * @param certainty certainty level for prime number generation.
+ * @param random the source of randomness to use.
+ */
+ public DsaParameterGenerationParameters(int L, int N, int certainty, SecureRandom random)
+ : this(L, N, certainty, random, -1)
+ {
+ }
+
+ /**
+ * Construct for a specific usage index - this has the effect of using verifiable canonical generation of G.
+ *
+ * @param L desired length of prime P in bits (the effective key size).
+ * @param N desired length of prime Q in bits.
+ * @param certainty certainty level for prime number generation.
+ * @param random the source of randomness to use.
+ * @param usageIndex a valid usage index.
+ */
+ public DsaParameterGenerationParameters(int L, int N, int certainty, SecureRandom random, int usageIndex)
+ {
+ this.l = L;
+ this.n = N;
+ this.certainty = certainty;
+ this.random = random;
+ this.usageIndex = usageIndex;
+ }
+
+ public virtual int L
+ {
+ get { return l; }
+ }
+
+ public virtual int N
+ {
+ get { return n; }
+ }
+
+ public virtual int UsageIndex
+ {
+ get { return usageIndex; }
+ }
+
+ public virtual int Certainty
+ {
+ get { return certainty; }
+ }
+
+ public virtual SecureRandom Random
+ {
+ get { return random; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/DesEdeParameters.cs b/bc-sharp-crypto/src/crypto/parameters/DesEdeParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6be56fb2cd654e176e8f47bf5ad5e29ffc44fc54
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/DesEdeParameters.cs
@@ -0,0 +1,140 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DesEdeParameters
+ : DesParameters
+ {
+ /*
+ * DES-EDE Key length in bytes.
+ */
+ public const int DesEdeKeyLength = 24;
+
+ private static byte[] FixKey(
+ byte[] key,
+ int keyOff,
+ int keyLen)
+ {
+ byte[] tmp = new byte[24];
+
+ switch (keyLen)
+ {
+ case 16:
+ Array.Copy(key, keyOff, tmp, 0, 16);
+ Array.Copy(key, keyOff, tmp, 16, 8);
+ break;
+ case 24:
+ Array.Copy(key, keyOff, tmp, 0, 24);
+ break;
+ default:
+ throw new ArgumentException("Bad length for DESede key: " + keyLen, "keyLen");
+ }
+
+ if (IsWeakKey(tmp))
+ throw new ArgumentException("attempt to create weak DESede key");
+
+ return tmp;
+ }
+
+ public DesEdeParameters(
+ byte[] key)
+ : base(FixKey(key, 0, key.Length))
+ {
+ }
+
+ public DesEdeParameters(
+ byte[] key,
+ int keyOff,
+ int keyLen)
+ : base(FixKey(key, keyOff, keyLen))
+ {
+ }
+
+ /**
+ * return true if the passed in key is a DES-EDE weak key.
+ *
+ * @param key bytes making up the key
+ * @param offset offset into the byte array the key starts at
+ * @param length number of bytes making up the key
+ */
+ public static bool IsWeakKey(
+ byte[] key,
+ int offset,
+ int length)
+ {
+ for (int i = offset; i < length; i += DesKeyLength)
+ {
+ if (DesParameters.IsWeakKey(key, i))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * return true if the passed in key is a DES-EDE weak key.
+ *
+ * @param key bytes making up the key
+ * @param offset offset into the byte array the key starts at
+ */
+ public static new bool IsWeakKey(
+ byte[] key,
+ int offset)
+ {
+ return IsWeakKey(key, offset, key.Length - offset);
+ }
+
+ public static new bool IsWeakKey(
+ byte[] key)
+ {
+ return IsWeakKey(key, 0, key.Length);
+ }
+
+ /**
+ * return true if the passed in key is a real 2/3 part DES-EDE key.
+ *
+ * @param key bytes making up the key
+ * @param offset offset into the byte array the key starts at
+ */
+ public static bool IsRealEdeKey(byte[] key, int offset)
+ {
+ return key.Length == 16 ? IsReal2Key(key, offset) : IsReal3Key(key, offset);
+ }
+
+ /**
+ * return true if the passed in key is a real 2 part DES-EDE key.
+ *
+ * @param key bytes making up the key
+ * @param offset offset into the byte array the key starts at
+ */
+ public static bool IsReal2Key(byte[] key, int offset)
+ {
+ bool isValid = false;
+ for (int i = offset; i != offset + 8; i++)
+ {
+ isValid |= (key[i] != key[i + 8]);
+ }
+ return isValid;
+ }
+
+ /**
+ * return true if the passed in key is a real 3 part DES-EDE key.
+ *
+ * @param key bytes making up the key
+ * @param offset offset into the byte array the key starts at
+ */
+ public static bool IsReal3Key(byte[] key, int offset)
+ {
+ bool diff12 = false, diff13 = false, diff23 = false;
+ for (int i = offset; i != offset + 8; i++)
+ {
+ diff12 |= (key[i] != key[i + 8]);
+ diff13 |= (key[i] != key[i + 16]);
+ diff23 |= (key[i + 8] != key[i + 16]);
+ }
+ return diff12 && diff13 && diff23;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/DesParameters.cs b/bc-sharp-crypto/src/crypto/parameters/DesParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a1f67e2b11cb8a0663285b638e601bd4e7aa55cd
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/DesParameters.cs
@@ -0,0 +1,139 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DesParameters
+ : KeyParameter
+ {
+ public DesParameters(
+ byte[] key)
+ : base(key)
+ {
+ if (IsWeakKey(key))
+ throw new ArgumentException("attempt to create weak DES key");
+ }
+
+ public DesParameters(
+ byte[] key,
+ int keyOff,
+ int keyLen)
+ : base(key, keyOff, keyLen)
+ {
+ if (IsWeakKey(key, keyOff))
+ throw new ArgumentException("attempt to create weak DES key");
+ }
+
+ /*
+ * DES Key Length in bytes.
+ */
+ public const int DesKeyLength = 8;
+
+ /*
+ * Table of weak and semi-weak keys taken from Schneier pp281
+ */
+ private const int N_DES_WEAK_KEYS = 16;
+
+ private static readonly byte[] DES_weak_keys =
+ {
+ /* weak keys */
+ (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01,
+ (byte)0x1f,(byte)0x1f,(byte)0x1f,(byte)0x1f, (byte)0x0e,(byte)0x0e,(byte)0x0e,(byte)0x0e,
+ (byte)0xe0,(byte)0xe0,(byte)0xe0,(byte)0xe0, (byte)0xf1,(byte)0xf1,(byte)0xf1,(byte)0xf1,
+ (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe, (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe,
+
+ /* semi-weak keys */
+ (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe, (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe,
+ (byte)0x1f,(byte)0xe0,(byte)0x1f,(byte)0xe0, (byte)0x0e,(byte)0xf1,(byte)0x0e,(byte)0xf1,
+ (byte)0x01,(byte)0xe0,(byte)0x01,(byte)0xe0, (byte)0x01,(byte)0xf1,(byte)0x01,(byte)0xf1,
+ (byte)0x1f,(byte)0xfe,(byte)0x1f,(byte)0xfe, (byte)0x0e,(byte)0xfe,(byte)0x0e,(byte)0xfe,
+ (byte)0x01,(byte)0x1f,(byte)0x01,(byte)0x1f, (byte)0x01,(byte)0x0e,(byte)0x01,(byte)0x0e,
+ (byte)0xe0,(byte)0xfe,(byte)0xe0,(byte)0xfe, (byte)0xf1,(byte)0xfe,(byte)0xf1,(byte)0xfe,
+ (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01, (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01,
+ (byte)0xe0,(byte)0x1f,(byte)0xe0,(byte)0x1f, (byte)0xf1,(byte)0x0e,(byte)0xf1,(byte)0x0e,
+ (byte)0xe0,(byte)0x01,(byte)0xe0,(byte)0x01, (byte)0xf1,(byte)0x01,(byte)0xf1,(byte)0x01,
+ (byte)0xfe,(byte)0x1f,(byte)0xfe,(byte)0x1f, (byte)0xfe,(byte)0x0e,(byte)0xfe,(byte)0x0e,
+ (byte)0x1f,(byte)0x01,(byte)0x1f,(byte)0x01, (byte)0x0e,(byte)0x01,(byte)0x0e,(byte)0x01,
+ (byte)0xfe,(byte)0xe0,(byte)0xfe,(byte)0xe0, (byte)0xfe,(byte)0xf1,(byte)0xfe,(byte)0xf1
+ };
+
+ /**
+ * DES has 16 weak keys. This method will check
+ * if the given DES key material is weak or semi-weak.
+ * Key material that is too short is regarded as weak.
+ *
+ * See "Applied
+ * Cryptography" by Bruce Schneier for more information.
+ *
+ * @return true if the given DES key material is weak or semi-weak,
+ * false otherwise.
+ */
+ public static bool IsWeakKey(
+ byte[] key,
+ int offset)
+ {
+ if (key.Length - offset < DesKeyLength)
+ throw new ArgumentException("key material too short.");
+
+ //nextkey:
+ for (int i = 0; i < N_DES_WEAK_KEYS; i++)
+ {
+ bool unmatch = false;
+ for (int j = 0; j < DesKeyLength; j++)
+ {
+ if (key[j + offset] != DES_weak_keys[i * DesKeyLength + j])
+ {
+ //continue nextkey;
+ unmatch = true;
+ break;
+ }
+ }
+
+ if (!unmatch)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public static bool IsWeakKey(
+ byte[] key)
+ {
+ return IsWeakKey(key, 0);
+ }
+
+ public static byte SetOddParity(byte b)
+ {
+ uint parity = b ^ 1U;
+ parity ^= (parity >> 4);
+ parity ^= (parity >> 2);
+ parity ^= (parity >> 1);
+ parity &= 1U;
+
+ return (byte)(b ^ parity);
+ }
+
+ /**
+ * DES Keys use the LSB as the odd parity bit. This can
+ * be used to check for corrupt keys.
+ *
+ * @param bytes the byte array to set the parity on.
+ */
+ public static void SetOddParity(byte[] bytes)
+ {
+ for (int i = 0; i < bytes.Length; i++)
+ {
+ bytes[i] = SetOddParity(bytes[i]);
+ }
+ }
+
+ public static void SetOddParity(byte[] bytes, int off, int len)
+ {
+ for (int i = 0; i < len; i++)
+ {
+ bytes[off + i] = SetOddParity(bytes[off + i]);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/DsaKeyGenerationParameters.cs b/bc-sharp-crypto/src/crypto/parameters/DsaKeyGenerationParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..86d6f5bd476a1ccbb20ea350a604b8df92a98311
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/DsaKeyGenerationParameters.cs
@@ -0,0 +1,26 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DsaKeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ private readonly DsaParameters parameters;
+
+ public DsaKeyGenerationParameters(
+ SecureRandom random,
+ DsaParameters parameters)
+ : base(random, parameters.P.BitLength - 1)
+ {
+ this.parameters = parameters;
+ }
+
+ public DsaParameters Parameters
+ {
+ get { return parameters; }
+ }
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/DsaKeyParameters.cs b/bc-sharp-crypto/src/crypto/parameters/DsaKeyParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5fe6d7ab497faeae10c07a55ce720f87e8222705
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/DsaKeyParameters.cs
@@ -0,0 +1,59 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public abstract class DsaKeyParameters
+ : AsymmetricKeyParameter
+ {
+ private readonly DsaParameters parameters;
+
+ protected DsaKeyParameters(
+ bool isPrivate,
+ DsaParameters parameters)
+ : base(isPrivate)
+ {
+ // Note: parameters may be null
+ this.parameters = parameters;
+ }
+
+ public DsaParameters Parameters
+ {
+ get { return parameters; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DsaKeyParameters other = obj as DsaKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ DsaKeyParameters other)
+ {
+ return Platform.Equals(parameters, other.parameters)
+ && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ int hc = base.GetHashCode();
+
+ if (parameters != null)
+ {
+ hc ^= parameters.GetHashCode();
+ }
+
+ return hc;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/DsaParameters.cs b/bc-sharp-crypto/src/crypto/parameters/DsaParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..50d080ee243f5141b9b7514a6ced2ebe537119e0
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/DsaParameters.cs
@@ -0,0 +1,85 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DsaParameters
+ : ICipherParameters
+ {
+ private readonly BigInteger p, q , g;
+ private readonly DsaValidationParameters validation;
+
+ public DsaParameters(
+ BigInteger p,
+ BigInteger q,
+ BigInteger g)
+ : this(p, q, g, null)
+ {
+ }
+
+ public DsaParameters(
+ BigInteger p,
+ BigInteger q,
+ BigInteger g,
+ DsaValidationParameters parameters)
+ {
+ if (p == null)
+ throw new ArgumentNullException("p");
+ if (q == null)
+ throw new ArgumentNullException("q");
+ if (g == null)
+ throw new ArgumentNullException("g");
+
+ this.p = p;
+ this.q = q;
+ this.g = g;
+ this.validation = parameters;
+ }
+
+ public BigInteger P
+ {
+ get { return p; }
+ }
+
+ public BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public BigInteger G
+ {
+ get { return g; }
+ }
+
+ public DsaValidationParameters ValidationParameters
+ {
+ get { return validation; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DsaParameters other = obj as DsaParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ DsaParameters other)
+ {
+ return p.Equals(other.p) && q.Equals(other.q) && g.Equals(other.g);
+ }
+
+ public override int GetHashCode()
+ {
+ return p.GetHashCode() ^ q.GetHashCode() ^ g.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/DsaPrivateKeyParameters.cs b/bc-sharp-crypto/src/crypto/parameters/DsaPrivateKeyParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2abdd0e4f5960998845b23ea7c9d50f8e6c820b4
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/DsaPrivateKeyParameters.cs
@@ -0,0 +1,53 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DsaPrivateKeyParameters
+ : DsaKeyParameters
+ {
+ private readonly BigInteger x;
+
+ public DsaPrivateKeyParameters(
+ BigInteger x,
+ DsaParameters parameters)
+ : base(true, parameters)
+ {
+ if (x == null)
+ throw new ArgumentNullException("x");
+
+ this.x = x;
+ }
+
+ public BigInteger X
+ {
+ get { return x; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DsaPrivateKeyParameters other = obj as DsaPrivateKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ DsaPrivateKeyParameters other)
+ {
+ return x.Equals(other.x) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return x.GetHashCode() ^ base.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/DsaPublicKeyParameters.cs b/bc-sharp-crypto/src/crypto/parameters/DsaPublicKeyParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3a81bfdd089ccd35524c63303f8abac3bbbbe210
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/DsaPublicKeyParameters.cs
@@ -0,0 +1,68 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DsaPublicKeyParameters
+ : DsaKeyParameters
+ {
+ private static BigInteger Validate(BigInteger y, DsaParameters parameters)
+ {
+ // we can't validate without params, fortunately we can't use the key either...
+ if (parameters != null)
+ {
+ if (y.CompareTo(BigInteger.Two) < 0
+ || y.CompareTo(parameters.P.Subtract(BigInteger.Two)) > 0
+ || !y.ModPow(parameters.Q, parameters.P).Equals(BigInteger.One))
+ {
+ throw new ArgumentException("y value does not appear to be in correct group");
+ }
+ }
+
+ return y;
+ }
+
+ private readonly BigInteger y;
+
+ public DsaPublicKeyParameters(
+ BigInteger y,
+ DsaParameters parameters)
+ : base(false, parameters)
+ {
+ if (y == null)
+ throw new ArgumentNullException("y");
+
+ this.y = Validate(y, parameters);
+ }
+
+ public BigInteger Y
+ {
+ get { return y; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DsaPublicKeyParameters other = obj as DsaPublicKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ DsaPublicKeyParameters other)
+ {
+ return y.Equals(other.y) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ base.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/DsaValidationParameters.cs b/bc-sharp-crypto/src/crypto/parameters/DsaValidationParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c2f84c785d046912d86e71622a8dad5869c96224
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/DsaValidationParameters.cs
@@ -0,0 +1,72 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class DsaValidationParameters
+ {
+ private readonly byte[] seed;
+ private readonly int counter;
+ private readonly int usageIndex;
+
+ public DsaValidationParameters(byte[] seed, int counter)
+ : this(seed, counter, -1)
+ {
+ }
+
+ public DsaValidationParameters(
+ byte[] seed,
+ int counter,
+ int usageIndex)
+ {
+ if (seed == null)
+ throw new ArgumentNullException("seed");
+
+ this.seed = (byte[]) seed.Clone();
+ this.counter = counter;
+ this.usageIndex = usageIndex;
+ }
+
+ public virtual byte[] GetSeed()
+ {
+ return (byte[]) seed.Clone();
+ }
+
+ public virtual int Counter
+ {
+ get { return counter; }
+ }
+
+ public virtual int UsageIndex
+ {
+ get { return usageIndex; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ DsaValidationParameters other = obj as DsaValidationParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected virtual bool Equals(
+ DsaValidationParameters other)
+ {
+ return counter == other.counter
+ && Arrays.AreEqual(seed, other.seed);
+ }
+
+ public override int GetHashCode()
+ {
+ return counter.GetHashCode() ^ Arrays.GetHashCode(seed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/ECDomainParameters.cs b/bc-sharp-crypto/src/crypto/parameters/ECDomainParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..732fbdfa4dd7be001925ca7691c1238d1ca29d4b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/ECDomainParameters.cs
@@ -0,0 +1,117 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ECDomainParameters
+ {
+ internal ECCurve curve;
+ internal byte[] seed;
+ internal ECPoint g;
+ internal BigInteger n;
+ internal BigInteger h;
+
+ public ECDomainParameters(
+ ECCurve curve,
+ ECPoint g,
+ BigInteger n)
+ : this(curve, g, n, BigInteger.One)
+ {
+ }
+
+ public ECDomainParameters(
+ ECCurve curve,
+ ECPoint g,
+ BigInteger n,
+ BigInteger h)
+ : this(curve, g, n, h, null)
+ {
+ }
+
+ public ECDomainParameters(
+ ECCurve curve,
+ ECPoint g,
+ BigInteger n,
+ BigInteger h,
+ byte[] seed)
+ {
+ if (curve == null)
+ throw new ArgumentNullException("curve");
+ if (g == null)
+ throw new ArgumentNullException("g");
+ if (n == null)
+ throw new ArgumentNullException("n");
+ if (h == null)
+ throw new ArgumentNullException("h");
+
+ this.curve = curve;
+ this.g = g.Normalize();
+ this.n = n;
+ this.h = h;
+ this.seed = Arrays.Clone(seed);
+ }
+
+ public ECCurve Curve
+ {
+ get { return curve; }
+ }
+
+ public ECPoint G
+ {
+ get { return g; }
+ }
+
+ public BigInteger N
+ {
+ get { return n; }
+ }
+
+ public BigInteger H
+ {
+ get { return h; }
+ }
+
+ public byte[] GetSeed()
+ {
+ return Arrays.Clone(seed);
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ECDomainParameters other = obj as ECDomainParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected virtual bool Equals(
+ ECDomainParameters other)
+ {
+ return curve.Equals(other.curve)
+ && g.Equals(other.g)
+ && n.Equals(other.n)
+ && h.Equals(other.h);
+ }
+
+ public override int GetHashCode()
+ {
+ int hc = curve.GetHashCode();
+ hc *= 37;
+ hc ^= g.GetHashCode();
+ hc *= 37;
+ hc ^= n.GetHashCode();
+ hc *= 37;
+ hc ^= h.GetHashCode();
+ return hc;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/ECKeyGenerationParameters.cs b/bc-sharp-crypto/src/crypto/parameters/ECKeyGenerationParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9b2b988457569114b7db9e1bd6760de07d248bd0
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/ECKeyGenerationParameters.cs
@@ -0,0 +1,41 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ECKeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ private readonly ECDomainParameters domainParams;
+ private readonly DerObjectIdentifier publicKeyParamSet;
+
+ public ECKeyGenerationParameters(
+ ECDomainParameters domainParameters,
+ SecureRandom random)
+ : base(random, domainParameters.N.BitLength)
+ {
+ this.domainParams = domainParameters;
+ }
+
+ public ECKeyGenerationParameters(
+ DerObjectIdentifier publicKeyParamSet,
+ SecureRandom random)
+ : this(ECKeyParameters.LookupParameters(publicKeyParamSet), random)
+ {
+ this.publicKeyParamSet = publicKeyParamSet;
+ }
+
+ public ECDomainParameters DomainParameters
+ {
+ get { return domainParams; }
+ }
+
+ public DerObjectIdentifier PublicKeyParamSet
+ {
+ get { return publicKeyParamSet; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/ECKeyParameters.cs b/bc-sharp-crypto/src/crypto/parameters/ECKeyParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..70b3543da7b9cb7a99c2ee238db92ae92d0ffc6f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/ECKeyParameters.cs
@@ -0,0 +1,136 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public abstract class ECKeyParameters
+ : AsymmetricKeyParameter
+ {
+ private static readonly string[] algorithms = { "EC", "ECDSA", "ECDH", "ECDHC", "ECGOST3410", "ECMQV" };
+
+ private readonly string algorithm;
+ private readonly ECDomainParameters parameters;
+ private readonly DerObjectIdentifier publicKeyParamSet;
+
+ protected ECKeyParameters(
+ string algorithm,
+ bool isPrivate,
+ ECDomainParameters parameters)
+ : base(isPrivate)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+ if (parameters == null)
+ throw new ArgumentNullException("parameters");
+
+ this.algorithm = VerifyAlgorithmName(algorithm);
+ this.parameters = parameters;
+ }
+
+ protected ECKeyParameters(
+ string algorithm,
+ bool isPrivate,
+ DerObjectIdentifier publicKeyParamSet)
+ : base(isPrivate)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+ if (publicKeyParamSet == null)
+ throw new ArgumentNullException("publicKeyParamSet");
+
+ this.algorithm = VerifyAlgorithmName(algorithm);
+ this.parameters = LookupParameters(publicKeyParamSet);
+ this.publicKeyParamSet = publicKeyParamSet;
+ }
+
+ public string AlgorithmName
+ {
+ get { return algorithm; }
+ }
+
+ public ECDomainParameters Parameters
+ {
+ get { return parameters; }
+ }
+
+ public DerObjectIdentifier PublicKeyParamSet
+ {
+ get { return publicKeyParamSet; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ECDomainParameters other = obj as ECDomainParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ ECKeyParameters other)
+ {
+ return parameters.Equals(other.parameters) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return parameters.GetHashCode() ^ base.GetHashCode();
+ }
+
+ internal ECKeyGenerationParameters CreateKeyGenerationParameters(
+ SecureRandom random)
+ {
+ if (publicKeyParamSet != null)
+ {
+ return new ECKeyGenerationParameters(publicKeyParamSet, random);
+ }
+
+ return new ECKeyGenerationParameters(parameters, random);
+ }
+
+ internal static string VerifyAlgorithmName(string algorithm)
+ {
+ string upper = Platform.ToUpperInvariant(algorithm);
+ if (Array.IndexOf(algorithms, algorithm, 0, algorithms.Length) < 0)
+ throw new ArgumentException("unrecognised algorithm: " + algorithm, "algorithm");
+ return upper;
+ }
+
+ internal static ECDomainParameters LookupParameters(
+ DerObjectIdentifier publicKeyParamSet)
+ {
+ if (publicKeyParamSet == null)
+ throw new ArgumentNullException("publicKeyParamSet");
+
+ ECDomainParameters p = ECGost3410NamedCurves.GetByOid(publicKeyParamSet);
+
+ if (p == null)
+ {
+ X9ECParameters x9 = ECKeyPairGenerator.FindECCurveByOid(publicKeyParamSet);
+
+ if (x9 == null)
+ {
+ throw new ArgumentException("OID is not a valid public key parameter set", "publicKeyParamSet");
+ }
+
+ p = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H, x9.GetSeed());
+ }
+
+ return p;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/ECPrivateKeyParameters.cs b/bc-sharp-crypto/src/crypto/parameters/ECPrivateKeyParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4d0fa1fc6c79b33948487b205ba194810bd8a056
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/ECPrivateKeyParameters.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ECPrivateKeyParameters
+ : ECKeyParameters
+ {
+ private readonly BigInteger d;
+
+ public ECPrivateKeyParameters(
+ BigInteger d,
+ ECDomainParameters parameters)
+ : this("EC", d, parameters)
+ {
+ }
+
+ [Obsolete("Use version with explicit 'algorithm' parameter")]
+ public ECPrivateKeyParameters(
+ BigInteger d,
+ DerObjectIdentifier publicKeyParamSet)
+ : base("ECGOST3410", true, publicKeyParamSet)
+ {
+ if (d == null)
+ throw new ArgumentNullException("d");
+
+ this.d = d;
+ }
+
+ public ECPrivateKeyParameters(
+ string algorithm,
+ BigInteger d,
+ ECDomainParameters parameters)
+ : base(algorithm, true, parameters)
+ {
+ if (d == null)
+ throw new ArgumentNullException("d");
+
+ this.d = d;
+ }
+
+ public ECPrivateKeyParameters(
+ string algorithm,
+ BigInteger d,
+ DerObjectIdentifier publicKeyParamSet)
+ : base(algorithm, true, publicKeyParamSet)
+ {
+ if (d == null)
+ throw new ArgumentNullException("d");
+
+ this.d = d;
+ }
+
+ public BigInteger D
+ {
+ get { return d; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ECPrivateKeyParameters other = obj as ECPrivateKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ ECPrivateKeyParameters other)
+ {
+ return d.Equals(other.d) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return d.GetHashCode() ^ base.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/ECPublicKeyParameters.cs b/bc-sharp-crypto/src/crypto/parameters/ECPublicKeyParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..474e5d82c5e9c11ece11de3b5bed82234dd42602
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/ECPublicKeyParameters.cs
@@ -0,0 +1,101 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ECPublicKeyParameters
+ : ECKeyParameters
+ {
+ private static ECPoint Validate(ECPoint q)
+ {
+ if (q == null)
+ throw new ArgumentNullException("q");
+ if (q.IsInfinity)
+ throw new ArgumentException("point at infinity", "q");
+
+ q = q.Normalize();
+
+ if (!q.IsValid())
+ throw new ArgumentException("point not on curve", "q");
+
+ return q;
+ }
+
+ private readonly ECPoint q;
+
+ public ECPublicKeyParameters(
+ ECPoint q,
+ ECDomainParameters parameters)
+ : this("EC", q, parameters)
+ {
+ }
+
+ [Obsolete("Use version with explicit 'algorithm' parameter")]
+ public ECPublicKeyParameters(
+ ECPoint q,
+ DerObjectIdentifier publicKeyParamSet)
+ : base("ECGOST3410", false, publicKeyParamSet)
+ {
+ if (q == null)
+ throw new ArgumentNullException("q");
+
+ this.q = Validate(q);
+ }
+
+ public ECPublicKeyParameters(
+ string algorithm,
+ ECPoint q,
+ ECDomainParameters parameters)
+ : base(algorithm, false, parameters)
+ {
+ if (q == null)
+ throw new ArgumentNullException("q");
+
+ this.q = Validate(q);
+ }
+
+ public ECPublicKeyParameters(
+ string algorithm,
+ ECPoint q,
+ DerObjectIdentifier publicKeyParamSet)
+ : base(algorithm, false, publicKeyParamSet)
+ {
+ if (q == null)
+ throw new ArgumentNullException("q");
+
+ this.q = Validate(q);
+ }
+
+ public ECPoint Q
+ {
+ get { return q; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ECPublicKeyParameters other = obj as ECPublicKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ ECPublicKeyParameters other)
+ {
+ return q.Equals(other.q) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return q.GetHashCode() ^ base.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/ElGamalKeyGenerationParameters.cs b/bc-sharp-crypto/src/crypto/parameters/ElGamalKeyGenerationParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..40ca70df4eaab047f6e6757ea57e56213320e13b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/ElGamalKeyGenerationParameters.cs
@@ -0,0 +1,31 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ElGamalKeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ private readonly ElGamalParameters parameters;
+
+ public ElGamalKeyGenerationParameters(
+ SecureRandom random,
+ ElGamalParameters parameters)
+ : base(random, GetStrength(parameters))
+ {
+ this.parameters = parameters;
+ }
+
+ public ElGamalParameters Parameters
+ {
+ get { return parameters; }
+ }
+
+ internal static int GetStrength(
+ ElGamalParameters parameters)
+ {
+ return parameters.L != 0 ? parameters.L : parameters.P.BitLength;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/ElGamalKeyParameters.cs b/bc-sharp-crypto/src/crypto/parameters/ElGamalKeyParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8b6e2795703a9855d1bf65dfe50f6eaada23e409
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/ElGamalKeyParameters.cs
@@ -0,0 +1,59 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ElGamalKeyParameters
+ : AsymmetricKeyParameter
+ {
+ private readonly ElGamalParameters parameters;
+
+ protected ElGamalKeyParameters(
+ bool isPrivate,
+ ElGamalParameters parameters)
+ : base(isPrivate)
+ {
+ // TODO Should we allow 'parameters' to be null?
+ this.parameters = parameters;
+ }
+
+ public ElGamalParameters Parameters
+ {
+ get { return parameters; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ElGamalKeyParameters other = obj as ElGamalKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ ElGamalKeyParameters other)
+ {
+ return Platform.Equals(parameters, other.parameters)
+ && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ int hc = base.GetHashCode();
+
+ if (parameters != null)
+ {
+ hc ^= parameters.GetHashCode();
+ }
+
+ return hc;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/ElGamalParameters.cs b/bc-sharp-crypto/src/crypto/parameters/ElGamalParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ab6d3e71087541d442310c032fb2b2f0865f57ac
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/ElGamalParameters.cs
@@ -0,0 +1,81 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ElGamalParameters
+ : ICipherParameters
+ {
+ private readonly BigInteger p, g;
+ private readonly int l;
+
+ public ElGamalParameters(
+ BigInteger p,
+ BigInteger g)
+ : this(p, g, 0)
+ {
+ }
+
+ public ElGamalParameters(
+ BigInteger p,
+ BigInteger g,
+ int l)
+ {
+ if (p == null)
+ throw new ArgumentNullException("p");
+ if (g == null)
+ throw new ArgumentNullException("g");
+
+ this.p = p;
+ this.g = g;
+ this.l = l;
+ }
+
+ public BigInteger P
+ {
+ get { return p; }
+ }
+
+ /**
+ * return the generator - g
+ */
+ public BigInteger G
+ {
+ get { return g; }
+ }
+
+ /**
+ * return private value limit - l
+ */
+ public int L
+ {
+ get { return l; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ElGamalParameters other = obj as ElGamalParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ ElGamalParameters other)
+ {
+ return p.Equals(other.p) && g.Equals(other.g) && l == other.l;
+ }
+
+ public override int GetHashCode()
+ {
+ return p.GetHashCode() ^ g.GetHashCode() ^ l;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/ElGamalPrivateKeyParameters.cs b/bc-sharp-crypto/src/crypto/parameters/ElGamalPrivateKeyParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6363f2bbb3f4f8960525fc0a5a1985c78f411a3b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/ElGamalPrivateKeyParameters.cs
@@ -0,0 +1,53 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ElGamalPrivateKeyParameters
+ : ElGamalKeyParameters
+ {
+ private readonly BigInteger x;
+
+ public ElGamalPrivateKeyParameters(
+ BigInteger x,
+ ElGamalParameters parameters)
+ : base(true, parameters)
+ {
+ if (x == null)
+ throw new ArgumentNullException("x");
+
+ this.x = x;
+ }
+
+ public BigInteger X
+ {
+ get { return x; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ElGamalPrivateKeyParameters other = obj as ElGamalPrivateKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ ElGamalPrivateKeyParameters other)
+ {
+ return other.x.Equals(x) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return x.GetHashCode() ^ base.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/ElGamalPublicKeyParameters.cs b/bc-sharp-crypto/src/crypto/parameters/ElGamalPublicKeyParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..25ac625d5f7875ef6c3250fdb733ee8762fdcf14
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/ElGamalPublicKeyParameters.cs
@@ -0,0 +1,53 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ElGamalPublicKeyParameters
+ : ElGamalKeyParameters
+ {
+ private readonly BigInteger y;
+
+ public ElGamalPublicKeyParameters(
+ BigInteger y,
+ ElGamalParameters parameters)
+ : base(false, parameters)
+ {
+ if (y == null)
+ throw new ArgumentNullException("y");
+
+ this.y = y;
+ }
+
+ public BigInteger Y
+ {
+ get { return y; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ ElGamalPublicKeyParameters other = obj as ElGamalPublicKeyParameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ ElGamalPublicKeyParameters other)
+ {
+ return y.Equals(other.y) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return y.GetHashCode() ^ base.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/GOST3410KeyGenerationParameters.cs b/bc-sharp-crypto/src/crypto/parameters/GOST3410KeyGenerationParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b06a5d89690a8cd9aa7c1a1d9ce81d52f58606b2
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/GOST3410KeyGenerationParameters.cs
@@ -0,0 +1,55 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class Gost3410KeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ private readonly Gost3410Parameters parameters;
+ private readonly DerObjectIdentifier publicKeyParamSet;
+
+ public Gost3410KeyGenerationParameters(
+ SecureRandom random,
+ Gost3410Parameters parameters)
+ : base(random, parameters.P.BitLength - 1)
+ {
+ this.parameters = parameters;
+ }
+
+ public Gost3410KeyGenerationParameters(
+ SecureRandom random,
+ DerObjectIdentifier publicKeyParamSet)
+ : this(random, LookupParameters(publicKeyParamSet))
+ {
+ this.publicKeyParamSet = publicKeyParamSet;
+ }
+
+ public Gost3410Parameters Parameters
+ {
+ get { return parameters; }
+ }
+
+ public DerObjectIdentifier PublicKeyParamSet
+ {
+ get { return publicKeyParamSet; }
+ }
+
+ private static Gost3410Parameters LookupParameters(
+ DerObjectIdentifier publicKeyParamSet)
+ {
+ if (publicKeyParamSet == null)
+ throw new ArgumentNullException("publicKeyParamSet");
+
+ Gost3410ParamSetParameters p = Gost3410NamedParameters.GetByOid(publicKeyParamSet);
+
+ if (p == null)
+ throw new ArgumentException("OID is not a valid CryptoPro public key parameter set", "publicKeyParamSet");
+
+ return new Gost3410Parameters(p.P, p.Q, p.A);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/GOST3410KeyParameters.cs b/bc-sharp-crypto/src/crypto/parameters/GOST3410KeyParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f771c4d9701efea70c82bc18e11003cb50bcad23
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/GOST3410KeyParameters.cs
@@ -0,0 +1,58 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public abstract class Gost3410KeyParameters
+ : AsymmetricKeyParameter
+ {
+ private readonly Gost3410Parameters parameters;
+ private readonly DerObjectIdentifier publicKeyParamSet;
+
+ protected Gost3410KeyParameters(
+ bool isPrivate,
+ Gost3410Parameters parameters)
+ : base(isPrivate)
+ {
+ this.parameters = parameters;
+ }
+
+ protected Gost3410KeyParameters(
+ bool isPrivate,
+ DerObjectIdentifier publicKeyParamSet)
+ : base(isPrivate)
+ {
+ this.parameters = LookupParameters(publicKeyParamSet);
+ this.publicKeyParamSet = publicKeyParamSet;
+ }
+
+ public Gost3410Parameters Parameters
+ {
+ get { return parameters; }
+ }
+
+ public DerObjectIdentifier PublicKeyParamSet
+ {
+ get { return publicKeyParamSet; }
+ }
+
+ // TODO Implement Equals/GetHashCode
+
+ private static Gost3410Parameters LookupParameters(
+ DerObjectIdentifier publicKeyParamSet)
+ {
+ if (publicKeyParamSet == null)
+ throw new ArgumentNullException("publicKeyParamSet");
+
+ Gost3410ParamSetParameters p = Gost3410NamedParameters.GetByOid(publicKeyParamSet);
+
+ if (p == null)
+ throw new ArgumentException("OID is not a valid CryptoPro public key parameter set", "publicKeyParamSet");
+
+ return new Gost3410Parameters(p.P, p.Q, p.A);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/GOST3410Parameters.cs b/bc-sharp-crypto/src/crypto/parameters/GOST3410Parameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2ec167ef06bdee313e1f01821043d3771f445c55
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/GOST3410Parameters.cs
@@ -0,0 +1,86 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class Gost3410Parameters
+ : ICipherParameters
+ {
+ private readonly BigInteger p, q, a;
+ private readonly Gost3410ValidationParameters validation;
+
+ public Gost3410Parameters(
+ BigInteger p,
+ BigInteger q,
+ BigInteger a)
+ : this(p, q, a, null)
+ {
+ }
+
+ public Gost3410Parameters(
+ BigInteger p,
+ BigInteger q,
+ BigInteger a,
+ Gost3410ValidationParameters validation)
+ {
+ if (p == null)
+ throw new ArgumentNullException("p");
+ if (q == null)
+ throw new ArgumentNullException("q");
+ if (a == null)
+ throw new ArgumentNullException("a");
+
+ this.p = p;
+ this.q = q;
+ this.a = a;
+ this.validation = validation;
+ }
+
+ public BigInteger P
+ {
+ get { return p; }
+ }
+
+ public BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public BigInteger A
+ {
+ get { return a; }
+ }
+
+ public Gost3410ValidationParameters ValidationParameters
+ {
+ get { return validation; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ Gost3410Parameters other = obj as Gost3410Parameters;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ protected bool Equals(
+ Gost3410Parameters other)
+ {
+ return p.Equals(other.p) && q.Equals(other.q) && a.Equals(other.a);
+ }
+
+ public override int GetHashCode()
+ {
+ return p.GetHashCode() ^ q.GetHashCode() ^ a.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/GOST3410PrivateKeyParameters.cs b/bc-sharp-crypto/src/crypto/parameters/GOST3410PrivateKeyParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e3a613de69009ffc36d7a6ca86a0dbb9a199d085
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/GOST3410PrivateKeyParameters.cs
@@ -0,0 +1,41 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class Gost3410PrivateKeyParameters
+ : Gost3410KeyParameters
+ {
+ private readonly BigInteger x;
+
+ public Gost3410PrivateKeyParameters(
+ BigInteger x,
+ Gost3410Parameters parameters)
+ : base(true, parameters)
+ {
+ if (x.SignValue < 1 || x.BitLength > 256 || x.CompareTo(Parameters.Q) >= 0)
+ throw new ArgumentException("Invalid x for GOST3410 private key", "x");
+
+ this.x = x;
+ }
+
+ public Gost3410PrivateKeyParameters(
+ BigInteger x,
+ DerObjectIdentifier publicKeyParamSet)
+ : base(true, publicKeyParamSet)
+ {
+ if (x.SignValue < 1 || x.BitLength > 256 || x.CompareTo(Parameters.Q) >= 0)
+ throw new ArgumentException("Invalid x for GOST3410 private key", "x");
+
+ this.x = x;
+ }
+
+ public BigInteger X
+ {
+ get { return x; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/GOST3410PublicKeyParameters.cs b/bc-sharp-crypto/src/crypto/parameters/GOST3410PublicKeyParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..96b7e91ea00844896b5a3ee81ab6a41c244b4747
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/GOST3410PublicKeyParameters.cs
@@ -0,0 +1,40 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class Gost3410PublicKeyParameters
+ : Gost3410KeyParameters
+ {
+ private readonly BigInteger y;
+
+ public Gost3410PublicKeyParameters(
+ BigInteger y,
+ Gost3410Parameters parameters)
+ : base(false, parameters)
+ {
+ if (y.SignValue < 1 || y.CompareTo(Parameters.P) >= 0)
+ throw new ArgumentException("Invalid y for GOST3410 public key", "y");
+
+ this.y = y;
+ }
+
+ public Gost3410PublicKeyParameters(
+ BigInteger y,
+ DerObjectIdentifier publicKeyParamSet)
+ : base(false, publicKeyParamSet)
+ {
+ if (y.SignValue < 1 || y.CompareTo(Parameters.P) >= 0)
+ throw new ArgumentException("Invalid y for GOST3410 public key", "y");
+
+ this.y = y;
+ }
+
+ public BigInteger Y
+ {
+ get { return y; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/GOST3410ValidationParameters.cs b/bc-sharp-crypto/src/crypto/parameters/GOST3410ValidationParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..21e5af8232a57003eb60d9b2c639b5e2048200a8
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/GOST3410ValidationParameters.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class Gost3410ValidationParameters
+ {
+ private int x0;
+ private int c;
+ private long x0L;
+ private long cL;
+
+ public Gost3410ValidationParameters(
+ int x0,
+ int c)
+ {
+ this.x0 = x0;
+ this.c = c;
+ }
+
+ public Gost3410ValidationParameters(
+ long x0L,
+ long cL)
+ {
+ this.x0L = x0L;
+ this.cL = cL;
+ }
+
+ public int C { get { return c; } }
+ public int X0 { get { return x0; } }
+ public long CL { get { return cL; } }
+ public long X0L { get { return x0L; } }
+
+ public override bool Equals(
+ object obj)
+ {
+ Gost3410ValidationParameters other = obj as Gost3410ValidationParameters;
+
+ return other != null
+ && other.c == this.c
+ && other.x0 == this.x0
+ && other.cL == this.cL
+ && other.x0L == this.x0L;
+ }
+
+ public override int GetHashCode()
+ {
+ return c.GetHashCode() ^ x0.GetHashCode() ^ cL.GetHashCode() ^ x0L.GetHashCode();
+ }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/HKDFParameters.cs b/bc-sharp-crypto/src/crypto/parameters/HKDFParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6d1465e4c8ca98cdee151bfe7250f0a666ba3e12
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/HKDFParameters.cs
@@ -0,0 +1,119 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ /**
+ * Parameter class for the HkdfBytesGenerator class.
+ */
+ public class HkdfParameters
+ : IDerivationParameters
+ {
+ private readonly byte[] ikm;
+ private readonly bool skipExpand;
+ private readonly byte[] salt;
+ private readonly byte[] info;
+
+ private HkdfParameters(byte[] ikm, bool skip, byte[] salt, byte[] info)
+ {
+ if (ikm == null)
+ throw new ArgumentNullException("ikm");
+
+ this.ikm = Arrays.Clone(ikm);
+ this.skipExpand = skip;
+
+ if (salt == null || salt.Length == 0)
+ {
+ this.salt = null;
+ }
+ else
+ {
+ this.salt = Arrays.Clone(salt);
+ }
+
+ if (info == null)
+ {
+ this.info = new byte[0];
+ }
+ else
+ {
+ this.info = Arrays.Clone(info);
+ }
+ }
+
+ /**
+ * Generates parameters for HKDF, specifying both the optional salt and
+ * optional info. Step 1: Extract won't be skipped.
+ *
+ * @param ikm the input keying material or seed
+ * @param salt the salt to use, may be null for a salt for hashLen zeros
+ * @param info the info to use, may be null for an info field of zero bytes
+ */
+ public HkdfParameters(byte[] ikm, byte[] salt, byte[] info)
+ : this(ikm, false, salt, info)
+ {
+ }
+
+ /**
+ * Factory method that makes the HKDF skip the extract part of the key
+ * derivation function.
+ *
+ * @param ikm the input keying material or seed, directly used for step 2:
+ * Expand
+ * @param info the info to use, may be null for an info field of zero bytes
+ * @return HKDFParameters that makes the implementation skip step 1
+ */
+ public static HkdfParameters SkipExtractParameters(byte[] ikm, byte[] info)
+ {
+ return new HkdfParameters(ikm, true, null, info);
+ }
+
+ public static HkdfParameters DefaultParameters(byte[] ikm)
+ {
+ return new HkdfParameters(ikm, false, null, null);
+ }
+
+ /**
+ * Returns the input keying material or seed.
+ *
+ * @return the keying material
+ */
+ public virtual byte[] GetIkm()
+ {
+ return Arrays.Clone(ikm);
+ }
+
+ /**
+ * Returns if step 1: extract has to be skipped or not
+ *
+ * @return true for skipping, false for no skipping of step 1
+ */
+ public virtual bool SkipExtract
+ {
+ get { return skipExpand; }
+ }
+
+ /**
+ * Returns the salt, or null if the salt should be generated as a byte array
+ * of HashLen zeros.
+ *
+ * @return the salt, or null
+ */
+ public virtual byte[] GetSalt()
+ {
+ return Arrays.Clone(salt);
+ }
+
+ /**
+ * Returns the info field, which may be empty (null is converted to empty).
+ *
+ * @return the info field, never null
+ */
+ public virtual byte[] GetInfo()
+ {
+ return Arrays.Clone(info);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/ISO18033KDFParameters.cs b/bc-sharp-crypto/src/crypto/parameters/ISO18033KDFParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2d8fff8e3bd0539f2ba73b2a1614ebb3135fe2eb
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/ISO18033KDFParameters.cs
@@ -0,0 +1,25 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ /**
+ * parameters for Key derivation functions for ISO-18033
+ */
+ public class Iso18033KdfParameters
+ : IDerivationParameters
+ {
+ byte[] seed;
+
+ public Iso18033KdfParameters(
+ byte[] seed)
+ {
+ this.seed = seed;
+ }
+
+ public byte[] GetSeed()
+ {
+ return seed;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/IesParameters.cs b/bc-sharp-crypto/src/crypto/parameters/IesParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d306b2c3341207adc5774d32a4050de57b210b9d
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/IesParameters.cs
@@ -0,0 +1,49 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ /**
+ * parameters for using an integrated cipher in stream mode.
+ */
+ public class IesParameters : ICipherParameters
+ {
+ private byte[] derivation;
+ private byte[] encoding;
+ private int macKeySize;
+
+ /**
+ * @param derivation the derivation parameter for the KDF function.
+ * @param encoding the encoding parameter for the KDF function.
+ * @param macKeySize the size of the MAC key (in bits).
+ */
+ public IesParameters(
+ byte[] derivation,
+ byte[] encoding,
+ int macKeySize)
+ {
+ this.derivation = derivation;
+ this.encoding = encoding;
+ this.macKeySize = macKeySize;
+ }
+
+ public byte[] GetDerivationV()
+ {
+ return derivation;
+ }
+
+ public byte[] GetEncodingV()
+ {
+ return encoding;
+ }
+
+ public int MacKeySize
+ {
+ get
+ {
+ return macKeySize;
+ }
+ }
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/IesWithCipherParameters.cs b/bc-sharp-crypto/src/crypto/parameters/IesWithCipherParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..70ef55d54670c9824259135ba7b9195f178bc82b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/IesWithCipherParameters.cs
@@ -0,0 +1,33 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class IesWithCipherParameters : IesParameters
+ {
+ private int cipherKeySize;
+
+ /**
+ * @param derivation the derivation parameter for the KDF function.
+ * @param encoding the encoding parameter for the KDF function.
+ * @param macKeySize the size of the MAC key (in bits).
+ * @param cipherKeySize the size of the associated Cipher key (in bits).
+ */
+ public IesWithCipherParameters(
+ byte[] derivation,
+ byte[] encoding,
+ int macKeySize,
+ int cipherKeySize) : base(derivation, encoding, macKeySize)
+ {
+ this.cipherKeySize = cipherKeySize;
+ }
+
+ public int CipherKeySize
+ {
+ get
+ {
+ return cipherKeySize;
+ }
+ }
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/KdfParameters.cs b/bc-sharp-crypto/src/crypto/parameters/KdfParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bc5c905d084798f775d6862edf75a1d25690e507
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/KdfParameters.cs
@@ -0,0 +1,33 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ /**
+ * parameters for Key derivation functions for IEEE P1363a
+ */
+ public class KdfParameters : IDerivationParameters
+ {
+ byte[] iv;
+ byte[] shared;
+
+ public KdfParameters(
+ byte[] shared,
+ byte[] iv)
+ {
+ this.shared = shared;
+ this.iv = iv;
+ }
+
+ public byte[] GetSharedSecret()
+ {
+ return shared;
+ }
+
+ public byte[] GetIV()
+ {
+ return iv;
+ }
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/KeyParameter.cs b/bc-sharp-crypto/src/crypto/parameters/KeyParameter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..33dff96d78043625311a67bf7609fa97dc18faa2
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/KeyParameter.cs
@@ -0,0 +1,43 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class KeyParameter
+ : ICipherParameters
+ {
+ private readonly byte[] key;
+
+ public KeyParameter(
+ byte[] key)
+ {
+ if (key == null)
+ throw new ArgumentNullException("key");
+
+ this.key = (byte[]) key.Clone();
+ }
+
+ public KeyParameter(
+ byte[] key,
+ int keyOff,
+ int keyLen)
+ {
+ if (key == null)
+ throw new ArgumentNullException("key");
+ if (keyOff < 0 || keyOff > key.Length)
+ throw new ArgumentOutOfRangeException("keyOff");
+ if (keyLen < 0 || (keyOff + keyLen) > key.Length)
+ throw new ArgumentOutOfRangeException("keyLen");
+
+ this.key = new byte[keyLen];
+ Array.Copy(key, keyOff, this.key, 0, keyLen);
+ }
+
+ public byte[] GetKey()
+ {
+ return (byte[]) key.Clone();
+ }
+ }
+
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/MgfParameters.cs b/bc-sharp-crypto/src/crypto/parameters/MgfParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..11983b877a836c35e308ae0db03c8092d8641020
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/MgfParameters.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ /// Parameters for mask derivation functions.
+ public class MgfParameters
+ : IDerivationParameters
+ {
+ private readonly byte[] seed;
+
+ public MgfParameters(
+ byte[] seed)
+ : this(seed, 0, seed.Length)
+ {
+ }
+
+ public MgfParameters(
+ byte[] seed,
+ int off,
+ int len)
+ {
+ this.seed = new byte[len];
+ Array.Copy(seed, off, this.seed, 0, len);
+ }
+
+ public byte[] GetSeed()
+ {
+ return (byte[]) seed.Clone();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/MqvPrivateParameters.cs b/bc-sharp-crypto/src/crypto/parameters/MqvPrivateParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9159cac12d6c16c868cfc5f317b9f228e78a8a73
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/MqvPrivateParameters.cs
@@ -0,0 +1,64 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class MqvPrivateParameters
+ : ICipherParameters
+ {
+ private readonly ECPrivateKeyParameters staticPrivateKey;
+ private readonly ECPrivateKeyParameters ephemeralPrivateKey;
+ private readonly ECPublicKeyParameters ephemeralPublicKey;
+
+ public MqvPrivateParameters(
+ ECPrivateKeyParameters staticPrivateKey,
+ ECPrivateKeyParameters ephemeralPrivateKey)
+ : this(staticPrivateKey, ephemeralPrivateKey, null)
+ {
+ }
+
+ public MqvPrivateParameters(
+ ECPrivateKeyParameters staticPrivateKey,
+ ECPrivateKeyParameters ephemeralPrivateKey,
+ ECPublicKeyParameters ephemeralPublicKey)
+ {
+ if (staticPrivateKey == null)
+ throw new ArgumentNullException("staticPrivateKey");
+ if (ephemeralPrivateKey == null)
+ throw new ArgumentNullException("ephemeralPrivateKey");
+
+ ECDomainParameters parameters = staticPrivateKey.Parameters;
+ if (!parameters.Equals(ephemeralPrivateKey.Parameters))
+ throw new ArgumentException("Static and ephemeral private keys have different domain parameters");
+
+ if (ephemeralPublicKey == null)
+ {
+ ephemeralPublicKey = new ECPublicKeyParameters(
+ parameters.G.Multiply(ephemeralPrivateKey.D),
+ parameters);
+ }
+ else if (!parameters.Equals(ephemeralPublicKey.Parameters))
+ {
+ throw new ArgumentException("Ephemeral public key has different domain parameters");
+ }
+
+ this.staticPrivateKey = staticPrivateKey;
+ this.ephemeralPrivateKey = ephemeralPrivateKey;
+ this.ephemeralPublicKey = ephemeralPublicKey;
+ }
+
+ public virtual ECPrivateKeyParameters StaticPrivateKey
+ {
+ get { return staticPrivateKey; }
+ }
+
+ public virtual ECPrivateKeyParameters EphemeralPrivateKey
+ {
+ get { return ephemeralPrivateKey; }
+ }
+
+ public virtual ECPublicKeyParameters EphemeralPublicKey
+ {
+ get { return ephemeralPublicKey; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/MqvPublicParameters.cs b/bc-sharp-crypto/src/crypto/parameters/MqvPublicParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..239afa321599c2a9e0aee15fd16562e74499be26
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/MqvPublicParameters.cs
@@ -0,0 +1,36 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class MqvPublicParameters
+ : ICipherParameters
+ {
+ private readonly ECPublicKeyParameters staticPublicKey;
+ private readonly ECPublicKeyParameters ephemeralPublicKey;
+
+ public MqvPublicParameters(
+ ECPublicKeyParameters staticPublicKey,
+ ECPublicKeyParameters ephemeralPublicKey)
+ {
+ if (staticPublicKey == null)
+ throw new ArgumentNullException("staticPublicKey");
+ if (ephemeralPublicKey == null)
+ throw new ArgumentNullException("ephemeralPublicKey");
+ if (!staticPublicKey.Parameters.Equals(ephemeralPublicKey.Parameters))
+ throw new ArgumentException("Static and ephemeral public keys have different domain parameters");
+
+ this.staticPublicKey = staticPublicKey;
+ this.ephemeralPublicKey = ephemeralPublicKey;
+ }
+
+ public virtual ECPublicKeyParameters StaticPublicKey
+ {
+ get { return staticPublicKey; }
+ }
+
+ public virtual ECPublicKeyParameters EphemeralPublicKey
+ {
+ get { return ephemeralPublicKey; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/NaccacheSternKeyGenerationParameters.cs b/bc-sharp-crypto/src/crypto/parameters/NaccacheSternKeyGenerationParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..44fc906b5edad1e43e565dddba0e154112b88fc1
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/NaccacheSternKeyGenerationParameters.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ /**
+ * Parameters for NaccacheStern public private key generation. For details on
+ * this cipher, please see
+ *
+ * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+ */
+ public class NaccacheSternKeyGenerationParameters : KeyGenerationParameters
+ {
+ // private BigInteger publicExponent;
+ private readonly int certainty;
+ private readonly int countSmallPrimes;
+
+ /**
+ * Parameters for generating a NaccacheStern KeyPair.
+ *
+ * @param random
+ * The source of randomness
+ * @param strength
+ * The desired strength of the Key in Bits
+ * @param certainty
+ * the probability that the generated primes are not really prime
+ * as integer: 2^(-certainty) is then the probability
+ * @param countSmallPrimes
+ * How many small key factors are desired
+ */
+ public NaccacheSternKeyGenerationParameters(
+ SecureRandom random,
+ int strength,
+ int certainty,
+ int countSmallPrimes)
+ : base(random, strength)
+ {
+ if (countSmallPrimes % 2 == 1)
+ throw new ArgumentException("countSmallPrimes must be a multiple of 2");
+ if (countSmallPrimes < 30)
+ throw new ArgumentException("countSmallPrimes must be >= 30 for security reasons");
+
+ this.certainty = certainty;
+ this.countSmallPrimes = countSmallPrimes;
+ }
+
+ /**
+ * Parameters for a NaccacheStern KeyPair.
+ *
+ * @param random
+ * The source of randomness
+ * @param strength
+ * The desired strength of the Key in Bits
+ * @param certainty
+ * the probability that the generated primes are not really prime
+ * as integer: 2^(-certainty) is then the probability
+ * @param cntSmallPrimes
+ * How many small key factors are desired
+ * @param debug
+ * Ignored
+ */
+ [Obsolete("Use version without 'debug' parameter")]
+ public NaccacheSternKeyGenerationParameters(
+ SecureRandom random,
+ int strength,
+ int certainty,
+ int countSmallPrimes,
+ bool debug)
+ : this(random, strength, certainty, countSmallPrimes)
+ {
+ }
+
+ /**
+ * @return Returns the certainty.
+ */
+ public int Certainty
+ {
+ get { return certainty; }
+ }
+
+ /**
+ * @return Returns the countSmallPrimes.
+ */
+ public int CountSmallPrimes
+ {
+ get { return countSmallPrimes; }
+ }
+
+ [Obsolete("Remove: always false")]
+ public bool IsDebug
+ {
+ get { return false; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/NaccacheSternKeyParameters.cs b/bc-sharp-crypto/src/crypto/parameters/NaccacheSternKeyParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8be7ad835476e1697c0d05dc099f641c19c78974
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/NaccacheSternKeyParameters.cs
@@ -0,0 +1,44 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ /**
+ * Public key parameters for NaccacheStern cipher. For details on this cipher,
+ * please see
+ *
+ * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+ */
+ public class NaccacheSternKeyParameters : AsymmetricKeyParameter
+ {
+ private readonly BigInteger g, n;
+ private readonly int lowerSigmaBound;
+
+ /**
+ * @param privateKey
+ */
+ public NaccacheSternKeyParameters(bool privateKey, BigInteger g, BigInteger n, int lowerSigmaBound)
+ : base(privateKey)
+ {
+ this.g = g;
+ this.n = n;
+ this.lowerSigmaBound = lowerSigmaBound;
+ }
+
+ /**
+ * @return Returns the g.
+ */
+ public BigInteger G { get { return g; } }
+
+ /**
+ * @return Returns the lowerSigmaBound.
+ */
+ public int LowerSigmaBound { get { return lowerSigmaBound; } }
+
+ /**
+ * @return Returns the n.
+ */
+ public BigInteger Modulus { get { return n; } }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/NaccacheSternPrivateKeyParameters.cs b/bc-sharp-crypto/src/crypto/parameters/NaccacheSternPrivateKeyParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..42a0454a1240f83ec8ae9f1caca3271e646db385
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/NaccacheSternPrivateKeyParameters.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ /**
+ * Private key parameters for NaccacheStern cipher. For details on this cipher,
+ * please see
+ *
+ * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+ */
+ public class NaccacheSternPrivateKeyParameters : NaccacheSternKeyParameters
+ {
+ private readonly BigInteger phiN;
+ private readonly IList smallPrimes;
+
+#if !(SILVERLIGHT || PORTABLE)
+ [Obsolete]
+ public NaccacheSternPrivateKeyParameters(
+ BigInteger g,
+ BigInteger n,
+ int lowerSigmaBound,
+ ArrayList smallPrimes,
+ BigInteger phiN)
+ : base(true, g, n, lowerSigmaBound)
+ {
+ this.smallPrimes = smallPrimes;
+ this.phiN = phiN;
+ }
+#endif
+
+ /**
+ * Constructs a NaccacheSternPrivateKey
+ *
+ * @param g
+ * the public enryption parameter g
+ * @param n
+ * the public modulus n = p*q
+ * @param lowerSigmaBound
+ * the public lower sigma bound up to which data can be encrypted
+ * @param smallPrimes
+ * the small primes, of which sigma is constructed in the right
+ * order
+ * @param phi_n
+ * the private modulus phi(n) = (p-1)(q-1)
+ */
+ public NaccacheSternPrivateKeyParameters(
+ BigInteger g,
+ BigInteger n,
+ int lowerSigmaBound,
+ IList smallPrimes,
+ BigInteger phiN)
+ : base(true, g, n, lowerSigmaBound)
+ {
+ this.smallPrimes = smallPrimes;
+ this.phiN = phiN;
+ }
+
+ public BigInteger PhiN
+ {
+ get { return phiN; }
+ }
+
+#if !(SILVERLIGHT || PORTABLE)
+ [Obsolete("Use 'SmallPrimesList' instead")]
+ public ArrayList SmallPrimes
+ {
+ get { return new ArrayList(smallPrimes); }
+ }
+#endif
+
+ public IList SmallPrimesList
+ {
+ get { return smallPrimes; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/ParametersWithIV.cs b/bc-sharp-crypto/src/crypto/parameters/ParametersWithIV.cs
new file mode 100644
index 0000000000000000000000000000000000000000..11a8b77a0fcd3636ae9336bb5b51238bb231366e
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/ParametersWithIV.cs
@@ -0,0 +1,43 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ParametersWithIV
+ : ICipherParameters
+ {
+ private readonly ICipherParameters parameters;
+ private readonly byte[] iv;
+
+ public ParametersWithIV(
+ ICipherParameters parameters,
+ byte[] iv)
+ : this(parameters, iv, 0, iv.Length)
+ {
+ }
+
+ public ParametersWithIV(
+ ICipherParameters parameters,
+ byte[] iv,
+ int ivOff,
+ int ivLen)
+ {
+ // NOTE: 'parameters' may be null to imply key re-use
+ if (iv == null)
+ throw new ArgumentNullException("iv");
+
+ this.parameters = parameters;
+ this.iv = new byte[ivLen];
+ Array.Copy(iv, ivOff, this.iv, 0, ivLen);
+ }
+
+ public byte[] GetIV()
+ {
+ return (byte[]) iv.Clone();
+ }
+
+ public ICipherParameters Parameters
+ {
+ get { return parameters; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/ParametersWithRandom.cs b/bc-sharp-crypto/src/crypto/parameters/ParametersWithRandom.cs
new file mode 100644
index 0000000000000000000000000000000000000000..276dc2666af31f889ee088caf97629bfabdf509e
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/ParametersWithRandom.cs
@@ -0,0 +1,48 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ParametersWithRandom
+ : ICipherParameters
+ {
+ private readonly ICipherParameters parameters;
+ private readonly SecureRandom random;
+
+ public ParametersWithRandom(
+ ICipherParameters parameters,
+ SecureRandom random)
+ {
+ if (parameters == null)
+ throw new ArgumentNullException("parameters");
+ if (random == null)
+ throw new ArgumentNullException("random");
+
+ this.parameters = parameters;
+ this.random = random;
+ }
+
+ public ParametersWithRandom(
+ ICipherParameters parameters)
+ : this(parameters, new SecureRandom())
+ {
+ }
+
+ [Obsolete("Use Random property instead")]
+ public SecureRandom GetRandom()
+ {
+ return Random;
+ }
+
+ public SecureRandom Random
+ {
+ get { return random; }
+ }
+
+ public ICipherParameters Parameters
+ {
+ get { return parameters; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/ParametersWithSBox.cs b/bc-sharp-crypto/src/crypto/parameters/ParametersWithSBox.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6473796e32ab226bf8d44ec65aafc875f1ad68ac
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/ParametersWithSBox.cs
@@ -0,0 +1,24 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class ParametersWithSBox : ICipherParameters
+ {
+ private ICipherParameters parameters;
+ private byte[] sBox;
+
+ public ParametersWithSBox(
+ ICipherParameters parameters,
+ byte[] sBox)
+ {
+ this.parameters = parameters;
+ this.sBox = sBox;
+ }
+
+ public byte[] GetSBox() { return sBox; }
+
+ public ICipherParameters Parameters { get { return parameters; } }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/ParametersWithSalt.cs b/bc-sharp-crypto/src/crypto/parameters/ParametersWithSalt.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7f4cd6cd1d61904974c7cfd48b536f7c3ef75855
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/ParametersWithSalt.cs
@@ -0,0 +1,39 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+
+ /// Cipher parameters with a fixed salt value associated with them.
+ public class ParametersWithSalt : ICipherParameters
+ {
+ private byte[] salt;
+ private ICipherParameters parameters;
+
+ public ParametersWithSalt(ICipherParameters parameters, byte[] salt):this(parameters, salt, 0, salt.Length)
+ {
+ }
+
+ public ParametersWithSalt(ICipherParameters parameters, byte[] salt, int saltOff, int saltLen)
+ {
+ this.salt = new byte[saltLen];
+ this.parameters = parameters;
+
+ Array.Copy(salt, saltOff, this.salt, 0, saltLen);
+ }
+
+ public byte[] GetSalt()
+ {
+ return salt;
+ }
+
+ public ICipherParameters Parameters
+ {
+ get
+ {
+ return parameters;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/RC2Parameters.cs b/bc-sharp-crypto/src/crypto/parameters/RC2Parameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7a6d5bb6ecc9b5fd67447f6ea6744c94e34c8fa7
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/RC2Parameters.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class RC2Parameters
+ : KeyParameter
+ {
+ private readonly int bits;
+
+ public RC2Parameters(
+ byte[] key)
+ : this(key, (key.Length > 128) ? 1024 : (key.Length * 8))
+ {
+ }
+
+ public RC2Parameters(
+ byte[] key,
+ int keyOff,
+ int keyLen)
+ : this(key, keyOff, keyLen, (keyLen > 128) ? 1024 : (keyLen * 8))
+ {
+ }
+
+ public RC2Parameters(
+ byte[] key,
+ int bits)
+ : base(key)
+ {
+ this.bits = bits;
+ }
+
+ public RC2Parameters(
+ byte[] key,
+ int keyOff,
+ int keyLen,
+ int bits)
+ : base(key, keyOff, keyLen)
+ {
+ this.bits = bits;
+ }
+
+ public int EffectiveKeyBits
+ {
+ get { return bits; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/RC5Parameters.cs b/bc-sharp-crypto/src/crypto/parameters/RC5Parameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..88a59e197b526ce848d91edfd2786ed83cca4937
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/RC5Parameters.cs
@@ -0,0 +1,27 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class RC5Parameters
+ : KeyParameter
+ {
+ private readonly int rounds;
+
+ public RC5Parameters(
+ byte[] key,
+ int rounds)
+ : base(key)
+ {
+ if (key.Length > 255)
+ throw new ArgumentException("RC5 key length can be no greater than 255");
+
+ this.rounds = rounds;
+ }
+
+ public int Rounds
+ {
+ get { return rounds; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/RSABlindingParameters.cs b/bc-sharp-crypto/src/crypto/parameters/RSABlindingParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..49c7bcce65bb70f443ae2de665641851dfaff901
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/RSABlindingParameters.cs
@@ -0,0 +1,34 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class RsaBlindingParameters
+ : ICipherParameters
+ {
+ private readonly RsaKeyParameters publicKey;
+ private readonly BigInteger blindingFactor;
+
+ public RsaBlindingParameters(
+ RsaKeyParameters publicKey,
+ BigInteger blindingFactor)
+ {
+ if (publicKey.IsPrivate)
+ throw new ArgumentException("RSA parameters should be for a public key");
+
+ this.publicKey = publicKey;
+ this.blindingFactor = blindingFactor;
+ }
+
+ public RsaKeyParameters PublicKey
+ {
+ get { return publicKey; }
+ }
+
+ public BigInteger BlindingFactor
+ {
+ get { return blindingFactor; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/RsaKeyGenerationParameters.cs b/bc-sharp-crypto/src/crypto/parameters/RsaKeyGenerationParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..619ab65b4228593c2d0c856e2c24b39191cc0b3d
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/RsaKeyGenerationParameters.cs
@@ -0,0 +1,55 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class RsaKeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ private readonly BigInteger publicExponent;
+ private readonly int certainty;
+
+ public RsaKeyGenerationParameters(
+ BigInteger publicExponent,
+ SecureRandom random,
+ int strength,
+ int certainty)
+ : base(random, strength)
+ {
+ this.publicExponent = publicExponent;
+ this.certainty = certainty;
+ }
+
+ public BigInteger PublicExponent
+ {
+ get { return publicExponent; }
+ }
+
+ public int Certainty
+ {
+ get { return certainty; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ RsaKeyGenerationParameters other = obj as RsaKeyGenerationParameters;
+
+ if (other == null)
+ {
+ return false;
+ }
+
+ return certainty == other.certainty
+ && publicExponent.Equals(other.publicExponent);
+ }
+
+ public override int GetHashCode()
+ {
+ return certainty.GetHashCode() ^ publicExponent.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/RsaKeyParameters.cs b/bc-sharp-crypto/src/crypto/parameters/RsaKeyParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5480f056131c8413477bda5057ea5574efe2a05e
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/RsaKeyParameters.cs
@@ -0,0 +1,85 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class RsaKeyParameters
+ : AsymmetricKeyParameter
+ {
+ // the value is the product of the 132 smallest primes from 3 to 751
+ private static BigInteger SmallPrimesProduct = new BigInteger(
+ "8138E8A0FCF3A4E84A771D40FD305D7F4AA59306D7251DE54D98AF8FE95729A1" +
+ "F73D893FA424CD2EDC8636A6C3285E022B0E3866A565AE8108EED8591CD4FE8D" +
+ "2CE86165A978D719EBF647F362D33FCA29CD179FB42401CBAF3DF0C614056F9C" +
+ "8F3CFD51E474AFB6BC6974F78DB8ABA8E9E517FDED658591AB7502BD41849462F",
+ 16);
+
+ private static BigInteger Validate(BigInteger modulus)
+ {
+ if ((modulus.IntValue & 1) == 0)
+ throw new ArgumentException("RSA modulus is even", "modulus");
+ if (!modulus.Gcd(SmallPrimesProduct).Equals(BigInteger.One))
+ throw new ArgumentException("RSA modulus has a small prime factor");
+
+ // TODO: add additional primePower/Composite test - expensive!!
+
+ return modulus;
+ }
+
+ private readonly BigInteger modulus;
+ private readonly BigInteger exponent;
+
+ public RsaKeyParameters(
+ bool isPrivate,
+ BigInteger modulus,
+ BigInteger exponent)
+ : base(isPrivate)
+ {
+ if (modulus == null)
+ throw new ArgumentNullException("modulus");
+ if (exponent == null)
+ throw new ArgumentNullException("exponent");
+ if (modulus.SignValue <= 0)
+ throw new ArgumentException("Not a valid RSA modulus", "modulus");
+ if (exponent.SignValue <= 0)
+ throw new ArgumentException("Not a valid RSA exponent", "exponent");
+ if (!isPrivate && (exponent.IntValue & 1) == 0)
+ throw new ArgumentException("RSA publicExponent is even", "exponent");
+
+ this.modulus = Validate(modulus);
+ this.exponent = exponent;
+ }
+
+ public BigInteger Modulus
+ {
+ get { return modulus; }
+ }
+
+ public BigInteger Exponent
+ {
+ get { return exponent; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ RsaKeyParameters kp = obj as RsaKeyParameters;
+
+ if (kp == null)
+ {
+ return false;
+ }
+
+ return kp.IsPrivate == this.IsPrivate
+ && kp.Modulus.Equals(this.modulus)
+ && kp.Exponent.Equals(this.exponent);
+ }
+
+ public override int GetHashCode()
+ {
+ return modulus.GetHashCode() ^ exponent.GetHashCode() ^ IsPrivate.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/RsaPrivateCrtKeyParameters.cs b/bc-sharp-crypto/src/crypto/parameters/RsaPrivateCrtKeyParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7bd8abd76b42a98edba3005e7e8fcdd20276a5b1
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/RsaPrivateCrtKeyParameters.cs
@@ -0,0 +1,104 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class RsaPrivateCrtKeyParameters
+ : RsaKeyParameters
+ {
+ private readonly BigInteger e, p, q, dP, dQ, qInv;
+
+ public RsaPrivateCrtKeyParameters(
+ BigInteger modulus,
+ BigInteger publicExponent,
+ BigInteger privateExponent,
+ BigInteger p,
+ BigInteger q,
+ BigInteger dP,
+ BigInteger dQ,
+ BigInteger qInv)
+ : base(true, modulus, privateExponent)
+ {
+ ValidateValue(publicExponent, "publicExponent", "exponent");
+ ValidateValue(p, "p", "P value");
+ ValidateValue(q, "q", "Q value");
+ ValidateValue(dP, "dP", "DP value");
+ ValidateValue(dQ, "dQ", "DQ value");
+ ValidateValue(qInv, "qInv", "InverseQ value");
+
+ this.e = publicExponent;
+ this.p = p;
+ this.q = q;
+ this.dP = dP;
+ this.dQ = dQ;
+ this.qInv = qInv;
+ }
+
+ public BigInteger PublicExponent
+ {
+ get { return e; }
+ }
+
+ public BigInteger P
+ {
+ get { return p; }
+ }
+
+ public BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public BigInteger DP
+ {
+ get { return dP; }
+ }
+
+ public BigInteger DQ
+ {
+ get { return dQ; }
+ }
+
+ public BigInteger QInv
+ {
+ get { return qInv; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ RsaPrivateCrtKeyParameters kp = obj as RsaPrivateCrtKeyParameters;
+
+ if (kp == null)
+ return false;
+
+ return kp.DP.Equals(dP)
+ && kp.DQ.Equals(dQ)
+ && kp.Exponent.Equals(this.Exponent)
+ && kp.Modulus.Equals(this.Modulus)
+ && kp.P.Equals(p)
+ && kp.Q.Equals(q)
+ && kp.PublicExponent.Equals(e)
+ && kp.QInv.Equals(qInv);
+ }
+
+ public override int GetHashCode()
+ {
+ return DP.GetHashCode() ^ DQ.GetHashCode() ^ Exponent.GetHashCode() ^ Modulus.GetHashCode()
+ ^ P.GetHashCode() ^ Q.GetHashCode() ^ PublicExponent.GetHashCode() ^ QInv.GetHashCode();
+ }
+
+ private static void ValidateValue(BigInteger x, string name, string desc)
+ {
+ if (x == null)
+ throw new ArgumentNullException(name);
+ if (x.SignValue <= 0)
+ throw new ArgumentException("Not a valid RSA " + desc, name);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/SkeinParameters.cs b/bc-sharp-crypto/src/crypto/parameters/SkeinParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cc57ef5ff1a0016969c00cd3da3293f6f90a70de
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/SkeinParameters.cs
@@ -0,0 +1,286 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+
+ ///
+ /// Parameters for the Skein hash function - a series of byte[] strings identified by integer tags.
+ ///
+ ///
+ /// Parameterised Skein can be used for:
+ ///
+ /// MAC generation, by providing a key .
+ /// Randomised hashing, by providing a nonce .
+ /// A hash function for digital signatures, associating a
+ /// public key with the message digest.
+ /// A key derivation function, by providing a
+ /// key identifier .
+ /// Personalised hashing, by providing a
+ /// recommended format or
+ /// arbitrary personalisation string.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public class SkeinParameters
+ : ICipherParameters
+ {
+ ///
+ /// The parameter type for a secret key, supporting MAC or KDF functions: 0
+ ///
+ public const int PARAM_TYPE_KEY = 0;
+
+ ///
+ /// The parameter type for the Skein configuration block: 4
+ ///
+ public const int PARAM_TYPE_CONFIG = 4;
+
+ ///
+ /// The parameter type for a personalisation string: 8
+ ///
+ public const int PARAM_TYPE_PERSONALISATION = 8;
+
+ ///
+ /// The parameter type for a public key: 12
+ ///
+ public const int PARAM_TYPE_PUBLIC_KEY = 12;
+
+ ///
+ /// The parameter type for a key identifier string: 16
+ ///
+ public const int PARAM_TYPE_KEY_IDENTIFIER = 16;
+
+ ///
+ /// The parameter type for a nonce: 20
+ ///
+ public const int PARAM_TYPE_NONCE = 20;
+
+ ///
+ /// The parameter type for the message: 48
+ ///
+ public const int PARAM_TYPE_MESSAGE = 48;
+
+ ///
+ /// The parameter type for the output transformation: 63
+ ///
+ public const int PARAM_TYPE_OUTPUT = 63;
+
+ private IDictionary parameters;
+
+ public SkeinParameters()
+ : this(Platform.CreateHashtable())
+
+ {
+ }
+
+ private SkeinParameters(IDictionary parameters)
+ {
+ this.parameters = parameters;
+ }
+
+ ///
+ /// Obtains a map of type (int) to value (byte[]) for the parameters tracked in this object.
+ ///
+ public IDictionary GetParameters()
+ {
+ return parameters;
+ }
+
+ ///
+ /// Obtains the value of the key parameter , or null
if not
+ /// set.
+ ///
+ /// The key.
+ public byte[] GetKey()
+ {
+ return (byte[])parameters[PARAM_TYPE_KEY];
+ }
+
+ ///
+ /// Obtains the value of the personalisation parameter , or
+ /// null
if not set.
+ ///
+ public byte[] GetPersonalisation()
+ {
+ return (byte[])parameters[PARAM_TYPE_PERSONALISATION];
+ }
+
+ ///
+ /// Obtains the value of the public key parameter , or
+ /// null
if not set.
+ ///
+ public byte[] GetPublicKey()
+ {
+ return (byte[])parameters[PARAM_TYPE_PUBLIC_KEY];
+ }
+
+ ///
+ /// Obtains the value of the key identifier parameter , or
+ /// null
if not set.
+ ///
+ public byte[] GetKeyIdentifier()
+ {
+ return (byte[])parameters[PARAM_TYPE_KEY_IDENTIFIER];
+ }
+
+ ///
+ /// Obtains the value of the nonce parameter , or null
if
+ /// not set.
+ ///
+ public byte[] GetNonce()
+ {
+ return (byte[])parameters[PARAM_TYPE_NONCE];
+ }
+
+ ///
+ /// A builder for .
+ ///
+ public class Builder
+ {
+ private IDictionary parameters = Platform.CreateHashtable();
+
+ public Builder()
+ {
+ }
+
+ public Builder(IDictionary paramsMap)
+ {
+ IEnumerator keys = paramsMap.Keys.GetEnumerator();
+ while (keys.MoveNext())
+ {
+ int key = (int)keys.Current;
+ parameters.Add(key, paramsMap[key]);
+ }
+ }
+
+ public Builder(SkeinParameters parameters)
+ {
+ IEnumerator keys = parameters.parameters.Keys.GetEnumerator();
+ while (keys.MoveNext())
+ {
+ int key = (int)keys.Current;
+ this.parameters.Add(key, parameters.parameters[key]);
+ }
+ }
+
+ ///
+ /// Sets a parameters to apply to the Skein hash function.
+ ///
+ ///
+ /// Parameter types must be in the range 0,5..62, and cannot use the value 48
+ /// (reserved for message body).
+ ///
+ /// Parameters with type < 48 are processed before
+ /// the message content, parameters with type > 48
+ /// are processed after the message and prior to output.
+ ///
+ /// the type of the parameter, in the range 5..62.
+ /// the byte sequence of the parameter.
+ public Builder Set(int type, byte[] value)
+ {
+ if (value == null)
+ {
+ throw new ArgumentException("Parameter value must not be null.");
+ }
+ if ((type != PARAM_TYPE_KEY)
+ && (type <= PARAM_TYPE_CONFIG || type >= PARAM_TYPE_OUTPUT || type == PARAM_TYPE_MESSAGE))
+ {
+ throw new ArgumentException("Parameter types must be in the range 0,5..47,49..62.");
+ }
+ if (type == PARAM_TYPE_CONFIG)
+ {
+ throw new ArgumentException("Parameter type " + PARAM_TYPE_CONFIG
+ + " is reserved for internal use.");
+ }
+ this.parameters.Add(type, value);
+ return this;
+ }
+
+ ///
+ /// Sets the parameter.
+ ///
+ public Builder SetKey(byte[] key)
+ {
+ return Set(PARAM_TYPE_KEY, key);
+ }
+
+ ///
+ /// Sets the parameter.
+ ///
+ public Builder SetPersonalisation(byte[] personalisation)
+ {
+ return Set(PARAM_TYPE_PERSONALISATION, personalisation);
+ }
+
+ ///
+ /// Implements the recommended personalisation format for Skein defined in Section 4.11 of
+ /// the Skein 1.3 specification.
+ ///
+ ///
+ /// The format is YYYYMMDD email@address distinguisher
, encoded to a byte
+ /// sequence using UTF-8 encoding.
+ ///
+ /// the date the personalised application of the Skein was defined.
+ /// the email address of the creation of the personalised application.
+ /// an arbitrary personalisation string distinguishing the application.
+ public Builder SetPersonalisation(DateTime date, string emailAddress, string distinguisher)
+ {
+ try
+ {
+ MemoryStream bout = new MemoryStream();
+ StreamWriter outBytes = new StreamWriter(bout, System.Text.Encoding.UTF8);
+ outBytes.Write(date.ToString("YYYYMMDD", CultureInfo.InvariantCulture));
+ outBytes.Write(" ");
+ outBytes.Write(emailAddress);
+ outBytes.Write(" ");
+ outBytes.Write(distinguisher);
+ Platform.Dispose(outBytes);
+ return Set(PARAM_TYPE_PERSONALISATION, bout.ToArray());
+ }
+ catch (IOException e)
+ {
+ throw new InvalidOperationException("Byte I/O failed.", e);
+ }
+ }
+
+ ///
+ /// Sets the parameter.
+ ///
+ public Builder SetPublicKey(byte[] publicKey)
+ {
+ return Set(PARAM_TYPE_PUBLIC_KEY, publicKey);
+ }
+
+ ///
+ /// Sets the parameter.
+ ///
+ public Builder SetKeyIdentifier(byte[] keyIdentifier)
+ {
+ return Set(PARAM_TYPE_KEY_IDENTIFIER, keyIdentifier);
+ }
+
+ ///
+ /// Sets the parameter.
+ ///
+ public Builder SetNonce(byte[] nonce)
+ {
+ return Set(PARAM_TYPE_NONCE, nonce);
+ }
+
+ ///
+ /// Constructs a new instance with the parameters provided to this
+ /// builder.
+ ///
+ public SkeinParameters Build()
+ {
+ return new SkeinParameters(parameters);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/crypto/parameters/Srp6GroupParameters.cs b/bc-sharp-crypto/src/crypto/parameters/Srp6GroupParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6762dd31dcdeb2c658876e84a79a2e3228dd6952
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/Srp6GroupParameters.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public sealed class Srp6GroupParameters
+ {
+ private readonly BigInteger n, g;
+
+ public Srp6GroupParameters(BigInteger N, BigInteger g)
+ {
+ this.n = N;
+ this.g = g;
+ }
+
+ public BigInteger G
+ {
+ get { return g; }
+ }
+
+ public BigInteger N
+ {
+ get { return n; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/parameters/TweakableBlockCipherParameters.cs b/bc-sharp-crypto/src/crypto/parameters/TweakableBlockCipherParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f757266001d3e13d2697bd93a90be0240fe3f55d
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/parameters/TweakableBlockCipherParameters.cs
@@ -0,0 +1,40 @@
+using System;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+
+ ///
+ /// Parameters for tweakable block ciphers.
+ ///
+ public class TweakableBlockCipherParameters
+ : ICipherParameters
+ {
+ private readonly byte[] tweak;
+ private readonly KeyParameter key;
+
+ public TweakableBlockCipherParameters(KeyParameter key, byte[] tweak)
+ {
+ this.key = key;
+ this.tweak = Arrays.Clone(tweak);
+ }
+
+ ///
+ /// Gets the key.
+ ///
+ /// the key to use, or null
to use the current key.
+ public KeyParameter Key
+ {
+ get { return key; }
+ }
+
+ ///
+ /// Gets the tweak value.
+ ///
+ /// The tweak to use, or null
to use the current tweak.
+ public byte[] Tweak
+ {
+ get { return tweak; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/crypto/prng/BasicEntropySourceProvider.cs b/bc-sharp-crypto/src/crypto/prng/BasicEntropySourceProvider.cs
new file mode 100644
index 0000000000000000000000000000000000000000..31a8461f0bce3b012e343787bb529d6a51e1c73b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/BasicEntropySourceProvider.cs
@@ -0,0 +1,71 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ /**
+ * An EntropySourceProvider where entropy generation is based on a SecureRandom output using SecureRandom.generateSeed().
+ */
+ public class BasicEntropySourceProvider
+ : IEntropySourceProvider
+ {
+ private readonly SecureRandom mSecureRandom;
+ private readonly bool mPredictionResistant;
+
+ /**
+ * Create a entropy source provider based on the passed in SecureRandom.
+ *
+ * @param secureRandom the SecureRandom to base EntropySource construction on.
+ * @param isPredictionResistant boolean indicating if the SecureRandom is based on prediction resistant entropy or not (true if it is).
+ */
+ public BasicEntropySourceProvider(SecureRandom secureRandom, bool isPredictionResistant)
+ {
+ mSecureRandom = secureRandom;
+ mPredictionResistant = isPredictionResistant;
+ }
+
+ /**
+ * Return an entropy source that will create bitsRequired bits of entropy on
+ * each invocation of getEntropy().
+ *
+ * @param bitsRequired size (in bits) of entropy to be created by the provided source.
+ * @return an EntropySource that generates bitsRequired bits of entropy on each call to its getEntropy() method.
+ */
+ public IEntropySource Get(int bitsRequired)
+ {
+ return new BasicEntropySource(mSecureRandom, mPredictionResistant, bitsRequired);
+ }
+
+ private class BasicEntropySource
+ : IEntropySource
+ {
+ private readonly SecureRandom mSecureRandom;
+ private readonly bool mPredictionResistant;
+ private readonly int mEntropySize;
+
+ internal BasicEntropySource(SecureRandom secureRandom, bool predictionResistant, int entropySize)
+ {
+ this.mSecureRandom = secureRandom;
+ this.mPredictionResistant = predictionResistant;
+ this.mEntropySize = entropySize;
+ }
+
+ bool IEntropySource.IsPredictionResistant
+ {
+ get { return mPredictionResistant; }
+ }
+
+ byte[] IEntropySource.GetEntropy()
+ {
+ // TODO[FIPS] Not all SecureRandom implementations are considered valid entropy sources
+ return SecureRandom.GetNextBytes(mSecureRandom, (mEntropySize + 7) / 8);
+ }
+
+ int IEntropySource.EntropySize
+ {
+ get { return mEntropySize; }
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs b/bc-sharp-crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs
new file mode 100644
index 0000000000000000000000000000000000000000..68579aaf4dda4f04a16d4cd51da3e84bedc4d186
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs
@@ -0,0 +1,70 @@
+#if !(NETCF_1_0 || PORTABLE)
+using System;
+using System.Security.Cryptography;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public class CryptoApiEntropySourceProvider
+ : IEntropySourceProvider
+ {
+ private readonly RandomNumberGenerator mRng;
+ private readonly bool mPredictionResistant;
+
+ public CryptoApiEntropySourceProvider()
+ : this(new RNGCryptoServiceProvider(), true)
+ {
+ }
+
+ public CryptoApiEntropySourceProvider(RandomNumberGenerator rng, bool isPredictionResistant)
+ {
+ if (rng == null)
+ throw new ArgumentNullException("rng");
+
+ mRng = rng;
+ mPredictionResistant = isPredictionResistant;
+ }
+
+ public IEntropySource Get(int bitsRequired)
+ {
+ return new CryptoApiEntropySource(mRng, mPredictionResistant, bitsRequired);
+ }
+
+ private class CryptoApiEntropySource
+ : IEntropySource
+ {
+ private readonly RandomNumberGenerator mRng;
+ private readonly bool mPredictionResistant;
+ private readonly int mEntropySize;
+
+ internal CryptoApiEntropySource(RandomNumberGenerator rng, bool predictionResistant, int entropySize)
+ {
+ this.mRng = rng;
+ this.mPredictionResistant = predictionResistant;
+ this.mEntropySize = entropySize;
+ }
+
+ #region IEntropySource Members
+
+ bool IEntropySource.IsPredictionResistant
+ {
+ get { return mPredictionResistant; }
+ }
+
+ byte[] IEntropySource.GetEntropy()
+ {
+ byte[] result = new byte[(mEntropySize + 7) / 8];
+ mRng.GetBytes(result);
+ return result;
+ }
+
+ int IEntropySource.EntropySize
+ {
+ get { return mEntropySize; }
+ }
+
+ #endregion
+ }
+ }
+}
+
+#endif
diff --git a/bc-sharp-crypto/src/crypto/prng/CryptoApiRandomGenerator.cs b/bc-sharp-crypto/src/crypto/prng/CryptoApiRandomGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fa5f523d3b0e4efd9fb757867fa3f49aa6e83e2a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/CryptoApiRandomGenerator.cs
@@ -0,0 +1,66 @@
+#if !(NETCF_1_0 || PORTABLE)
+
+using System;
+using System.Security.Cryptography;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ ///
+ /// Uses Microsoft's RNGCryptoServiceProvider
+ ///
+ public class CryptoApiRandomGenerator
+ : IRandomGenerator
+ {
+ private readonly RandomNumberGenerator rndProv;
+
+ public CryptoApiRandomGenerator()
+ : this(new RNGCryptoServiceProvider())
+ {
+ }
+
+ public CryptoApiRandomGenerator(RandomNumberGenerator rng)
+ {
+ this.rndProv = rng;
+ }
+
+ #region IRandomGenerator Members
+
+ public virtual void AddSeedMaterial(byte[] seed)
+ {
+ // We don't care about the seed
+ }
+
+ public virtual void AddSeedMaterial(long seed)
+ {
+ // We don't care about the seed
+ }
+
+ public virtual void NextBytes(byte[] bytes)
+ {
+ rndProv.GetBytes(bytes);
+ }
+
+ public virtual void NextBytes(byte[] bytes, int start, int len)
+ {
+ if (start < 0)
+ throw new ArgumentException("Start offset cannot be negative", "start");
+ if (bytes.Length < (start + len))
+ throw new ArgumentException("Byte array too small for requested offset and length");
+
+ if (bytes.Length == len && start == 0)
+ {
+ NextBytes(bytes);
+ }
+ else
+ {
+ byte[] tmpBuf = new byte[len];
+ NextBytes(tmpBuf);
+ Array.Copy(tmpBuf, 0, bytes, start, len);
+ }
+ }
+
+ #endregion
+ }
+}
+
+#endif
diff --git a/bc-sharp-crypto/src/crypto/prng/DigestRandomGenerator.cs b/bc-sharp-crypto/src/crypto/prng/DigestRandomGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f5a29952a11c4b4696bc890029671ec09c4c5669
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/DigestRandomGenerator.cs
@@ -0,0 +1,127 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ /**
+ * Random generation based on the digest with counter. Calling AddSeedMaterial will
+ * always increase the entropy of the hash.
+ *
+ * Internal access to the digest is synchronized so a single one of these can be shared.
+ *
+ */
+ public class DigestRandomGenerator
+ : IRandomGenerator
+ {
+ private const long CYCLE_COUNT = 10;
+
+ private long stateCounter;
+ private long seedCounter;
+ private IDigest digest;
+ private byte[] state;
+ private byte[] seed;
+
+ public DigestRandomGenerator(
+ IDigest digest)
+ {
+ this.digest = digest;
+
+ this.seed = new byte[digest.GetDigestSize()];
+ this.seedCounter = 1;
+
+ this.state = new byte[digest.GetDigestSize()];
+ this.stateCounter = 1;
+ }
+
+ public void AddSeedMaterial(
+ byte[] inSeed)
+ {
+ lock (this)
+ {
+ DigestUpdate(inSeed);
+ DigestUpdate(seed);
+ DigestDoFinal(seed);
+ }
+ }
+
+ public void AddSeedMaterial(
+ long rSeed)
+ {
+ lock (this)
+ {
+ DigestAddCounter(rSeed);
+ DigestUpdate(seed);
+ DigestDoFinal(seed);
+ }
+ }
+
+ public void NextBytes(
+ byte[] bytes)
+ {
+ NextBytes(bytes, 0, bytes.Length);
+ }
+
+ public void NextBytes(
+ byte[] bytes,
+ int start,
+ int len)
+ {
+ lock (this)
+ {
+ int stateOff = 0;
+
+ GenerateState();
+
+ int end = start + len;
+ for (int i = start; i < end; ++i)
+ {
+ if (stateOff == state.Length)
+ {
+ GenerateState();
+ stateOff = 0;
+ }
+ bytes[i] = state[stateOff++];
+ }
+ }
+ }
+
+ private void CycleSeed()
+ {
+ DigestUpdate(seed);
+ DigestAddCounter(seedCounter++);
+ DigestDoFinal(seed);
+ }
+
+ private void GenerateState()
+ {
+ DigestAddCounter(stateCounter++);
+ DigestUpdate(state);
+ DigestUpdate(seed);
+ DigestDoFinal(state);
+
+ if ((stateCounter % CYCLE_COUNT) == 0)
+ {
+ CycleSeed();
+ }
+ }
+
+ private void DigestAddCounter(long seedVal)
+ {
+ byte[] bytes = new byte[8];
+ Pack.UInt64_To_LE((ulong)seedVal, bytes);
+ digest.BlockUpdate(bytes, 0, bytes.Length);
+ }
+
+ private void DigestUpdate(byte[] inSeed)
+ {
+ digest.BlockUpdate(inSeed, 0, inSeed.Length);
+ }
+
+ private void DigestDoFinal(byte[] result)
+ {
+ digest.DoFinal(result, 0);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/prng/EntropyUtilities.cs b/bc-sharp-crypto/src/crypto/prng/EntropyUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..58c8703f4e85091d8171dc9e87fd4cc778744cde
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/EntropyUtilities.cs
@@ -0,0 +1,30 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public abstract class EntropyUtilities
+ {
+ /**
+ * Generate numBytes worth of entropy from the passed in entropy source.
+ *
+ * @param entropySource the entropy source to request the data from.
+ * @param numBytes the number of bytes of entropy requested.
+ * @return a byte array populated with the random data.
+ */
+ public static byte[] GenerateSeed(IEntropySource entropySource, int numBytes)
+ {
+ byte[] bytes = new byte[numBytes];
+ int count = 0;
+ while (count < numBytes)
+ {
+ byte[] entropy = entropySource.GetEntropy();
+ int toCopy = System.Math.Min(bytes.Length, numBytes - count);
+ Array.Copy(entropy, 0, bytes, count, toCopy);
+ count += toCopy;
+ }
+ return bytes;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/prng/IDrbgProvider.cs b/bc-sharp-crypto/src/crypto/prng/IDrbgProvider.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5ebf5fd8dfb16887f0d648990e7f247349b7d345
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/IDrbgProvider.cs
@@ -0,0 +1,11 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Prng.Drbg;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ internal interface IDrbgProvider
+ {
+ ISP80090Drbg Get(IEntropySource entropySource);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/prng/IRandomGenerator.cs b/bc-sharp-crypto/src/crypto/prng/IRandomGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8dbe4068f729b8a215963ed04b8fbc8f6321a011
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/IRandomGenerator.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ /// Generic interface for objects generating random bytes.
+ public interface IRandomGenerator
+ {
+ /// Add more seed material to the generator.
+ /// A byte array to be mixed into the generator's state.
+ void AddSeedMaterial(byte[] seed);
+
+ /// Add more seed material to the generator.
+ /// A long value to be mixed into the generator's state.
+ void AddSeedMaterial(long seed);
+
+ /// Fill byte array with random values.
+ /// Array to be filled.
+ void NextBytes(byte[] bytes);
+
+ /// Fill byte array with random values.
+ /// Array to receive bytes.
+ /// Index to start filling at.
+ /// Length of segment to fill.
+ void NextBytes(byte[] bytes, int start, int len);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/prng/ReversedWindowGenerator.cs b/bc-sharp-crypto/src/crypto/prng/ReversedWindowGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..dd28c525a24b43b7dbbc690bda2ced4d6569c4d0
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/ReversedWindowGenerator.cs
@@ -0,0 +1,98 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ ///
+ /// Takes bytes generated by an underling RandomGenerator and reverses the order in
+ /// each small window (of configurable size).
+ ///
+ /// Access to internals is synchronized so a single one of these can be shared.
+ ///
+ ///
+ public class ReversedWindowGenerator
+ : IRandomGenerator
+ {
+ private readonly IRandomGenerator generator;
+
+ private byte[] window;
+ private int windowCount;
+
+ public ReversedWindowGenerator(
+ IRandomGenerator generator,
+ int windowSize)
+ {
+ if (generator == null)
+ throw new ArgumentNullException("generator");
+ if (windowSize < 2)
+ throw new ArgumentException("Window size must be at least 2", "windowSize");
+
+ this.generator = generator;
+ this.window = new byte[windowSize];
+ }
+
+ /// Add more seed material to the generator.
+ /// A byte array to be mixed into the generator's state.
+ public virtual void AddSeedMaterial(
+ byte[] seed)
+ {
+ lock (this)
+ {
+ windowCount = 0;
+ generator.AddSeedMaterial(seed);
+ }
+ }
+
+ /// Add more seed material to the generator.
+ /// A long value to be mixed into the generator's state.
+ public virtual void AddSeedMaterial(
+ long seed)
+ {
+ lock (this)
+ {
+ windowCount = 0;
+ generator.AddSeedMaterial(seed);
+ }
+ }
+
+ /// Fill byte array with random values.
+ /// Array to be filled.
+ public virtual void NextBytes(
+ byte[] bytes)
+ {
+ doNextBytes(bytes, 0, bytes.Length);
+ }
+
+ /// Fill byte array with random values.
+ /// Array to receive bytes.
+ /// Index to start filling at.
+ /// Length of segment to fill.
+ public virtual void NextBytes(
+ byte[] bytes,
+ int start,
+ int len)
+ {
+ doNextBytes(bytes, start, len);
+ }
+
+ private void doNextBytes(
+ byte[] bytes,
+ int start,
+ int len)
+ {
+ lock (this)
+ {
+ int done = 0;
+ while (done < len)
+ {
+ if (windowCount < 1)
+ {
+ generator.NextBytes(window, 0, window.Length);
+ windowCount = window.Length;
+ }
+
+ bytes[start + done++] = window[--windowCount];
+ }
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/prng/SP800SecureRandom.cs b/bc-sharp-crypto/src/crypto/prng/SP800SecureRandom.cs
new file mode 100644
index 0000000000000000000000000000000000000000..30c838c1ba07bcb59b35afc02bd004f6c964a588
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/SP800SecureRandom.cs
@@ -0,0 +1,95 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Prng.Drbg;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public class SP800SecureRandom
+ : SecureRandom
+ {
+ private readonly IDrbgProvider mDrbgProvider;
+ private readonly bool mPredictionResistant;
+ private readonly SecureRandom mRandomSource;
+ private readonly IEntropySource mEntropySource;
+
+ private ISP80090Drbg mDrbg;
+
+ internal SP800SecureRandom(SecureRandom randomSource, IEntropySource entropySource, IDrbgProvider drbgProvider, bool predictionResistant)
+ : base((IRandomGenerator)null)
+ {
+ this.mRandomSource = randomSource;
+ this.mEntropySource = entropySource;
+ this.mDrbgProvider = drbgProvider;
+ this.mPredictionResistant = predictionResistant;
+ }
+
+ public override void SetSeed(byte[] seed)
+ {
+ lock (this)
+ {
+ if (mRandomSource != null)
+ {
+ this.mRandomSource.SetSeed(seed);
+ }
+ }
+ }
+
+ public override void SetSeed(long seed)
+ {
+ lock (this)
+ {
+ // this will happen when SecureRandom() is created
+ if (mRandomSource != null)
+ {
+ this.mRandomSource.SetSeed(seed);
+ }
+ }
+ }
+
+ public override void NextBytes(byte[] bytes)
+ {
+ lock (this)
+ {
+ if (mDrbg == null)
+ {
+ mDrbg = mDrbgProvider.Get(mEntropySource);
+ }
+
+ // check if a reseed is required...
+ if (mDrbg.Generate(bytes, null, mPredictionResistant) < 0)
+ {
+ mDrbg.Reseed(null);
+ mDrbg.Generate(bytes, null, mPredictionResistant);
+ }
+ }
+ }
+
+ public override void NextBytes(byte[] buf, int off, int len)
+ {
+ byte[] bytes = new byte[len];
+ NextBytes(bytes);
+ Array.Copy(bytes, 0, buf, off, len);
+ }
+
+ public override byte[] GenerateSeed(int numBytes)
+ {
+ return EntropyUtilities.GenerateSeed(mEntropySource, numBytes);
+ }
+
+ /// Force a reseed of the DRBG.
+ /// optional additional input
+ public virtual void Reseed(byte[] additionalInput)
+ {
+ lock (this)
+ {
+ if (mDrbg == null)
+ {
+ mDrbg = mDrbgProvider.Get(mEntropySource);
+ }
+
+ mDrbg.Reseed(additionalInput);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/prng/SP800SecureRandomBuilder.cs b/bc-sharp-crypto/src/crypto/prng/SP800SecureRandomBuilder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7199f1ae7fd886822b545c3ceb87e25a6091e4b9
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/SP800SecureRandomBuilder.cs
@@ -0,0 +1,208 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Prng.Drbg;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ /**
+ * Builder class for making SecureRandom objects based on SP 800-90A Deterministic Random Bit Generators (DRBG).
+ */
+ public class SP800SecureRandomBuilder
+ {
+ private readonly SecureRandom mRandom;
+ private readonly IEntropySourceProvider mEntropySourceProvider;
+
+ private byte[] mPersonalizationString = null;
+ private int mSecurityStrength = 256;
+ private int mEntropyBitsRequired = 256;
+
+ /**
+ * Basic constructor, creates a builder using an EntropySourceProvider based on the default SecureRandom with
+ * predictionResistant set to false.
+ *
+ * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if
+ * the default SecureRandom does for its generateSeed() call.
+ *
+ */
+ public SP800SecureRandomBuilder()
+ : this(new SecureRandom(), false)
+ {
+ }
+
+ /**
+ * Construct a builder with an EntropySourceProvider based on the passed in SecureRandom and the passed in value
+ * for prediction resistance.
+ *
+ * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if
+ * the passed in SecureRandom does for its generateSeed() call.
+ *
+ * @param entropySource
+ * @param predictionResistant
+ */
+ public SP800SecureRandomBuilder(SecureRandom entropySource, bool predictionResistant)
+ {
+ this.mRandom = entropySource;
+ this.mEntropySourceProvider = new BasicEntropySourceProvider(entropySource, predictionResistant);
+ }
+
+ /**
+ * Create a builder which makes creates the SecureRandom objects from a specified entropy source provider.
+ *
+ * Note: If this constructor is used any calls to setSeed() in the resulting SecureRandom will be ignored.
+ *
+ * @param entropySourceProvider a provider of EntropySource objects.
+ */
+ public SP800SecureRandomBuilder(IEntropySourceProvider entropySourceProvider)
+ {
+ this.mRandom = null;
+ this.mEntropySourceProvider = entropySourceProvider;
+ }
+
+ /**
+ * Set the personalization string for DRBG SecureRandoms created by this builder
+ * @param personalizationString the personalisation string for the underlying DRBG.
+ * @return the current builder.
+ */
+ public SP800SecureRandomBuilder SetPersonalizationString(byte[] personalizationString)
+ {
+ this.mPersonalizationString = personalizationString;
+ return this;
+ }
+
+ /**
+ * Set the security strength required for DRBGs used in building SecureRandom objects.
+ *
+ * @param securityStrength the security strength (in bits)
+ * @return the current builder.
+ */
+ public SP800SecureRandomBuilder SetSecurityStrength(int securityStrength)
+ {
+ this.mSecurityStrength = securityStrength;
+ return this;
+ }
+
+ /**
+ * Set the amount of entropy bits required for seeding and reseeding DRBGs used in building SecureRandom objects.
+ *
+ * @param entropyBitsRequired the number of bits of entropy to be requested from the entropy source on each seed/reseed.
+ * @return the current builder.
+ */
+ public SP800SecureRandomBuilder SetEntropyBitsRequired(int entropyBitsRequired)
+ {
+ this.mEntropyBitsRequired = entropyBitsRequired;
+ return this;
+ }
+
+ /**
+ * Build a SecureRandom based on a SP 800-90A Hash DRBG.
+ *
+ * @param digest digest algorithm to use in the DRBG underneath the SecureRandom.
+ * @param nonce nonce value to use in DRBG construction.
+ * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes.
+ * @return a SecureRandom supported by a Hash DRBG.
+ */
+ public SP800SecureRandom BuildHash(IDigest digest, byte[] nonce, bool predictionResistant)
+ {
+ return new SP800SecureRandom(mRandom, mEntropySourceProvider.Get(mEntropyBitsRequired),
+ new HashDrbgProvider(digest, nonce, mPersonalizationString, mSecurityStrength), predictionResistant);
+ }
+
+ /**
+ * Build a SecureRandom based on a SP 800-90A CTR DRBG.
+ *
+ * @param cipher the block cipher to base the DRBG on.
+ * @param keySizeInBits key size in bits to be used with the block cipher.
+ * @param nonce nonce value to use in DRBG construction.
+ * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes.
+ * @return a SecureRandom supported by a CTR DRBG.
+ */
+ public SP800SecureRandom BuildCtr(IBlockCipher cipher, int keySizeInBits, byte[] nonce, bool predictionResistant)
+ {
+ return new SP800SecureRandom(mRandom, mEntropySourceProvider.Get(mEntropyBitsRequired),
+ new CtrDrbgProvider(cipher, keySizeInBits, nonce, mPersonalizationString, mSecurityStrength), predictionResistant);
+ }
+
+ /**
+ * Build a SecureRandom based on a SP 800-90A HMAC DRBG.
+ *
+ * @param hMac HMAC algorithm to use in the DRBG underneath the SecureRandom.
+ * @param nonce nonce value to use in DRBG construction.
+ * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes.
+ * @return a SecureRandom supported by a HMAC DRBG.
+ */
+ public SP800SecureRandom BuildHMac(IMac hMac, byte[] nonce, bool predictionResistant)
+ {
+ return new SP800SecureRandom(mRandom, mEntropySourceProvider.Get(mEntropyBitsRequired),
+ new HMacDrbgProvider(hMac, nonce, mPersonalizationString, mSecurityStrength), predictionResistant);
+ }
+
+ private class HashDrbgProvider
+ : IDrbgProvider
+ {
+ private readonly IDigest mDigest;
+ private readonly byte[] mNonce;
+ private readonly byte[] mPersonalizationString;
+ private readonly int mSecurityStrength;
+
+ public HashDrbgProvider(IDigest digest, byte[] nonce, byte[] personalizationString, int securityStrength)
+ {
+ this.mDigest = digest;
+ this.mNonce = nonce;
+ this.mPersonalizationString = personalizationString;
+ this.mSecurityStrength = securityStrength;
+ }
+
+ public ISP80090Drbg Get(IEntropySource entropySource)
+ {
+ return new HashSP800Drbg(mDigest, mSecurityStrength, entropySource, mPersonalizationString, mNonce);
+ }
+ }
+
+ private class HMacDrbgProvider
+ : IDrbgProvider
+ {
+ private readonly IMac mHMac;
+ private readonly byte[] mNonce;
+ private readonly byte[] mPersonalizationString;
+ private readonly int mSecurityStrength;
+
+ public HMacDrbgProvider(IMac hMac, byte[] nonce, byte[] personalizationString, int securityStrength)
+ {
+ this.mHMac = hMac;
+ this.mNonce = nonce;
+ this.mPersonalizationString = personalizationString;
+ this.mSecurityStrength = securityStrength;
+ }
+
+ public ISP80090Drbg Get(IEntropySource entropySource)
+ {
+ return new HMacSP800Drbg(mHMac, mSecurityStrength, entropySource, mPersonalizationString, mNonce);
+ }
+ }
+
+ private class CtrDrbgProvider
+ : IDrbgProvider
+ {
+ private readonly IBlockCipher mBlockCipher;
+ private readonly int mKeySizeInBits;
+ private readonly byte[] mNonce;
+ private readonly byte[] mPersonalizationString;
+ private readonly int mSecurityStrength;
+
+ public CtrDrbgProvider(IBlockCipher blockCipher, int keySizeInBits, byte[] nonce, byte[] personalizationString, int securityStrength)
+ {
+ this.mBlockCipher = blockCipher;
+ this.mKeySizeInBits = keySizeInBits;
+ this.mNonce = nonce;
+ this.mPersonalizationString = personalizationString;
+ this.mSecurityStrength = securityStrength;
+ }
+
+ public ISP80090Drbg Get(IEntropySource entropySource)
+ {
+ return new CtrSP800Drbg(mBlockCipher, mKeySizeInBits, mSecurityStrength, entropySource, mPersonalizationString, mNonce);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/prng/ThreadedSeedGenerator.cs b/bc-sharp-crypto/src/crypto/prng/ThreadedSeedGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0a38e5f5a56cd8c7b99945d8b0753ad76f4d8e83
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/ThreadedSeedGenerator.cs
@@ -0,0 +1,129 @@
+using System;
+using System.Threading;
+
+#if NO_THREADS
+using System.Threading.Tasks;
+#endif
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ /**
+ * A thread based seed generator - one source of randomness.
+ *
+ * Based on an idea from Marcus Lippert.
+ *
+ */
+ public class ThreadedSeedGenerator
+ {
+ private class SeedGenerator
+ {
+#if NETCF_1_0
+ // No volatile keyword, but all fields implicitly volatile anyway
+ private int counter = 0;
+ private bool stop = false;
+#else
+ private volatile int counter = 0;
+ private volatile bool stop = false;
+#endif
+
+ private void Run(object ignored)
+ {
+ while (!this.stop)
+ {
+ this.counter++;
+ }
+ }
+
+ public byte[] GenerateSeed(
+ int numBytes,
+ bool fast)
+ {
+#if SILVERLIGHT || PORTABLE
+ return DoGenerateSeed(numBytes, fast);
+#else
+ ThreadPriority originalPriority = Thread.CurrentThread.Priority;
+ try
+ {
+ Thread.CurrentThread.Priority = ThreadPriority.Normal;
+ return DoGenerateSeed(numBytes, fast);
+ }
+ finally
+ {
+ Thread.CurrentThread.Priority = originalPriority;
+ }
+#endif
+ }
+
+ private byte[] DoGenerateSeed(
+ int numBytes,
+ bool fast)
+ {
+ this.counter = 0;
+ this.stop = false;
+
+ byte[] result = new byte[numBytes];
+ int last = 0;
+ int end = fast ? numBytes : numBytes * 8;
+
+#if NO_THREADS
+ Task.Factory.StartNew(() => Run(null), TaskCreationOptions.None);
+#else
+ ThreadPool.QueueUserWorkItem(new WaitCallback(Run));
+#endif
+
+ for (int i = 0; i < end; i++)
+ {
+ while (this.counter == last)
+ {
+ try
+ {
+#if PORTABLE
+ new AutoResetEvent(false).WaitOne(1);
+#else
+ Thread.Sleep(1);
+#endif
+ }
+ catch (Exception)
+ {
+ // ignore
+ }
+ }
+
+ last = this.counter;
+
+ if (fast)
+ {
+ result[i] = (byte)last;
+ }
+ else
+ {
+ int bytepos = i / 8;
+ result[bytepos] = (byte)((result[bytepos] << 1) | (last & 1));
+ }
+ }
+
+ this.stop = true;
+
+ return result;
+ }
+ }
+
+ /**
+ * Generate seed bytes. Set fast to false for best quality.
+ *
+ * If fast is set to true, the code should be round about 8 times faster when
+ * generating a long sequence of random bytes. 20 bytes of random values using
+ * the fast mode take less than half a second on a Nokia e70. If fast is set to false,
+ * it takes round about 2500 ms.
+ *
+ * @param numBytes the number of bytes to generate
+ * @param fast true if fast mode should be used
+ */
+ public byte[] GenerateSeed(
+ int numBytes,
+ bool fast)
+ {
+ return new SeedGenerator().GenerateSeed(numBytes, fast);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/prng/VMPCRandomGenerator.cs b/bc-sharp-crypto/src/crypto/prng/VMPCRandomGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..64f287d13992b06723c7460de2bbc6cde882449e
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/VMPCRandomGenerator.cs
@@ -0,0 +1,114 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public class VmpcRandomGenerator
+ : IRandomGenerator
+ {
+ private byte n = 0;
+
+ ///
+ /// Permutation generated by code:
+ ///
+ /// // First 1850 fractional digit of Pi number.
+ /// byte[] key = new BigInteger("14159265358979323846...5068006422512520511").ToByteArray();
+ /// s = 0;
+ /// P = new byte[256];
+ /// for (int i = 0; i < 256; i++)
+ /// {
+ /// P[i] = (byte) i;
+ /// }
+ /// for (int m = 0; m < 768; m++)
+ /// {
+ /// s = P[(s + P[m & 0xff] + key[m % key.length]) & 0xff];
+ /// byte temp = P[m & 0xff];
+ /// P[m & 0xff] = P[s & 0xff];
+ /// P[s & 0xff] = temp;
+ /// }
+ ///
+ private byte[] P =
+ {
+ (byte) 0xbb, (byte) 0x2c, (byte) 0x62, (byte) 0x7f, (byte) 0xb5, (byte) 0xaa, (byte) 0xd4,
+ (byte) 0x0d, (byte) 0x81, (byte) 0xfe, (byte) 0xb2, (byte) 0x82, (byte) 0xcb, (byte) 0xa0, (byte) 0xa1,
+ (byte) 0x08, (byte) 0x18, (byte) 0x71, (byte) 0x56, (byte) 0xe8, (byte) 0x49, (byte) 0x02, (byte) 0x10,
+ (byte) 0xc4, (byte) 0xde, (byte) 0x35, (byte) 0xa5, (byte) 0xec, (byte) 0x80, (byte) 0x12, (byte) 0xb8,
+ (byte) 0x69, (byte) 0xda, (byte) 0x2f, (byte) 0x75, (byte) 0xcc, (byte) 0xa2, (byte) 0x09, (byte) 0x36,
+ (byte) 0x03, (byte) 0x61, (byte) 0x2d, (byte) 0xfd, (byte) 0xe0, (byte) 0xdd, (byte) 0x05, (byte) 0x43,
+ (byte) 0x90, (byte) 0xad, (byte) 0xc8, (byte) 0xe1, (byte) 0xaf, (byte) 0x57, (byte) 0x9b, (byte) 0x4c,
+ (byte) 0xd8, (byte) 0x51, (byte) 0xae, (byte) 0x50, (byte) 0x85, (byte) 0x3c, (byte) 0x0a, (byte) 0xe4,
+ (byte) 0xf3, (byte) 0x9c, (byte) 0x26, (byte) 0x23, (byte) 0x53, (byte) 0xc9, (byte) 0x83, (byte) 0x97,
+ (byte) 0x46, (byte) 0xb1, (byte) 0x99, (byte) 0x64, (byte) 0x31, (byte) 0x77, (byte) 0xd5, (byte) 0x1d,
+ (byte) 0xd6, (byte) 0x78, (byte) 0xbd, (byte) 0x5e, (byte) 0xb0, (byte) 0x8a, (byte) 0x22, (byte) 0x38,
+ (byte) 0xf8, (byte) 0x68, (byte) 0x2b, (byte) 0x2a, (byte) 0xc5, (byte) 0xd3, (byte) 0xf7, (byte) 0xbc,
+ (byte) 0x6f, (byte) 0xdf, (byte) 0x04, (byte) 0xe5, (byte) 0x95, (byte) 0x3e, (byte) 0x25, (byte) 0x86,
+ (byte) 0xa6, (byte) 0x0b, (byte) 0x8f, (byte) 0xf1, (byte) 0x24, (byte) 0x0e, (byte) 0xd7, (byte) 0x40,
+ (byte) 0xb3, (byte) 0xcf, (byte) 0x7e, (byte) 0x06, (byte) 0x15, (byte) 0x9a, (byte) 0x4d, (byte) 0x1c,
+ (byte) 0xa3, (byte) 0xdb, (byte) 0x32, (byte) 0x92, (byte) 0x58, (byte) 0x11, (byte) 0x27, (byte) 0xf4,
+ (byte) 0x59, (byte) 0xd0, (byte) 0x4e, (byte) 0x6a, (byte) 0x17, (byte) 0x5b, (byte) 0xac, (byte) 0xff,
+ (byte) 0x07, (byte) 0xc0, (byte) 0x65, (byte) 0x79, (byte) 0xfc, (byte) 0xc7, (byte) 0xcd, (byte) 0x76,
+ (byte) 0x42, (byte) 0x5d, (byte) 0xe7, (byte) 0x3a, (byte) 0x34, (byte) 0x7a, (byte) 0x30, (byte) 0x28,
+ (byte) 0x0f, (byte) 0x73, (byte) 0x01, (byte) 0xf9, (byte) 0xd1, (byte) 0xd2, (byte) 0x19, (byte) 0xe9,
+ (byte) 0x91, (byte) 0xb9, (byte) 0x5a, (byte) 0xed, (byte) 0x41, (byte) 0x6d, (byte) 0xb4, (byte) 0xc3,
+ (byte) 0x9e, (byte) 0xbf, (byte) 0x63, (byte) 0xfa, (byte) 0x1f, (byte) 0x33, (byte) 0x60, (byte) 0x47,
+ (byte) 0x89, (byte) 0xf0, (byte) 0x96, (byte) 0x1a, (byte) 0x5f, (byte) 0x93, (byte) 0x3d, (byte) 0x37,
+ (byte) 0x4b, (byte) 0xd9, (byte) 0xa8, (byte) 0xc1, (byte) 0x1b, (byte) 0xf6, (byte) 0x39, (byte) 0x8b,
+ (byte) 0xb7, (byte) 0x0c, (byte) 0x20, (byte) 0xce, (byte) 0x88, (byte) 0x6e, (byte) 0xb6, (byte) 0x74,
+ (byte) 0x8e, (byte) 0x8d, (byte) 0x16, (byte) 0x29, (byte) 0xf2, (byte) 0x87, (byte) 0xf5, (byte) 0xeb,
+ (byte) 0x70, (byte) 0xe3, (byte) 0xfb, (byte) 0x55, (byte) 0x9f, (byte) 0xc6, (byte) 0x44, (byte) 0x4a,
+ (byte) 0x45, (byte) 0x7d, (byte) 0xe2, (byte) 0x6b, (byte) 0x5c, (byte) 0x6c, (byte) 0x66, (byte) 0xa9,
+ (byte) 0x8c, (byte) 0xee, (byte) 0x84, (byte) 0x13, (byte) 0xa7, (byte) 0x1e, (byte) 0x9d, (byte) 0xdc,
+ (byte) 0x67, (byte) 0x48, (byte) 0xba, (byte) 0x2e, (byte) 0xe6, (byte) 0xa4, (byte) 0xab, (byte) 0x7c,
+ (byte) 0x94, (byte) 0x00, (byte) 0x21, (byte) 0xef, (byte) 0xea, (byte) 0xbe, (byte) 0xca, (byte) 0x72,
+ (byte) 0x4f, (byte) 0x52, (byte) 0x98, (byte) 0x3f, (byte) 0xc2, (byte) 0x14, (byte) 0x7b, (byte) 0x3b,
+ (byte) 0x54
+ };
+
+ /// Value generated in the same way as P .
+ private byte s = (byte) 0xbe;
+
+ public VmpcRandomGenerator()
+ {
+ }
+
+ public virtual void AddSeedMaterial(byte[] seed)
+ {
+ for (int m = 0; m < seed.Length; m++)
+ {
+ s = P[(s + P[n & 0xff] + seed[m]) & 0xff];
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte) ((n + 1) & 0xff);
+ }
+ }
+
+ public virtual void AddSeedMaterial(long seed)
+ {
+ AddSeedMaterial(Pack.UInt64_To_BE((ulong)seed));
+ }
+
+ public virtual void NextBytes(byte[] bytes)
+ {
+ NextBytes(bytes, 0, bytes.Length);
+ }
+
+ public virtual void NextBytes(byte[] bytes, int start, int len)
+ {
+ lock (P)
+ {
+ int end = start + len;
+ for (int i = start; i != end; i++)
+ {
+ s = P[(s + P[n & 0xff]) & 0xff];
+ bytes[i] = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+ byte temp = P[n & 0xff];
+ P[n & 0xff] = P[s & 0xff];
+ P[s & 0xff] = temp;
+ n = (byte) ((n + 1) & 0xff);
+ }
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/prng/X931Rng.cs b/bc-sharp-crypto/src/crypto/prng/X931Rng.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2bd8e0c6b2ec3d7941c4250ce099fbf405c488aa
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/X931Rng.cs
@@ -0,0 +1,146 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ internal class X931Rng
+ {
+ private const long BLOCK64_RESEED_MAX = 1L << (16 - 1);
+ private const long BLOCK128_RESEED_MAX = 1L << (24 - 1);
+ private const int BLOCK64_MAX_BITS_REQUEST = 1 << (13 - 1);
+ private const int BLOCK128_MAX_BITS_REQUEST = 1 << (19 - 1);
+
+ private readonly IBlockCipher mEngine;
+ private readonly IEntropySource mEntropySource;
+
+ private readonly byte[] mDT;
+ private readonly byte[] mI;
+ private readonly byte[] mR;
+
+ private byte[] mV;
+
+ private long mReseedCounter = 1;
+
+ /**
+ *
+ * @param engine
+ * @param entropySource
+ */
+ internal X931Rng(IBlockCipher engine, byte[] dateTimeVector, IEntropySource entropySource)
+ {
+ this.mEngine = engine;
+ this.mEntropySource = entropySource;
+
+ this.mDT = new byte[engine.GetBlockSize()];
+
+ Array.Copy(dateTimeVector, 0, mDT, 0, mDT.Length);
+
+ this.mI = new byte[engine.GetBlockSize()];
+ this.mR = new byte[engine.GetBlockSize()];
+ }
+
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
+ internal int Generate(byte[] output, bool predictionResistant)
+ {
+ if (mR.Length == 8) // 64 bit block size
+ {
+ if (mReseedCounter > BLOCK64_RESEED_MAX)
+ return -1;
+
+ if (IsTooLarge(output, BLOCK64_MAX_BITS_REQUEST / 8))
+ throw new ArgumentException("Number of bits per request limited to " + BLOCK64_MAX_BITS_REQUEST, "output");
+ }
+ else
+ {
+ if (mReseedCounter > BLOCK128_RESEED_MAX)
+ return -1;
+
+ if (IsTooLarge(output, BLOCK128_MAX_BITS_REQUEST / 8))
+ throw new ArgumentException("Number of bits per request limited to " + BLOCK128_MAX_BITS_REQUEST, "output");
+ }
+
+ if (predictionResistant || mV == null)
+ {
+ mV = mEntropySource.GetEntropy();
+ if (mV.Length != mEngine.GetBlockSize())
+ throw new InvalidOperationException("Insufficient entropy returned");
+ }
+
+ int m = output.Length / mR.Length;
+
+ for (int i = 0; i < m; i++)
+ {
+ mEngine.ProcessBlock(mDT, 0, mI, 0);
+ Process(mR, mI, mV);
+ Process(mV, mR, mI);
+
+ Array.Copy(mR, 0, output, i * mR.Length, mR.Length);
+
+ Increment(mDT);
+ }
+
+ int bytesToCopy = (output.Length - m * mR.Length);
+
+ if (bytesToCopy > 0)
+ {
+ mEngine.ProcessBlock(mDT, 0, mI, 0);
+ Process(mR, mI, mV);
+ Process(mV, mR, mI);
+
+ Array.Copy(mR, 0, output, m * mR.Length, bytesToCopy);
+
+ Increment(mDT);
+ }
+
+ mReseedCounter++;
+
+ return output.Length;
+ }
+
+ /**
+ * Reseed the RNG.
+ */
+ internal void Reseed()
+ {
+ mV = mEntropySource.GetEntropy();
+ if (mV.Length != mEngine.GetBlockSize())
+ throw new InvalidOperationException("Insufficient entropy returned");
+ mReseedCounter = 1;
+ }
+
+ internal IEntropySource EntropySource
+ {
+ get { return mEntropySource; }
+ }
+
+ private void Process(byte[] res, byte[] a, byte[] b)
+ {
+ for (int i = 0; i != res.Length; i++)
+ {
+ res[i] = (byte)(a[i] ^ b[i]);
+ }
+
+ mEngine.ProcessBlock(res, 0, res, 0);
+ }
+
+ private void Increment(byte[] val)
+ {
+ for (int i = val.Length - 1; i >= 0; i--)
+ {
+ if (++val[i] != 0)
+ break;
+ }
+ }
+
+ private static bool IsTooLarge(byte[] bytes, int maxBytes)
+ {
+ return bytes != null && bytes.Length > maxBytes;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/prng/X931SecureRandom.cs b/bc-sharp-crypto/src/crypto/prng/X931SecureRandom.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d2e4849c5e263cf8107f7781381a1118c480f1ac
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/X931SecureRandom.cs
@@ -0,0 +1,70 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public class X931SecureRandom
+ : SecureRandom
+ {
+ private readonly bool mPredictionResistant;
+ private readonly SecureRandom mRandomSource;
+ private readonly X931Rng mDrbg;
+
+ internal X931SecureRandom(SecureRandom randomSource, X931Rng drbg, bool predictionResistant)
+ : base((IRandomGenerator)null)
+ {
+ this.mRandomSource = randomSource;
+ this.mDrbg = drbg;
+ this.mPredictionResistant = predictionResistant;
+ }
+
+ public override void SetSeed(byte[] seed)
+ {
+ lock (this)
+ {
+ if (mRandomSource != null)
+ {
+ this.mRandomSource.SetSeed(seed);
+ }
+ }
+ }
+
+ public override void SetSeed(long seed)
+ {
+ lock (this)
+ {
+ // this will happen when SecureRandom() is created
+ if (mRandomSource != null)
+ {
+ this.mRandomSource.SetSeed(seed);
+ }
+ }
+ }
+
+ public override void NextBytes(byte[] bytes)
+ {
+ lock (this)
+ {
+ // check if a reseed is required...
+ if (mDrbg.Generate(bytes, mPredictionResistant) < 0)
+ {
+ mDrbg.Reseed();
+ mDrbg.Generate(bytes, mPredictionResistant);
+ }
+ }
+ }
+
+ public override void NextBytes(byte[] buf, int off, int len)
+ {
+ byte[] bytes = new byte[len];
+ NextBytes(bytes);
+ Array.Copy(bytes, 0, buf, off, len);
+ }
+
+ public override byte[] GenerateSeed(int numBytes)
+ {
+ return EntropyUtilities.GenerateSeed(mDrbg.EntropySource, numBytes);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/prng/X931SecureRandomBuilder.cs b/bc-sharp-crypto/src/crypto/prng/X931SecureRandomBuilder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..31e94312e552c87c4c41dd488aedeb52b209cd48
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/X931SecureRandomBuilder.cs
@@ -0,0 +1,87 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+ public class X931SecureRandomBuilder
+ {
+ private readonly SecureRandom mRandom; // JDK 1.1 complains on final.
+
+ private IEntropySourceProvider mEntropySourceProvider;
+ private byte[] mDateTimeVector;
+
+ /**
+ * Basic constructor, creates a builder using an EntropySourceProvider based on the default SecureRandom with
+ * predictionResistant set to false.
+ *
+ * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if
+ * the default SecureRandom does for its generateSeed() call.
+ *
+ */
+ public X931SecureRandomBuilder()
+ : this(new SecureRandom(), false)
+ {
+ }
+
+ /**
+ * Construct a builder with an EntropySourceProvider based on the passed in SecureRandom and the passed in value
+ * for prediction resistance.
+ *
+ * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if
+ * the passed in SecureRandom does for its generateSeed() call.
+ *
+ * @param entropySource
+ * @param predictionResistant
+ */
+ public X931SecureRandomBuilder(SecureRandom entropySource, bool predictionResistant)
+ {
+ this.mRandom = entropySource;
+ this.mEntropySourceProvider = new BasicEntropySourceProvider(mRandom, predictionResistant);
+ }
+
+ /**
+ * Create a builder which makes creates the SecureRandom objects from a specified entropy source provider.
+ *
+ * Note: If this constructor is used any calls to setSeed() in the resulting SecureRandom will be ignored.
+ *
+ * @param entropySourceProvider a provider of EntropySource objects.
+ */
+ public X931SecureRandomBuilder(IEntropySourceProvider entropySourceProvider)
+ {
+ this.mRandom = null;
+ this.mEntropySourceProvider = entropySourceProvider;
+ }
+
+ public X931SecureRandomBuilder SetDateTimeVector(byte[] dateTimeVector)
+ {
+ this.mDateTimeVector = dateTimeVector;
+ return this;
+ }
+
+ /**
+ * Construct a X9.31 secure random generator using the passed in engine and key. If predictionResistant is true the
+ * generator will be reseeded on each request.
+ *
+ * @param engine a block cipher to use as the operator.
+ * @param key the block cipher key to initialise engine with.
+ * @param predictionResistant true if engine to be reseeded on each use, false otherwise.
+ * @return a SecureRandom.
+ */
+ public X931SecureRandom Build(IBlockCipher engine, KeyParameter key, bool predictionResistant)
+ {
+ if (mDateTimeVector == null)
+ {
+ mDateTimeVector = new byte[engine.GetBlockSize()];
+ Pack.UInt64_To_BE((ulong)DateTimeUtilities.CurrentUnixMs(), mDateTimeVector, 0);
+ }
+
+ engine.Init(true, key);
+
+ return new X931SecureRandom(mRandom, new X931Rng(engine, mDateTimeVector, mEntropySourceProvider.Get(engine.GetBlockSize() * 8)), predictionResistant);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs b/bc-sharp-crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs
new file mode 100644
index 0000000000000000000000000000000000000000..eca1821d3a4998cfb5364ac34670ad1349fb00aa
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/drbg/CtrSP800Drbg.cs
@@ -0,0 +1,466 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Prng.Drbg
+{
+ /**
+ * A SP800-90A CTR DRBG.
+ */
+ public class CtrSP800Drbg
+ : ISP80090Drbg
+ {
+ private static readonly long TDEA_RESEED_MAX = 1L << (32 - 1);
+ private static readonly long AES_RESEED_MAX = 1L << (48 - 1);
+ private static readonly int TDEA_MAX_BITS_REQUEST = 1 << (13 - 1);
+ private static readonly int AES_MAX_BITS_REQUEST = 1 << (19 - 1);
+
+ private readonly IEntropySource mEntropySource;
+ private readonly IBlockCipher mEngine;
+ private readonly int mKeySizeInBits;
+ private readonly int mSeedLength;
+ private readonly int mSecurityStrength;
+
+ // internal state
+ private byte[] mKey;
+ private byte[] mV;
+ private long mReseedCounter = 0;
+ private bool mIsTdea = false;
+
+ /**
+ * Construct a SP800-90A CTR DRBG.
+ *
+ * Minimum entropy requirement is the security strength requested.
+ *
+ * @param engine underlying block cipher to use to support DRBG
+ * @param keySizeInBits size of the key to use with the block cipher.
+ * @param securityStrength security strength required (in bits)
+ * @param entropySource source of entropy to use for seeding/reseeding.
+ * @param personalizationString personalization string to distinguish this DRBG (may be null).
+ * @param nonce nonce to further distinguish this DRBG (may be null).
+ */
+ public CtrSP800Drbg(IBlockCipher engine, int keySizeInBits, int securityStrength, IEntropySource entropySource,
+ byte[] personalizationString, byte[] nonce)
+ {
+ if (securityStrength > 256)
+ throw new ArgumentException("Requested security strength is not supported by the derivation function");
+ if (GetMaxSecurityStrength(engine, keySizeInBits) < securityStrength)
+ throw new ArgumentException("Requested security strength is not supported by block cipher and key size");
+ if (entropySource.EntropySize < securityStrength)
+ throw new ArgumentException("Not enough entropy for security strength required");
+
+ mEntropySource = entropySource;
+ mEngine = engine;
+
+ mKeySizeInBits = keySizeInBits;
+ mSecurityStrength = securityStrength;
+ mSeedLength = keySizeInBits + engine.GetBlockSize() * 8;
+ mIsTdea = IsTdea(engine);
+
+ byte[] entropy = GetEntropy(); // Get_entropy_input
+
+ CTR_DRBG_Instantiate_algorithm(entropy, nonce, personalizationString);
+ }
+
+ private void CTR_DRBG_Instantiate_algorithm(byte[] entropy, byte[] nonce, byte[] personalisationString)
+ {
+ byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalisationString);
+ byte[] seed = Block_Cipher_df(seedMaterial, mSeedLength);
+
+ int outlen = mEngine.GetBlockSize();
+
+ mKey = new byte[(mKeySizeInBits + 7) / 8];
+ mV = new byte[outlen];
+
+ // mKey & mV are modified by this call
+ CTR_DRBG_Update(seed, mKey, mV);
+
+ mReseedCounter = 1;
+ }
+
+ private void CTR_DRBG_Update(byte[] seed, byte[] key, byte[] v)
+ {
+ byte[] temp = new byte[seed.Length];
+ byte[] outputBlock = new byte[mEngine.GetBlockSize()];
+
+ int i = 0;
+ int outLen = mEngine.GetBlockSize();
+
+ mEngine.Init(true, new KeyParameter(ExpandKey(key)));
+ while (i*outLen < seed.Length)
+ {
+ AddOneTo(v);
+ mEngine.ProcessBlock(v, 0, outputBlock, 0);
+
+ int bytesToCopy = ((temp.Length - i * outLen) > outLen)
+ ? outLen : (temp.Length - i * outLen);
+
+ Array.Copy(outputBlock, 0, temp, i * outLen, bytesToCopy);
+ ++i;
+ }
+
+ XOR(temp, seed, temp, 0);
+
+ Array.Copy(temp, 0, key, 0, key.Length);
+ Array.Copy(temp, key.Length, v, 0, v.Length);
+ }
+
+ private void CTR_DRBG_Reseed_algorithm(byte[] additionalInput)
+ {
+ byte[] seedMaterial = Arrays.Concatenate(GetEntropy(), additionalInput);
+
+ seedMaterial = Block_Cipher_df(seedMaterial, mSeedLength);
+
+ CTR_DRBG_Update(seedMaterial, mKey, mV);
+
+ mReseedCounter = 1;
+ }
+
+ private void XOR(byte[] output, byte[] a, byte[] b, int bOff)
+ {
+ for (int i = 0; i < output.Length; i++)
+ {
+ output[i] = (byte)(a[i] ^ b[bOff + i]);
+ }
+ }
+
+ private void AddOneTo(byte[] longer)
+ {
+ uint carry = 1;
+ int i = longer.Length;
+ while (--i >= 0)
+ {
+ carry += longer[i];
+ longer[i] = (byte)carry;
+ carry >>= 8;
+ }
+ }
+
+ private byte[] GetEntropy()
+ {
+ byte[] entropy = mEntropySource.GetEntropy();
+ if (entropy.Length < (mSecurityStrength + 7) / 8)
+ throw new InvalidOperationException("Insufficient entropy provided by entropy source");
+ return entropy;
+ }
+
+ // -- Internal state migration ---
+
+ private static readonly byte[] K_BITS = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
+
+ // 1. If (number_of_bits_to_return > max_number_of_bits), then return an
+ // ERROR_FLAG.
+ // 2. L = len (input_string)/8.
+ // 3. N = number_of_bits_to_return/8.
+ // Comment: L is the bitstring represention of
+ // the integer resulting from len (input_string)/8.
+ // L shall be represented as a 32-bit integer.
+ //
+ // Comment : N is the bitstring represention of
+ // the integer resulting from
+ // number_of_bits_to_return/8. N shall be
+ // represented as a 32-bit integer.
+ //
+ // 4. S = L || N || input_string || 0x80.
+ // 5. While (len (S) mod outlen)
+ // Comment : Pad S with zeros, if necessary.
+ // 0, S = S || 0x00.
+ //
+ // Comment : Compute the starting value.
+ // 6. temp = the Null string.
+ // 7. i = 0.
+ // 8. K = Leftmost keylen bits of 0x00010203...1D1E1F.
+ // 9. While len (temp) < keylen + outlen, do
+ //
+ // IV = i || 0outlen - len (i).
+ //
+ // 9.1
+ //
+ // temp = temp || BCC (K, (IV || S)).
+ //
+ // 9.2
+ //
+ // i = i + 1.
+ //
+ // 9.3
+ //
+ // Comment : i shall be represented as a 32-bit
+ // integer, i.e., len (i) = 32.
+ //
+ // Comment: The 32-bit integer represenation of
+ // i is padded with zeros to outlen bits.
+ //
+ // Comment: Compute the requested number of
+ // bits.
+ //
+ // 10. K = Leftmost keylen bits of temp.
+ //
+ // 11. X = Next outlen bits of temp.
+ //
+ // 12. temp = the Null string.
+ //
+ // 13. While len (temp) < number_of_bits_to_return, do
+ //
+ // 13.1 X = Block_Encrypt (K, X).
+ //
+ // 13.2 temp = temp || X.
+ //
+ // 14. requested_bits = Leftmost number_of_bits_to_return of temp.
+ //
+ // 15. Return SUCCESS and requested_bits.
+ private byte[] Block_Cipher_df(byte[] inputString, int bitLength)
+ {
+ int outLen = mEngine.GetBlockSize();
+ int L = inputString.Length; // already in bytes
+ int N = bitLength / 8;
+ // 4 S = L || N || inputstring || 0x80
+ int sLen = 4 + 4 + L + 1;
+ int blockLen = ((sLen + outLen - 1) / outLen) * outLen;
+ byte[] S = new byte[blockLen];
+ copyIntToByteArray(S, L, 0);
+ copyIntToByteArray(S, N, 4);
+ Array.Copy(inputString, 0, S, 8, L);
+ S[8 + L] = (byte)0x80;
+ // S already padded with zeros
+
+ byte[] temp = new byte[mKeySizeInBits / 8 + outLen];
+ byte[] bccOut = new byte[outLen];
+
+ byte[] IV = new byte[outLen];
+
+ int i = 0;
+ byte[] K = new byte[mKeySizeInBits / 8];
+ Array.Copy(K_BITS, 0, K, 0, K.Length);
+
+ while (i*outLen*8 < mKeySizeInBits + outLen *8)
+ {
+ copyIntToByteArray(IV, i, 0);
+ BCC(bccOut, K, IV, S);
+
+ int bytesToCopy = ((temp.Length - i * outLen) > outLen)
+ ? outLen
+ : (temp.Length - i * outLen);
+
+ Array.Copy(bccOut, 0, temp, i * outLen, bytesToCopy);
+ ++i;
+ }
+
+ byte[] X = new byte[outLen];
+ Array.Copy(temp, 0, K, 0, K.Length);
+ Array.Copy(temp, K.Length, X, 0, X.Length);
+
+ temp = new byte[bitLength / 2];
+
+ i = 0;
+ mEngine.Init(true, new KeyParameter(ExpandKey(K)));
+
+ while (i * outLen < temp.Length)
+ {
+ mEngine.ProcessBlock(X, 0, X, 0);
+
+ int bytesToCopy = ((temp.Length - i * outLen) > outLen)
+ ? outLen
+ : (temp.Length - i * outLen);
+
+ Array.Copy(X, 0, temp, i * outLen, bytesToCopy);
+ i++;
+ }
+
+ return temp;
+ }
+
+ /*
+ * 1. chaining_value = 0^outlen
+ * . Comment: Set the first chaining value to outlen zeros.
+ * 2. n = len (data)/outlen.
+ * 3. Starting with the leftmost bits of data, split the data into n blocks of outlen bits
+ * each, forming block(1) to block(n).
+ * 4. For i = 1 to n do
+ * 4.1 input_block = chaining_value ^ block(i) .
+ * 4.2 chaining_value = Block_Encrypt (Key, input_block).
+ * 5. output_block = chaining_value.
+ * 6. Return output_block.
+ */
+ private void BCC(byte[] bccOut, byte[] k, byte[] iV, byte[] data)
+ {
+ int outlen = mEngine.GetBlockSize();
+ byte[] chainingValue = new byte[outlen]; // initial values = 0
+ int n = data.Length / outlen;
+
+ byte[] inputBlock = new byte[outlen];
+
+ mEngine.Init(true, new KeyParameter(ExpandKey(k)));
+
+ mEngine.ProcessBlock(iV, 0, chainingValue, 0);
+
+ for (int i = 0; i < n; i++)
+ {
+ XOR(inputBlock, chainingValue, data, i*outlen);
+ mEngine.ProcessBlock(inputBlock, 0, chainingValue, 0);
+ }
+
+ Array.Copy(chainingValue, 0, bccOut, 0, bccOut.Length);
+ }
+
+ private void copyIntToByteArray(byte[] buf, int value, int offSet)
+ {
+ buf[offSet + 0] = ((byte)(value >> 24));
+ buf[offSet + 1] = ((byte)(value >> 16));
+ buf[offSet + 2] = ((byte)(value >> 8));
+ buf[offSet + 3] = ((byte)(value));
+ }
+
+ /**
+ * Return the block size (in bits) of the DRBG.
+ *
+ * @return the number of bits produced on each internal round of the DRBG.
+ */
+ public int BlockSize
+ {
+ get { return mV.Length * 8; }
+ }
+
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
+ public int Generate(byte[] output, byte[] additionalInput, bool predictionResistant)
+ {
+ if (mIsTdea)
+ {
+ if (mReseedCounter > TDEA_RESEED_MAX)
+ return -1;
+
+ if (DrbgUtilities.IsTooLarge(output, TDEA_MAX_BITS_REQUEST / 8))
+ throw new ArgumentException("Number of bits per request limited to " + TDEA_MAX_BITS_REQUEST, "output");
+ }
+ else
+ {
+ if (mReseedCounter > AES_RESEED_MAX)
+ return -1;
+
+ if (DrbgUtilities.IsTooLarge(output, AES_MAX_BITS_REQUEST / 8))
+ throw new ArgumentException("Number of bits per request limited to " + AES_MAX_BITS_REQUEST, "output");
+ }
+
+ if (predictionResistant)
+ {
+ CTR_DRBG_Reseed_algorithm(additionalInput);
+ additionalInput = null;
+ }
+
+ if (additionalInput != null)
+ {
+ additionalInput = Block_Cipher_df(additionalInput, mSeedLength);
+ CTR_DRBG_Update(additionalInput, mKey, mV);
+ }
+ else
+ {
+ additionalInput = new byte[mSeedLength];
+ }
+
+ byte[] tmp = new byte[mV.Length];
+
+ mEngine.Init(true, new KeyParameter(ExpandKey(mKey)));
+
+ for (int i = 0; i <= output.Length / tmp.Length; i++)
+ {
+ int bytesToCopy = ((output.Length - i * tmp.Length) > tmp.Length)
+ ? tmp.Length
+ : (output.Length - i * mV.Length);
+
+ if (bytesToCopy != 0)
+ {
+ AddOneTo(mV);
+
+ mEngine.ProcessBlock(mV, 0, tmp, 0);
+
+ Array.Copy(tmp, 0, output, i * tmp.Length, bytesToCopy);
+ }
+ }
+
+ CTR_DRBG_Update(additionalInput, mKey, mV);
+
+ mReseedCounter++;
+
+ return output.Length * 8;
+ }
+
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
+ public void Reseed(byte[] additionalInput)
+ {
+ CTR_DRBG_Reseed_algorithm(additionalInput);
+ }
+
+ private bool IsTdea(IBlockCipher cipher)
+ {
+ return cipher.AlgorithmName.Equals("DESede") || cipher.AlgorithmName.Equals("TDEA");
+ }
+
+ private int GetMaxSecurityStrength(IBlockCipher cipher, int keySizeInBits)
+ {
+ if (IsTdea(cipher) && keySizeInBits == 168)
+ {
+ return 112;
+ }
+ if (cipher.AlgorithmName.Equals("AES"))
+ {
+ return keySizeInBits;
+ }
+
+ return -1;
+ }
+
+ private byte[] ExpandKey(byte[] key)
+ {
+ if (mIsTdea)
+ {
+ // expand key to 192 bits.
+ byte[] tmp = new byte[24];
+
+ PadKey(key, 0, tmp, 0);
+ PadKey(key, 7, tmp, 8);
+ PadKey(key, 14, tmp, 16);
+
+ return tmp;
+ }
+ else
+ {
+ return key;
+ }
+ }
+
+ /**
+ * Pad out a key for TDEA, setting odd parity for each byte.
+ *
+ * @param keyMaster
+ * @param keyOff
+ * @param tmp
+ * @param tmpOff
+ */
+ private void PadKey(byte[] keyMaster, int keyOff, byte[] tmp, int tmpOff)
+ {
+ tmp[tmpOff + 0] = (byte)(keyMaster[keyOff + 0] & 0xfe);
+ tmp[tmpOff + 1] = (byte)((keyMaster[keyOff + 0] << 7) | ((keyMaster[keyOff + 1] & 0xfc) >> 1));
+ tmp[tmpOff + 2] = (byte)((keyMaster[keyOff + 1] << 6) | ((keyMaster[keyOff + 2] & 0xf8) >> 2));
+ tmp[tmpOff + 3] = (byte)((keyMaster[keyOff + 2] << 5) | ((keyMaster[keyOff + 3] & 0xf0) >> 3));
+ tmp[tmpOff + 4] = (byte)((keyMaster[keyOff + 3] << 4) | ((keyMaster[keyOff + 4] & 0xe0) >> 4));
+ tmp[tmpOff + 5] = (byte)((keyMaster[keyOff + 4] << 3) | ((keyMaster[keyOff + 5] & 0xc0) >> 5));
+ tmp[tmpOff + 6] = (byte)((keyMaster[keyOff + 5] << 2) | ((keyMaster[keyOff + 6] & 0x80) >> 6));
+ tmp[tmpOff + 7] = (byte)(keyMaster[keyOff + 6] << 1);
+
+ DesParameters.SetOddParity(tmp, tmpOff, 8);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/prng/drbg/DrbgUtilities.cs b/bc-sharp-crypto/src/crypto/prng/drbg/DrbgUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d9a1c439cc614d804f65aa4bce143e83fd911edd
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/drbg/DrbgUtilities.cs
@@ -0,0 +1,103 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Prng.Drbg
+{
+ internal class DrbgUtilities
+ {
+ private static readonly IDictionary maxSecurityStrengths = Platform.CreateHashtable();
+
+ static DrbgUtilities()
+ {
+ maxSecurityStrengths.Add("SHA-1", 128);
+
+ maxSecurityStrengths.Add("SHA-224", 192);
+ maxSecurityStrengths.Add("SHA-256", 256);
+ maxSecurityStrengths.Add("SHA-384", 256);
+ maxSecurityStrengths.Add("SHA-512", 256);
+
+ maxSecurityStrengths.Add("SHA-512/224", 192);
+ maxSecurityStrengths.Add("SHA-512/256", 256);
+ }
+
+ internal static int GetMaxSecurityStrength(IDigest d)
+ {
+ return (int)maxSecurityStrengths[d.AlgorithmName];
+ }
+
+ internal static int GetMaxSecurityStrength(IMac m)
+ {
+ string name = m.AlgorithmName;
+
+ return (int)maxSecurityStrengths[name.Substring(0, name.IndexOf("/"))];
+ }
+
+ /**
+ * Used by both Dual EC and Hash.
+ */
+ internal static byte[] HashDF(IDigest digest, byte[] seedMaterial, int seedLength)
+ {
+ // 1. temp = the Null string.
+ // 2. .
+ // 3. counter = an 8-bit binary value representing the integer "1".
+ // 4. For i = 1 to len do
+ // Comment : In step 4.1, no_of_bits_to_return
+ // is used as a 32-bit string.
+ // 4.1 temp = temp || Hash (counter || no_of_bits_to_return ||
+ // input_string).
+ // 4.2 counter = counter + 1.
+ // 5. requested_bits = Leftmost (no_of_bits_to_return) of temp.
+ // 6. Return SUCCESS and requested_bits.
+ byte[] temp = new byte[(seedLength + 7) / 8];
+
+ int len = temp.Length / digest.GetDigestSize();
+ int counter = 1;
+
+ byte[] dig = new byte[digest.GetDigestSize()];
+
+ for (int i = 0; i <= len; i++)
+ {
+ digest.Update((byte)counter);
+
+ digest.Update((byte)(seedLength >> 24));
+ digest.Update((byte)(seedLength >> 16));
+ digest.Update((byte)(seedLength >> 8));
+ digest.Update((byte)seedLength);
+
+ digest.BlockUpdate(seedMaterial, 0, seedMaterial.Length);
+
+ digest.DoFinal(dig, 0);
+
+ int bytesToCopy = ((temp.Length - i * dig.Length) > dig.Length)
+ ? dig.Length
+ : (temp.Length - i * dig.Length);
+ Array.Copy(dig, 0, temp, i * dig.Length, bytesToCopy);
+
+ counter++;
+ }
+
+ // do a left shift to get rid of excess bits.
+ if (seedLength % 8 != 0)
+ {
+ int shift = 8 - (seedLength % 8);
+ uint carry = 0;
+
+ for (int i = 0; i != temp.Length; i++)
+ {
+ uint b = temp[i];
+ temp[i] = (byte)((b >> shift) | (carry << (8 - shift)));
+ carry = b;
+ }
+ }
+
+ return temp;
+ }
+
+ internal static bool IsTooLarge(byte[] bytes, int maxBytes)
+ {
+ return bytes != null && bytes.Length > maxBytes;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/prng/drbg/HMacSP800Drbg.cs b/bc-sharp-crypto/src/crypto/prng/drbg/HMacSP800Drbg.cs
new file mode 100644
index 0000000000000000000000000000000000000000..78331705e37619c5ac48aaba05cf8baf7ba155a2
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/drbg/HMacSP800Drbg.cs
@@ -0,0 +1,186 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Prng.Drbg
+{
+ /**
+ * A SP800-90A HMAC DRBG.
+ */
+ public class HMacSP800Drbg
+ : ISP80090Drbg
+ {
+ private readonly static long RESEED_MAX = 1L << (48 - 1);
+ private readonly static int MAX_BITS_REQUEST = 1 << (19 - 1);
+
+ private readonly byte[] mK;
+ private readonly byte[] mV;
+ private readonly IEntropySource mEntropySource;
+ private readonly IMac mHMac;
+ private readonly int mSecurityStrength;
+
+ private long mReseedCounter;
+
+ /**
+ * Construct a SP800-90A Hash DRBG.
+ *
+ * Minimum entropy requirement is the security strength requested.
+ *
+ * @param hMac Hash MAC to base the DRBG on.
+ * @param securityStrength security strength required (in bits)
+ * @param entropySource source of entropy to use for seeding/reseeding.
+ * @param personalizationString personalization string to distinguish this DRBG (may be null).
+ * @param nonce nonce to further distinguish this DRBG (may be null).
+ */
+ public HMacSP800Drbg(IMac hMac, int securityStrength, IEntropySource entropySource, byte[] personalizationString, byte[] nonce)
+ {
+ if (securityStrength > DrbgUtilities.GetMaxSecurityStrength(hMac))
+ throw new ArgumentException("Requested security strength is not supported by the derivation function");
+ if (entropySource.EntropySize < securityStrength)
+ throw new ArgumentException("Not enough entropy for security strength required");
+
+ mHMac = hMac;
+ mSecurityStrength = securityStrength;
+ mEntropySource = entropySource;
+
+ byte[] entropy = GetEntropy();
+ byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalizationString);
+
+ mK = new byte[hMac.GetMacSize()];
+ mV = new byte[mK.Length];
+ Arrays.Fill(mV, (byte)1);
+
+ hmac_DRBG_Update(seedMaterial);
+
+ mReseedCounter = 1;
+ }
+
+ private void hmac_DRBG_Update(byte[] seedMaterial)
+ {
+ hmac_DRBG_Update_Func(seedMaterial, (byte)0x00);
+ if (seedMaterial != null)
+ {
+ hmac_DRBG_Update_Func(seedMaterial, (byte)0x01);
+ }
+ }
+
+ private void hmac_DRBG_Update_Func(byte[] seedMaterial, byte vValue)
+ {
+ mHMac.Init(new KeyParameter(mK));
+
+ mHMac.BlockUpdate(mV, 0, mV.Length);
+ mHMac.Update(vValue);
+
+ if (seedMaterial != null)
+ {
+ mHMac.BlockUpdate(seedMaterial, 0, seedMaterial.Length);
+ }
+
+ mHMac.DoFinal(mK, 0);
+
+ mHMac.Init(new KeyParameter(mK));
+ mHMac.BlockUpdate(mV, 0, mV.Length);
+
+ mHMac.DoFinal(mV, 0);
+ }
+
+ /**
+ * Return the block size (in bits) of the DRBG.
+ *
+ * @return the number of bits produced on each round of the DRBG.
+ */
+ public int BlockSize
+ {
+ get { return mV.Length * 8; }
+ }
+
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
+ public int Generate(byte[] output, byte[] additionalInput, bool predictionResistant)
+ {
+ int numberOfBits = output.Length * 8;
+
+ if (numberOfBits > MAX_BITS_REQUEST)
+ throw new ArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST, "output");
+
+ if (mReseedCounter > RESEED_MAX)
+ {
+ return -1;
+ }
+
+ if (predictionResistant)
+ {
+ Reseed(additionalInput);
+ additionalInput = null;
+ }
+
+ // 2.
+ if (additionalInput != null)
+ {
+ hmac_DRBG_Update(additionalInput);
+ }
+
+ // 3.
+ byte[] rv = new byte[output.Length];
+
+ int m = output.Length / mV.Length;
+
+ mHMac.Init(new KeyParameter(mK));
+
+ for (int i = 0; i < m; i++)
+ {
+ mHMac.BlockUpdate(mV, 0, mV.Length);
+ mHMac.DoFinal(mV, 0);
+
+ Array.Copy(mV, 0, rv, i * mV.Length, mV.Length);
+ }
+
+ if (m * mV.Length < rv.Length)
+ {
+ mHMac.BlockUpdate(mV, 0, mV.Length);
+ mHMac.DoFinal(mV, 0);
+
+ Array.Copy(mV, 0, rv, m * mV.Length, rv.Length - (m * mV.Length));
+ }
+
+ hmac_DRBG_Update(additionalInput);
+
+ mReseedCounter++;
+
+ Array.Copy(rv, 0, output, 0, output.Length);
+
+ return numberOfBits;
+ }
+
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
+ public void Reseed(byte[] additionalInput)
+ {
+ byte[] entropy = GetEntropy();
+ byte[] seedMaterial = Arrays.Concatenate(entropy, additionalInput);
+
+ hmac_DRBG_Update(seedMaterial);
+
+ mReseedCounter = 1;
+ }
+
+ private byte[] GetEntropy()
+ {
+ byte[] entropy = mEntropySource.GetEntropy();
+ if (entropy.Length < (mSecurityStrength + 7) / 8)
+ throw new InvalidOperationException("Insufficient entropy provided by entropy source");
+ return entropy;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/prng/drbg/HashSP800Drbg.cs b/bc-sharp-crypto/src/crypto/prng/drbg/HashSP800Drbg.cs
new file mode 100644
index 0000000000000000000000000000000000000000..493da5a7577ce7b9d71b81acb3a089198bf60677
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/drbg/HashSP800Drbg.cs
@@ -0,0 +1,287 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Prng.Drbg
+{
+ /**
+ * A SP800-90A Hash DRBG.
+ */
+ public class HashSP800Drbg
+ : ISP80090Drbg
+ {
+ private readonly static byte[] ONE = { 0x01 };
+
+ private readonly static long RESEED_MAX = 1L << (48 - 1);
+ private readonly static int MAX_BITS_REQUEST = 1 << (19 - 1);
+
+ private static readonly IDictionary seedlens = Platform.CreateHashtable();
+
+ static HashSP800Drbg()
+ {
+ seedlens.Add("SHA-1", 440);
+ seedlens.Add("SHA-224", 440);
+ seedlens.Add("SHA-256", 440);
+ seedlens.Add("SHA-512/256", 440);
+ seedlens.Add("SHA-512/224", 440);
+ seedlens.Add("SHA-384", 888);
+ seedlens.Add("SHA-512", 888);
+ }
+
+ private readonly IDigest mDigest;
+ private readonly IEntropySource mEntropySource;
+ private readonly int mSecurityStrength;
+ private readonly int mSeedLength;
+
+ private byte[] mV;
+ private byte[] mC;
+ private long mReseedCounter;
+
+ /**
+ * Construct a SP800-90A Hash DRBG.
+ *
+ * Minimum entropy requirement is the security strength requested.
+ *
+ * @param digest source digest to use for DRB stream.
+ * @param securityStrength security strength required (in bits)
+ * @param entropySource source of entropy to use for seeding/reseeding.
+ * @param personalizationString personalization string to distinguish this DRBG (may be null).
+ * @param nonce nonce to further distinguish this DRBG (may be null).
+ */
+ public HashSP800Drbg(IDigest digest, int securityStrength, IEntropySource entropySource, byte[] personalizationString, byte[] nonce)
+ {
+ if (securityStrength > DrbgUtilities.GetMaxSecurityStrength(digest))
+ throw new ArgumentException("Requested security strength is not supported by the derivation function");
+ if (entropySource.EntropySize < securityStrength)
+ throw new ArgumentException("Not enough entropy for security strength required");
+
+ mDigest = digest;
+ mEntropySource = entropySource;
+ mSecurityStrength = securityStrength;
+ mSeedLength = (int)seedlens[digest.AlgorithmName];
+
+ // 1. seed_material = entropy_input || nonce || personalization_string.
+ // 2. seed = Hash_df (seed_material, seedlen).
+ // 3. V = seed.
+ // 4. C = Hash_df ((0x00 || V), seedlen). Comment: Preceed V with a byte
+ // of zeros.
+ // 5. reseed_counter = 1.
+ // 6. Return V, C, and reseed_counter as the initial_working_state
+
+ byte[] entropy = GetEntropy();
+ byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalizationString);
+ byte[] seed = DrbgUtilities.HashDF(mDigest, seedMaterial, mSeedLength);
+
+ mV = seed;
+ byte[] subV = new byte[mV.Length + 1];
+ Array.Copy(mV, 0, subV, 1, mV.Length);
+ mC = DrbgUtilities.HashDF(mDigest, subV, mSeedLength);
+
+ mReseedCounter = 1;
+ }
+
+ /**
+ * Return the block size (in bits) of the DRBG.
+ *
+ * @return the number of bits produced on each internal round of the DRBG.
+ */
+ public int BlockSize
+ {
+ get { return mDigest.GetDigestSize () * 8; }
+ }
+
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
+ public int Generate(byte[] output, byte[] additionalInput, bool predictionResistant)
+ {
+ // 1. If reseed_counter > reseed_interval, then return an indication that a
+ // reseed is required.
+ // 2. If (additional_input != Null), then do
+ // 2.1 w = Hash (0x02 || V || additional_input).
+ // 2.2 V = (V + w) mod 2^seedlen
+ // .
+ // 3. (returned_bits) = Hashgen (requested_number_of_bits, V).
+ // 4. H = Hash (0x03 || V).
+ // 5. V = (V + H + C + reseed_counter) mod 2^seedlen
+ // .
+ // 6. reseed_counter = reseed_counter + 1.
+ // 7. Return SUCCESS, returned_bits, and the new values of V, C, and
+ // reseed_counter for the new_working_state.
+ int numberOfBits = output.Length * 8;
+
+ if (numberOfBits > MAX_BITS_REQUEST)
+ throw new ArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST, "output");
+
+ if (mReseedCounter > RESEED_MAX)
+ return -1;
+
+ if (predictionResistant)
+ {
+ Reseed(additionalInput);
+ additionalInput = null;
+ }
+
+ // 2.
+ if (additionalInput != null)
+ {
+ byte[] newInput = new byte[1 + mV.Length + additionalInput.Length];
+ newInput[0] = 0x02;
+ Array.Copy(mV, 0, newInput, 1, mV.Length);
+ // TODO: inOff / inLength
+ Array.Copy(additionalInput, 0, newInput, 1 + mV.Length, additionalInput.Length);
+ byte[] w = Hash(newInput);
+
+ AddTo(mV, w);
+ }
+
+ // 3.
+ byte[] rv = hashgen(mV, numberOfBits);
+
+ // 4.
+ byte[] subH = new byte[mV.Length + 1];
+ Array.Copy(mV, 0, subH, 1, mV.Length);
+ subH[0] = 0x03;
+
+ byte[] H = Hash(subH);
+
+ // 5.
+ AddTo(mV, H);
+ AddTo(mV, mC);
+ byte[] c = new byte[4];
+ c[0] = (byte)(mReseedCounter >> 24);
+ c[1] = (byte)(mReseedCounter >> 16);
+ c[2] = (byte)(mReseedCounter >> 8);
+ c[3] = (byte)mReseedCounter;
+
+ AddTo(mV, c);
+
+ mReseedCounter++;
+
+ Array.Copy(rv, 0, output, 0, output.Length);
+
+ return numberOfBits;
+ }
+
+ private byte[] GetEntropy()
+ {
+ byte[] entropy = mEntropySource.GetEntropy();
+ if (entropy.Length < (mSecurityStrength + 7) / 8)
+ throw new InvalidOperationException("Insufficient entropy provided by entropy source");
+ return entropy;
+ }
+
+ // this will always add the shorter length byte array mathematically to the
+ // longer length byte array.
+ // be careful....
+ private void AddTo(byte[] longer, byte[] shorter)
+ {
+ int off = longer.Length - shorter.Length;
+
+ uint carry = 0;
+ int i = shorter.Length;
+ while (--i >= 0)
+ {
+ carry += (uint)longer[off + i] + (uint)shorter[i];
+ longer[off + i] = (byte)carry;
+ carry >>= 8;
+ }
+
+ i = off;
+ while (--i >= 0)
+ {
+ carry += longer[i];
+ longer[i] = (byte)carry;
+ carry >>= 8;
+ }
+ }
+
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
+ public void Reseed(byte[] additionalInput)
+ {
+ // 1. seed_material = 0x01 || V || entropy_input || additional_input.
+ //
+ // 2. seed = Hash_df (seed_material, seedlen).
+ //
+ // 3. V = seed.
+ //
+ // 4. C = Hash_df ((0x00 || V), seedlen).
+ //
+ // 5. reseed_counter = 1.
+ //
+ // 6. Return V, C, and reseed_counter for the new_working_state.
+ //
+ // Comment: Precede with a byte of all zeros.
+ byte[] entropy = GetEntropy();
+ byte[] seedMaterial = Arrays.ConcatenateAll(ONE, mV, entropy, additionalInput);
+ byte[] seed = DrbgUtilities.HashDF(mDigest, seedMaterial, mSeedLength);
+
+ mV = seed;
+ byte[] subV = new byte[mV.Length + 1];
+ subV[0] = 0x00;
+ Array.Copy(mV, 0, subV, 1, mV.Length);
+ mC = DrbgUtilities.HashDF(mDigest, subV, mSeedLength);
+
+ mReseedCounter = 1;
+ }
+
+ private byte[] Hash(byte[] input)
+ {
+ byte[] hash = new byte[mDigest.GetDigestSize()];
+ DoHash(input, hash);
+ return hash;
+ }
+
+ private void DoHash(byte[] input, byte[] output)
+ {
+ mDigest.BlockUpdate(input, 0, input.Length);
+ mDigest.DoFinal(output, 0);
+ }
+
+ // 1. m = [requested_number_of_bits / outlen]
+ // 2. data = V.
+ // 3. W = the Null string.
+ // 4. For i = 1 to m
+ // 4.1 wi = Hash (data).
+ // 4.2 W = W || wi.
+ // 4.3 data = (data + 1) mod 2^seedlen
+ // .
+ // 5. returned_bits = Leftmost (requested_no_of_bits) bits of W.
+ private byte[] hashgen(byte[] input, int lengthInBits)
+ {
+ int digestSize = mDigest.GetDigestSize();
+ int m = (lengthInBits / 8) / digestSize;
+
+ byte[] data = new byte[input.Length];
+ Array.Copy(input, 0, data, 0, input.Length);
+
+ byte[] W = new byte[lengthInBits / 8];
+
+ byte[] dig = new byte[mDigest.GetDigestSize()];
+ for (int i = 0; i <= m; i++)
+ {
+ DoHash(data, dig);
+
+ int bytesToCopy = ((W.Length - i * dig.Length) > dig.Length)
+ ? dig.Length
+ : (W.Length - i * dig.Length);
+ Array.Copy(dig, 0, W, i * dig.Length, bytesToCopy);
+
+ AddTo(data, ONE);
+ }
+
+ return W;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/prng/drbg/ISP80090Drbg.cs b/bc-sharp-crypto/src/crypto/prng/drbg/ISP80090Drbg.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0e398209ed948cf4125e6516f4718224e744d183
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/prng/drbg/ISP80090Drbg.cs
@@ -0,0 +1,35 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Prng.Drbg
+{
+ /**
+ * Interface to SP800-90A deterministic random bit generators.
+ */
+ public interface ISP80090Drbg
+ {
+ /**
+ * Return the block size of the DRBG.
+ *
+ * @return the block size (in bits) produced by each round of the DRBG.
+ */
+ int BlockSize { get; }
+
+ /**
+ * Populate a passed in array with random data.
+ *
+ * @param output output array for generated bits.
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ * @param predictionResistant true if a reseed should be forced, false otherwise.
+ *
+ * @return number of bits generated, -1 if a reseed required.
+ */
+ int Generate(byte[] output, byte[] additionalInput, bool predictionResistant);
+
+ /**
+ * Reseed the DRBG.
+ *
+ * @param additionalInput additional input to be added to the DRBG in this step.
+ */
+ void Reseed(byte[] additionalInput);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/signers/DsaDigestSigner.cs b/bc-sharp-crypto/src/crypto/signers/DsaDigestSigner.cs
new file mode 100644
index 0000000000000000000000000000000000000000..08660148133f041dd6c1efdb77d7423c1bbd6228
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/signers/DsaDigestSigner.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class DsaDigestSigner
+ : ISigner
+ {
+ private readonly IDigest digest;
+ private readonly IDsa dsaSigner;
+ private bool forSigning;
+
+ public DsaDigestSigner(
+ IDsa signer,
+ IDigest digest)
+ {
+ this.digest = digest;
+ this.dsaSigner = signer;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return digest.AlgorithmName + "with" + dsaSigner.AlgorithmName; }
+ }
+
+ public virtual void Init(
+ bool forSigning,
+ ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ AsymmetricKeyParameter k;
+
+ if (parameters is ParametersWithRandom)
+ {
+ k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
+ }
+ else
+ {
+ k = (AsymmetricKeyParameter)parameters;
+ }
+
+ if (forSigning && !k.IsPrivate)
+ throw new InvalidKeyException("Signing Requires Private Key.");
+
+ if (!forSigning && k.IsPrivate)
+ throw new InvalidKeyException("Verification Requires Public Key.");
+
+ Reset();
+
+ dsaSigner.Init(forSigning, parameters);
+ }
+
+ /**
+ * update the internal digest with the byte b
+ */
+ public virtual void Update(
+ byte input)
+ {
+ digest.Update(input);
+ }
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ public virtual void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ digest.BlockUpdate(input, inOff, length);
+ }
+
+ /**
+ * Generate a signature for the message we've been loaded with using
+ * the key we were initialised with.
+ */
+ public virtual byte[] GenerateSignature()
+ {
+ if (!forSigning)
+ throw new InvalidOperationException("DSADigestSigner not initialised for signature generation.");
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ BigInteger[] sig = dsaSigner.GenerateSignature(hash);
+
+ return DerEncode(sig[0], sig[1]);
+ }
+
+ /// true if the internal state represents the signature described in the passed in array.
+ public virtual bool VerifySignature(
+ byte[] signature)
+ {
+ if (forSigning)
+ throw new InvalidOperationException("DSADigestSigner not initialised for verification");
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ try
+ {
+ BigInteger[] sig = DerDecode(signature);
+ return dsaSigner.VerifySignature(hash, sig[0], sig[1]);
+ }
+ catch (IOException)
+ {
+ return false;
+ }
+ }
+
+ /// Reset the internal state
+ public virtual void Reset()
+ {
+ digest.Reset();
+ }
+
+ private byte[] DerEncode(
+ BigInteger r,
+ BigInteger s)
+ {
+ return new DerSequence(new DerInteger(r), new DerInteger(s)).GetDerEncoded();
+ }
+
+ private BigInteger[] DerDecode(
+ byte[] encoding)
+ {
+ Asn1Sequence s = (Asn1Sequence) Asn1Object.FromByteArray(encoding);
+
+ return new BigInteger[]
+ {
+ ((DerInteger) s[0]).Value,
+ ((DerInteger) s[1]).Value
+ };
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/signers/DsaSigner.cs b/bc-sharp-crypto/src/crypto/signers/DsaSigner.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bb28addfc7da6ebd32142e4d2189d5f2e9605d08
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/signers/DsaSigner.cs
@@ -0,0 +1,156 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /**
+ * The Digital Signature Algorithm - as described in "Handbook of Applied
+ * Cryptography", pages 452 - 453.
+ */
+ public class DsaSigner
+ : IDsa
+ {
+ protected readonly IDsaKCalculator kCalculator;
+
+ protected DsaKeyParameters key = null;
+ protected SecureRandom random = null;
+
+ /**
+ * Default configuration, random K values.
+ */
+ public DsaSigner()
+ {
+ this.kCalculator = new RandomDsaKCalculator();
+ }
+
+ /**
+ * Configuration with an alternate, possibly deterministic calculator of K.
+ *
+ * @param kCalculator a K value calculator.
+ */
+ public DsaSigner(IDsaKCalculator kCalculator)
+ {
+ this.kCalculator = kCalculator;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "DSA"; }
+ }
+
+ public virtual void Init(bool forSigning, ICipherParameters parameters)
+ {
+ SecureRandom providedRandom = null;
+
+ if (forSigning)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+
+ providedRandom = rParam.Random;
+ parameters = rParam.Parameters;
+ }
+
+ if (!(parameters is DsaPrivateKeyParameters))
+ throw new InvalidKeyException("DSA private key required for signing");
+
+ this.key = (DsaPrivateKeyParameters)parameters;
+ }
+ else
+ {
+ if (!(parameters is DsaPublicKeyParameters))
+ throw new InvalidKeyException("DSA public key required for verification");
+
+ this.key = (DsaPublicKeyParameters)parameters;
+ }
+
+ this.random = InitSecureRandom(forSigning && !kCalculator.IsDeterministic, providedRandom);
+ }
+
+ /**
+ * Generate a signature for the given message using the key we were
+ * initialised with. For conventional DSA the message should be a SHA-1
+ * hash of the message of interest.
+ *
+ * @param message the message that will be verified later.
+ */
+ public virtual BigInteger[] GenerateSignature(byte[] message)
+ {
+ DsaParameters parameters = key.Parameters;
+ BigInteger q = parameters.Q;
+ BigInteger m = CalculateE(q, message);
+ BigInteger x = ((DsaPrivateKeyParameters)key).X;
+
+ if (kCalculator.IsDeterministic)
+ {
+ kCalculator.Init(q, x, message);
+ }
+ else
+ {
+ kCalculator.Init(q, random);
+ }
+
+ BigInteger k = kCalculator.NextK();
+
+ BigInteger r = parameters.G.ModPow(k, parameters.P).Mod(q);
+
+ k = k.ModInverse(q).Multiply(m.Add(x.Multiply(r)));
+
+ BigInteger s = k.Mod(q);
+
+ return new BigInteger[]{ r, s };
+ }
+
+ /**
+ * return true if the value r and s represent a DSA signature for
+ * the passed in message for standard DSA the message should be a
+ * SHA-1 hash of the real message to be verified.
+ */
+ public virtual bool VerifySignature(byte[] message, BigInteger r, BigInteger s)
+ {
+ DsaParameters parameters = key.Parameters;
+ BigInteger q = parameters.Q;
+ BigInteger m = CalculateE(q, message);
+
+ if (r.SignValue <= 0 || q.CompareTo(r) <= 0)
+ {
+ return false;
+ }
+
+ if (s.SignValue <= 0 || q.CompareTo(s) <= 0)
+ {
+ return false;
+ }
+
+ BigInteger w = s.ModInverse(q);
+
+ BigInteger u1 = m.Multiply(w).Mod(q);
+ BigInteger u2 = r.Multiply(w).Mod(q);
+
+ BigInteger p = parameters.P;
+ u1 = parameters.G.ModPow(u1, p);
+ u2 = ((DsaPublicKeyParameters)key).Y.ModPow(u2, p);
+
+ BigInteger v = u1.Multiply(u2).Mod(p).Mod(q);
+
+ return v.Equals(r);
+ }
+
+ protected virtual BigInteger CalculateE(BigInteger n, byte[] message)
+ {
+ int length = System.Math.Min(message.Length, n.BitLength / 8);
+
+ return new BigInteger(1, message, 0, length);
+ }
+
+ protected virtual SecureRandom InitSecureRandom(bool needed, SecureRandom provided)
+ {
+ return !needed ? null : (provided != null) ? provided : new SecureRandom();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/signers/ECDsaSigner.cs b/bc-sharp-crypto/src/crypto/signers/ECDsaSigner.cs
new file mode 100644
index 0000000000000000000000000000000000000000..520507b8cf38e3d3bd49b58cebbb81dbad1cf1c5
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/signers/ECDsaSigner.cs
@@ -0,0 +1,240 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /**
+ * EC-DSA as described in X9.62
+ */
+ public class ECDsaSigner
+ : IDsa
+ {
+ private static readonly BigInteger Eight = BigInteger.ValueOf(8);
+
+ protected readonly IDsaKCalculator kCalculator;
+
+ protected ECKeyParameters key = null;
+ protected SecureRandom random = null;
+
+ /**
+ * Default configuration, random K values.
+ */
+ public ECDsaSigner()
+ {
+ this.kCalculator = new RandomDsaKCalculator();
+ }
+
+ /**
+ * Configuration with an alternate, possibly deterministic calculator of K.
+ *
+ * @param kCalculator a K value calculator.
+ */
+ public ECDsaSigner(IDsaKCalculator kCalculator)
+ {
+ this.kCalculator = kCalculator;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "ECDSA"; }
+ }
+
+ public virtual void Init(bool forSigning, ICipherParameters parameters)
+ {
+ SecureRandom providedRandom = null;
+
+ if (forSigning)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+
+ providedRandom = rParam.Random;
+ parameters = rParam.Parameters;
+ }
+
+ if (!(parameters is ECPrivateKeyParameters))
+ throw new InvalidKeyException("EC private key required for signing");
+
+ this.key = (ECPrivateKeyParameters)parameters;
+ }
+ else
+ {
+ if (!(parameters is ECPublicKeyParameters))
+ throw new InvalidKeyException("EC public key required for verification");
+
+ this.key = (ECPublicKeyParameters)parameters;
+ }
+
+ this.random = InitSecureRandom(forSigning && !kCalculator.IsDeterministic, providedRandom);
+ }
+
+ // 5.3 pg 28
+ /**
+ * Generate a signature for the given message using the key we were
+ * initialised with. For conventional DSA the message should be a SHA-1
+ * hash of the message of interest.
+ *
+ * @param message the message that will be verified later.
+ */
+ public virtual BigInteger[] GenerateSignature(byte[] message)
+ {
+ ECDomainParameters ec = key.Parameters;
+ BigInteger n = ec.N;
+ BigInteger e = CalculateE(n, message);
+ BigInteger d = ((ECPrivateKeyParameters)key).D;
+
+ if (kCalculator.IsDeterministic)
+ {
+ kCalculator.Init(n, d, message);
+ }
+ else
+ {
+ kCalculator.Init(n, random);
+ }
+
+ BigInteger r, s;
+
+ ECMultiplier basePointMultiplier = CreateBasePointMultiplier();
+
+ // 5.3.2
+ do // Generate s
+ {
+ BigInteger k;
+ do // Generate r
+ {
+ k = kCalculator.NextK();
+
+ ECPoint p = basePointMultiplier.Multiply(ec.G, k).Normalize();
+
+ // 5.3.3
+ r = p.AffineXCoord.ToBigInteger().Mod(n);
+ }
+ while (r.SignValue == 0);
+
+ s = k.ModInverse(n).Multiply(e.Add(d.Multiply(r))).Mod(n);
+ }
+ while (s.SignValue == 0);
+
+ return new BigInteger[]{ r, s };
+ }
+
+ // 5.4 pg 29
+ /**
+ * return true if the value r and s represent a DSA signature for
+ * the passed in message (for standard DSA the message should be
+ * a SHA-1 hash of the real message to be verified).
+ */
+ public virtual bool VerifySignature(byte[] message, BigInteger r, BigInteger s)
+ {
+ BigInteger n = key.Parameters.N;
+
+ // r and s should both in the range [1,n-1]
+ if (r.SignValue < 1 || s.SignValue < 1
+ || r.CompareTo(n) >= 0 || s.CompareTo(n) >= 0)
+ {
+ return false;
+ }
+
+ BigInteger e = CalculateE(n, message);
+ BigInteger c = s.ModInverse(n);
+
+ BigInteger u1 = e.Multiply(c).Mod(n);
+ BigInteger u2 = r.Multiply(c).Mod(n);
+
+ ECPoint G = key.Parameters.G;
+ ECPoint Q = ((ECPublicKeyParameters) key).Q;
+
+ ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, u1, Q, u2);
+
+ if (point.IsInfinity)
+ return false;
+
+ /*
+ * If possible, avoid normalizing the point (to save a modular inversion in the curve field).
+ *
+ * There are ~cofactor elements of the curve field that reduce (modulo the group order) to 'r'.
+ * If the cofactor is known and small, we generate those possible field values and project each
+ * of them to the same "denominator" (depending on the particular projective coordinates in use)
+ * as the calculated point.X. If any of the projected values matches point.X, then we have:
+ * (point.X / Denominator mod p) mod n == r
+ * as required, and verification succeeds.
+ *
+ * Based on an original idea by Gregory Maxwell (https://github.com/gmaxwell), as implemented in
+ * the libsecp256k1 project (https://github.com/bitcoin/secp256k1).
+ */
+ ECCurve curve = point.Curve;
+ if (curve != null)
+ {
+ BigInteger cofactor = curve.Cofactor;
+ if (cofactor != null && cofactor.CompareTo(Eight) <= 0)
+ {
+ ECFieldElement D = GetDenominator(curve.CoordinateSystem, point);
+ if (D != null && !D.IsZero)
+ {
+ ECFieldElement X = point.XCoord;
+ while (curve.IsValidFieldElement(r))
+ {
+ ECFieldElement R = curve.FromBigInteger(r).Multiply(D);
+ if (R.Equals(X))
+ {
+ return true;
+ }
+ r = r.Add(n);
+ }
+ return false;
+ }
+ }
+ }
+
+ BigInteger v = point.Normalize().AffineXCoord.ToBigInteger().Mod(n);
+ return v.Equals(r);
+ }
+
+ protected virtual BigInteger CalculateE(BigInteger n, byte[] message)
+ {
+ int messageBitLength = message.Length * 8;
+ BigInteger trunc = new BigInteger(1, message);
+
+ if (n.BitLength < messageBitLength)
+ {
+ trunc = trunc.ShiftRight(messageBitLength - n.BitLength);
+ }
+
+ return trunc;
+ }
+
+ protected virtual ECMultiplier CreateBasePointMultiplier()
+ {
+ return new FixedPointCombMultiplier();
+ }
+
+ protected virtual ECFieldElement GetDenominator(int coordinateSystem, ECPoint p)
+ {
+ switch (coordinateSystem)
+ {
+ case ECCurve.COORD_HOMOGENEOUS:
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ case ECCurve.COORD_SKEWED:
+ return p.GetZCoord(0);
+ case ECCurve.COORD_JACOBIAN:
+ case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+ case ECCurve.COORD_JACOBIAN_MODIFIED:
+ return p.GetZCoord(0).Square();
+ default:
+ return null;
+ }
+ }
+
+ protected virtual SecureRandom InitSecureRandom(bool needed, SecureRandom provided)
+ {
+ return !needed ? null : (provided != null) ? provided : new SecureRandom();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/signers/ECGOST3410Signer.cs b/bc-sharp-crypto/src/crypto/signers/ECGOST3410Signer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..28ab79c1cfd8e1faaffe478bef3b7d0f2c967ff6
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/signers/ECGOST3410Signer.cs
@@ -0,0 +1,162 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /**
+ * GOST R 34.10-2001 Signature Algorithm
+ */
+ public class ECGost3410Signer
+ : IDsa
+ {
+ private ECKeyParameters key;
+ private SecureRandom random;
+
+ public virtual string AlgorithmName
+ {
+ get { return "ECGOST3410"; }
+ }
+
+ public virtual void Init(
+ bool forSigning,
+ ICipherParameters parameters)
+ {
+ if (forSigning)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+
+ this.random = rParam.Random;
+ parameters = rParam.Parameters;
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ }
+
+ if (!(parameters is ECPrivateKeyParameters))
+ throw new InvalidKeyException("EC private key required for signing");
+
+ this.key = (ECPrivateKeyParameters) parameters;
+ }
+ else
+ {
+ if (!(parameters is ECPublicKeyParameters))
+ throw new InvalidKeyException("EC public key required for verification");
+
+ this.key = (ECPublicKeyParameters)parameters;
+ }
+ }
+
+ /**
+ * generate a signature for the given message using the key we were
+ * initialised with. For conventional GOST3410 the message should be a GOST3411
+ * hash of the message of interest.
+ *
+ * @param message the message that will be verified later.
+ */
+ public virtual BigInteger[] GenerateSignature(
+ byte[] message)
+ {
+ byte[] mRev = new byte[message.Length]; // conversion is little-endian
+ for (int i = 0; i != mRev.Length; i++)
+ {
+ mRev[i] = message[mRev.Length - 1 - i];
+ }
+
+ BigInteger e = new BigInteger(1, mRev);
+
+ ECDomainParameters ec = key.Parameters;
+ BigInteger n = ec.N;
+ BigInteger d = ((ECPrivateKeyParameters)key).D;
+
+ BigInteger r, s = null;
+
+ ECMultiplier basePointMultiplier = CreateBasePointMultiplier();
+
+ do // generate s
+ {
+ BigInteger k;
+ do // generate r
+ {
+ do
+ {
+ k = new BigInteger(n.BitLength, random);
+ }
+ while (k.SignValue == 0);
+
+ ECPoint p = basePointMultiplier.Multiply(ec.G, k).Normalize();
+
+ r = p.AffineXCoord.ToBigInteger().Mod(n);
+ }
+ while (r.SignValue == 0);
+
+ s = (k.Multiply(e)).Add(d.Multiply(r)).Mod(n);
+ }
+ while (s.SignValue == 0);
+
+ return new BigInteger[]{ r, s };
+ }
+
+ /**
+ * return true if the value r and s represent a GOST3410 signature for
+ * the passed in message (for standard GOST3410 the message should be
+ * a GOST3411 hash of the real message to be verified).
+ */
+ public virtual bool VerifySignature(
+ byte[] message,
+ BigInteger r,
+ BigInteger s)
+ {
+ byte[] mRev = new byte[message.Length]; // conversion is little-endian
+ for (int i = 0; i != mRev.Length; i++)
+ {
+ mRev[i] = message[mRev.Length - 1 - i];
+ }
+
+ BigInteger e = new BigInteger(1, mRev);
+ BigInteger n = key.Parameters.N;
+
+ // r in the range [1,n-1]
+ if (r.CompareTo(BigInteger.One) < 0 || r.CompareTo(n) >= 0)
+ {
+ return false;
+ }
+
+ // s in the range [1,n-1]
+ if (s.CompareTo(BigInteger.One) < 0 || s.CompareTo(n) >= 0)
+ {
+ return false;
+ }
+
+ BigInteger v = e.ModInverse(n);
+
+ BigInteger z1 = s.Multiply(v).Mod(n);
+ BigInteger z2 = (n.Subtract(r)).Multiply(v).Mod(n);
+
+ ECPoint G = key.Parameters.G; // P
+ ECPoint Q = ((ECPublicKeyParameters)key).Q;
+
+ ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, z1, Q, z2).Normalize();
+
+ if (point.IsInfinity)
+ return false;
+
+ BigInteger R = point.AffineXCoord.ToBigInteger().Mod(n);
+
+ return R.Equals(r);
+ }
+
+ protected virtual ECMultiplier CreateBasePointMultiplier()
+ {
+ return new FixedPointCombMultiplier();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/signers/ECNRSigner.cs b/bc-sharp-crypto/src/crypto/signers/ECNRSigner.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bb21a49940ab958e6dca56fecaebec69f095db74
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/signers/ECNRSigner.cs
@@ -0,0 +1,188 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /**
+ * EC-NR as described in IEEE 1363-2000
+ */
+ public class ECNRSigner
+ : IDsa
+ {
+ private bool forSigning;
+ private ECKeyParameters key;
+ private SecureRandom random;
+
+ public virtual string AlgorithmName
+ {
+ get { return "ECNR"; }
+ }
+
+ public virtual void Init(
+ bool forSigning,
+ ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ if (forSigning)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom) parameters;
+
+ this.random = rParam.Random;
+ parameters = rParam.Parameters;
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ }
+
+ if (!(parameters is ECPrivateKeyParameters))
+ throw new InvalidKeyException("EC private key required for signing");
+
+ this.key = (ECPrivateKeyParameters) parameters;
+ }
+ else
+ {
+ if (!(parameters is ECPublicKeyParameters))
+ throw new InvalidKeyException("EC public key required for verification");
+
+ this.key = (ECPublicKeyParameters) parameters;
+ }
+ }
+
+ // Section 7.2.5 ECSP-NR, pg 34
+ /**
+ * generate a signature for the given message using the key we were
+ * initialised with. Generally, the order of the curve should be at
+ * least as long as the hash of the message of interest, and with
+ * ECNR it *must* be at least as long.
+ *
+ * @param digest the digest to be signed.
+ * @exception DataLengthException if the digest is longer than the key allows
+ */
+ public virtual BigInteger[] GenerateSignature(
+ byte[] message)
+ {
+ if (!this.forSigning)
+ {
+ // not properly initilaized... deal with it
+ throw new InvalidOperationException("not initialised for signing");
+ }
+
+ BigInteger n = ((ECPrivateKeyParameters) this.key).Parameters.N;
+ int nBitLength = n.BitLength;
+
+ BigInteger e = new BigInteger(1, message);
+ int eBitLength = e.BitLength;
+
+ ECPrivateKeyParameters privKey = (ECPrivateKeyParameters)key;
+
+ if (eBitLength > nBitLength)
+ {
+ throw new DataLengthException("input too large for ECNR key.");
+ }
+
+ BigInteger r = null;
+ BigInteger s = null;
+
+ AsymmetricCipherKeyPair tempPair;
+ do // generate r
+ {
+ // generate another, but very temporary, key pair using
+ // the same EC parameters
+ ECKeyPairGenerator keyGen = new ECKeyPairGenerator();
+
+ keyGen.Init(new ECKeyGenerationParameters(privKey.Parameters, this.random));
+
+ tempPair = keyGen.GenerateKeyPair();
+
+ // BigInteger Vx = tempPair.getPublic().getW().getAffineX();
+ ECPublicKeyParameters V = (ECPublicKeyParameters) tempPair.Public; // get temp's public key
+ BigInteger Vx = V.Q.AffineXCoord.ToBigInteger(); // get the point's x coordinate
+
+ r = Vx.Add(e).Mod(n);
+ }
+ while (r.SignValue == 0);
+
+ // generate s
+ BigInteger x = privKey.D; // private key value
+ BigInteger u = ((ECPrivateKeyParameters) tempPair.Private).D; // temp's private key value
+ s = u.Subtract(r.Multiply(x)).Mod(n);
+
+ return new BigInteger[]{ r, s };
+ }
+
+ // Section 7.2.6 ECVP-NR, pg 35
+ /**
+ * return true if the value r and s represent a signature for the
+ * message passed in. Generally, the order of the curve should be at
+ * least as long as the hash of the message of interest, and with
+ * ECNR, it *must* be at least as long. But just in case the signer
+ * applied mod(n) to the longer digest, this implementation will
+ * apply mod(n) during verification.
+ *
+ * @param digest the digest to be verified.
+ * @param r the r value of the signature.
+ * @param s the s value of the signature.
+ * @exception DataLengthException if the digest is longer than the key allows
+ */
+ public virtual bool VerifySignature(
+ byte[] message,
+ BigInteger r,
+ BigInteger s)
+ {
+ if (this.forSigning)
+ {
+ // not properly initilaized... deal with it
+ throw new InvalidOperationException("not initialised for verifying");
+ }
+
+ ECPublicKeyParameters pubKey = (ECPublicKeyParameters)key;
+ BigInteger n = pubKey.Parameters.N;
+ int nBitLength = n.BitLength;
+
+ BigInteger e = new BigInteger(1, message);
+ int eBitLength = e.BitLength;
+
+ if (eBitLength > nBitLength)
+ {
+ throw new DataLengthException("input too large for ECNR key.");
+ }
+
+ // r in the range [1,n-1]
+ if (r.CompareTo(BigInteger.One) < 0 || r.CompareTo(n) >= 0)
+ {
+ return false;
+ }
+
+ // s in the range [0,n-1] NB: ECNR spec says 0
+ if (s.CompareTo(BigInteger.Zero) < 0 || s.CompareTo(n) >= 0)
+ {
+ return false;
+ }
+
+ // compute P = sG + rW
+
+ ECPoint G = pubKey.Parameters.G;
+ ECPoint W = pubKey.Q;
+ // calculate P using Bouncy math
+ ECPoint P = ECAlgorithms.SumOfTwoMultiplies(G, s, W, r).Normalize();
+
+ if (P.IsInfinity)
+ return false;
+
+ BigInteger x = P.AffineXCoord.ToBigInteger();
+ BigInteger t = r.Subtract(x).Mod(n);
+
+ return t.Equals(e);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/signers/GOST3410DigestSigner.cs b/bc-sharp-crypto/src/crypto/signers/GOST3410DigestSigner.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bc32808df5692308b8d7b057ccf1a7ce13df109a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/signers/GOST3410DigestSigner.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class Gost3410DigestSigner
+ : ISigner
+ {
+ private readonly IDigest digest;
+ private readonly IDsa dsaSigner;
+ private bool forSigning;
+
+ public Gost3410DigestSigner(
+ IDsa signer,
+ IDigest digest)
+ {
+ this.dsaSigner = signer;
+ this.digest = digest;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return digest.AlgorithmName + "with" + dsaSigner.AlgorithmName; }
+ }
+
+ public virtual void Init(
+ bool forSigning,
+ ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ AsymmetricKeyParameter k;
+ if (parameters is ParametersWithRandom)
+ {
+ k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
+ }
+ else
+ {
+ k = (AsymmetricKeyParameter)parameters;
+ }
+
+ if (forSigning && !k.IsPrivate)
+ {
+ throw new InvalidKeyException("Signing Requires Private Key.");
+ }
+
+ if (!forSigning && k.IsPrivate)
+ {
+ throw new InvalidKeyException("Verification Requires Public Key.");
+ }
+
+ Reset();
+
+ dsaSigner.Init(forSigning, parameters);
+ }
+
+ /**
+ * update the internal digest with the byte b
+ */
+ public virtual void Update(
+ byte input)
+ {
+ digest.Update(input);
+ }
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ public virtual void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ digest.BlockUpdate(input, inOff, length);
+ }
+
+ /**
+ * Generate a signature for the message we've been loaded with using
+ * the key we were initialised with.
+ */
+ public virtual byte[] GenerateSignature()
+ {
+ if (!forSigning)
+ throw new InvalidOperationException("GOST3410DigestSigner not initialised for signature generation.");
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ try
+ {
+ BigInteger[] sig = dsaSigner.GenerateSignature(hash);
+ byte[] sigBytes = new byte[64];
+
+ // TODO Add methods to allow writing BigInteger to existing byte array?
+ byte[] r = sig[0].ToByteArrayUnsigned();
+ byte[] s = sig[1].ToByteArrayUnsigned();
+ s.CopyTo(sigBytes, 32 - s.Length);
+ r.CopyTo(sigBytes, 64 - r.Length);
+ return sigBytes;
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.Message, e);
+ }
+ }
+
+ /// true if the internal state represents the signature described in the passed in array.
+ public virtual bool VerifySignature(
+ byte[] signature)
+ {
+ if (forSigning)
+ throw new InvalidOperationException("DSADigestSigner not initialised for verification");
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ BigInteger R, S;
+ try
+ {
+ R = new BigInteger(1, signature, 32, 32);
+ S = new BigInteger(1, signature, 0, 32);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("error decoding signature bytes.", e);
+ }
+
+ return dsaSigner.VerifySignature(hash, R, S);
+ }
+
+ /// Reset the internal state
+ public virtual void Reset()
+ {
+ digest.Reset();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/signers/GOST3410Signer.cs b/bc-sharp-crypto/src/crypto/signers/GOST3410Signer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f1832ae37c708ff29e1711eced6f6870fd967a85
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/signers/GOST3410Signer.cs
@@ -0,0 +1,132 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /**
+ * Gost R 34.10-94 Signature Algorithm
+ */
+ public class Gost3410Signer
+ : IDsa
+ {
+ private Gost3410KeyParameters key;
+ private SecureRandom random;
+
+ public virtual string AlgorithmName
+ {
+ get { return "GOST3410"; }
+ }
+
+ public virtual void Init(
+ bool forSigning,
+ ICipherParameters parameters)
+ {
+ if (forSigning)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+
+ this.random = rParam.Random;
+ parameters = rParam.Parameters;
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ }
+
+ if (!(parameters is Gost3410PrivateKeyParameters))
+ throw new InvalidKeyException("GOST3410 private key required for signing");
+
+ this.key = (Gost3410PrivateKeyParameters) parameters;
+ }
+ else
+ {
+ if (!(parameters is Gost3410PublicKeyParameters))
+ throw new InvalidKeyException("GOST3410 public key required for signing");
+
+ this.key = (Gost3410PublicKeyParameters) parameters;
+ }
+ }
+
+ /**
+ * generate a signature for the given message using the key we were
+ * initialised with. For conventional Gost3410 the message should be a Gost3411
+ * hash of the message of interest.
+ *
+ * @param message the message that will be verified later.
+ */
+ public virtual BigInteger[] GenerateSignature(
+ byte[] message)
+ {
+ byte[] mRev = new byte[message.Length]; // conversion is little-endian
+ for (int i = 0; i != mRev.Length; i++)
+ {
+ mRev[i] = message[mRev.Length - 1 - i];
+ }
+
+ BigInteger m = new BigInteger(1, mRev);
+ Gost3410Parameters parameters = key.Parameters;
+ BigInteger k;
+
+ do
+ {
+ k = new BigInteger(parameters.Q.BitLength, random);
+ }
+ while (k.CompareTo(parameters.Q) >= 0);
+
+ BigInteger r = parameters.A.ModPow(k, parameters.P).Mod(parameters.Q);
+
+ BigInteger s = k.Multiply(m).
+ Add(((Gost3410PrivateKeyParameters)key).X.Multiply(r)).
+ Mod(parameters.Q);
+
+ return new BigInteger[]{ r, s };
+ }
+
+ /**
+ * return true if the value r and s represent a Gost3410 signature for
+ * the passed in message for standard Gost3410 the message should be a
+ * Gost3411 hash of the real message to be verified.
+ */
+ public virtual bool VerifySignature(
+ byte[] message,
+ BigInteger r,
+ BigInteger s)
+ {
+ byte[] mRev = new byte[message.Length]; // conversion is little-endian
+ for (int i = 0; i != mRev.Length; i++)
+ {
+ mRev[i] = message[mRev.Length - 1 - i];
+ }
+
+ BigInteger m = new BigInteger(1, mRev);
+ Gost3410Parameters parameters = key.Parameters;
+
+ if (r.SignValue < 0 || parameters.Q.CompareTo(r) <= 0)
+ {
+ return false;
+ }
+
+ if (s.SignValue < 0 || parameters.Q.CompareTo(s) <= 0)
+ {
+ return false;
+ }
+
+ BigInteger v = m.ModPow(parameters.Q.Subtract(BigInteger.Two), parameters.Q);
+
+ BigInteger z1 = s.Multiply(v).Mod(parameters.Q);
+ BigInteger z2 = (parameters.Q.Subtract(r)).Multiply(v).Mod(parameters.Q);
+
+ z1 = parameters.A.ModPow(z1, parameters.P);
+ z2 = ((Gost3410PublicKeyParameters)key).Y.ModPow(z2, parameters.P);
+
+ BigInteger u = z1.Multiply(z2).Mod(parameters.P).Mod(parameters.Q);
+
+ return u.Equals(r);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/signers/GenericSigner.cs b/bc-sharp-crypto/src/crypto/signers/GenericSigner.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a5512176f57514e5650ae3d60ae91f22c421c26d
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/signers/GenericSigner.cs
@@ -0,0 +1,130 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class GenericSigner
+ : ISigner
+ {
+ private readonly IAsymmetricBlockCipher engine;
+ private readonly IDigest digest;
+ private bool forSigning;
+
+ public GenericSigner(
+ IAsymmetricBlockCipher engine,
+ IDigest digest)
+ {
+ this.engine = engine;
+ this.digest = digest;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Generic(" + engine.AlgorithmName + "/" + digest.AlgorithmName + ")"; }
+ }
+
+ /**
+ * initialise the signer for signing or verification.
+ *
+ * @param forSigning
+ * true if for signing, false otherwise
+ * @param parameters
+ * necessary parameters.
+ */
+ public virtual void Init(bool forSigning, ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ AsymmetricKeyParameter k;
+ if (parameters is ParametersWithRandom)
+ {
+ k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
+ }
+ else
+ {
+ k = (AsymmetricKeyParameter)parameters;
+ }
+
+ if (forSigning && !k.IsPrivate)
+ throw new InvalidKeyException("Signing requires private key.");
+
+ if (!forSigning && k.IsPrivate)
+ throw new InvalidKeyException("Verification requires public key.");
+
+ Reset();
+
+ engine.Init(forSigning, parameters);
+ }
+
+ /**
+ * update the internal digest with the byte b
+ */
+ public virtual void Update(byte input)
+ {
+ digest.Update(input);
+ }
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ public virtual void BlockUpdate(byte[] input, int inOff, int length)
+ {
+ digest.BlockUpdate(input, inOff, length);
+ }
+
+ /**
+ * Generate a signature for the message we've been loaded with using the key
+ * we were initialised with.
+ */
+ public virtual byte[] GenerateSignature()
+ {
+ if (!forSigning)
+ throw new InvalidOperationException("GenericSigner not initialised for signature generation.");
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ return engine.ProcessBlock(hash, 0, hash.Length);
+ }
+
+ /**
+ * return true if the internal state represents the signature described in
+ * the passed in array.
+ */
+ public virtual bool VerifySignature(byte[] signature)
+ {
+ if (forSigning)
+ throw new InvalidOperationException("GenericSigner not initialised for verification");
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ try
+ {
+ byte[] sig = engine.ProcessBlock(signature, 0, signature.Length);
+
+ // Extend with leading zeroes to match the digest size, if necessary.
+ if (sig.Length < hash.Length)
+ {
+ byte[] tmp = new byte[hash.Length];
+ Array.Copy(sig, 0, tmp, tmp.Length - sig.Length, sig.Length);
+ sig = tmp;
+ }
+
+ return Arrays.ConstantTimeAreEqual(sig, hash);
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+ }
+
+ public virtual void Reset()
+ {
+ digest.Reset();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/signers/HMacDsaKCalculator.cs b/bc-sharp-crypto/src/crypto/signers/HMacDsaKCalculator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8231197b9157700070fbcc7940699928a3272578
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/signers/HMacDsaKCalculator.cs
@@ -0,0 +1,150 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /**
+ * A deterministic K calculator based on the algorithm in section 3.2 of RFC 6979.
+ */
+ public class HMacDsaKCalculator
+ : IDsaKCalculator
+ {
+ private readonly HMac hMac;
+ private readonly byte[] K;
+ private readonly byte[] V;
+
+ private BigInteger n;
+
+ /**
+ * Base constructor.
+ *
+ * @param digest digest to build the HMAC on.
+ */
+ public HMacDsaKCalculator(IDigest digest)
+ {
+ this.hMac = new HMac(digest);
+ this.V = new byte[hMac.GetMacSize()];
+ this.K = new byte[hMac.GetMacSize()];
+ }
+
+ public virtual bool IsDeterministic
+ {
+ get { return true; }
+ }
+
+ public virtual void Init(BigInteger n, SecureRandom random)
+ {
+ throw new InvalidOperationException("Operation not supported");
+ }
+
+ public void Init(BigInteger n, BigInteger d, byte[] message)
+ {
+ this.n = n;
+
+ Arrays.Fill(V, (byte)0x01);
+ Arrays.Fill(K, (byte)0);
+
+ byte[] x = new byte[(n.BitLength + 7) / 8];
+ byte[] dVal = BigIntegers.AsUnsignedByteArray(d);
+
+ Array.Copy(dVal, 0, x, x.Length - dVal.Length, dVal.Length);
+
+ byte[] m = new byte[(n.BitLength + 7) / 8];
+
+ BigInteger mInt = BitsToInt(message);
+
+ if (mInt.CompareTo(n) >= 0)
+ {
+ mInt = mInt.Subtract(n);
+ }
+
+ byte[] mVal = BigIntegers.AsUnsignedByteArray(mInt);
+
+ Array.Copy(mVal, 0, m, m.Length - mVal.Length, mVal.Length);
+
+ hMac.Init(new KeyParameter(K));
+
+ hMac.BlockUpdate(V, 0, V.Length);
+ hMac.Update((byte)0x00);
+ hMac.BlockUpdate(x, 0, x.Length);
+ hMac.BlockUpdate(m, 0, m.Length);
+
+ hMac.DoFinal(K, 0);
+
+ hMac.Init(new KeyParameter(K));
+
+ hMac.BlockUpdate(V, 0, V.Length);
+
+ hMac.DoFinal(V, 0);
+
+ hMac.BlockUpdate(V, 0, V.Length);
+ hMac.Update((byte)0x01);
+ hMac.BlockUpdate(x, 0, x.Length);
+ hMac.BlockUpdate(m, 0, m.Length);
+
+ hMac.DoFinal(K, 0);
+
+ hMac.Init(new KeyParameter(K));
+
+ hMac.BlockUpdate(V, 0, V.Length);
+
+ hMac.DoFinal(V, 0);
+ }
+
+ public virtual BigInteger NextK()
+ {
+ byte[] t = new byte[((n.BitLength + 7) / 8)];
+
+ for (;;)
+ {
+ int tOff = 0;
+
+ while (tOff < t.Length)
+ {
+ hMac.BlockUpdate(V, 0, V.Length);
+
+ hMac.DoFinal(V, 0);
+
+ int len = System.Math.Min(t.Length - tOff, V.Length);
+ Array.Copy(V, 0, t, tOff, len);
+ tOff += len;
+ }
+
+ BigInteger k = BitsToInt(t);
+
+ if (k.SignValue > 0 && k.CompareTo(n) < 0)
+ {
+ return k;
+ }
+
+ hMac.BlockUpdate(V, 0, V.Length);
+ hMac.Update((byte)0x00);
+
+ hMac.DoFinal(K, 0);
+
+ hMac.Init(new KeyParameter(K));
+
+ hMac.BlockUpdate(V, 0, V.Length);
+
+ hMac.DoFinal(V, 0);
+ }
+ }
+
+ private BigInteger BitsToInt(byte[] t)
+ {
+ BigInteger v = new BigInteger(1, t);
+
+ if (t.Length * 8 > n.BitLength)
+ {
+ v = v.ShiftRight(t.Length * 8 - n.BitLength);
+ }
+
+ return v;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/signers/IDsaKCalculator.cs b/bc-sharp-crypto/src/crypto/signers/IDsaKCalculator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..645186d41f3c74ca361e8528a7bf1ecb88a4cc69
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/signers/IDsaKCalculator.cs
@@ -0,0 +1,44 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /**
+ * Interface define calculators of K values for DSA/ECDSA.
+ */
+ public interface IDsaKCalculator
+ {
+ /**
+ * Return true if this calculator is deterministic, false otherwise.
+ *
+ * @return true if deterministic, otherwise false.
+ */
+ bool IsDeterministic { get; }
+
+ /**
+ * Non-deterministic initialiser.
+ *
+ * @param n the order of the DSA group.
+ * @param random a source of randomness.
+ */
+ void Init(BigInteger n, SecureRandom random);
+
+ /**
+ * Deterministic initialiser.
+ *
+ * @param n the order of the DSA group.
+ * @param d the DSA private value.
+ * @param message the message being signed.
+ */
+ void Init(BigInteger n, BigInteger d, byte[] message);
+
+ /**
+ * Return the next valid value of K.
+ *
+ * @return a K value.
+ */
+ BigInteger NextK();
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/signers/Iso9796d2PssSigner.cs b/bc-sharp-crypto/src/crypto/signers/Iso9796d2PssSigner.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6b8037095193be1883c41b9dc05e762a2c9ed1f8
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/signers/Iso9796d2PssSigner.cs
@@ -0,0 +1,619 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /// ISO9796-2 - mechanism using a hash function with recovery (scheme 2 and 3).
+ ///
+ /// Note: the usual length for the salt is the length of the hash
+ /// function used in bytes.
+ ///
+ public class Iso9796d2PssSigner
+ : ISignerWithRecovery
+ {
+ ///
+ /// Return a reference to the recoveredMessage message.
+ ///
+ /// The full/partial recoveredMessage message.
+ ///
+ public byte[] GetRecoveredMessage()
+ {
+ return recoveredMessage;
+ }
+
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TrailerImplicit = 0xBC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TrailerRipeMD160 = 0x31CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TrailerRipeMD128 = 0x32CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TrailerSha1 = 0x33CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TrailerSha256 = 0x34CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TrailerSha512 = 0x35CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TrailerSha384 = 0x36CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TrailerWhirlpool = 0x37CC;
+
+ private IDigest digest;
+ private IAsymmetricBlockCipher cipher;
+
+ private SecureRandom random;
+ private byte[] standardSalt;
+
+ private int hLen;
+ private int trailer;
+ private int keyBits;
+ private byte[] block;
+ private byte[] mBuf;
+ private int messageLength;
+ private readonly int saltLength;
+ private bool fullMessage;
+ private byte[] recoveredMessage;
+
+ private byte[] preSig;
+ private byte[] preBlock;
+ private int preMStart;
+ private int preTLength;
+
+ ///
+ /// Generate a signer with either implicit or explicit trailers for ISO9796-2, scheme 2 or 3.
+ ///
+ /// base cipher to use for signature creation/verification
+ /// digest to use.
+ /// length of salt in bytes.
+ /// whether or not the trailer is implicit or gives the hash.
+ public Iso9796d2PssSigner(
+ IAsymmetricBlockCipher cipher,
+ IDigest digest,
+ int saltLength,
+ bool isImplicit)
+ {
+ this.cipher = cipher;
+ this.digest = digest;
+ this.hLen = digest.GetDigestSize();
+ this.saltLength = saltLength;
+
+ if (isImplicit)
+ {
+ trailer = IsoTrailers.TRAILER_IMPLICIT;
+ }
+ else if (IsoTrailers.NoTrailerAvailable(digest))
+ {
+ throw new ArgumentException("no valid trailer", "digest");
+ }
+ else
+ {
+ trailer = IsoTrailers.GetTrailer(digest);
+ }
+ }
+
+ /// Constructor for a signer with an explicit digest trailer.
+ ///
+ ///
+ /// cipher to use.
+ ///
+ /// digest to sign with.
+ ///
+ /// length of salt in bytes.
+ ///
+ public Iso9796d2PssSigner(
+ IAsymmetricBlockCipher cipher,
+ IDigest digest,
+ int saltLength)
+ : this(cipher, digest, saltLength, false)
+ {
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return digest.AlgorithmName + "with" + "ISO9796-2S2"; }
+ }
+
+ /// Initialise the signer.
+ /// true if for signing, false if for verification.
+ /// parameters for signature generation/verification. If the
+ /// parameters are for generation they should be a ParametersWithRandom,
+ /// a ParametersWithSalt, or just an RsaKeyParameters object. If RsaKeyParameters
+ /// are passed in a SecureRandom will be created.
+ ///
+ /// if wrong parameter type or a fixed
+ /// salt is passed in which is the wrong length.
+ ///
+ public virtual void Init(
+ bool forSigning,
+ ICipherParameters parameters)
+ {
+ RsaKeyParameters kParam;
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom p = (ParametersWithRandom) parameters;
+
+ kParam = (RsaKeyParameters) p.Parameters;
+
+ if (forSigning)
+ {
+ random = p.Random;
+ }
+ }
+ else if (parameters is ParametersWithSalt)
+ {
+ if (!forSigning)
+ throw new ArgumentException("ParametersWithSalt only valid for signing", "parameters");
+
+ ParametersWithSalt p = (ParametersWithSalt) parameters;
+
+ kParam = (RsaKeyParameters) p.Parameters;
+ standardSalt = p.GetSalt();
+
+ if (standardSalt.Length != saltLength)
+ throw new ArgumentException("Fixed salt is of wrong length");
+ }
+ else
+ {
+ kParam = (RsaKeyParameters) parameters;
+
+ if (forSigning)
+ {
+ random = new SecureRandom();
+ }
+ }
+
+ cipher.Init(forSigning, kParam);
+
+ keyBits = kParam.Modulus.BitLength;
+
+ block = new byte[(keyBits + 7) / 8];
+
+ if (trailer == IsoTrailers.TRAILER_IMPLICIT)
+ {
+ mBuf = new byte[block.Length - digest.GetDigestSize() - saltLength - 1 - 1];
+ }
+ else
+ {
+ mBuf = new byte[block.Length - digest.GetDigestSize() - saltLength - 1 - 2];
+ }
+
+ Reset();
+ }
+
+ /// compare two byte arrays - constant time.
+ private bool IsSameAs(byte[] a, byte[] b)
+ {
+ if (messageLength != b.Length)
+ {
+ return false;
+ }
+
+ bool isOkay = true;
+
+ for (int i = 0; i != b.Length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ isOkay = false;
+ }
+ }
+
+ return isOkay;
+ }
+
+ /// clear possible sensitive data
+ private void ClearBlock(
+ byte[] block)
+ {
+ Array.Clear(block, 0, block.Length);
+ }
+
+ public virtual void UpdateWithRecoveredMessage(
+ byte[] signature)
+ {
+ byte[] block = cipher.ProcessBlock(signature, 0, signature.Length);
+
+ //
+ // adjust block size for leading zeroes if necessary
+ //
+ if (block.Length < (keyBits + 7) / 8)
+ {
+ byte[] tmp = new byte[(keyBits + 7) / 8];
+
+ Array.Copy(block, 0, tmp, tmp.Length - block.Length, block.Length);
+ ClearBlock(block);
+ block = tmp;
+ }
+
+ int tLength;
+
+ if (((block[block.Length - 1] & 0xFF) ^ 0xBC) == 0)
+ {
+ tLength = 1;
+ }
+ else
+ {
+ int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
+
+ if (IsoTrailers.NoTrailerAvailable(digest))
+ throw new ArgumentException("unrecognised hash in signature");
+
+ if (sigTrail != IsoTrailers.GetTrailer(digest))
+ throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail);
+
+ tLength = 2;
+ }
+
+ //
+ // calculate H(m2)
+ //
+ byte[] m2Hash = new byte[hLen];
+ digest.DoFinal(m2Hash, 0);
+
+ //
+ // remove the mask
+ //
+ byte[] dbMask = MaskGeneratorFunction1(block, block.Length - hLen - tLength, hLen, block.Length - hLen - tLength);
+ for (int i = 0; i != dbMask.Length; i++)
+ {
+ block[i] ^= dbMask[i];
+ }
+
+ block[0] &= 0x7f;
+
+ //
+ // find out how much padding we've got
+ //
+ int mStart = 0;
+
+ while (mStart < block.Length)
+ {
+ if (block[mStart++] == 0x01)
+ break;
+ }
+
+ if (mStart >= block.Length)
+ {
+ ClearBlock(block);
+ }
+
+ fullMessage = (mStart > 1);
+
+ recoveredMessage = new byte[dbMask.Length - mStart - saltLength];
+
+ Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
+ recoveredMessage.CopyTo(mBuf, 0);
+
+ preSig = signature;
+ preBlock = block;
+ preMStart = mStart;
+ preTLength = tLength;
+ }
+
+ /// update the internal digest with the byte b
+ public virtual void Update(
+ byte input)
+ {
+ if (preSig == null && messageLength < mBuf.Length)
+ {
+ mBuf[messageLength++] = input;
+ }
+ else
+ {
+ digest.Update(input);
+ }
+ }
+
+ /// update the internal digest with the byte array in
+ public virtual void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (preSig == null)
+ {
+ while (length > 0 && messageLength < mBuf.Length)
+ {
+ this.Update(input[inOff]);
+ inOff++;
+ length--;
+ }
+ }
+
+ if (length > 0)
+ {
+ digest.BlockUpdate(input, inOff, length);
+ }
+ }
+
+ /// reset the internal state
+ public virtual void Reset()
+ {
+ digest.Reset();
+ messageLength = 0;
+ if (mBuf != null)
+ {
+ ClearBlock(mBuf);
+ }
+ if (recoveredMessage != null)
+ {
+ ClearBlock(recoveredMessage);
+ recoveredMessage = null;
+ }
+ fullMessage = false;
+ if (preSig != null)
+ {
+ preSig = null;
+ ClearBlock(preBlock);
+ preBlock = null;
+ }
+ }
+
+ /// Generate a signature for the loaded message using the key we were
+ /// initialised with.
+ ///
+ public virtual byte[] GenerateSignature()
+ {
+ int digSize = digest.GetDigestSize();
+ byte[] m2Hash = new byte[digSize];
+ digest.DoFinal(m2Hash, 0);
+
+ byte[] C = new byte[8];
+ LtoOSP(messageLength * 8, C);
+
+ digest.BlockUpdate(C, 0, C.Length);
+ digest.BlockUpdate(mBuf, 0, messageLength);
+ digest.BlockUpdate(m2Hash, 0, m2Hash.Length);
+
+ byte[] salt;
+ if (standardSalt != null)
+ {
+ salt = standardSalt;
+ }
+ else
+ {
+ salt = new byte[saltLength];
+ random.NextBytes(salt);
+ }
+
+ digest.BlockUpdate(salt, 0, salt.Length);
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ int tLength = 2;
+ if (trailer == IsoTrailers.TRAILER_IMPLICIT)
+ {
+ tLength = 1;
+ }
+
+ int off = block.Length - messageLength - salt.Length - hLen - tLength - 1;
+
+ block[off] = (byte) (0x01);
+
+ Array.Copy(mBuf, 0, block, off + 1, messageLength);
+ Array.Copy(salt, 0, block, off + 1 + messageLength, salt.Length);
+
+ byte[] dbMask = MaskGeneratorFunction1(hash, 0, hash.Length, block.Length - hLen - tLength);
+ for (int i = 0; i != dbMask.Length; i++)
+ {
+ block[i] ^= dbMask[i];
+ }
+
+ Array.Copy(hash, 0, block, block.Length - hLen - tLength, hLen);
+
+ if (trailer == IsoTrailers.TRAILER_IMPLICIT)
+ {
+ block[block.Length - 1] = (byte)IsoTrailers.TRAILER_IMPLICIT;
+ }
+ else
+ {
+ block[block.Length - 2] = (byte) ((uint)trailer >> 8);
+ block[block.Length - 1] = (byte) trailer;
+ }
+
+ block[0] &= (byte) (0x7f);
+
+ byte[] b = cipher.ProcessBlock(block, 0, block.Length);
+
+ ClearBlock(mBuf);
+ ClearBlock(block);
+ messageLength = 0;
+
+ return b;
+ }
+
+ /// return true if the signature represents a ISO9796-2 signature
+ /// for the passed in message.
+ ///
+ public virtual bool VerifySignature(
+ byte[] signature)
+ {
+ //
+ // calculate H(m2)
+ //
+ byte[] m2Hash = new byte[hLen];
+ digest.DoFinal(m2Hash, 0);
+
+ byte[] block;
+ int tLength;
+ int mStart = 0;
+
+ if (preSig == null)
+ {
+ try
+ {
+ UpdateWithRecoveredMessage(signature);
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (!Arrays.AreEqual(preSig, signature))
+ {
+ throw new InvalidOperationException("UpdateWithRecoveredMessage called on different signature");
+ }
+ }
+
+ block = preBlock;
+ mStart = preMStart;
+ tLength = preTLength;
+
+ preSig = null;
+ preBlock = null;
+
+ //
+ // check the hashes
+ //
+ byte[] C = new byte[8];
+ LtoOSP(recoveredMessage.Length * 8, C);
+
+ digest.BlockUpdate(C, 0, C.Length);
+
+ if (recoveredMessage.Length != 0)
+ {
+ digest.BlockUpdate(recoveredMessage, 0, recoveredMessage.Length);
+ }
+
+ digest.BlockUpdate(m2Hash, 0, m2Hash.Length);
+
+ // Update for the salt
+ if (standardSalt != null)
+ {
+ digest.BlockUpdate(standardSalt, 0, standardSalt.Length);
+ }
+ else
+ {
+ digest.BlockUpdate(block, mStart + recoveredMessage.Length, saltLength);
+ }
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ int off = block.Length - tLength - hash.Length;
+
+ bool isOkay = true;
+
+ for (int i = 0; i != hash.Length; i++)
+ {
+ if (hash[i] != block[off + i])
+ {
+ isOkay = false;
+ }
+ }
+
+ ClearBlock(block);
+ ClearBlock(hash);
+
+ if (!isOkay)
+ {
+ fullMessage = false;
+ messageLength = 0;
+ ClearBlock(recoveredMessage);
+ return false;
+ }
+
+ //
+ // if they've input a message check what we've recovered against
+ // what was input.
+ //
+ if (messageLength != 0)
+ {
+ if (!IsSameAs(mBuf, recoveredMessage))
+ {
+ messageLength = 0;
+ ClearBlock(mBuf);
+ return false;
+ }
+ }
+
+ messageLength = 0;
+
+ ClearBlock(mBuf);
+ return true;
+ }
+
+ ///
+ /// Return true if the full message was recoveredMessage.
+ ///
+ /// true on full message recovery, false otherwise, or if not sure.
+ ///
+ public virtual bool HasFullMessage()
+ {
+ return fullMessage;
+ }
+
+ /// int to octet string.
+ /// int to octet string.
+ private void ItoOSP(
+ int i,
+ byte[] sp)
+ {
+ sp[0] = (byte)((uint)i >> 24);
+ sp[1] = (byte)((uint)i >> 16);
+ sp[2] = (byte)((uint)i >> 8);
+ sp[3] = (byte)((uint)i >> 0);
+ }
+
+ /// long to octet string.
+ private void LtoOSP(long l, byte[] sp)
+ {
+ sp[0] = (byte)((ulong)l >> 56);
+ sp[1] = (byte)((ulong)l >> 48);
+ sp[2] = (byte)((ulong)l >> 40);
+ sp[3] = (byte)((ulong)l >> 32);
+ sp[4] = (byte)((ulong)l >> 24);
+ sp[5] = (byte)((ulong)l >> 16);
+ sp[6] = (byte)((ulong)l >> 8);
+ sp[7] = (byte)((ulong)l >> 0);
+ }
+
+ /// mask generator function, as described in Pkcs1v2.
+ private byte[] MaskGeneratorFunction1(
+ byte[] Z,
+ int zOff,
+ int zLen,
+ int length)
+ {
+ byte[] mask = new byte[length];
+ byte[] hashBuf = new byte[hLen];
+ byte[] C = new byte[4];
+ int counter = 0;
+
+ digest.Reset();
+
+ do
+ {
+ ItoOSP(counter, C);
+
+ digest.BlockUpdate(Z, zOff, zLen);
+ digest.BlockUpdate(C, 0, C.Length);
+ digest.DoFinal(hashBuf, 0);
+
+ Array.Copy(hashBuf, 0, mask, counter * hLen, hLen);
+ }
+ while (++counter < (length / hLen));
+
+ if ((counter * hLen) < length)
+ {
+ ItoOSP(counter, C);
+
+ digest.BlockUpdate(Z, zOff, zLen);
+ digest.BlockUpdate(C, 0, C.Length);
+ digest.DoFinal(hashBuf, 0);
+
+ Array.Copy(hashBuf, 0, mask, counter * hLen, mask.Length - (counter * hLen));
+ }
+
+ return mask;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/signers/Iso9796d2Signer.cs b/bc-sharp-crypto/src/crypto/signers/Iso9796d2Signer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..303913068d7a93a04af00c2cc9fe580c0c09d882
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/signers/Iso9796d2Signer.cs
@@ -0,0 +1,556 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /// ISO9796-2 - mechanism using a hash function with recovery (scheme 1)
+ public class Iso9796d2Signer : ISignerWithRecovery
+ {
+ ///
+ /// Return a reference to the recoveredMessage message.
+ ///
+ /// The full/partial recoveredMessage message.
+ ///
+ public byte[] GetRecoveredMessage()
+ {
+ return recoveredMessage;
+ }
+
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TrailerImplicit = 0xBC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TrailerRipeMD160 = 0x31CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TrailerRipeMD128 = 0x32CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TrailerSha1 = 0x33CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TrailerSha256 = 0x34CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TrailerSha512 = 0x35CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TrailerSha384 = 0x36CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TrailerWhirlpool = 0x37CC;
+
+ private IDigest digest;
+ private IAsymmetricBlockCipher cipher;
+
+ private int trailer;
+ private int keyBits;
+ private byte[] block;
+ private byte[] mBuf;
+ private int messageLength;
+ private bool fullMessage;
+ private byte[] recoveredMessage;
+
+ private byte[] preSig;
+ private byte[] preBlock;
+
+ ///
+ /// Generate a signer with either implicit or explicit trailers for ISO9796-2.
+ ///
+ /// base cipher to use for signature creation/verification
+ /// digest to use.
+ /// whether or not the trailer is implicit or gives the hash.
+ public Iso9796d2Signer(
+ IAsymmetricBlockCipher cipher,
+ IDigest digest,
+ bool isImplicit)
+ {
+ this.cipher = cipher;
+ this.digest = digest;
+
+ if (isImplicit)
+ {
+ trailer = IsoTrailers.TRAILER_IMPLICIT;
+ }
+ else if (IsoTrailers.NoTrailerAvailable(digest))
+ {
+ throw new ArgumentException("no valid trailer", "digest");
+ }
+ else
+ {
+ trailer = IsoTrailers.GetTrailer(digest);
+ }
+ }
+
+ /// Constructor for a signer with an explicit digest trailer.
+ ///
+ ///
+ /// cipher to use.
+ ///
+ /// digest to sign with.
+ ///
+ public Iso9796d2Signer(IAsymmetricBlockCipher cipher, IDigest digest)
+ : this(cipher, digest, false)
+ {
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return digest.AlgorithmName + "with" + "ISO9796-2S1"; }
+ }
+
+ public virtual void Init(bool forSigning, ICipherParameters parameters)
+ {
+ RsaKeyParameters kParam = (RsaKeyParameters) parameters;
+
+ cipher.Init(forSigning, kParam);
+
+ keyBits = kParam.Modulus.BitLength;
+
+ block = new byte[(keyBits + 7) / 8];
+ if (trailer == IsoTrailers.TRAILER_IMPLICIT)
+ {
+ mBuf = new byte[block.Length - digest.GetDigestSize() - 2];
+ }
+ else
+ {
+ mBuf = new byte[block.Length - digest.GetDigestSize() - 3];
+ }
+
+ Reset();
+ }
+
+ /// compare two byte arrays - constant time.
+ private bool IsSameAs(byte[] a, byte[] b)
+ {
+ int checkLen;
+ if (messageLength > mBuf.Length)
+ {
+ if (mBuf.Length > b.Length)
+ {
+ return false;
+ }
+
+ checkLen = mBuf.Length;
+ }
+ else
+ {
+ if (messageLength != b.Length)
+ {
+ return false;
+ }
+
+ checkLen = b.Length;
+ }
+
+ bool isOkay = true;
+
+ for (int i = 0; i != checkLen; i++)
+ {
+ if (a[i] != b[i])
+ {
+ isOkay = false;
+ }
+ }
+
+ return isOkay;
+ }
+
+ /// clear possible sensitive data
+ private void ClearBlock(
+ byte[] block)
+ {
+ Array.Clear(block, 0, block.Length);
+ }
+
+ public virtual void UpdateWithRecoveredMessage(
+ byte[] signature)
+ {
+ byte[] block = cipher.ProcessBlock(signature, 0, signature.Length);
+
+ if (((block[0] & 0xC0) ^ 0x40) != 0)
+ throw new InvalidCipherTextException("malformed signature");
+
+ if (((block[block.Length - 1] & 0xF) ^ 0xC) != 0)
+ throw new InvalidCipherTextException("malformed signature");
+
+ int delta = 0;
+
+ if (((block[block.Length - 1] & 0xFF) ^ 0xBC) == 0)
+ {
+ delta = 1;
+ }
+ else
+ {
+ int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
+
+ if (IsoTrailers.NoTrailerAvailable(digest))
+ throw new ArgumentException("unrecognised hash in signature");
+
+ if (sigTrail != IsoTrailers.GetTrailer(digest))
+ throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail);
+
+ delta = 2;
+ }
+
+ //
+ // find out how much padding we've got
+ //
+ int mStart = 0;
+
+ for (mStart = 0; mStart != block.Length; mStart++)
+ {
+ if (((block[mStart] & 0x0f) ^ 0x0a) == 0)
+ break;
+ }
+
+ mStart++;
+
+ int off = block.Length - delta - digest.GetDigestSize();
+
+ //
+ // there must be at least one byte of message string
+ //
+ if ((off - mStart) <= 0)
+ throw new InvalidCipherTextException("malformed block");
+
+ //
+ // if we contain the whole message as well, check the hash of that.
+ //
+ if ((block[0] & 0x20) == 0)
+ {
+ fullMessage = true;
+
+ recoveredMessage = new byte[off - mStart];
+ Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
+ }
+ else
+ {
+ fullMessage = false;
+
+ recoveredMessage = new byte[off - mStart];
+ Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
+ }
+
+ preSig = signature;
+ preBlock = block;
+
+ digest.BlockUpdate(recoveredMessage, 0, recoveredMessage.Length);
+ messageLength = recoveredMessage.Length;
+ recoveredMessage.CopyTo(mBuf, 0);
+ }
+
+ /// update the internal digest with the byte b
+ public virtual void Update(
+ byte input)
+ {
+ digest.Update(input);
+
+ if (messageLength < mBuf.Length)
+ {
+ mBuf[messageLength] = input;
+ }
+
+ messageLength++;
+ }
+
+ /// update the internal digest with the byte array in
+ public virtual void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ while (length > 0 && messageLength < mBuf.Length)
+ {
+ //for (int i = 0; i < length && (i + messageLength) < mBuf.Length; i++)
+ //{
+ // mBuf[messageLength + i] = input[inOff + i];
+ //}
+ this.Update(input[inOff]);
+ inOff++;
+ length--;
+ }
+
+ digest.BlockUpdate(input, inOff, length);
+ messageLength += length;
+ }
+
+ /// reset the internal state
+ public virtual void Reset()
+ {
+ digest.Reset();
+ messageLength = 0;
+ ClearBlock(mBuf);
+
+ if (recoveredMessage != null)
+ {
+ ClearBlock(recoveredMessage);
+ }
+
+ recoveredMessage = null;
+ fullMessage = false;
+
+ if (preSig != null)
+ {
+ preSig = null;
+ ClearBlock(preBlock);
+ preBlock = null;
+ }
+ }
+
+ /// Generate a signature for the loaded message using the key we were
+ /// initialised with.
+ ///
+ public virtual byte[] GenerateSignature()
+ {
+ int digSize = digest.GetDigestSize();
+
+ int t = 0;
+ int delta = 0;
+
+ if (trailer == IsoTrailers.TRAILER_IMPLICIT)
+ {
+ t = 8;
+ delta = block.Length - digSize - 1;
+ digest.DoFinal(block, delta);
+ block[block.Length - 1] = (byte)IsoTrailers.TRAILER_IMPLICIT;
+ }
+ else
+ {
+ t = 16;
+ delta = block.Length - digSize - 2;
+ digest.DoFinal(block, delta);
+ block[block.Length - 2] = (byte) ((uint)trailer >> 8);
+ block[block.Length - 1] = (byte) trailer;
+ }
+
+ byte header = 0;
+ int x = (digSize + messageLength) * 8 + t + 4 - keyBits;
+
+ if (x > 0)
+ {
+ int mR = messageLength - ((x + 7) / 8);
+ header = (byte) (0x60);
+
+ delta -= mR;
+
+ Array.Copy(mBuf, 0, block, delta, mR);
+ }
+ else
+ {
+ header = (byte) (0x40);
+ delta -= messageLength;
+
+ Array.Copy(mBuf, 0, block, delta, messageLength);
+ }
+
+ if ((delta - 1) > 0)
+ {
+ for (int i = delta - 1; i != 0; i--)
+ {
+ block[i] = (byte) 0xbb;
+ }
+ block[delta - 1] ^= (byte) 0x01;
+ block[0] = (byte) 0x0b;
+ block[0] |= header;
+ }
+ else
+ {
+ block[0] = (byte) 0x0a;
+ block[0] |= header;
+ }
+
+ byte[] b = cipher.ProcessBlock(block, 0, block.Length);
+
+ messageLength = 0;
+
+ ClearBlock(mBuf);
+ ClearBlock(block);
+
+ return b;
+ }
+
+ /// return true if the signature represents a ISO9796-2 signature
+ /// for the passed in message.
+ ///
+ public virtual bool VerifySignature(byte[] signature)
+ {
+ byte[] block;
+
+ if (preSig == null)
+ {
+ try
+ {
+ block = cipher.ProcessBlock(signature, 0, signature.Length);
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (!Arrays.AreEqual(preSig, signature))
+ throw new InvalidOperationException("updateWithRecoveredMessage called on different signature");
+
+ block = preBlock;
+
+ preSig = null;
+ preBlock = null;
+ }
+
+ if (((block[0] & 0xC0) ^ 0x40) != 0)
+ return ReturnFalse(block);
+
+ if (((block[block.Length - 1] & 0xF) ^ 0xC) != 0)
+ return ReturnFalse(block);
+
+ int delta = 0;
+
+ if (((block[block.Length - 1] & 0xFF) ^ 0xBC) == 0)
+ {
+ delta = 1;
+ }
+ else
+ {
+ int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
+
+ if (IsoTrailers.NoTrailerAvailable(digest))
+ throw new ArgumentException("unrecognised hash in signature");
+
+ if (sigTrail != IsoTrailers.GetTrailer(digest))
+ throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail);
+
+ delta = 2;
+ }
+
+ //
+ // find out how much padding we've got
+ //
+ int mStart = 0;
+ for (; mStart != block.Length; mStart++)
+ {
+ if (((block[mStart] & 0x0f) ^ 0x0a) == 0)
+ {
+ break;
+ }
+ }
+
+ mStart++;
+
+ //
+ // check the hashes
+ //
+ byte[] hash = new byte[digest.GetDigestSize()];
+
+ int off = block.Length - delta - hash.Length;
+
+ //
+ // there must be at least one byte of message string
+ //
+ if ((off - mStart) <= 0)
+ {
+ return ReturnFalse(block);
+ }
+
+ //
+ // if we contain the whole message as well, check the hash of that.
+ //
+ if ((block[0] & 0x20) == 0)
+ {
+ fullMessage = true;
+
+ // check right number of bytes passed in.
+ if (messageLength > off - mStart)
+ {
+ return ReturnFalse(block);
+ }
+
+ digest.Reset();
+ digest.BlockUpdate(block, mStart, off - mStart);
+ digest.DoFinal(hash, 0);
+
+ bool isOkay = true;
+
+ for (int i = 0; i != hash.Length; i++)
+ {
+ block[off + i] ^= hash[i];
+ if (block[off + i] != 0)
+ {
+ isOkay = false;
+ }
+ }
+
+ if (!isOkay)
+ {
+ return ReturnFalse(block);
+ }
+
+ recoveredMessage = new byte[off - mStart];
+ Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
+ }
+ else
+ {
+ fullMessage = false;
+
+ digest.DoFinal(hash, 0);
+
+ bool isOkay = true;
+
+ for (int i = 0; i != hash.Length; i++)
+ {
+ block[off + i] ^= hash[i];
+ if (block[off + i] != 0)
+ {
+ isOkay = false;
+ }
+ }
+
+ if (!isOkay)
+ {
+ return ReturnFalse(block);
+ }
+
+ recoveredMessage = new byte[off - mStart];
+ Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
+ }
+
+ //
+ // if they've input a message check what we've recovered against
+ // what was input.
+ //
+ if (messageLength != 0)
+ {
+ if (!IsSameAs(mBuf, recoveredMessage))
+ {
+ return ReturnFalse(block);
+ }
+ }
+
+ ClearBlock(mBuf);
+ ClearBlock(block);
+
+ messageLength = 0;
+
+ return true;
+ }
+
+ private bool ReturnFalse(byte[] block)
+ {
+ messageLength = 0;
+
+ ClearBlock(mBuf);
+ ClearBlock(block);
+
+ return false;
+ }
+
+ ///
+ /// Return true if the full message was recoveredMessage.
+ ///
+ /// true on full message recovery, false otherwise.
+ ///
+ public virtual bool HasFullMessage()
+ {
+ return fullMessage;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/signers/IsoTrailers.cs b/bc-sharp-crypto/src/crypto/signers/IsoTrailers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..497ffaf783eb85de933119e56993ef84911f7c21
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/signers/IsoTrailers.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class IsoTrailers
+ {
+ public const int TRAILER_IMPLICIT = 0xBC;
+ public const int TRAILER_RIPEMD160 = 0x31CC;
+ public const int TRAILER_RIPEMD128 = 0x32CC;
+ public const int TRAILER_SHA1 = 0x33CC;
+ public const int TRAILER_SHA256 = 0x34CC;
+ public const int TRAILER_SHA512 = 0x35CC;
+ public const int TRAILER_SHA384 = 0x36CC;
+ public const int TRAILER_WHIRLPOOL = 0x37CC;
+ public const int TRAILER_SHA224 = 0x38CC;
+ public const int TRAILER_SHA512_224 = 0x39CC;
+ public const int TRAILER_SHA512_256 = 0x40CC;
+
+ private static IDictionary CreateTrailerMap()
+ {
+ IDictionary trailers = Platform.CreateHashtable();
+
+ trailers.Add("RIPEMD128", TRAILER_RIPEMD128);
+ trailers.Add("RIPEMD160", TRAILER_RIPEMD160);
+
+ trailers.Add("SHA-1", TRAILER_SHA1);
+ trailers.Add("SHA-224", TRAILER_SHA224);
+ trailers.Add("SHA-256", TRAILER_SHA256);
+ trailers.Add("SHA-384", TRAILER_SHA384);
+ trailers.Add("SHA-512", TRAILER_SHA512);
+ trailers.Add("SHA-512/224", TRAILER_SHA512_224);
+ trailers.Add("SHA-512/256", TRAILER_SHA512_256);
+
+ trailers.Add("Whirlpool", TRAILER_WHIRLPOOL);
+
+ return CollectionUtilities.ReadOnly(trailers);
+ }
+
+ // IDictionary is (string -> Int32)
+ private static readonly IDictionary trailerMap = CreateTrailerMap();
+
+ public static int GetTrailer(IDigest digest)
+ {
+ return (int)trailerMap[digest.AlgorithmName];
+ }
+
+ public static bool NoTrailerAvailable(IDigest digest)
+ {
+ return !trailerMap.Contains(digest.AlgorithmName);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/signers/PssSigner.cs b/bc-sharp-crypto/src/crypto/signers/PssSigner.cs
new file mode 100644
index 0000000000000000000000000000000000000000..23b7c0f49bcf5bad302cabc199a833d8f5e6a22f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/signers/PssSigner.cs
@@ -0,0 +1,386 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /// RSA-PSS as described in Pkcs# 1 v 2.1.
+ ///
+ /// Note: the usual value for the salt length is the number of
+ /// bytes in the hash function.
+ ///
+ public class PssSigner
+ : ISigner
+ {
+ public const byte TrailerImplicit = (byte)0xBC;
+
+ private readonly IDigest contentDigest1, contentDigest2;
+ private readonly IDigest mgfDigest;
+ private readonly IAsymmetricBlockCipher cipher;
+
+ private SecureRandom random;
+
+ private int hLen;
+ private int mgfhLen;
+ private int sLen;
+ private bool sSet;
+ private int emBits;
+ private byte[] salt;
+ private byte[] mDash;
+ private byte[] block;
+ private byte trailer;
+
+ public static PssSigner CreateRawSigner(
+ IAsymmetricBlockCipher cipher,
+ IDigest digest)
+ {
+ return new PssSigner(cipher, new NullDigest(), digest, digest, digest.GetDigestSize(), null, TrailerImplicit);
+ }
+
+ public static PssSigner CreateRawSigner(
+ IAsymmetricBlockCipher cipher,
+ IDigest contentDigest,
+ IDigest mgfDigest,
+ int saltLen,
+ byte trailer)
+ {
+ return new PssSigner(cipher, new NullDigest(), contentDigest, mgfDigest, saltLen, null, trailer);
+ }
+
+ public PssSigner(
+ IAsymmetricBlockCipher cipher,
+ IDigest digest)
+ : this(cipher, digest, digest.GetDigestSize())
+ {
+ }
+
+ /// Basic constructor
+ /// the asymmetric cipher to use.
+ /// the digest to use.
+ /// the length of the salt to use (in bytes).
+ public PssSigner(
+ IAsymmetricBlockCipher cipher,
+ IDigest digest,
+ int saltLen)
+ : this(cipher, digest, saltLen, TrailerImplicit)
+ {
+ }
+
+ /// Basic constructor
+ /// the asymmetric cipher to use.
+ /// the digest to use.
+ /// the fixed salt to be used.
+ public PssSigner(
+ IAsymmetricBlockCipher cipher,
+ IDigest digest,
+ byte[] salt)
+ : this(cipher, digest, digest, digest, salt.Length, salt, TrailerImplicit)
+ {
+ }
+
+ public PssSigner(
+ IAsymmetricBlockCipher cipher,
+ IDigest contentDigest,
+ IDigest mgfDigest,
+ int saltLen)
+ : this(cipher, contentDigest, mgfDigest, saltLen, TrailerImplicit)
+ {
+ }
+
+ public PssSigner(
+ IAsymmetricBlockCipher cipher,
+ IDigest contentDigest,
+ IDigest mgfDigest,
+ byte[] salt)
+ : this(cipher, contentDigest, contentDigest, mgfDigest, salt.Length, salt, TrailerImplicit)
+ {
+ }
+
+ public PssSigner(
+ IAsymmetricBlockCipher cipher,
+ IDigest digest,
+ int saltLen,
+ byte trailer)
+ : this(cipher, digest, digest, saltLen, TrailerImplicit)
+ {
+ }
+
+ public PssSigner(
+ IAsymmetricBlockCipher cipher,
+ IDigest contentDigest,
+ IDigest mgfDigest,
+ int saltLen,
+ byte trailer)
+ : this(cipher, contentDigest, contentDigest, mgfDigest, saltLen, null, trailer)
+ {
+ }
+
+ private PssSigner(
+ IAsymmetricBlockCipher cipher,
+ IDigest contentDigest1,
+ IDigest contentDigest2,
+ IDigest mgfDigest,
+ int saltLen,
+ byte[] salt,
+ byte trailer)
+ {
+ this.cipher = cipher;
+ this.contentDigest1 = contentDigest1;
+ this.contentDigest2 = contentDigest2;
+ this.mgfDigest = mgfDigest;
+ this.hLen = contentDigest2.GetDigestSize();
+ this.mgfhLen = mgfDigest.GetDigestSize();
+ this.sLen = saltLen;
+ this.sSet = salt != null;
+ if (sSet)
+ {
+ this.salt = salt;
+ }
+ else
+ {
+ this.salt = new byte[saltLen];
+ }
+ this.mDash = new byte[8 + saltLen + hLen];
+ this.trailer = trailer;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return mgfDigest.AlgorithmName + "withRSAandMGF1"; }
+ }
+
+ public virtual void Init(
+ bool forSigning,
+ ICipherParameters parameters)
+ {
+ if (parameters is ParametersWithRandom)
+ {
+ ParametersWithRandom p = (ParametersWithRandom) parameters;
+
+ parameters = p.Parameters;
+ random = p.Random;
+ }
+ else
+ {
+ if (forSigning)
+ {
+ random = new SecureRandom();
+ }
+ }
+
+ cipher.Init(forSigning, parameters);
+
+ RsaKeyParameters kParam;
+ if (parameters is RsaBlindingParameters)
+ {
+ kParam = ((RsaBlindingParameters) parameters).PublicKey;
+ }
+ else
+ {
+ kParam = (RsaKeyParameters) parameters;
+ }
+
+ emBits = kParam.Modulus.BitLength - 1;
+
+ if (emBits < (8 * hLen + 8 * sLen + 9))
+ throw new ArgumentException("key too small for specified hash and salt lengths");
+
+ block = new byte[(emBits + 7) / 8];
+ }
+
+ /// clear possible sensitive data
+ private void ClearBlock(
+ byte[] block)
+ {
+ Array.Clear(block, 0, block.Length);
+ }
+
+ /// update the internal digest with the byte b
+ public virtual void Update(
+ byte input)
+ {
+ contentDigest1.Update(input);
+ }
+
+ /// update the internal digest with the byte array in
+ public virtual void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ contentDigest1.BlockUpdate(input, inOff, length);
+ }
+
+ /// reset the internal state
+ public virtual void Reset()
+ {
+ contentDigest1.Reset();
+ }
+
+ /// Generate a signature for the message we've been loaded with using
+ /// the key we were initialised with.
+ ///
+ public virtual byte[] GenerateSignature()
+ {
+ contentDigest1.DoFinal(mDash, mDash.Length - hLen - sLen);
+
+ if (sLen != 0)
+ {
+ if (!sSet)
+ {
+ random.NextBytes(salt);
+ }
+ salt.CopyTo(mDash, mDash.Length - sLen);
+ }
+
+ byte[] h = new byte[hLen];
+
+ contentDigest2.BlockUpdate(mDash, 0, mDash.Length);
+
+ contentDigest2.DoFinal(h, 0);
+
+ block[block.Length - sLen - 1 - hLen - 1] = (byte) (0x01);
+ salt.CopyTo(block, block.Length - sLen - hLen - 1);
+
+ byte[] dbMask = MaskGeneratorFunction1(h, 0, h.Length, block.Length - hLen - 1);
+ for (int i = 0; i != dbMask.Length; i++)
+ {
+ block[i] ^= dbMask[i];
+ }
+
+ block[0] &= (byte) ((0xff >> ((block.Length * 8) - emBits)));
+
+ h.CopyTo(block, block.Length - hLen - 1);
+
+ block[block.Length - 1] = trailer;
+
+ byte[] b = cipher.ProcessBlock(block, 0, block.Length);
+
+ ClearBlock(block);
+
+ return b;
+ }
+
+ /// return true if the internal state represents the signature described
+ /// in the passed in array.
+ ///
+ public virtual bool VerifySignature(
+ byte[] signature)
+ {
+ contentDigest1.DoFinal(mDash, mDash.Length - hLen - sLen);
+
+ byte[] b = cipher.ProcessBlock(signature, 0, signature.Length);
+ b.CopyTo(block, block.Length - b.Length);
+
+ if (block[block.Length - 1] != trailer)
+ {
+ ClearBlock(block);
+ return false;
+ }
+
+ byte[] dbMask = MaskGeneratorFunction1(block, block.Length - hLen - 1, hLen, block.Length - hLen - 1);
+
+ for (int i = 0; i != dbMask.Length; i++)
+ {
+ block[i] ^= dbMask[i];
+ }
+
+ block[0] &= (byte) ((0xff >> ((block.Length * 8) - emBits)));
+
+ for (int i = 0; i != block.Length - hLen - sLen - 2; i++)
+ {
+ if (block[i] != 0)
+ {
+ ClearBlock(block);
+ return false;
+ }
+ }
+
+ if (block[block.Length - hLen - sLen - 2] != 0x01)
+ {
+ ClearBlock(block);
+ return false;
+ }
+
+ if (sSet)
+ {
+ Array.Copy(salt, 0, mDash, mDash.Length - sLen, sLen);
+ }
+ else
+ {
+ Array.Copy(block, block.Length - sLen - hLen - 1, mDash, mDash.Length - sLen, sLen);
+ }
+
+ contentDigest2.BlockUpdate(mDash, 0, mDash.Length);
+ contentDigest2.DoFinal(mDash, mDash.Length - hLen);
+
+ for (int i = block.Length - hLen - 1, j = mDash.Length - hLen; j != mDash.Length; i++, j++)
+ {
+ if ((block[i] ^ mDash[j]) != 0)
+ {
+ ClearBlock(mDash);
+ ClearBlock(block);
+ return false;
+ }
+ }
+
+ ClearBlock(mDash);
+ ClearBlock(block);
+
+ return true;
+ }
+
+ /// int to octet string.
+ private void ItoOSP(
+ int i,
+ byte[] sp)
+ {
+ sp[0] = (byte)((uint) i >> 24);
+ sp[1] = (byte)((uint) i >> 16);
+ sp[2] = (byte)((uint) i >> 8);
+ sp[3] = (byte)((uint) i >> 0);
+ }
+
+ /// mask generator function, as described in Pkcs1v2.
+ private byte[] MaskGeneratorFunction1(
+ byte[] Z,
+ int zOff,
+ int zLen,
+ int length)
+ {
+ byte[] mask = new byte[length];
+ byte[] hashBuf = new byte[mgfhLen];
+ byte[] C = new byte[4];
+ int counter = 0;
+
+ mgfDigest.Reset();
+
+ while (counter < (length / mgfhLen))
+ {
+ ItoOSP(counter, C);
+
+ mgfDigest.BlockUpdate(Z, zOff, zLen);
+ mgfDigest.BlockUpdate(C, 0, C.Length);
+ mgfDigest.DoFinal(hashBuf, 0);
+
+ hashBuf.CopyTo(mask, counter * mgfhLen);
+ ++counter;
+ }
+
+ if ((counter * mgfhLen) < length)
+ {
+ ItoOSP(counter, C);
+
+ mgfDigest.BlockUpdate(Z, zOff, zLen);
+ mgfDigest.BlockUpdate(C, 0, C.Length);
+ mgfDigest.DoFinal(hashBuf, 0);
+
+ Array.Copy(hashBuf, 0, mask, counter * mgfhLen, mask.Length - (counter * mgfhLen));
+ }
+
+ return mask;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/signers/RandomDsaKCalculator.cs b/bc-sharp-crypto/src/crypto/signers/RandomDsaKCalculator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..022cc268d613a89e04fb8107acc4efb84d258ee9
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/signers/RandomDsaKCalculator.cs
@@ -0,0 +1,44 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class RandomDsaKCalculator
+ : IDsaKCalculator
+ {
+ private BigInteger q;
+ private SecureRandom random;
+
+ public virtual bool IsDeterministic
+ {
+ get { return false; }
+ }
+
+ public virtual void Init(BigInteger n, SecureRandom random)
+ {
+ this.q = n;
+ this.random = random;
+ }
+
+ public virtual void Init(BigInteger n, BigInteger d, byte[] message)
+ {
+ throw new InvalidOperationException("Operation not supported");
+ }
+
+ public virtual BigInteger NextK()
+ {
+ int qBitLength = q.BitLength;
+
+ BigInteger k;
+ do
+ {
+ k = new BigInteger(qBitLength, random);
+ }
+ while (k.SignValue < 1 || k.CompareTo(q) >= 0);
+
+ return k;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/signers/RsaDigestSigner.cs b/bc-sharp-crypto/src/crypto/signers/RsaDigestSigner.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d9b19cf6b0f4c1b20eeb4c0063a369ee049e0bfa
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/signers/RsaDigestSigner.cs
@@ -0,0 +1,217 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class RsaDigestSigner
+ : ISigner
+ {
+ private readonly IAsymmetricBlockCipher rsaEngine = new Pkcs1Encoding(new RsaBlindedEngine());
+ private readonly AlgorithmIdentifier algId;
+ private readonly IDigest digest;
+ private bool forSigning;
+
+ private static readonly IDictionary oidMap = Platform.CreateHashtable();
+
+ ///
+ /// Load oid table.
+ ///
+ static RsaDigestSigner()
+ {
+ oidMap["RIPEMD128"] = TeleTrusTObjectIdentifiers.RipeMD128;
+ oidMap["RIPEMD160"] = TeleTrusTObjectIdentifiers.RipeMD160;
+ oidMap["RIPEMD256"] = TeleTrusTObjectIdentifiers.RipeMD256;
+
+ oidMap["SHA-1"] = X509ObjectIdentifiers.IdSha1;
+ oidMap["SHA-224"] = NistObjectIdentifiers.IdSha224;
+ oidMap["SHA-256"] = NistObjectIdentifiers.IdSha256;
+ oidMap["SHA-384"] = NistObjectIdentifiers.IdSha384;
+ oidMap["SHA-512"] = NistObjectIdentifiers.IdSha512;
+
+ oidMap["MD2"] = PkcsObjectIdentifiers.MD2;
+ oidMap["MD4"] = PkcsObjectIdentifiers.MD4;
+ oidMap["MD5"] = PkcsObjectIdentifiers.MD5;
+ }
+
+ public RsaDigestSigner(IDigest digest)
+ : this(digest, (DerObjectIdentifier)oidMap[digest.AlgorithmName])
+ {
+ }
+
+ public RsaDigestSigner(IDigest digest, DerObjectIdentifier digestOid)
+ : this(digest, new AlgorithmIdentifier(digestOid, DerNull.Instance))
+ {
+ }
+
+ public RsaDigestSigner(IDigest digest, AlgorithmIdentifier algId)
+ {
+ this.digest = digest;
+ this.algId = algId;
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return digest.AlgorithmName + "withRSA"; }
+ }
+
+ /**
+ * Initialise the signer for signing or verification.
+ *
+ * @param forSigning true if for signing, false otherwise
+ * @param param necessary parameters.
+ */
+ public virtual void Init(
+ bool forSigning,
+ ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+ AsymmetricKeyParameter k;
+
+ if (parameters is ParametersWithRandom)
+ {
+ k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
+ }
+ else
+ {
+ k = (AsymmetricKeyParameter)parameters;
+ }
+
+ if (forSigning && !k.IsPrivate)
+ throw new InvalidKeyException("Signing requires private key.");
+
+ if (!forSigning && k.IsPrivate)
+ throw new InvalidKeyException("Verification requires public key.");
+
+ Reset();
+
+ rsaEngine.Init(forSigning, parameters);
+ }
+
+ /**
+ * update the internal digest with the byte b
+ */
+ public virtual void Update(
+ byte input)
+ {
+ digest.Update(input);
+ }
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ public virtual void BlockUpdate(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ digest.BlockUpdate(input, inOff, length);
+ }
+
+ /**
+ * Generate a signature for the message we've been loaded with using
+ * the key we were initialised with.
+ */
+ public virtual byte[] GenerateSignature()
+ {
+ if (!forSigning)
+ throw new InvalidOperationException("RsaDigestSigner not initialised for signature generation.");
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ byte[] data = DerEncode(hash);
+ return rsaEngine.ProcessBlock(data, 0, data.Length);
+ }
+
+ /**
+ * return true if the internal state represents the signature described
+ * in the passed in array.
+ */
+ public virtual bool VerifySignature(
+ byte[] signature)
+ {
+ if (forSigning)
+ throw new InvalidOperationException("RsaDigestSigner not initialised for verification");
+
+ byte[] hash = new byte[digest.GetDigestSize()];
+ digest.DoFinal(hash, 0);
+
+ byte[] sig;
+ byte[] expected;
+
+ try
+ {
+ sig = rsaEngine.ProcessBlock(signature, 0, signature.Length);
+ expected = DerEncode(hash);
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+
+ if (sig.Length == expected.Length)
+ {
+ return Arrays.ConstantTimeAreEqual(sig, expected);
+ }
+ else if (sig.Length == expected.Length - 2) // NULL left out
+ {
+ int sigOffset = sig.Length - hash.Length - 2;
+ int expectedOffset = expected.Length - hash.Length - 2;
+
+ expected[1] -= 2; // adjust lengths
+ expected[3] -= 2;
+
+ int nonEqual = 0;
+
+ for (int i = 0; i < hash.Length; i++)
+ {
+ nonEqual |= (sig[sigOffset + i] ^ expected[expectedOffset + i]);
+ }
+
+ for (int i = 0; i < sigOffset; i++)
+ {
+ nonEqual |= (sig[i] ^ expected[i]); // check header less NULL
+ }
+
+ return nonEqual == 0;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public virtual void Reset()
+ {
+ digest.Reset();
+ }
+
+ private byte[] DerEncode(byte[] hash)
+ {
+ if (algId == null)
+ {
+ // For raw RSA, the DigestInfo must be prepared externally
+ return hash;
+ }
+
+ DigestInfo dInfo = new DigestInfo(algId, hash);
+
+ return dInfo.GetDerEncoded();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/signers/X931Signer.cs b/bc-sharp-crypto/src/crypto/signers/X931Signer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c6e44bad827882369fd76f8029f387c233f84adf
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/signers/X931Signer.cs
@@ -0,0 +1,225 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ /**
+ * X9.31-1998 - signing using a hash.
+ *
+ * The message digest hash, H, is encapsulated to form a byte string as follows
+ *
+ *
+ * EB = 06 || PS || 0xBA || H || TRAILER
+ *
+ * where PS is a string of bytes all of value 0xBB of length such that |EB|=|n|, and TRAILER is the ISO/IEC 10118 part number†for the digest. The byte string, EB, is converted to an integer value, the message representative, f.
+ */
+ public class X931Signer
+ : ISigner
+ {
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TRAILER_IMPLICIT = 0xBC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TRAILER_RIPEMD160 = 0x31CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TRAILER_RIPEMD128 = 0x32CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TRAILER_SHA1 = 0x33CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TRAILER_SHA256 = 0x34CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TRAILER_SHA512 = 0x35CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TRAILER_SHA384 = 0x36CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TRAILER_WHIRLPOOL = 0x37CC;
+ [Obsolete("Use 'IsoTrailers' instead")]
+ public const int TRAILER_SHA224 = 0x38CC;
+
+ private IDigest digest;
+ private IAsymmetricBlockCipher cipher;
+ private RsaKeyParameters kParam;
+
+ private int trailer;
+ private int keyBits;
+ private byte[] block;
+
+ /**
+ * Generate a signer with either implicit or explicit trailers for X9.31.
+ *
+ * @param cipher base cipher to use for signature creation/verification
+ * @param digest digest to use.
+ * @param implicit whether or not the trailer is implicit or gives the hash.
+ */
+ public X931Signer(IAsymmetricBlockCipher cipher, IDigest digest, bool isImplicit)
+ {
+ this.cipher = cipher;
+ this.digest = digest;
+
+ if (isImplicit)
+ {
+ trailer = IsoTrailers.TRAILER_IMPLICIT;
+ }
+ else if (IsoTrailers.NoTrailerAvailable(digest))
+ {
+ throw new ArgumentException("no valid trailer", "digest");
+ }
+ else
+ {
+ trailer = IsoTrailers.GetTrailer(digest);
+ }
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return digest.AlgorithmName + "with" + cipher.AlgorithmName + "/X9.31"; }
+ }
+
+ /**
+ * Constructor for a signer with an explicit digest trailer.
+ *
+ * @param cipher cipher to use.
+ * @param digest digest to sign with.
+ */
+ public X931Signer(IAsymmetricBlockCipher cipher, IDigest digest)
+ : this(cipher, digest, false)
+ {
+ }
+
+ public virtual void Init(bool forSigning, ICipherParameters parameters)
+ {
+ kParam = (RsaKeyParameters)parameters;
+
+ cipher.Init(forSigning, kParam);
+
+ keyBits = kParam.Modulus.BitLength;
+
+ block = new byte[(keyBits + 7) / 8];
+
+ Reset();
+ }
+
+ /// clear possible sensitive data
+ private void ClearBlock(byte[] block)
+ {
+ Array.Clear(block, 0, block.Length);
+ }
+
+ /**
+ * update the internal digest with the byte b
+ */
+ public virtual void Update(byte b)
+ {
+ digest.Update(b);
+ }
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ public virtual void BlockUpdate(byte[] input, int off, int len)
+ {
+ digest.BlockUpdate(input, off, len);
+ }
+
+ /**
+ * reset the internal state
+ */
+ public virtual void Reset()
+ {
+ digest.Reset();
+ }
+
+ /**
+ * generate a signature for the loaded message using the key we were
+ * initialised with.
+ */
+ public virtual byte[] GenerateSignature()
+ {
+ CreateSignatureBlock();
+
+ BigInteger t = new BigInteger(1, cipher.ProcessBlock(block, 0, block.Length));
+ ClearBlock(block);
+
+ t = t.Min(kParam.Modulus.Subtract(t));
+
+ return BigIntegers.AsUnsignedByteArray((kParam.Modulus.BitLength + 7) / 8, t);
+ }
+
+ private void CreateSignatureBlock()
+ {
+ int digSize = digest.GetDigestSize();
+
+ int delta;
+ if (trailer == IsoTrailers.TRAILER_IMPLICIT)
+ {
+ delta = block.Length - digSize - 1;
+ digest.DoFinal(block, delta);
+ block[block.Length - 1] = (byte)IsoTrailers.TRAILER_IMPLICIT;
+ }
+ else
+ {
+ delta = block.Length - digSize - 2;
+ digest.DoFinal(block, delta);
+ block[block.Length - 2] = (byte)(trailer >> 8);
+ block[block.Length - 1] = (byte)trailer;
+ }
+
+ block[0] = 0x6b;
+ for (int i = delta - 2; i != 0; i--)
+ {
+ block[i] = (byte)0xbb;
+ }
+ block[delta - 1] = (byte)0xba;
+ }
+
+ /**
+ * return true if the signature represents a ISO9796-2 signature
+ * for the passed in message.
+ */
+ public virtual bool VerifySignature(byte[] signature)
+ {
+ try
+ {
+ block = cipher.ProcessBlock(signature, 0, signature.Length);
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+
+ BigInteger t = new BigInteger(1, block);
+ BigInteger f;
+
+ if ((t.IntValue & 15) == 12)
+ {
+ f = t;
+ }
+ else
+ {
+ t = kParam.Modulus.Subtract(t);
+ if ((t.IntValue & 15) == 12)
+ {
+ f = t;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ CreateSignatureBlock();
+
+ byte[] fBlock = BigIntegers.AsUnsignedByteArray(block.Length, f);
+
+ bool rv = Arrays.ConstantTimeAreEqual(block, fBlock);
+
+ ClearBlock(block);
+ ClearBlock(fBlock);
+
+ return rv;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/AbstractTlsAgreementCredentials.cs b/bc-sharp-crypto/src/crypto/tls/AbstractTlsAgreementCredentials.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2d7af80e87d0978d3ab19eba913b93babc67e8bd
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/AbstractTlsAgreementCredentials.cs
@@ -0,0 +1,12 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class AbstractTlsAgreementCredentials
+ : AbstractTlsCredentials, TlsAgreementCredentials
+ {
+ ///
+ public abstract byte[] GenerateAgreement(AsymmetricKeyParameter peerPublicKey);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/AbstractTlsCipherFactory.cs b/bc-sharp-crypto/src/crypto/tls/AbstractTlsCipherFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..141ee650755bf98f8e2c47d35977017aa3c5ce2b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/AbstractTlsCipherFactory.cs
@@ -0,0 +1,15 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class AbstractTlsCipherFactory
+ : TlsCipherFactory
+ {
+ ///
+ public virtual TlsCipher CreateCipher(TlsContext context, int encryptionAlgorithm, int macAlgorithm)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/AbstractTlsClient.cs b/bc-sharp-crypto/src/crypto/tls/AbstractTlsClient.cs
new file mode 100644
index 0000000000000000000000000000000000000000..be4702e5ef2affdc59873c6081e360dd8ecff23c
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/AbstractTlsClient.cs
@@ -0,0 +1,256 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class AbstractTlsClient
+ : AbstractTlsPeer, TlsClient
+ {
+ protected TlsCipherFactory mCipherFactory;
+
+ protected TlsClientContext mContext;
+
+ protected IList mSupportedSignatureAlgorithms;
+ protected int[] mNamedCurves;
+ protected byte[] mClientECPointFormats, mServerECPointFormats;
+
+ protected int mSelectedCipherSuite;
+ protected short mSelectedCompressionMethod;
+
+ public AbstractTlsClient()
+ : this(new DefaultTlsCipherFactory())
+ {
+ }
+
+ public AbstractTlsClient(TlsCipherFactory cipherFactory)
+ {
+ this.mCipherFactory = cipherFactory;
+ }
+
+ protected virtual bool AllowUnexpectedServerExtension(int extensionType, byte[] extensionData)
+ {
+ switch (extensionType)
+ {
+ case ExtensionType.elliptic_curves:
+ /*
+ * Exception added based on field reports that some servers do send this, although the
+ * Supported Elliptic Curves Extension is clearly intended to be client-only. If
+ * present, we still require that it is a valid EllipticCurveList.
+ */
+ TlsEccUtilities.ReadSupportedEllipticCurvesExtension(extensionData);
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ protected virtual void CheckForUnexpectedServerExtension(IDictionary serverExtensions, int extensionType)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(serverExtensions, extensionType);
+ if (extensionData != null && !AllowUnexpectedServerExtension(extensionType, extensionData))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+
+ public virtual void Init(TlsClientContext context)
+ {
+ this.mContext = context;
+ }
+
+ public virtual TlsSession GetSessionToResume()
+ {
+ return null;
+ }
+
+ public virtual ProtocolVersion ClientHelloRecordLayerVersion
+ {
+ get
+ {
+ // "{03,00}"
+ //return ProtocolVersion.SSLv3;
+
+ // "the lowest version number supported by the client"
+ //return MinimumVersion;
+
+ // "the value of ClientHello.client_version"
+ return ClientVersion;
+ }
+ }
+
+ public virtual ProtocolVersion ClientVersion
+ {
+ get { return ProtocolVersion.TLSv12; }
+ }
+
+ public virtual bool IsFallback
+ {
+ /*
+ * RFC 7507 4. The TLS_FALLBACK_SCSV cipher suite value is meant for use by clients that
+ * repeat a connection attempt with a downgraded protocol (perform a "fallback retry") in
+ * order to work around interoperability problems with legacy servers.
+ */
+ get { return false; }
+ }
+
+ public virtual IDictionary GetClientExtensions()
+ {
+ IDictionary clientExtensions = null;
+
+ ProtocolVersion clientVersion = mContext.ClientVersion;
+
+ /*
+ * RFC 5246 7.4.1.4.1. Note: this extension is not meaningful for TLS versions prior to 1.2.
+ * Clients MUST NOT offer it if they are offering prior versions.
+ */
+ if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(clientVersion))
+ {
+ // TODO Provide a way for the user to specify the acceptable hash/signature algorithms.
+
+ this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultSupportedSignatureAlgorithms();
+
+ clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(clientExtensions);
+
+ TlsUtilities.AddSignatureAlgorithmsExtension(clientExtensions, mSupportedSignatureAlgorithms);
+ }
+
+ if (TlsEccUtilities.ContainsEccCipherSuites(GetCipherSuites()))
+ {
+ /*
+ * RFC 4492 5.1. A client that proposes ECC cipher suites in its ClientHello message
+ * appends these extensions (along with any others), enumerating the curves it supports
+ * and the point formats it can parse. Clients SHOULD send both the Supported Elliptic
+ * Curves Extension and the Supported Point Formats Extension.
+ */
+ /*
+ * TODO Could just add all the curves since we support them all, but users may not want
+ * to use unnecessarily large fields. Need configuration options.
+ */
+ this.mNamedCurves = new int[]{ NamedCurve.secp256r1, NamedCurve.secp384r1 };
+ this.mClientECPointFormats = new byte[]{ ECPointFormat.uncompressed,
+ ECPointFormat.ansiX962_compressed_prime, ECPointFormat.ansiX962_compressed_char2, };
+
+ clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(clientExtensions);
+
+ TlsEccUtilities.AddSupportedEllipticCurvesExtension(clientExtensions, mNamedCurves);
+ TlsEccUtilities.AddSupportedPointFormatsExtension(clientExtensions, mClientECPointFormats);
+ }
+
+ return clientExtensions;
+ }
+
+ public virtual ProtocolVersion MinimumVersion
+ {
+ get { return ProtocolVersion.TLSv10; }
+ }
+
+ public virtual void NotifyServerVersion(ProtocolVersion serverVersion)
+ {
+ if (!MinimumVersion.IsEqualOrEarlierVersionOf(serverVersion))
+ throw new TlsFatalAlert(AlertDescription.protocol_version);
+ }
+
+ public abstract int[] GetCipherSuites();
+
+ public virtual byte[] GetCompressionMethods()
+ {
+ return new byte[]{ CompressionMethod.cls_null };
+ }
+
+ public virtual void NotifySessionID(byte[] sessionID)
+ {
+ // Currently ignored
+ }
+
+ public virtual void NotifySelectedCipherSuite(int selectedCipherSuite)
+ {
+ this.mSelectedCipherSuite = selectedCipherSuite;
+ }
+
+ public virtual void NotifySelectedCompressionMethod(byte selectedCompressionMethod)
+ {
+ this.mSelectedCompressionMethod = selectedCompressionMethod;
+ }
+
+ public virtual void ProcessServerExtensions(IDictionary serverExtensions)
+ {
+ /*
+ * TlsProtocol implementation validates that any server extensions received correspond to
+ * client extensions sent. By default, we don't send any, and this method is not called.
+ */
+ if (serverExtensions != null)
+ {
+ /*
+ * RFC 5246 7.4.1.4.1. Servers MUST NOT send this extension.
+ */
+ CheckForUnexpectedServerExtension(serverExtensions, ExtensionType.signature_algorithms);
+
+ CheckForUnexpectedServerExtension(serverExtensions, ExtensionType.elliptic_curves);
+
+ if (TlsEccUtilities.IsEccCipherSuite(this.mSelectedCipherSuite))
+ {
+ this.mServerECPointFormats = TlsEccUtilities.GetSupportedPointFormatsExtension(serverExtensions);
+ }
+ else
+ {
+ CheckForUnexpectedServerExtension(serverExtensions, ExtensionType.ec_point_formats);
+ }
+
+ /*
+ * RFC 7685 3. The server MUST NOT echo the extension.
+ */
+ CheckForUnexpectedServerExtension(serverExtensions, ExtensionType.padding);
+ }
+ }
+
+ public virtual void ProcessServerSupplementalData(IList serverSupplementalData)
+ {
+ if (serverSupplementalData != null)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public abstract TlsKeyExchange GetKeyExchange();
+
+ public abstract TlsAuthentication GetAuthentication();
+
+ public virtual IList GetClientSupplementalData()
+ {
+ return null;
+ }
+
+ public override TlsCompression GetCompression()
+ {
+ switch (mSelectedCompressionMethod)
+ {
+ case CompressionMethod.cls_null:
+ return new TlsNullCompression();
+
+ case CompressionMethod.DEFLATE:
+ return new TlsDeflateCompression();
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocol implementation verifies that the
+ * server-selected compression method was in the list of client-offered compression
+ * methods, so if we now can't produce an implementation, we shouldn't have offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public override TlsCipher GetCipher()
+ {
+ int encryptionAlgorithm = TlsUtilities.GetEncryptionAlgorithm(mSelectedCipherSuite);
+ int macAlgorithm = TlsUtilities.GetMacAlgorithm(mSelectedCipherSuite);
+
+ return mCipherFactory.CreateCipher(mContext, encryptionAlgorithm, macAlgorithm);
+ }
+
+ public virtual void NotifyNewSessionTicket(NewSessionTicket newSessionTicket)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/AbstractTlsContext.cs b/bc-sharp-crypto/src/crypto/tls/AbstractTlsContext.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ae7efc64d23a70bf6ac464add0d585a99943e28a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/AbstractTlsContext.cs
@@ -0,0 +1,152 @@
+using System;
+using System.Threading;
+
+using Org.BouncyCastle.Crypto.Prng;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ internal abstract class AbstractTlsContext
+ : TlsContext
+ {
+ private static long counter = Times.NanoTime();
+
+#if NETCF_1_0
+ private static object counterLock = new object();
+ private static long NextCounterValue()
+ {
+ lock (counterLock)
+ {
+ return ++counter;
+ }
+ }
+#else
+ private static long NextCounterValue()
+ {
+ return Interlocked.Increment(ref counter);
+ }
+#endif
+
+ private readonly IRandomGenerator mNonceRandom;
+ private readonly SecureRandom mSecureRandom;
+ private readonly SecurityParameters mSecurityParameters;
+
+ private ProtocolVersion mClientVersion = null;
+ private ProtocolVersion mServerVersion = null;
+ private TlsSession mSession = null;
+ private object mUserObject = null;
+
+ internal AbstractTlsContext(SecureRandom secureRandom, SecurityParameters securityParameters)
+ {
+ IDigest d = TlsUtilities.CreateHash(HashAlgorithm.sha256);
+ byte[] seed = new byte[d.GetDigestSize()];
+ secureRandom.NextBytes(seed);
+
+ this.mNonceRandom = new DigestRandomGenerator(d);
+ mNonceRandom.AddSeedMaterial(NextCounterValue());
+ mNonceRandom.AddSeedMaterial(Times.NanoTime());
+ mNonceRandom.AddSeedMaterial(seed);
+
+ this.mSecureRandom = secureRandom;
+ this.mSecurityParameters = securityParameters;
+ }
+
+ public virtual IRandomGenerator NonceRandomGenerator
+ {
+ get { return mNonceRandom; }
+ }
+
+ public virtual SecureRandom SecureRandom
+ {
+ get { return mSecureRandom; }
+ }
+
+ public virtual SecurityParameters SecurityParameters
+ {
+ get { return mSecurityParameters; }
+ }
+
+ public abstract bool IsServer { get; }
+
+ public virtual ProtocolVersion ClientVersion
+ {
+ get { return mClientVersion; }
+ }
+
+ internal virtual void SetClientVersion(ProtocolVersion clientVersion)
+ {
+ this.mClientVersion = clientVersion;
+ }
+
+ public virtual ProtocolVersion ServerVersion
+ {
+ get { return mServerVersion; }
+ }
+
+ internal virtual void SetServerVersion(ProtocolVersion serverVersion)
+ {
+ this.mServerVersion = serverVersion;
+ }
+
+ public virtual TlsSession ResumableSession
+ {
+ get { return mSession; }
+ }
+
+ internal virtual void SetResumableSession(TlsSession session)
+ {
+ this.mSession = session;
+ }
+
+ public virtual object UserObject
+ {
+ get { return mUserObject; }
+ set { this.mUserObject = value; }
+ }
+
+ public virtual byte[] ExportKeyingMaterial(string asciiLabel, byte[] context_value, int length)
+ {
+ /*
+ * TODO[session-hash]
+ *
+ * draft-ietf-tls-session-hash-04 5.4. If a client or server chooses to continue with a full
+ * handshake without the extended master secret extension, [..] the client or server MUST
+ * NOT export any key material based on the new master secret for any subsequent
+ * application-level authentication. In particular, it MUST disable [RFC5705] [..].
+ */
+
+ if (context_value != null && !TlsUtilities.IsValidUint16(context_value.Length))
+ throw new ArgumentException("must have length less than 2^16 (or be null)", "context_value");
+
+ SecurityParameters sp = SecurityParameters;
+ byte[] cr = sp.ClientRandom, sr = sp.ServerRandom;
+
+ int seedLength = cr.Length + sr.Length;
+ if (context_value != null)
+ {
+ seedLength += (2 + context_value.Length);
+ }
+
+ byte[] seed = new byte[seedLength];
+ int seedPos = 0;
+
+ Array.Copy(cr, 0, seed, seedPos, cr.Length);
+ seedPos += cr.Length;
+ Array.Copy(sr, 0, seed, seedPos, sr.Length);
+ seedPos += sr.Length;
+ if (context_value != null)
+ {
+ TlsUtilities.WriteUint16(context_value.Length, seed, seedPos);
+ seedPos += 2;
+ Array.Copy(context_value, 0, seed, seedPos, context_value.Length);
+ seedPos += context_value.Length;
+ }
+
+ if (seedPos != seedLength)
+ throw new InvalidOperationException("error in calculation of seed for export");
+
+ return TlsUtilities.PRF(this, sp.MasterSecret, asciiLabel, seed, length);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/AbstractTlsCredentials.cs b/bc-sharp-crypto/src/crypto/tls/AbstractTlsCredentials.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6411b811cf29d50fa354e5d60d9afc8edaad9762
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/AbstractTlsCredentials.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class AbstractTlsCredentials
+ : TlsCredentials
+ {
+ public abstract Certificate Certificate { get; }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/AbstractTlsEncryptionCredentials.cs b/bc-sharp-crypto/src/crypto/tls/AbstractTlsEncryptionCredentials.cs
new file mode 100644
index 0000000000000000000000000000000000000000..05b129c600697de9d9e1d118e98990033e9b18b9
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/AbstractTlsEncryptionCredentials.cs
@@ -0,0 +1,12 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class AbstractTlsEncryptionCredentials
+ : AbstractTlsCredentials, TlsEncryptionCredentials
+ {
+ ///
+ public abstract byte[] DecryptPreMasterSecret(byte[] encryptedPreMasterSecret);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/AbstractTlsKeyExchange.cs b/bc-sharp-crypto/src/crypto/tls/AbstractTlsKeyExchange.cs
new file mode 100644
index 0000000000000000000000000000000000000000..294b249293e824932ef57dc6a1c8ea2d5b5130f3
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/AbstractTlsKeyExchange.cs
@@ -0,0 +1,177 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class AbstractTlsKeyExchange
+ : TlsKeyExchange
+ {
+ protected readonly int mKeyExchange;
+ protected IList mSupportedSignatureAlgorithms;
+
+ protected TlsContext mContext;
+
+ protected AbstractTlsKeyExchange(int keyExchange, IList supportedSignatureAlgorithms)
+ {
+ this.mKeyExchange = keyExchange;
+ this.mSupportedSignatureAlgorithms = supportedSignatureAlgorithms;
+ }
+
+ protected virtual DigitallySigned ParseSignature(Stream input)
+ {
+ DigitallySigned signature = DigitallySigned.Parse(mContext, input);
+ SignatureAndHashAlgorithm signatureAlgorithm = signature.Algorithm;
+ if (signatureAlgorithm != null)
+ {
+ TlsUtilities.VerifySupportedSignatureAlgorithm(mSupportedSignatureAlgorithms, signatureAlgorithm);
+ }
+ return signature;
+ }
+
+ public virtual void Init(TlsContext context)
+ {
+ this.mContext = context;
+
+ ProtocolVersion clientVersion = context.ClientVersion;
+
+ if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(clientVersion))
+ {
+ /*
+ * RFC 5246 7.4.1.4.1. If the client does not send the signature_algorithms extension,
+ * the server MUST do the following:
+ *
+ * - If the negotiated key exchange algorithm is one of (RSA, DHE_RSA, DH_RSA, RSA_PSK,
+ * ECDH_RSA, ECDHE_RSA), behave as if client had sent the value {sha1,rsa}.
+ *
+ * - If the negotiated key exchange algorithm is one of (DHE_DSS, DH_DSS), behave as if
+ * the client had sent the value {sha1,dsa}.
+ *
+ * - If the negotiated key exchange algorithm is one of (ECDH_ECDSA, ECDHE_ECDSA),
+ * behave as if the client had sent value {sha1,ecdsa}.
+ */
+ if (this.mSupportedSignatureAlgorithms == null)
+ {
+ switch (mKeyExchange)
+ {
+ case KeyExchangeAlgorithm.DH_DSS:
+ case KeyExchangeAlgorithm.DHE_DSS:
+ case KeyExchangeAlgorithm.SRP_DSS:
+ {
+ this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultDssSignatureAlgorithms();
+ break;
+ }
+
+ case KeyExchangeAlgorithm.ECDH_ECDSA:
+ case KeyExchangeAlgorithm.ECDHE_ECDSA:
+ {
+ this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultECDsaSignatureAlgorithms();
+ break;
+ }
+
+ case KeyExchangeAlgorithm.DH_RSA:
+ case KeyExchangeAlgorithm.DHE_RSA:
+ case KeyExchangeAlgorithm.ECDH_RSA:
+ case KeyExchangeAlgorithm.ECDHE_RSA:
+ case KeyExchangeAlgorithm.RSA:
+ case KeyExchangeAlgorithm.RSA_PSK:
+ case KeyExchangeAlgorithm.SRP_RSA:
+ {
+ this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultRsaSignatureAlgorithms();
+ break;
+ }
+
+ case KeyExchangeAlgorithm.DHE_PSK:
+ case KeyExchangeAlgorithm.ECDHE_PSK:
+ case KeyExchangeAlgorithm.PSK:
+ case KeyExchangeAlgorithm.SRP:
+ break;
+
+ default:
+ throw new InvalidOperationException("unsupported key exchange algorithm");
+ }
+ }
+
+ }
+ else if (this.mSupportedSignatureAlgorithms != null)
+ {
+ throw new InvalidOperationException("supported_signature_algorithms not allowed for " + clientVersion);
+ }
+ }
+
+ public abstract void SkipServerCredentials();
+
+ public virtual void ProcessServerCertificate(Certificate serverCertificate)
+ {
+ if (mSupportedSignatureAlgorithms == null)
+ {
+ /*
+ * TODO RFC 2246 7.4.2. Unless otherwise specified, the signing algorithm for the
+ * certificate must be the same as the algorithm for the certificate key.
+ */
+ }
+ else
+ {
+ /*
+ * TODO RFC 5246 7.4.2. If the client provided a "signature_algorithms" extension, then
+ * all certificates provided by the server MUST be signed by a hash/signature algorithm
+ * pair that appears in that extension.
+ */
+ }
+ }
+
+ public virtual void ProcessServerCredentials(TlsCredentials serverCredentials)
+ {
+ ProcessServerCertificate(serverCredentials.Certificate);
+ }
+
+ public virtual bool RequiresServerKeyExchange
+ {
+ get { return false; }
+ }
+
+ public virtual byte[] GenerateServerKeyExchange()
+ {
+ if (RequiresServerKeyExchange)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ return null;
+ }
+
+ public virtual void SkipServerKeyExchange()
+ {
+ if (RequiresServerKeyExchange)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public virtual void ProcessServerKeyExchange(Stream input)
+ {
+ if (!RequiresServerKeyExchange)
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ }
+
+ public abstract void ValidateCertificateRequest(CertificateRequest certificateRequest);
+
+ public virtual void SkipClientCredentials()
+ {
+ }
+
+ public abstract void ProcessClientCredentials(TlsCredentials clientCredentials);
+
+ public virtual void ProcessClientCertificate(Certificate clientCertificate)
+ {
+ }
+
+ public abstract void GenerateClientKeyExchange(Stream output);
+
+ public virtual void ProcessClientKeyExchange(Stream input)
+ {
+ // Key exchange implementation MUST support client key exchange
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public abstract byte[] GeneratePremasterSecret();
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/AbstractTlsPeer.cs b/bc-sharp-crypto/src/crypto/tls/AbstractTlsPeer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..81a53386c511d4ea34003ad1d55dabb1f7c93777
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/AbstractTlsPeer.cs
@@ -0,0 +1,48 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class AbstractTlsPeer
+ : TlsPeer
+ {
+ public virtual bool ShouldUseGmtUnixTime()
+ {
+ /*
+ * draft-mathewson-no-gmtunixtime-00 2. For the reasons we discuss above, we recommend that
+ * TLS implementors MUST by default set the entire value the ClientHello.Random and
+ * ServerHello.Random fields, including gmt_unix_time, to a cryptographically random
+ * sequence.
+ */
+ return false;
+ }
+
+ public virtual void NotifySecureRenegotiation(bool secureRenegotiation)
+ {
+ if (!secureRenegotiation)
+ {
+ /*
+ * RFC 5746 3.4/3.6. In this case, some clients/servers may want to terminate the handshake instead
+ * of continuing; see Section 4.1/4.3 for discussion.
+ */
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+ }
+
+ public abstract TlsCompression GetCompression();
+
+ public abstract TlsCipher GetCipher();
+
+ public virtual void NotifyAlertRaised(byte alertLevel, byte alertDescription, string message, Exception cause)
+ {
+ }
+
+ public virtual void NotifyAlertReceived(byte alertLevel, byte alertDescription)
+ {
+ }
+
+ public virtual void NotifyHandshakeComplete()
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/AbstractTlsServer.cs b/bc-sharp-crypto/src/crypto/tls/AbstractTlsServer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..52a79c9d86e8ebe2c93d9b4447e0be68a87e7e6b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/AbstractTlsServer.cs
@@ -0,0 +1,351 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class AbstractTlsServer
+ : AbstractTlsPeer, TlsServer
+ {
+ protected TlsCipherFactory mCipherFactory;
+
+ protected TlsServerContext mContext;
+
+ protected ProtocolVersion mClientVersion;
+ protected int[] mOfferedCipherSuites;
+ protected byte[] mOfferedCompressionMethods;
+ protected IDictionary mClientExtensions;
+
+ protected bool mEncryptThenMacOffered;
+ protected short mMaxFragmentLengthOffered;
+ protected bool mTruncatedHMacOffered;
+ protected IList mSupportedSignatureAlgorithms;
+ protected bool mEccCipherSuitesOffered;
+ protected int[] mNamedCurves;
+ protected byte[] mClientECPointFormats, mServerECPointFormats;
+
+ protected ProtocolVersion mServerVersion;
+ protected int mSelectedCipherSuite;
+ protected byte mSelectedCompressionMethod;
+ protected IDictionary mServerExtensions;
+
+ public AbstractTlsServer()
+ : this(new DefaultTlsCipherFactory())
+ {
+ }
+
+ public AbstractTlsServer(TlsCipherFactory cipherFactory)
+ {
+ this.mCipherFactory = cipherFactory;
+ }
+
+ protected virtual bool AllowEncryptThenMac
+ {
+ get { return true; }
+ }
+
+ protected virtual bool AllowTruncatedHMac
+ {
+ get { return false; }
+ }
+
+ protected virtual IDictionary CheckServerExtensions()
+ {
+ return this.mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(this.mServerExtensions);
+ }
+
+ protected abstract int[] GetCipherSuites();
+
+ protected byte[] GetCompressionMethods()
+ {
+ return new byte[] { CompressionMethod.cls_null };
+ }
+
+ protected virtual ProtocolVersion MaximumVersion
+ {
+ get { return ProtocolVersion.TLSv11; }
+ }
+
+ protected virtual ProtocolVersion MinimumVersion
+ {
+ get { return ProtocolVersion.TLSv10; }
+ }
+
+ protected virtual bool SupportsClientEccCapabilities(int[] namedCurves, byte[] ecPointFormats)
+ {
+ // NOTE: BC supports all the current set of point formats so we don't check them here
+
+ if (namedCurves == null)
+ {
+ /*
+ * RFC 4492 4. A client that proposes ECC cipher suites may choose not to include these
+ * extensions. In this case, the server is free to choose any one of the elliptic curves
+ * or point formats [...].
+ */
+ return TlsEccUtilities.HasAnySupportedNamedCurves();
+ }
+
+ for (int i = 0; i < namedCurves.Length; ++i)
+ {
+ int namedCurve = namedCurves[i];
+ if (NamedCurve.IsValid(namedCurve)
+ && (!NamedCurve.RefersToASpecificNamedCurve(namedCurve) || TlsEccUtilities.IsSupportedNamedCurve(namedCurve)))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public virtual void Init(TlsServerContext context)
+ {
+ this.mContext = context;
+ }
+
+ public virtual void NotifyClientVersion(ProtocolVersion clientVersion)
+ {
+ this.mClientVersion = clientVersion;
+ }
+
+ public virtual void NotifyFallback(bool isFallback)
+ {
+ /*
+ * RFC 7507 3. If TLS_FALLBACK_SCSV appears in ClientHello.cipher_suites and the highest
+ * protocol version supported by the server is higher than the version indicated in
+ * ClientHello.client_version, the server MUST respond with a fatal inappropriate_fallback
+ * alert [..].
+ */
+ if (isFallback && MaximumVersion.IsLaterVersionOf(mClientVersion))
+ throw new TlsFatalAlert(AlertDescription.inappropriate_fallback);
+ }
+
+ public virtual void NotifyOfferedCipherSuites(int[] offeredCipherSuites)
+ {
+ this.mOfferedCipherSuites = offeredCipherSuites;
+ this.mEccCipherSuitesOffered = TlsEccUtilities.ContainsEccCipherSuites(this.mOfferedCipherSuites);
+ }
+
+ public virtual void NotifyOfferedCompressionMethods(byte[] offeredCompressionMethods)
+ {
+ this.mOfferedCompressionMethods = offeredCompressionMethods;
+ }
+
+ public virtual void ProcessClientExtensions(IDictionary clientExtensions)
+ {
+ this.mClientExtensions = clientExtensions;
+
+ if (clientExtensions != null)
+ {
+ this.mEncryptThenMacOffered = TlsExtensionsUtilities.HasEncryptThenMacExtension(clientExtensions);
+
+ this.mMaxFragmentLengthOffered = TlsExtensionsUtilities.GetMaxFragmentLengthExtension(clientExtensions);
+ if (mMaxFragmentLengthOffered >= 0 && !MaxFragmentLength.IsValid((byte)mMaxFragmentLengthOffered))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ this.mTruncatedHMacOffered = TlsExtensionsUtilities.HasTruncatedHMacExtension(clientExtensions);
+
+ this.mSupportedSignatureAlgorithms = TlsUtilities.GetSignatureAlgorithmsExtension(clientExtensions);
+ if (this.mSupportedSignatureAlgorithms != null)
+ {
+ /*
+ * RFC 5246 7.4.1.4.1. Note: this extension is not meaningful for TLS versions prior
+ * to 1.2. Clients MUST NOT offer it if they are offering prior versions.
+ */
+ if (!TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(mClientVersion))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ this.mNamedCurves = TlsEccUtilities.GetSupportedEllipticCurvesExtension(clientExtensions);
+ this.mClientECPointFormats = TlsEccUtilities.GetSupportedPointFormatsExtension(clientExtensions);
+ }
+
+ /*
+ * RFC 4429 4. The client MUST NOT include these extensions in the ClientHello message if it
+ * does not propose any ECC cipher suites.
+ *
+ * NOTE: This was overly strict as there may be ECC cipher suites that we don't recognize.
+ * Also, draft-ietf-tls-negotiated-ff-dhe will be overloading the 'elliptic_curves'
+ * extension to explicitly allow FFDHE (i.e. non-ECC) groups.
+ */
+ //if (!this.mEccCipherSuitesOffered && (this.mNamedCurves != null || this.mClientECPointFormats != null))
+ // throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ public virtual ProtocolVersion GetServerVersion()
+ {
+ if (MinimumVersion.IsEqualOrEarlierVersionOf(mClientVersion))
+ {
+ ProtocolVersion maximumVersion = MaximumVersion;
+ if (mClientVersion.IsEqualOrEarlierVersionOf(maximumVersion))
+ {
+ return mServerVersion = mClientVersion;
+ }
+ if (mClientVersion.IsLaterVersionOf(maximumVersion))
+ {
+ return mServerVersion = maximumVersion;
+ }
+ }
+ throw new TlsFatalAlert(AlertDescription.protocol_version);
+ }
+
+ public virtual int GetSelectedCipherSuite()
+ {
+ /*
+ * RFC 5246 7.4.3. In order to negotiate correctly, the server MUST check any candidate
+ * cipher suites against the "signature_algorithms" extension before selecting them. This is
+ * somewhat inelegant but is a compromise designed to minimize changes to the original
+ * cipher suite design.
+ */
+ IList sigAlgs = TlsUtilities.GetUsableSignatureAlgorithms(this.mSupportedSignatureAlgorithms);
+
+ /*
+ * RFC 4429 5.1. A server that receives a ClientHello containing one or both of these
+ * extensions MUST use the client's enumerated capabilities to guide its selection of an
+ * appropriate cipher suite. One of the proposed ECC cipher suites must be negotiated only
+ * if the server can successfully complete the handshake while using the curves and point
+ * formats supported by the client [...].
+ */
+ bool eccCipherSuitesEnabled = SupportsClientEccCapabilities(this.mNamedCurves, this.mClientECPointFormats);
+
+ int[] cipherSuites = GetCipherSuites();
+ for (int i = 0; i < cipherSuites.Length; ++i)
+ {
+ int cipherSuite = cipherSuites[i];
+
+ if (Arrays.Contains(this.mOfferedCipherSuites, cipherSuite)
+ && (eccCipherSuitesEnabled || !TlsEccUtilities.IsEccCipherSuite(cipherSuite))
+ && TlsUtilities.IsValidCipherSuiteForVersion(cipherSuite, mServerVersion)
+ && TlsUtilities.IsValidCipherSuiteForSignatureAlgorithms(cipherSuite, sigAlgs))
+ {
+ return this.mSelectedCipherSuite = cipherSuite;
+ }
+ }
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+
+ public virtual byte GetSelectedCompressionMethod()
+ {
+ byte[] compressionMethods = GetCompressionMethods();
+ for (int i = 0; i < compressionMethods.Length; ++i)
+ {
+ if (Arrays.Contains(mOfferedCompressionMethods, compressionMethods[i]))
+ {
+ return this.mSelectedCompressionMethod = compressionMethods[i];
+ }
+ }
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+
+ // IDictionary is (Int32 -> byte[])
+ public virtual IDictionary GetServerExtensions()
+ {
+ if (this.mEncryptThenMacOffered && AllowEncryptThenMac)
+ {
+ /*
+ * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client
+ * and then selects a stream or Authenticated Encryption with Associated Data (AEAD)
+ * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the
+ * client.
+ */
+ if (TlsUtilities.IsBlockCipherSuite(this.mSelectedCipherSuite))
+ {
+ TlsExtensionsUtilities.AddEncryptThenMacExtension(CheckServerExtensions());
+ }
+ }
+
+ if (this.mMaxFragmentLengthOffered >= 0
+ && TlsUtilities.IsValidUint8(mMaxFragmentLengthOffered)
+ && MaxFragmentLength.IsValid((byte)mMaxFragmentLengthOffered))
+ {
+ TlsExtensionsUtilities.AddMaxFragmentLengthExtension(CheckServerExtensions(), (byte)mMaxFragmentLengthOffered);
+ }
+
+ if (this.mTruncatedHMacOffered && AllowTruncatedHMac)
+ {
+ TlsExtensionsUtilities.AddTruncatedHMacExtension(CheckServerExtensions());
+ }
+
+ if (this.mClientECPointFormats != null && TlsEccUtilities.IsEccCipherSuite(this.mSelectedCipherSuite))
+ {
+ /*
+ * RFC 4492 5.2. A server that selects an ECC cipher suite in response to a ClientHello
+ * message including a Supported Point Formats Extension appends this extension (along
+ * with others) to its ServerHello message, enumerating the point formats it can parse.
+ */
+ this.mServerECPointFormats = new byte[]{ ECPointFormat.uncompressed,
+ ECPointFormat.ansiX962_compressed_prime, ECPointFormat.ansiX962_compressed_char2, };
+
+ TlsEccUtilities.AddSupportedPointFormatsExtension(CheckServerExtensions(), mServerECPointFormats);
+ }
+
+ return mServerExtensions;
+ }
+
+ public virtual IList GetServerSupplementalData()
+ {
+ return null;
+ }
+
+ public abstract TlsCredentials GetCredentials();
+
+ public virtual CertificateStatus GetCertificateStatus()
+ {
+ return null;
+ }
+
+ public abstract TlsKeyExchange GetKeyExchange();
+
+ public virtual CertificateRequest GetCertificateRequest()
+ {
+ return null;
+ }
+
+ public virtual void ProcessClientSupplementalData(IList clientSupplementalData)
+ {
+ if (clientSupplementalData != null)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public virtual void NotifyClientCertificate(Certificate clientCertificate)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public override TlsCompression GetCompression()
+ {
+ switch (mSelectedCompressionMethod)
+ {
+ case CompressionMethod.cls_null:
+ return new TlsNullCompression();
+
+ default:
+ /*
+ * Note: internal error here; we selected the compression method, so if we now can't
+ * produce an implementation, we shouldn't have chosen it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public override TlsCipher GetCipher()
+ {
+ int encryptionAlgorithm = TlsUtilities.GetEncryptionAlgorithm(mSelectedCipherSuite);
+ int macAlgorithm = TlsUtilities.GetMacAlgorithm(mSelectedCipherSuite);
+
+ return mCipherFactory.CreateCipher(mContext, encryptionAlgorithm, macAlgorithm);
+ }
+
+ public virtual NewSessionTicket GetNewSessionTicket()
+ {
+ /*
+ * RFC 5077 3.3. If the server determines that it does not want to include a ticket after it
+ * has included the SessionTicket extension in the ServerHello, then it sends a zero-length
+ * ticket in the NewSessionTicket handshake message.
+ */
+ return new NewSessionTicket(0L, TlsUtilities.EmptyBytes);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/AbstractTlsSigner.cs b/bc-sharp-crypto/src/crypto/tls/AbstractTlsSigner.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1f4aabf744c90aee2dc4dbf3a40612ebe1d1d2c5
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/AbstractTlsSigner.cs
@@ -0,0 +1,50 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class AbstractTlsSigner
+ : TlsSigner
+ {
+ protected TlsContext mContext;
+
+ public virtual void Init(TlsContext context)
+ {
+ this.mContext = context;
+ }
+
+ public virtual byte[] GenerateRawSignature(AsymmetricKeyParameter privateKey, byte[] md5AndSha1)
+ {
+ return GenerateRawSignature(null, privateKey, md5AndSha1);
+ }
+
+ public abstract byte[] GenerateRawSignature(SignatureAndHashAlgorithm algorithm,
+ AsymmetricKeyParameter privateKey, byte[] hash);
+
+ public virtual bool VerifyRawSignature(byte[] sigBytes, AsymmetricKeyParameter publicKey, byte[] md5AndSha1)
+ {
+ return VerifyRawSignature(null, sigBytes, publicKey, md5AndSha1);
+ }
+
+ public abstract bool VerifyRawSignature(SignatureAndHashAlgorithm algorithm, byte[] sigBytes,
+ AsymmetricKeyParameter publicKey, byte[] hash);
+
+ public virtual ISigner CreateSigner(AsymmetricKeyParameter privateKey)
+ {
+ return CreateSigner(null, privateKey);
+ }
+
+ public abstract ISigner CreateSigner(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter privateKey);
+
+ public virtual ISigner CreateVerifyer(AsymmetricKeyParameter publicKey)
+ {
+ return CreateVerifyer(null, publicKey);
+ }
+
+ public abstract ISigner CreateVerifyer(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter publicKey);
+
+ public abstract bool IsValidPublicKey(AsymmetricKeyParameter publicKey);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/AbstractTlsSignerCredentials.cs b/bc-sharp-crypto/src/crypto/tls/AbstractTlsSignerCredentials.cs
new file mode 100644
index 0000000000000000000000000000000000000000..886c46c6e25b0a59bffb80d93f44882c74a73bea
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/AbstractTlsSignerCredentials.cs
@@ -0,0 +1,20 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class AbstractTlsSignerCredentials
+ : AbstractTlsCredentials, TlsSignerCredentials
+ {
+ ///
+ public abstract byte[] GenerateCertificateSignature(byte[] hash);
+
+ public virtual SignatureAndHashAlgorithm SignatureAndHashAlgorithm
+ {
+ get
+ {
+ throw new InvalidOperationException("TlsSignerCredentials implementation does not support (D)TLS 1.2+");
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/AlertDescription.cs b/bc-sharp-crypto/src/crypto/tls/AlertDescription.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4e2464b508c1be54503d12d68b626a327be4b759
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/AlertDescription.cs
@@ -0,0 +1,304 @@
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ ///
+ /// RFC 5246 7.2
+ ///
+ public abstract class AlertDescription
+ {
+ /**
+ * This message notifies the recipient that the sender will not send any more messages on this
+ * connection. Note that as of TLS 1.1, failure to properly close a connection no longer
+ * requires that a session not be resumed. This is a change from TLS 1.0 ("The session becomes
+ * unresumable if any connection is terminated without proper close_notify messages with level
+ * equal to warning.") to conform with widespread implementation practice.
+ */
+ public const byte close_notify = 0;
+
+ /**
+ * An inappropriate message was received. This alert is always fatal and should never be
+ * observed in communication between proper implementations.
+ */
+ public const byte unexpected_message = 10;
+
+ /**
+ * This alert is returned if a record is received with an incorrect MAC. This alert also MUST be
+ * returned if an alert is sent because a TLSCiphertext decrypted in an invalid way: either it
+ * wasn't an even multiple of the block length, or its padding values, when checked, weren't
+ * correct. This message is always fatal and should never be observed in communication between
+ * proper implementations (except when messages were corrupted in the network).
+ */
+ public const byte bad_record_mac = 20;
+
+ /**
+ * This alert was used in some earlier versions of TLS, and may have permitted certain attacks
+ * against the CBC mode [CBCATT]. It MUST NOT be sent by compliant implementations.
+ */
+ public const byte decryption_failed = 21;
+
+ /**
+ * A TLSCiphertext record was received that had a length more than 2^14+2048 bytes, or a record
+ * decrypted to a TLSCompressed record with more than 2^14+1024 bytes. This message is always
+ * fatal and should never be observed in communication between proper implementations (except
+ * when messages were corrupted in the network).
+ */
+ public const byte record_overflow = 22;
+
+ /**
+ * The decompression function received improper input (e.g., data that would expand to excessive
+ * length). This message is always fatal and should never be observed in communication between
+ * proper implementations.
+ */
+ public const byte decompression_failure = 30;
+
+ /**
+ * Reception of a handshake_failure alert message indicates that the sender was unable to
+ * negotiate an acceptable set of security parameters given the options available. This is a
+ * fatal error.
+ */
+ public const byte handshake_failure = 40;
+
+ /**
+ * This alert was used in SSLv3 but not any version of TLS. It MUST NOT be sent by compliant
+ * implementations.
+ */
+ public const byte no_certificate = 41;
+
+ /**
+ * A certificate was corrupt, contained signatures that did not verify correctly, etc.
+ */
+ public const byte bad_certificate = 42;
+
+ /**
+ * A certificate was of an unsupported type.
+ */
+ public const byte unsupported_certificate = 43;
+
+ /**
+ * A certificate was revoked by its signer.
+ */
+ public const byte certificate_revoked = 44;
+
+ /**
+ * A certificate has expired or is not currently valid.
+ */
+ public const byte certificate_expired = 45;
+
+ /**
+ * Some other (unspecified) issue arose in processing the certificate, rendering it
+ * unacceptable.
+ */
+ public const byte certificate_unknown = 46;
+
+ /**
+ * A field in the handshake was out of range or inconsistent with other fields. This message is
+ * always fatal.
+ */
+ public const byte illegal_parameter = 47;
+
+ /**
+ * A valid certificate chain or partial chain was received, but the certificate was not accepted
+ * because the CA certificate could not be located or couldn't be matched with a known, trusted
+ * CA. This message is always fatal.
+ */
+ public const byte unknown_ca = 48;
+
+ /**
+ * A valid certificate was received, but when access control was applied, the sender decided not
+ * to proceed with negotiation. This message is always fatal.
+ */
+ public const byte access_denied = 49;
+
+ /**
+ * A message could not be decoded because some field was out of the specified range or the
+ * length of the message was incorrect. This message is always fatal and should never be
+ * observed in communication between proper implementations (except when messages were corrupted
+ * in the network).
+ */
+ public const byte decode_error = 50;
+
+ /**
+ * A handshake cryptographic operation failed, including being unable to correctly verify a
+ * signature or validate a Finished message. This message is always fatal.
+ */
+ public const byte decrypt_error = 51;
+
+ /**
+ * This alert was used in some earlier versions of TLS. It MUST NOT be sent by compliant
+ * implementations.
+ */
+ public const byte export_restriction = 60;
+
+ /**
+ * The protocol version the client has attempted to negotiate is recognized but not supported.
+ * (For example, old protocol versions might be avoided for security reasons.) This message is
+ * always fatal.
+ */
+ public const byte protocol_version = 70;
+
+ /**
+ * Returned instead of handshake_failure when a negotiation has failed specifically because the
+ * server requires ciphers more secure than those supported by the client. This message is
+ * always fatal.
+ */
+ public const byte insufficient_security = 71;
+
+ /**
+ * An internal error unrelated to the peer or the correctness of the protocol (such as a memory
+ * allocation failure) makes it impossible to continue. This message is always fatal.
+ */
+ public const byte internal_error = 80;
+
+ /**
+ * This handshake is being canceled for some reason unrelated to a protocol failure. If the user
+ * cancels an operation after the handshake is complete, just closing the connection by sending
+ * a close_notify is more appropriate. This alert should be followed by a close_notify. This
+ * message is generally a warning.
+ */
+ public const byte user_canceled = 90;
+
+ /**
+ * Sent by the client in response to a hello request or by the server in response to a client
+ * hello after initial handshaking. Either of these would normally lead to renegotiation; when
+ * that is not appropriate, the recipient should respond with this alert. At that point, the
+ * original requester can decide whether to proceed with the connection. One case where this
+ * would be appropriate is where a server has spawned a process to satisfy a request; the
+ * process might receive security parameters (key length, authentication, etc.) at startup, and
+ * it might be difficult to communicate changes to these parameters after that point. This
+ * message is always a warning.
+ */
+ public const byte no_renegotiation = 100;
+
+ /**
+ * Sent by clients that receive an extended server hello containing an extension that they did
+ * not put in the corresponding client hello. This message is always fatal.
+ */
+ public const byte unsupported_extension = 110;
+
+ /*
+ * RFC 3546
+ */
+
+ /**
+ * This alert is sent by servers who are unable to retrieve a certificate chain from the URL
+ * supplied by the client (see Section 3.3). This message MAY be fatal - for example if client
+ * authentication is required by the server for the handshake to continue and the server is
+ * unable to retrieve the certificate chain, it may send a fatal alert.
+ */
+ public const byte certificate_unobtainable = 111;
+
+ /**
+ * This alert is sent by servers that receive a server_name extension request, but do not
+ * recognize the server name. This message MAY be fatal.
+ */
+ public const byte unrecognized_name = 112;
+
+ /**
+ * This alert is sent by clients that receive an invalid certificate status response (see
+ * Section 3.6). This message is always fatal.
+ */
+ public const byte bad_certificate_status_response = 113;
+
+ /**
+ * This alert is sent by servers when a certificate hash does not match a client provided
+ * certificate_hash. This message is always fatal.
+ */
+ public const byte bad_certificate_hash_value = 114;
+
+ /*
+ * RFC 4279
+ */
+
+ /**
+ * If the server does not recognize the PSK identity, it MAY respond with an
+ * "unknown_psk_identity" alert message.
+ */
+ public const byte unknown_psk_identity = 115;
+
+ /*
+ * RFC 7507
+ */
+
+ /**
+ * If TLS_FALLBACK_SCSV appears in ClientHello.cipher_suites and the highest protocol version
+ * supported by the server is higher than the version indicated in ClientHello.client_version,
+ * the server MUST respond with a fatal inappropriate_fallback alert [..].
+ */
+ public const byte inappropriate_fallback = 86;
+
+ public static string GetName(byte alertDescription)
+ {
+ switch (alertDescription)
+ {
+ case close_notify:
+ return "close_notify";
+ case unexpected_message:
+ return "unexpected_message";
+ case bad_record_mac:
+ return "bad_record_mac";
+ case decryption_failed:
+ return "decryption_failed";
+ case record_overflow:
+ return "record_overflow";
+ case decompression_failure:
+ return "decompression_failure";
+ case handshake_failure:
+ return "handshake_failure";
+ case no_certificate:
+ return "no_certificate";
+ case bad_certificate:
+ return "bad_certificate";
+ case unsupported_certificate:
+ return "unsupported_certificate";
+ case certificate_revoked:
+ return "certificate_revoked";
+ case certificate_expired:
+ return "certificate_expired";
+ case certificate_unknown:
+ return "certificate_unknown";
+ case illegal_parameter:
+ return "illegal_parameter";
+ case unknown_ca:
+ return "unknown_ca";
+ case access_denied:
+ return "access_denied";
+ case decode_error:
+ return "decode_error";
+ case decrypt_error:
+ return "decrypt_error";
+ case export_restriction:
+ return "export_restriction";
+ case protocol_version:
+ return "protocol_version";
+ case insufficient_security:
+ return "insufficient_security";
+ case internal_error:
+ return "internal_error";
+ case user_canceled:
+ return "user_canceled";
+ case no_renegotiation:
+ return "no_renegotiation";
+ case unsupported_extension:
+ return "unsupported_extension";
+ case certificate_unobtainable:
+ return "certificate_unobtainable";
+ case unrecognized_name:
+ return "unrecognized_name";
+ case bad_certificate_status_response:
+ return "bad_certificate_status_response";
+ case bad_certificate_hash_value:
+ return "bad_certificate_hash_value";
+ case unknown_psk_identity:
+ return "unknown_psk_identity";
+ case inappropriate_fallback:
+ return "inappropriate_fallback";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ public static string GetText(byte alertDescription)
+ {
+ return GetName(alertDescription) + "(" + alertDescription + ")";
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/AlertLevel.cs b/bc-sharp-crypto/src/crypto/tls/AlertLevel.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9461a0b58606e681c67035bad4e6f13293fe3320
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/AlertLevel.cs
@@ -0,0 +1,29 @@
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ ///
+ /// RFC 5246 7.2
+ ///
+ public abstract class AlertLevel
+ {
+ public const byte warning = 1;
+ public const byte fatal = 2;
+
+ public static string GetName(byte alertDescription)
+ {
+ switch (alertDescription)
+ {
+ case warning:
+ return "warning";
+ case fatal:
+ return "fatal";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ public static string GetText(byte alertDescription)
+ {
+ return GetName(alertDescription) + "(" + alertDescription + ")";
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/BasicTlsPskIdentity.cs b/bc-sharp-crypto/src/crypto/tls/BasicTlsPskIdentity.cs
new file mode 100644
index 0000000000000000000000000000000000000000..db59544221e1f7655117a1fda5608d38500bb3b1
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/BasicTlsPskIdentity.cs
@@ -0,0 +1,43 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class BasicTlsPskIdentity
+ : TlsPskIdentity
+ {
+ protected byte[] mIdentity;
+ protected byte[] mPsk;
+
+ public BasicTlsPskIdentity(byte[] identity, byte[] psk)
+ {
+ this.mIdentity = Arrays.Clone(identity);
+ this.mPsk = Arrays.Clone(psk);
+ }
+
+ public BasicTlsPskIdentity(string identity, byte[] psk)
+ {
+ this.mIdentity = Strings.ToUtf8ByteArray(identity);
+ this.mPsk = Arrays.Clone(psk);
+ }
+
+ public virtual void SkipIdentityHint()
+ {
+ }
+
+ public virtual void NotifyIdentityHint(byte[] psk_identity_hint)
+ {
+ }
+
+ public virtual byte[] GetPskIdentity()
+ {
+ return mIdentity;
+ }
+
+ public virtual byte[] GetPsk()
+ {
+ return mPsk;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/BulkCipherAlgorithm.cs b/bc-sharp-crypto/src/crypto/tls/BulkCipherAlgorithm.cs
new file mode 100644
index 0000000000000000000000000000000000000000..07ff8dc07cf277dbc2ff74c1a4e84dee94110b6e
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/BulkCipherAlgorithm.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// RFC 2246
+ ///
+ /// Note that the values here are implementation-specific and arbitrary. It is recommended not to
+ /// depend on the particular values (e.g. serialization).
+ ///
+ public abstract class BulkCipherAlgorithm
+ {
+ public const int cls_null = 0;
+ public const int rc4 = 1;
+ public const int rc2 = 2;
+ public const int des = 3;
+ public const int cls_3des = 4;
+ public const int des40 = 5;
+
+ /*
+ * RFC 4346
+ */
+ public const int aes = 6;
+ public const int idea = 7;
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/ByteQueue.cs b/bc-sharp-crypto/src/crypto/tls/ByteQueue.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b4df6850e67ec86f5d92ba097198017bc1efccaf
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/ByteQueue.cs
@@ -0,0 +1,211 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ ///
+ /// A queue for bytes.
+ ///
+ /// This file could be more optimized.
+ ///
+ ///
+ public class ByteQueue
+ {
+ /// The smallest number which can be written as 2^x which is bigger than i.
+ public static int NextTwoPow(
+ int i)
+ {
+ /*
+ * This code is based of a lot of code I found on the Internet
+ * which mostly referenced a book called "Hacking delight".
+ *
+ */
+ i |= (i >> 1);
+ i |= (i >> 2);
+ i |= (i >> 4);
+ i |= (i >> 8);
+ i |= (i >> 16);
+ return i + 1;
+ }
+
+ /**
+ * The initial size for our buffer.
+ */
+ private const int DefaultCapacity = 1024;
+
+ /**
+ * The buffer where we store our data.
+ */
+ private byte[] databuf;
+
+ /**
+ * How many bytes at the beginning of the buffer are skipped.
+ */
+ private int skipped = 0;
+
+ /**
+ * How many bytes in the buffer are valid data.
+ */
+ private int available = 0;
+
+ private bool readOnlyBuf = false;
+
+ public ByteQueue()
+ : this(DefaultCapacity)
+ {
+ }
+
+ public ByteQueue(int capacity)
+ {
+ this.databuf = capacity == 0 ? TlsUtilities.EmptyBytes : new byte[capacity];
+ }
+
+ public ByteQueue(byte[] buf, int off, int len)
+ {
+ this.databuf = buf;
+ this.skipped = off;
+ this.available = len;
+ this.readOnlyBuf = true;
+ }
+
+ /// Add some data to our buffer.
+ /// A byte-array to read data from.
+ /// How many bytes to skip at the beginning of the array.
+ /// How many bytes to read from the array.
+ public void AddData(
+ byte[] data,
+ int offset,
+ int len)
+ {
+ if (readOnlyBuf)
+ throw new InvalidOperationException("Cannot add data to read-only buffer");
+
+ if ((skipped + available + len) > databuf.Length)
+ {
+ int desiredSize = ByteQueue.NextTwoPow(available + len);
+ if (desiredSize > databuf.Length)
+ {
+ byte[] tmp = new byte[desiredSize];
+ Array.Copy(databuf, skipped, tmp, 0, available);
+ databuf = tmp;
+ }
+ else
+ {
+ Array.Copy(databuf, skipped, databuf, 0, available);
+ }
+ skipped = 0;
+ }
+
+ Array.Copy(data, offset, databuf, skipped + available, len);
+ available += len;
+ }
+
+ /// The number of bytes which are available in this buffer.
+ public int Available
+ {
+ get { return available; }
+ }
+
+ /// Copy some bytes from the beginning of the data to the provided Stream .
+ /// The Stream to copy the bytes to.
+ /// How many bytes to copy.
+ /// If insufficient data is available.
+ /// If there is a problem copying the data.
+ public void CopyTo(Stream output, int length)
+ {
+ if (length > available)
+ throw new InvalidOperationException("Cannot copy " + length + " bytes, only got " + available);
+
+ output.Write(databuf, skipped, length);
+ }
+
+ /// Read data from the buffer.
+ /// The buffer where the read data will be copied to.
+ /// How many bytes to skip at the beginning of buf.
+ /// How many bytes to read at all.
+ /// How many bytes from our data to skip.
+ public void Read(
+ byte[] buf,
+ int offset,
+ int len,
+ int skip)
+ {
+ if ((buf.Length - offset) < len)
+ {
+ throw new ArgumentException("Buffer size of " + buf.Length + " is too small for a read of " + len + " bytes");
+ }
+ if ((available - skip) < len)
+ {
+ throw new InvalidOperationException("Not enough data to read");
+ }
+ Array.Copy(databuf, skipped + skip, buf, offset, len);
+ }
+
+ /// Return a MemoryStream over some bytes at the beginning of the data.
+ /// How many bytes will be readable.
+ /// A MemoryStream over the data.
+ /// If insufficient data is available.
+ public MemoryStream ReadFrom(int length)
+ {
+ if (length > available)
+ throw new InvalidOperationException("Cannot read " + length + " bytes, only got " + available);
+
+ int position = skipped;
+
+ available -= length;
+ skipped += length;
+
+ return new MemoryStream(databuf, position, length, false);
+ }
+
+ /// Remove some bytes from our data from the beginning.
+ /// How many bytes to remove.
+ public void RemoveData(
+ int i)
+ {
+ if (i > available)
+ {
+ throw new InvalidOperationException("Cannot remove " + i + " bytes, only got " + available);
+ }
+
+ /*
+ * Skip the data.
+ */
+ available -= i;
+ skipped += i;
+ }
+
+ public void RemoveData(byte[] buf, int off, int len, int skip)
+ {
+ Read(buf, off, len, skip);
+ RemoveData(skip + len);
+ }
+
+ public byte[] RemoveData(int len, int skip)
+ {
+ byte[] buf = new byte[len];
+ RemoveData(buf, 0, len, skip);
+ return buf;
+ }
+
+ public void Shrink()
+ {
+ if (available == 0)
+ {
+ databuf = TlsUtilities.EmptyBytes;
+ skipped = 0;
+ }
+ else
+ {
+ int desiredSize = ByteQueue.NextTwoPow(available);
+ if (desiredSize < databuf.Length)
+ {
+ byte[] tmp = new byte[desiredSize];
+ Array.Copy(databuf, skipped, tmp, 0, available);
+ databuf = tmp;
+ skipped = 0;
+ }
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/ByteQueueStream.cs b/bc-sharp-crypto/src/crypto/tls/ByteQueueStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..249e6099b054e271236902a85aaf4e9e622b6de8
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/ByteQueueStream.cs
@@ -0,0 +1,110 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class ByteQueueStream
+ : Stream
+ {
+ private readonly ByteQueue buffer;
+
+ public ByteQueueStream()
+ {
+ this.buffer = new ByteQueue();
+ }
+
+ public virtual int Available
+ {
+ get { return buffer.Available; }
+ }
+
+ public override bool CanRead
+ {
+ get { return true; }
+ }
+
+ public override bool CanSeek
+ {
+ get { return false; }
+ }
+
+ public override bool CanWrite
+ {
+ get { return true; }
+ }
+
+ public override void Flush()
+ {
+ }
+
+ public override long Length
+ {
+ get { throw new NotSupportedException(); }
+ }
+
+ public virtual int Peek(byte[] buf)
+ {
+ int bytesToRead = System.Math.Min(buffer.Available, buf.Length);
+ buffer.Read(buf, 0, bytesToRead, 0);
+ return bytesToRead;
+ }
+
+ public override long Position
+ {
+ get { throw new NotSupportedException(); }
+ set { throw new NotSupportedException(); }
+ }
+
+ public virtual int Read(byte[] buf)
+ {
+ return Read(buf, 0, buf.Length);
+ }
+
+ public override int Read(byte[] buf, int off, int len)
+ {
+ int bytesToRead = System.Math.Min(buffer.Available, len);
+ buffer.RemoveData(buf, off, bytesToRead, 0);
+ return bytesToRead;
+ }
+
+ public override int ReadByte()
+ {
+ if (buffer.Available == 0)
+ return -1;
+
+ return buffer.RemoveData(1, 0)[0] & 0xFF;
+ }
+
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void SetLength(long value)
+ {
+ throw new NotSupportedException();
+ }
+
+ public virtual int Skip(int n)
+ {
+ int bytesToSkip = System.Math.Min(buffer.Available, n);
+ buffer.RemoveData(bytesToSkip);
+ return bytesToSkip;
+ }
+
+ public virtual void Write(byte[] buf)
+ {
+ buffer.AddData(buf, 0, buf.Length);
+ }
+
+ public override void Write(byte[] buf, int off, int len)
+ {
+ buffer.AddData(buf, off, len);
+ }
+
+ public override void WriteByte(byte b)
+ {
+ buffer.AddData(new byte[]{ b }, 0, 1);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/CertChainType.cs b/bc-sharp-crypto/src/crypto/tls/CertChainType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cbb1834419092038a49163ca33181d7d56960d8f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/CertChainType.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /*
+ * RFC 3546 3.3.
+ */
+ public abstract class CertChainType
+ {
+ public const byte individual_certs = 0;
+ public const byte pkipath = 1;
+
+ public static bool IsValid(byte certChainType)
+ {
+ return certChainType >= individual_certs && certChainType <= pkipath;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/Certificate.cs b/bc-sharp-crypto/src/crypto/tls/Certificate.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e0479997afdb9d9d74c54fac16ec4b57031cfb4a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/Certificate.cs
@@ -0,0 +1,136 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * Parsing and encoding of a Certificate struct from RFC 4346.
+ *
+ *
+ * opaque ASN.1Cert<2^24-1>;
+ *
+ * struct {
+ * ASN.1Cert certificate_list<0..2^24-1>;
+ * } Certificate;
+ *
+ *
+ * @see Org.BouncyCastle.Asn1.X509.X509CertificateStructure
+ */
+ public class Certificate
+ {
+ public static readonly Certificate EmptyChain = new Certificate(new X509CertificateStructure[0]);
+
+ /**
+ * The certificates.
+ */
+ protected readonly X509CertificateStructure[] mCertificateList;
+
+ public Certificate(X509CertificateStructure[] certificateList)
+ {
+ if (certificateList == null)
+ throw new ArgumentNullException("certificateList");
+
+ this.mCertificateList = certificateList;
+ }
+
+ /**
+ * @return an array of {@link org.bouncycastle.asn1.x509.Certificate} representing a certificate
+ * chain.
+ */
+ public virtual X509CertificateStructure[] GetCertificateList()
+ {
+ return CloneCertificateList();
+ }
+
+ public virtual X509CertificateStructure GetCertificateAt(int index)
+ {
+ return mCertificateList[index];
+ }
+
+ public virtual int Length
+ {
+ get { return mCertificateList.Length; }
+ }
+
+ /**
+ * @return true
if this certificate chain contains no certificates, or
+ * false
otherwise.
+ */
+ public virtual bool IsEmpty
+ {
+ get { return mCertificateList.Length == 0; }
+ }
+
+ /**
+ * Encode this {@link Certificate} to a {@link Stream}.
+ *
+ * @param output the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ IList derEncodings = Platform.CreateArrayList(mCertificateList.Length);
+
+ int totalLength = 0;
+ foreach (Asn1Encodable asn1Cert in mCertificateList)
+ {
+ byte[] derEncoding = asn1Cert.GetEncoded(Asn1Encodable.Der);
+ derEncodings.Add(derEncoding);
+ totalLength += derEncoding.Length + 3;
+ }
+
+ TlsUtilities.CheckUint24(totalLength);
+ TlsUtilities.WriteUint24(totalLength, output);
+
+ foreach (byte[] derEncoding in derEncodings)
+ {
+ TlsUtilities.WriteOpaque24(derEncoding, output);
+ }
+ }
+
+ /**
+ * Parse a {@link Certificate} from a {@link Stream}.
+ *
+ * @param input the {@link Stream} to parse from.
+ * @return a {@link Certificate} object.
+ * @throws IOException
+ */
+ public static Certificate Parse(Stream input)
+ {
+ int totalLength = TlsUtilities.ReadUint24(input);
+ if (totalLength == 0)
+ {
+ return EmptyChain;
+ }
+
+ byte[] certListData = TlsUtilities.ReadFully(totalLength, input);
+
+ MemoryStream buf = new MemoryStream(certListData, false);
+
+ IList certificate_list = Platform.CreateArrayList();
+ while (buf.Position < buf.Length)
+ {
+ byte[] berEncoding = TlsUtilities.ReadOpaque24(buf);
+ Asn1Object asn1Cert = TlsUtilities.ReadAsn1Object(berEncoding);
+ certificate_list.Add(X509CertificateStructure.GetInstance(asn1Cert));
+ }
+
+ X509CertificateStructure[] certificateList = new X509CertificateStructure[certificate_list.Count];
+ for (int i = 0; i < certificate_list.Count; ++i)
+ {
+ certificateList[i] = (X509CertificateStructure)certificate_list[i];
+ }
+ return new Certificate(certificateList);
+ }
+
+ protected virtual X509CertificateStructure[] CloneCertificateList()
+ {
+ return (X509CertificateStructure[])mCertificateList.Clone();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/CertificateRequest.cs b/bc-sharp-crypto/src/crypto/tls/CertificateRequest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f3dcb3bbd9276617b1346f0cf385efcbb882e51a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/CertificateRequest.cs
@@ -0,0 +1,156 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * Parsing and encoding of a CertificateRequest struct from RFC 4346.
+ *
+ *
+ * struct {
+ * ClientCertificateType certificate_types<1..2^8-1>;
+ * DistinguishedName certificate_authorities<3..2^16-1>
+ * } CertificateRequest;
+ *
+ *
+ * @see ClientCertificateType
+ * @see X509Name
+ */
+ public class CertificateRequest
+ {
+ protected readonly byte[] mCertificateTypes;
+ protected readonly IList mSupportedSignatureAlgorithms;
+ protected readonly IList mCertificateAuthorities;
+
+ /**
+ * @param certificateTypes see {@link ClientCertificateType} for valid constants.
+ * @param certificateAuthorities an {@link IList} of {@link X509Name}.
+ */
+ public CertificateRequest(byte[] certificateTypes, IList supportedSignatureAlgorithms,
+ IList certificateAuthorities)
+ {
+ this.mCertificateTypes = certificateTypes;
+ this.mSupportedSignatureAlgorithms = supportedSignatureAlgorithms;
+ this.mCertificateAuthorities = certificateAuthorities;
+ }
+
+ /**
+ * @return an array of certificate types
+ * @see {@link ClientCertificateType}
+ */
+ public virtual byte[] CertificateTypes
+ {
+ get { return mCertificateTypes; }
+ }
+
+ /**
+ * @return an {@link IList} of {@link SignatureAndHashAlgorithm} (or null before TLS 1.2).
+ */
+ public virtual IList SupportedSignatureAlgorithms
+ {
+ get { return mSupportedSignatureAlgorithms; }
+ }
+
+ /**
+ * @return an {@link IList} of {@link X509Name}
+ */
+ public virtual IList CertificateAuthorities
+ {
+ get { return mCertificateAuthorities; }
+ }
+
+ /**
+ * Encode this {@link CertificateRequest} to a {@link Stream}.
+ *
+ * @param output the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ if (mCertificateTypes == null || mCertificateTypes.Length == 0)
+ {
+ TlsUtilities.WriteUint8(0, output);
+ }
+ else
+ {
+ TlsUtilities.WriteUint8ArrayWithUint8Length(mCertificateTypes, output);
+ }
+
+ if (mSupportedSignatureAlgorithms != null)
+ {
+ // TODO Check whether SignatureAlgorithm.anonymous is allowed here
+ TlsUtilities.EncodeSupportedSignatureAlgorithms(mSupportedSignatureAlgorithms, false, output);
+ }
+
+ if (mCertificateAuthorities == null || mCertificateAuthorities.Count < 1)
+ {
+ TlsUtilities.WriteUint16(0, output);
+ }
+ else
+ {
+ IList derEncodings = Platform.CreateArrayList(mCertificateAuthorities.Count);
+
+ int totalLength = 0;
+ foreach (Asn1Encodable certificateAuthority in mCertificateAuthorities)
+ {
+ byte[] derEncoding = certificateAuthority.GetEncoded(Asn1Encodable.Der);
+ derEncodings.Add(derEncoding);
+ totalLength += derEncoding.Length + 2;
+ }
+
+ TlsUtilities.CheckUint16(totalLength);
+ TlsUtilities.WriteUint16(totalLength, output);
+
+ foreach (byte[] derEncoding in derEncodings)
+ {
+ TlsUtilities.WriteOpaque16(derEncoding, output);
+ }
+ }
+ }
+
+ /**
+ * Parse a {@link CertificateRequest} from a {@link Stream}.
+ *
+ * @param context
+ * the {@link TlsContext} of the current connection.
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link CertificateRequest} object.
+ * @throws IOException
+ */
+ public static CertificateRequest Parse(TlsContext context, Stream input)
+ {
+ int numTypes = TlsUtilities.ReadUint8(input);
+ byte[] certificateTypes = new byte[numTypes];
+ for (int i = 0; i < numTypes; ++i)
+ {
+ certificateTypes[i] = TlsUtilities.ReadUint8(input);
+ }
+
+ IList supportedSignatureAlgorithms = null;
+ if (TlsUtilities.IsTlsV12(context))
+ {
+ // TODO Check whether SignatureAlgorithm.anonymous is allowed here
+ supportedSignatureAlgorithms = TlsUtilities.ParseSupportedSignatureAlgorithms(false, input);
+ }
+
+ IList certificateAuthorities = Platform.CreateArrayList();
+ byte[] certAuthData = TlsUtilities.ReadOpaque16(input);
+ MemoryStream bis = new MemoryStream(certAuthData, false);
+ while (bis.Position < bis.Length)
+ {
+ byte[] derEncoding = TlsUtilities.ReadOpaque16(bis);
+ Asn1Object asn1 = TlsUtilities.ReadDerObject(derEncoding);
+ // TODO Switch to X500Name when available
+ certificateAuthorities.Add(X509Name.GetInstance(asn1));
+ }
+
+ return new CertificateRequest(certificateTypes, supportedSignatureAlgorithms, certificateAuthorities);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/CertificateStatus.cs b/bc-sharp-crypto/src/crypto/tls/CertificateStatus.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0f95475b92b3db1b7daad8992c67a9a6ffc61772
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/CertificateStatus.cs
@@ -0,0 +1,102 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class CertificateStatus
+ {
+ protected readonly byte mStatusType;
+ protected readonly object mResponse;
+
+ public CertificateStatus(byte statusType, object response)
+ {
+ if (!IsCorrectType(statusType, response))
+ throw new ArgumentException("not an instance of the correct type", "response");
+
+ this.mStatusType = statusType;
+ this.mResponse = response;
+ }
+
+ public virtual byte StatusType
+ {
+ get { return mStatusType; }
+ }
+
+ public virtual object Response
+ {
+ get { return mResponse; }
+ }
+
+ public virtual OcspResponse GetOcspResponse()
+ {
+ if (!IsCorrectType(CertificateStatusType.ocsp, mResponse))
+ throw new InvalidOperationException("'response' is not an OcspResponse");
+
+ return (OcspResponse)mResponse;
+ }
+
+ /**
+ * Encode this {@link CertificateStatus} to a {@link Stream}.
+ *
+ * @param output
+ * the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ TlsUtilities.WriteUint8(mStatusType, output);
+
+ switch (mStatusType)
+ {
+ case CertificateStatusType.ocsp:
+ byte[] derEncoding = ((OcspResponse)mResponse).GetEncoded(Asn1Encodable.Der);
+ TlsUtilities.WriteOpaque24(derEncoding, output);
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ /**
+ * Parse a {@link CertificateStatus} from a {@link Stream}.
+ *
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link CertificateStatus} object.
+ * @throws IOException
+ */
+ public static CertificateStatus Parse(Stream input)
+ {
+ byte status_type = TlsUtilities.ReadUint8(input);
+ object response;
+
+ switch (status_type)
+ {
+ case CertificateStatusType.ocsp:
+ {
+ byte[] derEncoding = TlsUtilities.ReadOpaque24(input);
+ response = OcspResponse.GetInstance(TlsUtilities.ReadDerObject(derEncoding));
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ }
+
+ return new CertificateStatus(status_type, response);
+ }
+
+ protected static bool IsCorrectType(byte statusType, object response)
+ {
+ switch (statusType)
+ {
+ case CertificateStatusType.ocsp:
+ return response is OcspResponse;
+ default:
+ throw new ArgumentException("unsupported value", "statusType");
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/CertificateStatusRequest.cs b/bc-sharp-crypto/src/crypto/tls/CertificateStatusRequest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9587d7df8b4b877e9d843c0ea4bf50d35514ccef
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/CertificateStatusRequest.cs
@@ -0,0 +1,95 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class CertificateStatusRequest
+ {
+ protected readonly byte mStatusType;
+ protected readonly object mRequest;
+
+ public CertificateStatusRequest(byte statusType, Object request)
+ {
+ if (!IsCorrectType(statusType, request))
+ throw new ArgumentException("not an instance of the correct type", "request");
+
+ this.mStatusType = statusType;
+ this.mRequest = request;
+ }
+
+ public virtual byte StatusType
+ {
+ get { return mStatusType; }
+ }
+
+ public virtual object Request
+ {
+ get { return mRequest; }
+ }
+
+ public virtual OcspStatusRequest GetOcspStatusRequest()
+ {
+ if (!IsCorrectType(CertificateStatusType.ocsp, mRequest))
+ throw new InvalidOperationException("'request' is not an OCSPStatusRequest");
+
+ return (OcspStatusRequest)mRequest;
+ }
+
+ /**
+ * Encode this {@link CertificateStatusRequest} to a {@link Stream}.
+ *
+ * @param output
+ * the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ TlsUtilities.WriteUint8(mStatusType, output);
+
+ switch (mStatusType)
+ {
+ case CertificateStatusType.ocsp:
+ ((OcspStatusRequest)mRequest).Encode(output);
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ /**
+ * Parse a {@link CertificateStatusRequest} from a {@link Stream}.
+ *
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link CertificateStatusRequest} object.
+ * @throws IOException
+ */
+ public static CertificateStatusRequest Parse(Stream input)
+ {
+ byte status_type = TlsUtilities.ReadUint8(input);
+ object result;
+
+ switch (status_type)
+ {
+ case CertificateStatusType.ocsp:
+ result = OcspStatusRequest.Parse(input);
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ }
+
+ return new CertificateStatusRequest(status_type, result);
+ }
+
+ protected static bool IsCorrectType(byte statusType, object request)
+ {
+ switch (statusType)
+ {
+ case CertificateStatusType.ocsp:
+ return request is OcspStatusRequest;
+ default:
+ throw new ArgumentException("unsupported value", "statusType");
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/CertificateStatusType.cs b/bc-sharp-crypto/src/crypto/tls/CertificateStatusType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..54b741b422ea551ff8aedb9f4c8e1a2b9ee1db0b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/CertificateStatusType.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class CertificateStatusType
+ {
+ /*
+ * RFC 3546 3.6
+ */
+ public const byte ocsp = 1;
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/CertificateType.cs b/bc-sharp-crypto/src/crypto/tls/CertificateType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..47ec05c801174d8ae471ef16525e1a04d9751ade
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/CertificateType.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * RFC 6091
+ */
+ public class CertificateType
+ {
+ public const byte X509 = 0;
+ public const byte OpenPGP = 1;
+
+ /*
+ * RFC 7250
+ */
+ public const byte RawPublicKey = 2;
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/CertificateUrl.cs b/bc-sharp-crypto/src/crypto/tls/CertificateUrl.cs
new file mode 100644
index 0000000000000000000000000000000000000000..aff999551f21ffd8ce3c6a9103e1c5b286f6b648
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/CertificateUrl.cs
@@ -0,0 +1,125 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /*
+ * RFC 3546 3.3
+ */
+ public class CertificateUrl
+ {
+ protected readonly byte mType;
+ protected readonly IList mUrlAndHashList;
+
+ /**
+ * @param type
+ * see {@link CertChainType} for valid constants.
+ * @param urlAndHashList
+ * a {@link IList} of {@link UrlAndHash}.
+ */
+ public CertificateUrl(byte type, IList urlAndHashList)
+ {
+ if (!CertChainType.IsValid(type))
+ throw new ArgumentException("not a valid CertChainType value", "type");
+ if (urlAndHashList == null || urlAndHashList.Count < 1)
+ throw new ArgumentException("must have length > 0", "urlAndHashList");
+
+ this.mType = type;
+ this.mUrlAndHashList = urlAndHashList;
+ }
+
+ /**
+ * @return {@link CertChainType}
+ */
+ public virtual byte Type
+ {
+ get { return mType; }
+ }
+
+ /**
+ * @return an {@link IList} of {@link UrlAndHash}
+ */
+ public virtual IList UrlAndHashList
+ {
+ get { return mUrlAndHashList; }
+ }
+
+ /**
+ * Encode this {@link CertificateUrl} to a {@link Stream}.
+ *
+ * @param output the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ TlsUtilities.WriteUint8(this.mType, output);
+
+ ListBuffer16 buf = new ListBuffer16();
+ foreach (UrlAndHash urlAndHash in this.mUrlAndHashList)
+ {
+ urlAndHash.Encode(buf);
+ }
+ buf.EncodeTo(output);
+ }
+
+ /**
+ * Parse a {@link CertificateUrl} from a {@link Stream}.
+ *
+ * @param context
+ * the {@link TlsContext} of the current connection.
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link CertificateUrl} object.
+ * @throws IOException
+ */
+ public static CertificateUrl parse(TlsContext context, Stream input)
+ {
+ byte type = TlsUtilities.ReadUint8(input);
+ if (!CertChainType.IsValid(type))
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ int totalLength = TlsUtilities.ReadUint16(input);
+ if (totalLength < 1)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ byte[] urlAndHashListData = TlsUtilities.ReadFully(totalLength, input);
+
+ MemoryStream buf = new MemoryStream(urlAndHashListData, false);
+
+ IList url_and_hash_list = Platform.CreateArrayList();
+ while (buf.Position < buf.Length)
+ {
+ UrlAndHash url_and_hash = UrlAndHash.Parse(context, buf);
+ url_and_hash_list.Add(url_and_hash);
+ }
+
+ return new CertificateUrl(type, url_and_hash_list);
+ }
+
+ // TODO Could be more generally useful
+ internal class ListBuffer16
+ : MemoryStream
+ {
+ internal ListBuffer16()
+ {
+ // Reserve space for length
+ TlsUtilities.WriteUint16(0, this);
+ }
+
+ internal void EncodeTo(Stream output)
+ {
+ // Patch actual length back in
+ long length = Length - 2;
+ TlsUtilities.CheckUint16(length);
+ this.Position = 0;
+ TlsUtilities.WriteUint16((int)length, this);
+ Streams.WriteBufTo(this, output);
+ Platform.Dispose(this);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/Chacha20Poly1305.cs b/bc-sharp-crypto/src/crypto/tls/Chacha20Poly1305.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8687803b404a8c8db94bdddb28b62db447d4932e
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/Chacha20Poly1305.cs
@@ -0,0 +1,199 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * draft-ietf-tls-chacha20-poly1305-04
+ */
+ public class Chacha20Poly1305
+ : TlsCipher
+ {
+ private static readonly byte[] Zeroes = new byte[15];
+
+ protected readonly TlsContext context;
+
+ protected readonly ChaCha7539Engine encryptCipher, decryptCipher;
+ protected readonly byte[] encryptIV, decryptIV;
+
+ ///
+ public Chacha20Poly1305(TlsContext context)
+ {
+ if (!TlsUtilities.IsTlsV12(context))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ this.context = context;
+
+ int cipherKeySize = 32;
+ // TODO SecurityParameters.fixed_iv_length
+ int fixed_iv_length = 12;
+ // TODO SecurityParameters.record_iv_length = 0
+
+ int key_block_size = (2 * cipherKeySize) + (2 * fixed_iv_length);
+
+ byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size);
+
+ int offset = 0;
+
+ KeyParameter client_write_key = new KeyParameter(key_block, offset, cipherKeySize);
+ offset += cipherKeySize;
+ KeyParameter server_write_key = new KeyParameter(key_block, offset, cipherKeySize);
+ offset += cipherKeySize;
+ byte[] client_write_IV = Arrays.CopyOfRange(key_block, offset, offset + fixed_iv_length);
+ offset += fixed_iv_length;
+ byte[] server_write_IV = Arrays.CopyOfRange(key_block, offset, offset + fixed_iv_length);
+ offset += fixed_iv_length;
+
+ if (offset != key_block_size)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ this.encryptCipher = new ChaCha7539Engine();
+ this.decryptCipher = new ChaCha7539Engine();
+
+ KeyParameter encryptKey, decryptKey;
+ if (context.IsServer)
+ {
+ encryptKey = server_write_key;
+ decryptKey = client_write_key;
+ this.encryptIV = server_write_IV;
+ this.decryptIV = client_write_IV;
+ }
+ else
+ {
+ encryptKey = client_write_key;
+ decryptKey = server_write_key;
+ this.encryptIV = client_write_IV;
+ this.decryptIV = server_write_IV;
+ }
+
+ this.encryptCipher.Init(true, new ParametersWithIV(encryptKey, encryptIV));
+ this.decryptCipher.Init(false, new ParametersWithIV(decryptKey, decryptIV));
+ }
+
+ public virtual int GetPlaintextLimit(int ciphertextLimit)
+ {
+ return ciphertextLimit - 16;
+ }
+
+ ///
+ public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
+ {
+ KeyParameter macKey = InitRecord(encryptCipher, true, seqNo, encryptIV);
+
+ byte[] output = new byte[len + 16];
+ encryptCipher.ProcessBytes(plaintext, offset, len, output, 0);
+
+ byte[] additionalData = GetAdditionalData(seqNo, type, len);
+ byte[] mac = CalculateRecordMac(macKey, additionalData, output, 0, len);
+ Array.Copy(mac, 0, output, len, mac.Length);
+
+ return output;
+ }
+
+ ///
+ public virtual byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len)
+ {
+ if (GetPlaintextLimit(len) < 0)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ KeyParameter macKey = InitRecord(decryptCipher, false, seqNo, decryptIV);
+
+ int plaintextLength = len - 16;
+
+ byte[] additionalData = GetAdditionalData(seqNo, type, plaintextLength);
+ byte[] calculatedMac = CalculateRecordMac(macKey, additionalData, ciphertext, offset, plaintextLength);
+ byte[] receivedMac = Arrays.CopyOfRange(ciphertext, offset + plaintextLength, offset + len);
+
+ if (!Arrays.ConstantTimeAreEqual(calculatedMac, receivedMac))
+ throw new TlsFatalAlert(AlertDescription.bad_record_mac);
+
+ byte[] output = new byte[plaintextLength];
+ decryptCipher.ProcessBytes(ciphertext, offset, plaintextLength, output, 0);
+ return output;
+ }
+
+ protected virtual KeyParameter InitRecord(IStreamCipher cipher, bool forEncryption, long seqNo, byte[] iv)
+ {
+ byte[] nonce = CalculateNonce(seqNo, iv);
+ cipher.Init(forEncryption, new ParametersWithIV(null, nonce));
+ return GenerateRecordMacKey(cipher);
+ }
+
+ protected virtual byte[] CalculateNonce(long seqNo, byte[] iv)
+ {
+ byte[] nonce = new byte[12];
+ TlsUtilities.WriteUint64(seqNo, nonce, 4);
+
+ for (int i = 0; i < 12; ++i)
+ {
+ nonce[i] ^= iv[i];
+ }
+
+ return nonce;
+ }
+
+ protected virtual KeyParameter GenerateRecordMacKey(IStreamCipher cipher)
+ {
+ byte[] firstBlock = new byte[64];
+ cipher.ProcessBytes(firstBlock, 0, firstBlock.Length, firstBlock, 0);
+
+ KeyParameter macKey = new KeyParameter(firstBlock, 0, 32);
+ Arrays.Fill(firstBlock, (byte)0);
+ return macKey;
+ }
+
+ protected virtual byte[] CalculateRecordMac(KeyParameter macKey, byte[] additionalData, byte[] buf, int off, int len)
+ {
+ IMac mac = new Poly1305();
+ mac.Init(macKey);
+
+ UpdateRecordMacText(mac, additionalData, 0, additionalData.Length);
+ UpdateRecordMacText(mac, buf, off, len);
+ UpdateRecordMacLength(mac, additionalData.Length);
+ UpdateRecordMacLength(mac, len);
+
+ return MacUtilities.DoFinal(mac);
+ }
+
+ protected virtual void UpdateRecordMacLength(IMac mac, int len)
+ {
+ byte[] longLen = Pack.UInt64_To_LE((ulong)len);
+ mac.BlockUpdate(longLen, 0, longLen.Length);
+ }
+
+ protected virtual void UpdateRecordMacText(IMac mac, byte[] buf, int off, int len)
+ {
+ mac.BlockUpdate(buf, off, len);
+
+ int partial = len % 16;
+ if (partial != 0)
+ {
+ mac.BlockUpdate(Zeroes, 0, 16 - partial);
+ }
+ }
+
+ ///
+ protected virtual byte[] GetAdditionalData(long seqNo, byte type, int len)
+ {
+ /*
+ * additional_data = seq_num + TLSCompressed.type + TLSCompressed.version +
+ * TLSCompressed.length
+ */
+ byte[] additional_data = new byte[13];
+ TlsUtilities.WriteUint64(seqNo, additional_data, 0);
+ TlsUtilities.WriteUint8(type, additional_data, 8);
+ TlsUtilities.WriteVersion(context.ServerVersion, additional_data, 9);
+ TlsUtilities.WriteUint16(len, additional_data, 11);
+
+ return additional_data;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/ChangeCipherSpec.cs b/bc-sharp-crypto/src/crypto/tls/ChangeCipherSpec.cs
new file mode 100644
index 0000000000000000000000000000000000000000..323de916234993f4c6d3fbc0d622031e197be15e
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/ChangeCipherSpec.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class ChangeCipherSpec
+ {
+ public const byte change_cipher_spec = 1;
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/CipherSuite.cs b/bc-sharp-crypto/src/crypto/tls/CipherSuite.cs
new file mode 100644
index 0000000000000000000000000000000000000000..679a8be85ac406a80a89eedb3635358609545ac3
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/CipherSuite.cs
@@ -0,0 +1,377 @@
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ ///
+ /// RFC 2246 A.5
+ ///
+ public abstract class CipherSuite
+ {
+ public const int TLS_NULL_WITH_NULL_NULL = 0x0000;
+ public const int TLS_RSA_WITH_NULL_MD5 = 0x0001;
+ public const int TLS_RSA_WITH_NULL_SHA = 0x0002;
+ public const int TLS_RSA_EXPORT_WITH_RC4_40_MD5 = 0x0003;
+ public const int TLS_RSA_WITH_RC4_128_MD5 = 0x0004;
+ public const int TLS_RSA_WITH_RC4_128_SHA = 0x0005;
+ public const int TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = 0x0006;
+ public const int TLS_RSA_WITH_IDEA_CBC_SHA = 0x0007;
+ public const int TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0008;
+ public const int TLS_RSA_WITH_DES_CBC_SHA = 0x0009;
+ public const int TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A;
+ public const int TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x000B;
+ public const int TLS_DH_DSS_WITH_DES_CBC_SHA = 0x000C;
+ public const int TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x000D;
+ public const int TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x000E;
+ public const int TLS_DH_RSA_WITH_DES_CBC_SHA = 0x000F;
+ public const int TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x0010;
+ public const int TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x0011;
+ public const int TLS_DHE_DSS_WITH_DES_CBC_SHA = 0x0012;
+ public const int TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013;
+ public const int TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0014;
+ public const int TLS_DHE_RSA_WITH_DES_CBC_SHA = 0x0015;
+ public const int TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016;
+ public const int TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = 0x0017;
+ public const int TLS_DH_anon_WITH_RC4_128_MD5 = 0x0018;
+ public const int TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = 0x0019;
+ public const int TLS_DH_anon_WITH_DES_CBC_SHA = 0x001A;
+ public const int TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0x001B;
+
+ /*
+ * Note: The cipher suite values { 0x00, 0x1C } and { 0x00, 0x1D } are reserved to avoid
+ * collision with Fortezza-based cipher suites in SSL 3.
+ */
+
+ /*
+ * RFC 3268
+ */
+ public const int TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F;
+ public const int TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0x0030;
+ public const int TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0x0031;
+ public const int TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032;
+ public const int TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033;
+ public const int TLS_DH_anon_WITH_AES_128_CBC_SHA = 0x0034;
+ public const int TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035;
+ public const int TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0x0036;
+ public const int TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0x0037;
+ public const int TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038;
+ public const int TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039;
+ public const int TLS_DH_anon_WITH_AES_256_CBC_SHA = 0x003A;
+
+ /*
+ * RFC 5932
+ */
+ public const int TLS_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0041;
+ public const int TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0042;
+ public const int TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0043;
+ public const int TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0044;
+ public const int TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0045;
+ public const int TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA = 0x0046;
+
+ public const int TLS_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0084;
+ public const int TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0085;
+ public const int TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0086;
+ public const int TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0087;
+ public const int TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0088;
+ public const int TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA = 0x0089;
+
+ public const int TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BA;
+ public const int TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BB;
+ public const int TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BC;
+ public const int TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BD;
+ public const int TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BE;
+ public const int TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BF;
+
+ public const int TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C0;
+ public const int TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C1;
+ public const int TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C2;
+ public const int TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C3;
+ public const int TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C4;
+ public const int TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C5;
+
+ /*
+ * RFC 4162
+ */
+ public const int TLS_RSA_WITH_SEED_CBC_SHA = 0x0096;
+ public const int TLS_DH_DSS_WITH_SEED_CBC_SHA = 0x0097;
+ public const int TLS_DH_RSA_WITH_SEED_CBC_SHA = 0x0098;
+ public const int TLS_DHE_DSS_WITH_SEED_CBC_SHA = 0x0099;
+ public const int TLS_DHE_RSA_WITH_SEED_CBC_SHA = 0x009A;
+ public const int TLS_DH_anon_WITH_SEED_CBC_SHA = 0x009B;
+
+ /*
+ * RFC 4279
+ */
+ public const int TLS_PSK_WITH_RC4_128_SHA = 0x008A;
+ public const int TLS_PSK_WITH_3DES_EDE_CBC_SHA = 0x008B;
+ public const int TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C;
+ public const int TLS_PSK_WITH_AES_256_CBC_SHA = 0x008D;
+ public const int TLS_DHE_PSK_WITH_RC4_128_SHA = 0x008E;
+ public const int TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = 0x008F;
+ public const int TLS_DHE_PSK_WITH_AES_128_CBC_SHA = 0x0090;
+ public const int TLS_DHE_PSK_WITH_AES_256_CBC_SHA = 0x0091;
+ public const int TLS_RSA_PSK_WITH_RC4_128_SHA = 0x0092;
+ public const int TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = 0x0093;
+ public const int TLS_RSA_PSK_WITH_AES_128_CBC_SHA = 0x0094;
+ public const int TLS_RSA_PSK_WITH_AES_256_CBC_SHA = 0x0095;
+
+ /*
+ * RFC 4492
+ */
+ public const int TLS_ECDH_ECDSA_WITH_NULL_SHA = 0xC001;
+ public const int TLS_ECDH_ECDSA_WITH_RC4_128_SHA = 0xC002;
+ public const int TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC003;
+ public const int TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = 0xC004;
+ public const int TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = 0xC005;
+ public const int TLS_ECDHE_ECDSA_WITH_NULL_SHA = 0xC006;
+ public const int TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007;
+ public const int TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC008;
+ public const int TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009;
+ public const int TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A;
+ public const int TLS_ECDH_RSA_WITH_NULL_SHA = 0xC00B;
+ public const int TLS_ECDH_RSA_WITH_RC4_128_SHA = 0xC00C;
+ public const int TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = 0xC00D;
+ public const int TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = 0xC00E;
+ public const int TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = 0xC00F;
+ public const int TLS_ECDHE_RSA_WITH_NULL_SHA = 0xC010;
+ public const int TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011;
+ public const int TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xC012;
+ public const int TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013;
+ public const int TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014;
+ public const int TLS_ECDH_anon_WITH_NULL_SHA = 0xC015;
+ public const int TLS_ECDH_anon_WITH_RC4_128_SHA = 0xC016;
+ public const int TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = 0xC017;
+ public const int TLS_ECDH_anon_WITH_AES_128_CBC_SHA = 0xC018;
+ public const int TLS_ECDH_anon_WITH_AES_256_CBC_SHA = 0xC019;
+
+ /*
+ * RFC 4785
+ */
+ public const int TLS_PSK_WITH_NULL_SHA = 0x002C;
+ public const int TLS_DHE_PSK_WITH_NULL_SHA = 0x002D;
+ public const int TLS_RSA_PSK_WITH_NULL_SHA = 0x002E;
+
+ /*
+ * RFC 5054
+ */
+ public const int TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = 0xC01A;
+ public const int TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = 0xC01B;
+ public const int TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = 0xC01C;
+ public const int TLS_SRP_SHA_WITH_AES_128_CBC_SHA = 0xC01D;
+ public const int TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = 0xC01E;
+ public const int TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = 0xC01F;
+ public const int TLS_SRP_SHA_WITH_AES_256_CBC_SHA = 0xC020;
+ public const int TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = 0xC021;
+ public const int TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = 0xC022;
+
+ /*
+ * RFC 5246
+ */
+ public const int TLS_RSA_WITH_NULL_SHA256 = 0x003B;
+ public const int TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C;
+ public const int TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D;
+ public const int TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = 0x003E;
+ public const int TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = 0x003F;
+ public const int TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x0040;
+ public const int TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067;
+ public const int TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = 0x0068;
+ public const int TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = 0x0069;
+ public const int TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x006A;
+ public const int TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B;
+ public const int TLS_DH_anon_WITH_AES_128_CBC_SHA256 = 0x006C;
+ public const int TLS_DH_anon_WITH_AES_256_CBC_SHA256 = 0x006D;
+
+ /*
+ * RFC 5288
+ */
+ public const int TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C;
+ public const int TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D;
+ public const int TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E;
+ public const int TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F;
+ public const int TLS_DH_RSA_WITH_AES_128_GCM_SHA256 = 0x00A0;
+ public const int TLS_DH_RSA_WITH_AES_256_GCM_SHA384 = 0x00A1;
+ public const int TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = 0x00A2;
+ public const int TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 = 0x00A3;
+ public const int TLS_DH_DSS_WITH_AES_128_GCM_SHA256 = 0x00A4;
+ public const int TLS_DH_DSS_WITH_AES_256_GCM_SHA384 = 0x00A5;
+ public const int TLS_DH_anon_WITH_AES_128_GCM_SHA256 = 0x00A6;
+ public const int TLS_DH_anon_WITH_AES_256_GCM_SHA384 = 0x00A7;
+
+ /*
+ * RFC 5289
+ */
+ public const int TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023;
+ public const int TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024;
+ public const int TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC025;
+ public const int TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC026;
+ public const int TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027;
+ public const int TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028;
+ public const int TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = 0xC029;
+ public const int TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = 0xC02A;
+ public const int TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B;
+ public const int TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C;
+ public const int TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02D;
+ public const int TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02E;
+ public const int TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F;
+ public const int TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030;
+ public const int TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 = 0xC031;
+ public const int TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = 0xC032;
+
+ /*
+ * RFC 5487
+ */
+ public const int TLS_PSK_WITH_AES_128_GCM_SHA256 = 0x00A8;
+ public const int TLS_PSK_WITH_AES_256_GCM_SHA384 = 0x00A9;
+ public const int TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 = 0x00AA;
+ public const int TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 = 0x00AB;
+ public const int TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 = 0x00AC;
+ public const int TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 = 0x00AD;
+ public const int TLS_PSK_WITH_AES_128_CBC_SHA256 = 0x00AE;
+ public const int TLS_PSK_WITH_AES_256_CBC_SHA384 = 0x00AF;
+ public const int TLS_PSK_WITH_NULL_SHA256 = 0x00B0;
+ public const int TLS_PSK_WITH_NULL_SHA384 = 0x00B1;
+ public const int TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = 0x00B2;
+ public const int TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = 0x00B3;
+ public const int TLS_DHE_PSK_WITH_NULL_SHA256 = 0x00B4;
+ public const int TLS_DHE_PSK_WITH_NULL_SHA384 = 0x00B5;
+ public const int TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 = 0x00B6;
+ public const int TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 = 0x00B7;
+ public const int TLS_RSA_PSK_WITH_NULL_SHA256 = 0x00B8;
+ public const int TLS_RSA_PSK_WITH_NULL_SHA384 = 0x00B9;
+
+ /*
+ * RFC 5489
+ */
+ public const int TLS_ECDHE_PSK_WITH_RC4_128_SHA = 0xC033;
+ public const int TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA = 0xC034;
+ public const int TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = 0xC035;
+ public const int TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = 0xC036;
+ public const int TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 = 0xC037;
+ public const int TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 = 0xC038;
+ public const int TLS_ECDHE_PSK_WITH_NULL_SHA = 0xC039;
+ public const int TLS_ECDHE_PSK_WITH_NULL_SHA256 = 0xC03A;
+ public const int TLS_ECDHE_PSK_WITH_NULL_SHA384 = 0xC03B;
+
+ /*
+ * RFC 5746
+ */
+ public const int TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF;
+
+ /*
+ * RFC 6367
+ */
+ public const int TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC072;
+ public const int TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC073;
+ public const int TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC074;
+ public const int TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC075;
+ public const int TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC076;
+ public const int TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC077;
+ public const int TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC078;
+ public const int TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC079;
+
+ public const int TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07A;
+ public const int TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07B;
+ public const int TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07C;
+ public const int TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07D;
+ public const int TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07E;
+ public const int TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07F;
+ public const int TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 = 0xC080;
+ public const int TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 = 0xC081;
+ public const int TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 = 0xC082;
+ public const int TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 = 0xC083;
+ public const int TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 = 0xC084;
+ public const int TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 = 0xC085;
+ public const int TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC086;
+ public const int TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC087;
+ public const int TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC088;
+ public const int TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC089;
+ public const int TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08A;
+ public const int TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08B;
+ public const int TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08C;
+ public const int TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08D;
+
+ public const int TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08E;
+ public const int TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08F;
+ public const int TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC090;
+ public const int TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC091;
+ public const int TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC092;
+ public const int TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC093;
+ public const int TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC094;
+ public const int TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC095;
+ public const int TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC096;
+ public const int TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC097;
+ public const int TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC098;
+ public const int TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC099;
+ public const int TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC09A;
+ public const int TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC09B;
+
+ /*
+ * RFC 6655
+ */
+ public const int TLS_RSA_WITH_AES_128_CCM = 0xC09C;
+ public const int TLS_RSA_WITH_AES_256_CCM = 0xC09D;
+ public const int TLS_DHE_RSA_WITH_AES_128_CCM = 0xC09E;
+ public const int TLS_DHE_RSA_WITH_AES_256_CCM = 0xC09F;
+ public const int TLS_RSA_WITH_AES_128_CCM_8 = 0xC0A0;
+ public const int TLS_RSA_WITH_AES_256_CCM_8 = 0xC0A1;
+ public const int TLS_DHE_RSA_WITH_AES_128_CCM_8 = 0xC0A2;
+ public const int TLS_DHE_RSA_WITH_AES_256_CCM_8 = 0xC0A3;
+ public const int TLS_PSK_WITH_AES_128_CCM = 0xC0A4;
+ public const int TLS_PSK_WITH_AES_256_CCM = 0xC0A5;
+ public const int TLS_DHE_PSK_WITH_AES_128_CCM = 0xC0A6;
+ public const int TLS_DHE_PSK_WITH_AES_256_CCM = 0xC0A7;
+ public const int TLS_PSK_WITH_AES_128_CCM_8 = 0xC0A8;
+ public const int TLS_PSK_WITH_AES_256_CCM_8 = 0xC0A9;
+ public const int TLS_PSK_DHE_WITH_AES_128_CCM_8 = 0xC0AA;
+ public const int TLS_PSK_DHE_WITH_AES_256_CCM_8 = 0xC0AB;
+
+ /*
+ * RFC 7251
+ */
+ public const int TLS_ECDHE_ECDSA_WITH_AES_128_CCM = 0xC0AC;
+ public const int TLS_ECDHE_ECDSA_WITH_AES_256_CCM = 0xC0AD;
+ public const int TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 = 0xC0AE;
+ public const int TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 = 0xC0AF;
+
+ /*
+ * RFC 7507
+ */
+ public const int TLS_FALLBACK_SCSV = 0x5600;
+
+ /*
+ * draft-ietf-tls-chacha20-poly1305-04
+ */
+ public const int DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA8;
+ public const int DRAFT_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA9;
+ public const int DRAFT_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAA;
+ public const int DRAFT_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAB;
+ public const int DRAFT_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAC;
+ public const int DRAFT_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAD;
+ public const int DRAFT_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAE;
+
+ /*
+ * draft-zauner-tls-aes-ocb-04 (code points TBD)
+ */
+ public const int DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB = 0xFF00;
+ public const int DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB = 0xFF01;
+ public const int DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB = 0xFF02;
+ public const int DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB = 0xFF03;
+ public const int DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB = 0xFF04;
+ public const int DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB = 0xFF05;
+ public const int DRAFT_TLS_PSK_WITH_AES_128_OCB = 0xFF10;
+ public const int DRAFT_TLS_PSK_WITH_AES_256_OCB = 0xFF11;
+ public const int DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB = 0xFF12;
+ public const int DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB = 0xFF13;
+ public const int DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB = 0xFF14;
+ public const int DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB = 0xFF15;
+
+ public static bool IsScsv(int cipherSuite)
+ {
+ switch (cipherSuite)
+ {
+ case TLS_EMPTY_RENEGOTIATION_INFO_SCSV:
+ case TLS_FALLBACK_SCSV:
+ return true;
+ default:
+ return false;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/CipherType.cs b/bc-sharp-crypto/src/crypto/tls/CipherType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b2ad7d8e1159e1c051644bc5a84b2c8cf186fdeb
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/CipherType.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// RFC 2246
+ ///
+ /// Note that the values here are implementation-specific and arbitrary. It is recommended not to
+ /// depend on the particular values (e.g. serialization).
+ ///
+ public abstract class CipherType
+ {
+ public const int stream = 0;
+ public const int block = 1;
+
+ /*
+ * RFC 5246
+ */
+ public const int aead = 2;
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/ClientAuthenticationType.cs b/bc-sharp-crypto/src/crypto/tls/ClientAuthenticationType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..dd248f3dfbe35a1e26600ab331957ac2ac24c0b4
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/ClientAuthenticationType.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class ClientAuthenticationType
+ {
+ /*
+ * RFC 5077 4
+ */
+ public const byte anonymous = 0;
+ public const byte certificate_based = 1;
+ public const byte psk = 2;
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/ClientCertificateType.cs b/bc-sharp-crypto/src/crypto/tls/ClientCertificateType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a291a46e63f4d0c86545eed1450a3c12c3c56305
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/ClientCertificateType.cs
@@ -0,0 +1,23 @@
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class ClientCertificateType
+ {
+ /*
+ * RFC 4346 7.4.4
+ */
+ public const byte rsa_sign = 1;
+ public const byte dss_sign = 2;
+ public const byte rsa_fixed_dh = 3;
+ public const byte dss_fixed_dh = 4;
+ public const byte rsa_ephemeral_dh_RESERVED = 5;
+ public const byte dss_ephemeral_dh_RESERVED = 6;
+ public const byte fortezza_dms_RESERVED = 20;
+
+ /*
+ * RFC 4492 5.5
+ */
+ public const byte ecdsa_sign = 64;
+ public const byte rsa_fixed_ecdh = 65;
+ public const byte ecdsa_fixed_ecdh = 66;
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/CombinedHash.cs b/bc-sharp-crypto/src/crypto/tls/CombinedHash.cs
new file mode 100644
index 0000000000000000000000000000000000000000..74a52d5987274508c2c4ca3b9d46019eb72ea724
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/CombinedHash.cs
@@ -0,0 +1,133 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * A combined hash, which implements md5(m) || sha1(m).
+ */
+ internal class CombinedHash
+ : TlsHandshakeHash
+ {
+ protected TlsContext mContext;
+ protected IDigest mMd5;
+ protected IDigest mSha1;
+
+ internal CombinedHash()
+ {
+ this.mMd5 = TlsUtilities.CreateHash(HashAlgorithm.md5);
+ this.mSha1 = TlsUtilities.CreateHash(HashAlgorithm.sha1);
+ }
+
+ internal CombinedHash(CombinedHash t)
+ {
+ this.mContext = t.mContext;
+ this.mMd5 = TlsUtilities.CloneHash(HashAlgorithm.md5, t.mMd5);
+ this.mSha1 = TlsUtilities.CloneHash(HashAlgorithm.sha1, t.mSha1);
+ }
+
+ public virtual void Init(TlsContext context)
+ {
+ this.mContext = context;
+ }
+
+ public virtual TlsHandshakeHash NotifyPrfDetermined()
+ {
+ return this;
+ }
+
+ public virtual void TrackHashAlgorithm(byte hashAlgorithm)
+ {
+ throw new InvalidOperationException("CombinedHash only supports calculating the legacy PRF for handshake hash");
+ }
+
+ public virtual void SealHashAlgorithms()
+ {
+ }
+
+ public virtual TlsHandshakeHash StopTracking()
+ {
+ return new CombinedHash(this);
+ }
+
+ public virtual IDigest ForkPrfHash()
+ {
+ return new CombinedHash(this);
+ }
+
+ public virtual byte[] GetFinalHash(byte hashAlgorithm)
+ {
+ throw new InvalidOperationException("CombinedHash doesn't support multiple hashes");
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return mMd5.AlgorithmName + " and " + mSha1.AlgorithmName; }
+ }
+
+ public virtual int GetByteLength()
+ {
+ return System.Math.Max(mMd5.GetByteLength(), mSha1.GetByteLength());
+ }
+
+ public virtual int GetDigestSize()
+ {
+ return mMd5.GetDigestSize() + mSha1.GetDigestSize();
+ }
+
+ public virtual void Update(byte input)
+ {
+ mMd5.Update(input);
+ mSha1.Update(input);
+ }
+
+ /**
+ * @see org.bouncycastle.crypto.Digest#update(byte[], int, int)
+ */
+ public virtual void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ mMd5.BlockUpdate(input, inOff, len);
+ mSha1.BlockUpdate(input, inOff, len);
+ }
+
+ /**
+ * @see org.bouncycastle.crypto.Digest#doFinal(byte[], int)
+ */
+ public virtual int DoFinal(byte[] output, int outOff)
+ {
+ if (mContext != null && TlsUtilities.IsSsl(mContext))
+ {
+ Ssl3Complete(mMd5, Ssl3Mac.IPAD, Ssl3Mac.OPAD, 48);
+ Ssl3Complete(mSha1, Ssl3Mac.IPAD, Ssl3Mac.OPAD, 40);
+ }
+
+ int i1 = mMd5.DoFinal(output, outOff);
+ int i2 = mSha1.DoFinal(output, outOff + i1);
+ return i1 + i2;
+ }
+
+ /**
+ * @see org.bouncycastle.crypto.Digest#reset()
+ */
+ public virtual void Reset()
+ {
+ mMd5.Reset();
+ mSha1.Reset();
+ }
+
+ protected virtual void Ssl3Complete(IDigest d, byte[] ipad, byte[] opad, int padLength)
+ {
+ byte[] master_secret = mContext.SecurityParameters.masterSecret;
+
+ d.BlockUpdate(master_secret, 0, master_secret.Length);
+ d.BlockUpdate(ipad, 0, padLength);
+
+ byte[] tmp = DigestUtilities.DoFinal(d);
+
+ d.BlockUpdate(master_secret, 0, master_secret.Length);
+ d.BlockUpdate(opad, 0, padLength);
+ d.BlockUpdate(tmp, 0, tmp.Length);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/CompressionMethod.cs b/bc-sharp-crypto/src/crypto/tls/CompressionMethod.cs
new file mode 100644
index 0000000000000000000000000000000000000000..89c1f5ff4e3bcd2628e714b9c0c53fc8c7d99c37
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/CompressionMethod.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ ///
+ /// RFC 2246 6.1
+ ///
+ public abstract class CompressionMethod
+ {
+ public const byte cls_null = 0;
+
+ /*
+ * RFC 3749 2
+ */
+ public const byte DEFLATE = 1;
+
+ /*
+ * Values from 224 decimal (0xE0) through 255 decimal (0xFF)
+ * inclusive are reserved for private use.
+ */
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/ConnectionEnd.cs b/bc-sharp-crypto/src/crypto/tls/ConnectionEnd.cs
new file mode 100644
index 0000000000000000000000000000000000000000..afc9460f2d2a9e6c30721d6b6a42889c167aa960
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/ConnectionEnd.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// RFC 2246
+ ///
+ /// Note that the values here are implementation-specific and arbitrary. It is recommended not to
+ /// depend on the particular values (e.g. serialization).
+ ///
+ public abstract class ConnectionEnd
+ {
+ public const int server = 0;
+ public const int client = 1;
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/ContentType.cs b/bc-sharp-crypto/src/crypto/tls/ContentType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d6ab43857de7b2859893484cd46695b9e7d1a6e1
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/ContentType.cs
@@ -0,0 +1,14 @@
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * RFC 2246 6.2.1
+ */
+ public abstract class ContentType
+ {
+ public const byte change_cipher_spec = 20;
+ public const byte alert = 21;
+ public const byte handshake = 22;
+ public const byte application_data = 23;
+ public const byte heartbeat = 24;
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DatagramTransport.cs b/bc-sharp-crypto/src/crypto/tls/DatagramTransport.cs
new file mode 100644
index 0000000000000000000000000000000000000000..524a8b181831382d1aee1265b5ffef564379a33d
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DatagramTransport.cs
@@ -0,0 +1,23 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface DatagramTransport
+ {
+ ///
+ int GetReceiveLimit();
+
+ ///
+ int GetSendLimit();
+
+ ///
+ int Receive(byte[] buf, int off, int len, int waitMillis);
+
+ ///
+ void Send(byte[] buf, int off, int len);
+
+ ///
+ void Close();
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs b/bc-sharp-crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fab978886131f382b88ebbf0beb974fc6355e9b0
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs
@@ -0,0 +1,69 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class DefaultTlsAgreementCredentials
+ : AbstractTlsAgreementCredentials
+ {
+ protected readonly Certificate mCertificate;
+ protected readonly AsymmetricKeyParameter mPrivateKey;
+
+ protected readonly IBasicAgreement mBasicAgreement;
+ protected readonly bool mTruncateAgreement;
+
+ public DefaultTlsAgreementCredentials(Certificate certificate, AsymmetricKeyParameter privateKey)
+ {
+ if (certificate == null)
+ throw new ArgumentNullException("certificate");
+ if (certificate.IsEmpty)
+ throw new ArgumentException("cannot be empty", "certificate");
+ if (privateKey == null)
+ throw new ArgumentNullException("privateKey");
+ if (!privateKey.IsPrivate)
+ throw new ArgumentException("must be private", "privateKey");
+
+ if (privateKey is DHPrivateKeyParameters)
+ {
+ mBasicAgreement = new DHBasicAgreement();
+ mTruncateAgreement = true;
+ }
+ else if (privateKey is ECPrivateKeyParameters)
+ {
+ mBasicAgreement = new ECDHBasicAgreement();
+ mTruncateAgreement = false;
+ }
+ else
+ {
+ throw new ArgumentException("type not supported: " + Platform.GetTypeName(privateKey), "privateKey");
+ }
+
+ this.mCertificate = certificate;
+ this.mPrivateKey = privateKey;
+ }
+
+ public override Certificate Certificate
+ {
+ get { return mCertificate; }
+ }
+
+ ///
+ public override byte[] GenerateAgreement(AsymmetricKeyParameter peerPublicKey)
+ {
+ mBasicAgreement.Init(mPrivateKey);
+ BigInteger agreementValue = mBasicAgreement.CalculateAgreement(peerPublicKey);
+
+ if (mTruncateAgreement)
+ {
+ return BigIntegers.AsUnsignedByteArray(agreementValue);
+ }
+
+ return BigIntegers.AsUnsignedByteArray(mBasicAgreement.GetFieldSize(), agreementValue);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DefaultTlsCipherFactory.cs b/bc-sharp-crypto/src/crypto/tls/DefaultTlsCipherFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..af0ec126a45e1e0984853a6f6da5be30a973ba20
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DefaultTlsCipherFactory.cs
@@ -0,0 +1,227 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class DefaultTlsCipherFactory
+ : AbstractTlsCipherFactory
+ {
+ ///
+ public override TlsCipher CreateCipher(TlsContext context, int encryptionAlgorithm, int macAlgorithm)
+ {
+ switch (encryptionAlgorithm)
+ {
+ case EncryptionAlgorithm.cls_3DES_EDE_CBC:
+ return CreateDesEdeCipher(context, macAlgorithm);
+ case EncryptionAlgorithm.AES_128_CBC:
+ return CreateAESCipher(context, 16, macAlgorithm);
+ case EncryptionAlgorithm.AES_128_CCM:
+ // NOTE: Ignores macAlgorithm
+ return CreateCipher_Aes_Ccm(context, 16, 16);
+ case EncryptionAlgorithm.AES_128_CCM_8:
+ // NOTE: Ignores macAlgorithm
+ return CreateCipher_Aes_Ccm(context, 16, 8);
+ case EncryptionAlgorithm.AES_128_GCM:
+ // NOTE: Ignores macAlgorithm
+ return CreateCipher_Aes_Gcm(context, 16, 16);
+ case EncryptionAlgorithm.AES_128_OCB_TAGLEN96:
+ // NOTE: Ignores macAlgorithm
+ return CreateCipher_Aes_Ocb(context, 16, 12);
+ case EncryptionAlgorithm.AES_256_CBC:
+ return CreateAESCipher(context, 32, macAlgorithm);
+ case EncryptionAlgorithm.AES_256_CCM:
+ // NOTE: Ignores macAlgorithm
+ return CreateCipher_Aes_Ccm(context, 32, 16);
+ case EncryptionAlgorithm.AES_256_CCM_8:
+ // NOTE: Ignores macAlgorithm
+ return CreateCipher_Aes_Ccm(context, 32, 8);
+ case EncryptionAlgorithm.AES_256_GCM:
+ // NOTE: Ignores macAlgorithm
+ return CreateCipher_Aes_Gcm(context, 32, 16);
+ case EncryptionAlgorithm.AES_256_OCB_TAGLEN96:
+ // NOTE: Ignores macAlgorithm
+ return CreateCipher_Aes_Ocb(context, 32, 12);
+ case EncryptionAlgorithm.CAMELLIA_128_CBC:
+ return CreateCamelliaCipher(context, 16, macAlgorithm);
+ case EncryptionAlgorithm.CAMELLIA_128_GCM:
+ // NOTE: Ignores macAlgorithm
+ return CreateCipher_Camellia_Gcm(context, 16, 16);
+ case EncryptionAlgorithm.CAMELLIA_256_CBC:
+ return CreateCamelliaCipher(context, 32, macAlgorithm);
+ case EncryptionAlgorithm.CAMELLIA_256_GCM:
+ // NOTE: Ignores macAlgorithm
+ return CreateCipher_Camellia_Gcm(context, 32, 16);
+ case EncryptionAlgorithm.CHACHA20_POLY1305:
+ // NOTE: Ignores macAlgorithm
+ return CreateChaCha20Poly1305(context);
+ case EncryptionAlgorithm.NULL:
+ return CreateNullCipher(context, macAlgorithm);
+ case EncryptionAlgorithm.RC4_128:
+ return CreateRC4Cipher(context, 16, macAlgorithm);
+ case EncryptionAlgorithm.SEED_CBC:
+ return CreateSeedCipher(context, macAlgorithm);
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ ///
+ protected virtual TlsBlockCipher CreateAESCipher(TlsContext context, int cipherKeySize, int macAlgorithm)
+ {
+ return new TlsBlockCipher(context, CreateAesBlockCipher(), CreateAesBlockCipher(),
+ CreateHMacDigest(macAlgorithm), CreateHMacDigest(macAlgorithm), cipherKeySize);
+ }
+
+ ///
+ protected virtual TlsBlockCipher CreateCamelliaCipher(TlsContext context, int cipherKeySize, int macAlgorithm)
+ {
+ return new TlsBlockCipher(context, CreateCamelliaBlockCipher(),
+ CreateCamelliaBlockCipher(), CreateHMacDigest(macAlgorithm),
+ CreateHMacDigest(macAlgorithm), cipherKeySize);
+ }
+
+ ///
+ protected virtual TlsCipher CreateChaCha20Poly1305(TlsContext context)
+ {
+ return new Chacha20Poly1305(context);
+ }
+
+ ///
+ protected virtual TlsAeadCipher CreateCipher_Aes_Ccm(TlsContext context, int cipherKeySize, int macSize)
+ {
+ return new TlsAeadCipher(context, CreateAeadBlockCipher_Aes_Ccm(),
+ CreateAeadBlockCipher_Aes_Ccm(), cipherKeySize, macSize);
+ }
+
+ ///
+ protected virtual TlsAeadCipher CreateCipher_Aes_Gcm(TlsContext context, int cipherKeySize, int macSize)
+ {
+ return new TlsAeadCipher(context, CreateAeadBlockCipher_Aes_Gcm(),
+ CreateAeadBlockCipher_Aes_Gcm(), cipherKeySize, macSize);
+ }
+
+ ///
+ protected virtual TlsAeadCipher CreateCipher_Aes_Ocb(TlsContext context, int cipherKeySize, int macSize)
+ {
+ return new TlsAeadCipher(context, CreateAeadBlockCipher_Aes_Ocb(),
+ CreateAeadBlockCipher_Aes_Ocb(), cipherKeySize, macSize, TlsAeadCipher.NONCE_DRAFT_CHACHA20_POLY1305);
+ }
+
+ ///
+ protected virtual TlsAeadCipher CreateCipher_Camellia_Gcm(TlsContext context, int cipherKeySize, int macSize)
+ {
+ return new TlsAeadCipher(context, CreateAeadBlockCipher_Camellia_Gcm(),
+ CreateAeadBlockCipher_Camellia_Gcm(), cipherKeySize, macSize);
+ }
+
+ ///
+ protected virtual TlsBlockCipher CreateDesEdeCipher(TlsContext context, int macAlgorithm)
+ {
+ return new TlsBlockCipher(context, CreateDesEdeBlockCipher(), CreateDesEdeBlockCipher(),
+ CreateHMacDigest(macAlgorithm), CreateHMacDigest(macAlgorithm), 24);
+ }
+
+ ///
+ protected virtual TlsNullCipher CreateNullCipher(TlsContext context, int macAlgorithm)
+ {
+ return new TlsNullCipher(context, CreateHMacDigest(macAlgorithm),
+ CreateHMacDigest(macAlgorithm));
+ }
+
+ ///
+ protected virtual TlsStreamCipher CreateRC4Cipher(TlsContext context, int cipherKeySize, int macAlgorithm)
+ {
+ return new TlsStreamCipher(context, CreateRC4StreamCipher(), CreateRC4StreamCipher(),
+ CreateHMacDigest(macAlgorithm), CreateHMacDigest(macAlgorithm), cipherKeySize, false);
+ }
+
+ ///
+ protected virtual TlsBlockCipher CreateSeedCipher(TlsContext context, int macAlgorithm)
+ {
+ return new TlsBlockCipher(context, CreateSeedBlockCipher(), CreateSeedBlockCipher(),
+ CreateHMacDigest(macAlgorithm), CreateHMacDigest(macAlgorithm), 16);
+ }
+
+ protected virtual IBlockCipher CreateAesEngine()
+ {
+ return new AesEngine();
+ }
+
+ protected virtual IBlockCipher CreateCamelliaEngine()
+ {
+ return new CamelliaEngine();
+ }
+
+ protected virtual IBlockCipher CreateAesBlockCipher()
+ {
+ return new CbcBlockCipher(CreateAesEngine());
+ }
+
+ protected virtual IAeadBlockCipher CreateAeadBlockCipher_Aes_Ccm()
+ {
+ return new CcmBlockCipher(CreateAesEngine());
+ }
+
+ protected virtual IAeadBlockCipher CreateAeadBlockCipher_Aes_Gcm()
+ {
+ // TODO Consider allowing custom configuration of multiplier
+ return new GcmBlockCipher(CreateAesEngine());
+ }
+
+ protected virtual IAeadBlockCipher CreateAeadBlockCipher_Aes_Ocb()
+ {
+ return new OcbBlockCipher(CreateAesEngine(), CreateAesEngine());
+ }
+
+ protected virtual IAeadBlockCipher CreateAeadBlockCipher_Camellia_Gcm()
+ {
+ // TODO Consider allowing custom configuration of multiplier
+ return new GcmBlockCipher(CreateCamelliaEngine());
+ }
+
+ protected virtual IBlockCipher CreateCamelliaBlockCipher()
+ {
+ return new CbcBlockCipher(CreateCamelliaEngine());
+ }
+
+ protected virtual IBlockCipher CreateDesEdeBlockCipher()
+ {
+ return new CbcBlockCipher(new DesEdeEngine());
+ }
+
+ protected virtual IStreamCipher CreateRC4StreamCipher()
+ {
+ return new RC4Engine();
+ }
+
+ protected virtual IBlockCipher CreateSeedBlockCipher()
+ {
+ return new CbcBlockCipher(new SeedEngine());
+ }
+
+ ///
+ protected virtual IDigest CreateHMacDigest(int macAlgorithm)
+ {
+ switch (macAlgorithm)
+ {
+ case MacAlgorithm.cls_null:
+ return null;
+ case MacAlgorithm.hmac_md5:
+ return TlsUtilities.CreateHash(HashAlgorithm.md5);
+ case MacAlgorithm.hmac_sha1:
+ return TlsUtilities.CreateHash(HashAlgorithm.sha1);
+ case MacAlgorithm.hmac_sha256:
+ return TlsUtilities.CreateHash(HashAlgorithm.sha256);
+ case MacAlgorithm.hmac_sha384:
+ return TlsUtilities.CreateHash(HashAlgorithm.sha384);
+ case MacAlgorithm.hmac_sha512:
+ return TlsUtilities.CreateHash(HashAlgorithm.sha512);
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DefaultTlsClient.cs b/bc-sharp-crypto/src/crypto/tls/DefaultTlsClient.cs
new file mode 100644
index 0000000000000000000000000000000000000000..32a86e50309427a0d27f37a6e4a56fb222712466
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DefaultTlsClient.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class DefaultTlsClient
+ : AbstractTlsClient
+ {
+ public DefaultTlsClient()
+ : base()
+ {
+ }
+
+ public DefaultTlsClient(TlsCipherFactory cipherFactory)
+ : base(cipherFactory)
+ {
+ }
+
+ public override int[] GetCipherSuites()
+ {
+ return new int[]
+ {
+ CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
+ };
+ }
+
+ public override TlsKeyExchange GetKeyExchange()
+ {
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
+
+ switch (keyExchangeAlgorithm)
+ {
+ case KeyExchangeAlgorithm.DH_anon:
+ case KeyExchangeAlgorithm.DH_DSS:
+ case KeyExchangeAlgorithm.DH_RSA:
+ return CreateDHKeyExchange(keyExchangeAlgorithm);
+
+ case KeyExchangeAlgorithm.DHE_DSS:
+ case KeyExchangeAlgorithm.DHE_RSA:
+ return CreateDheKeyExchange(keyExchangeAlgorithm);
+
+ case KeyExchangeAlgorithm.ECDH_anon:
+ case KeyExchangeAlgorithm.ECDH_ECDSA:
+ case KeyExchangeAlgorithm.ECDH_RSA:
+ return CreateECDHKeyExchange(keyExchangeAlgorithm);
+
+ case KeyExchangeAlgorithm.ECDHE_ECDSA:
+ case KeyExchangeAlgorithm.ECDHE_RSA:
+ return CreateECDheKeyExchange(keyExchangeAlgorithm);
+
+ case KeyExchangeAlgorithm.RSA:
+ return CreateRsaKeyExchange();
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocol implementation verifies that the
+ * server-selected cipher suite was in the list of client-offered cipher suites, so if
+ * we now can't produce an implementation, we shouldn't have offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ protected virtual TlsKeyExchange CreateDHKeyExchange(int keyExchange)
+ {
+ return new TlsDHKeyExchange(keyExchange, mSupportedSignatureAlgorithms, null);
+ }
+
+ protected virtual TlsKeyExchange CreateDheKeyExchange(int keyExchange)
+ {
+ return new TlsDheKeyExchange(keyExchange, mSupportedSignatureAlgorithms, null);
+ }
+
+ protected virtual TlsKeyExchange CreateECDHKeyExchange(int keyExchange)
+ {
+ return new TlsECDHKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mNamedCurves, mClientECPointFormats,
+ mServerECPointFormats);
+ }
+
+ protected virtual TlsKeyExchange CreateECDheKeyExchange(int keyExchange)
+ {
+ return new TlsECDheKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mNamedCurves, mClientECPointFormats,
+ mServerECPointFormats);
+ }
+
+ protected virtual TlsKeyExchange CreateRsaKeyExchange()
+ {
+ return new TlsRsaKeyExchange(mSupportedSignatureAlgorithms);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DefaultTlsEncryptionCredentials.cs b/bc-sharp-crypto/src/crypto/tls/DefaultTlsEncryptionCredentials.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5348ee88d8d4a9518e2c3dbe0a942eeef8d286b9
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DefaultTlsEncryptionCredentials.cs
@@ -0,0 +1,52 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class DefaultTlsEncryptionCredentials
+ : AbstractTlsEncryptionCredentials
+ {
+ protected readonly TlsContext mContext;
+ protected readonly Certificate mCertificate;
+ protected readonly AsymmetricKeyParameter mPrivateKey;
+
+ public DefaultTlsEncryptionCredentials(TlsContext context, Certificate certificate,
+ AsymmetricKeyParameter privateKey)
+ {
+ if (certificate == null)
+ throw new ArgumentNullException("certificate");
+ if (certificate.IsEmpty)
+ throw new ArgumentException("cannot be empty", "certificate");
+ if (privateKey == null)
+ throw new ArgumentNullException("'privateKey' cannot be null");
+ if (!privateKey.IsPrivate)
+ throw new ArgumentException("must be private", "privateKey");
+
+ if (privateKey is RsaKeyParameters)
+ {
+ }
+ else
+ {
+ throw new ArgumentException("type not supported: " + Platform.GetTypeName(privateKey), "privateKey");
+ }
+
+ this.mContext = context;
+ this.mCertificate = certificate;
+ this.mPrivateKey = privateKey;
+ }
+
+ public override Certificate Certificate
+ {
+ get { return mCertificate; }
+ }
+
+ ///
+ public override byte[] DecryptPreMasterSecret(byte[] encryptedPreMasterSecret)
+ {
+ return TlsRsaUtilities.SafeDecryptPreMasterSecret(mContext, (RsaKeyParameters)mPrivateKey, encryptedPreMasterSecret);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DefaultTlsServer.cs b/bc-sharp-crypto/src/crypto/tls/DefaultTlsServer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..97eaa079df22e976bcf7b9d362ae8b62a7a5db90
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DefaultTlsServer.cs
@@ -0,0 +1,166 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class DefaultTlsServer
+ : AbstractTlsServer
+ {
+ public DefaultTlsServer()
+ : base()
+ {
+ }
+
+ public DefaultTlsServer(TlsCipherFactory cipherFactory)
+ : base(cipherFactory)
+ {
+ }
+
+ protected virtual TlsSignerCredentials GetDsaSignerCredentials()
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ protected virtual TlsSignerCredentials GetECDsaSignerCredentials()
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ protected virtual TlsEncryptionCredentials GetRsaEncryptionCredentials()
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ protected virtual TlsSignerCredentials GetRsaSignerCredentials()
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ protected virtual DHParameters GetDHParameters()
+ {
+ return DHStandardGroups.rfc7919_ffdhe2048;
+ }
+
+ protected override int[] GetCipherSuites()
+ {
+ return new int[]
+ {
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384,
+ CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256,
+ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
+ };
+ }
+
+ public override TlsCredentials GetCredentials()
+ {
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
+
+ switch (keyExchangeAlgorithm)
+ {
+ case KeyExchangeAlgorithm.DHE_DSS:
+ return GetDsaSignerCredentials();
+
+ case KeyExchangeAlgorithm.DH_anon:
+ case KeyExchangeAlgorithm.ECDH_anon:
+ return null;
+
+ case KeyExchangeAlgorithm.ECDHE_ECDSA:
+ return GetECDsaSignerCredentials();
+
+ case KeyExchangeAlgorithm.DHE_RSA:
+ case KeyExchangeAlgorithm.ECDHE_RSA:
+ return GetRsaSignerCredentials();
+
+ case KeyExchangeAlgorithm.RSA:
+ return GetRsaEncryptionCredentials();
+
+ default:
+ /* Note: internal error here; selected a key exchange we don't implement! */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public override TlsKeyExchange GetKeyExchange()
+ {
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
+
+ switch (keyExchangeAlgorithm)
+ {
+ case KeyExchangeAlgorithm.DH_anon:
+ case KeyExchangeAlgorithm.DH_DSS:
+ case KeyExchangeAlgorithm.DH_RSA:
+ return CreateDHKeyExchange(keyExchangeAlgorithm);
+
+ case KeyExchangeAlgorithm.DHE_DSS:
+ case KeyExchangeAlgorithm.DHE_RSA:
+ return CreateDheKeyExchange(keyExchangeAlgorithm);
+
+ case KeyExchangeAlgorithm.ECDH_anon:
+ case KeyExchangeAlgorithm.ECDH_ECDSA:
+ case KeyExchangeAlgorithm.ECDH_RSA:
+ return CreateECDHKeyExchange(keyExchangeAlgorithm);
+
+ case KeyExchangeAlgorithm.ECDHE_ECDSA:
+ case KeyExchangeAlgorithm.ECDHE_RSA:
+ return CreateECDheKeyExchange(keyExchangeAlgorithm);
+
+ case KeyExchangeAlgorithm.RSA:
+ return CreateRsaKeyExchange();
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocol implementation verifies that the
+ * server-selected cipher suite was in the list of client-offered cipher suites, so if
+ * we now can't produce an implementation, we shouldn't have offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ protected virtual TlsKeyExchange CreateDHKeyExchange(int keyExchange)
+ {
+ return new TlsDHKeyExchange(keyExchange, mSupportedSignatureAlgorithms, GetDHParameters());
+ }
+
+ protected virtual TlsKeyExchange CreateDheKeyExchange(int keyExchange)
+ {
+ return new TlsDheKeyExchange(keyExchange, mSupportedSignatureAlgorithms, GetDHParameters());
+ }
+
+ protected virtual TlsKeyExchange CreateECDHKeyExchange(int keyExchange)
+ {
+ return new TlsECDHKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mNamedCurves, mClientECPointFormats,
+ mServerECPointFormats);
+ }
+
+ protected virtual TlsKeyExchange CreateECDheKeyExchange(int keyExchange)
+ {
+ return new TlsECDheKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mNamedCurves, mClientECPointFormats,
+ mServerECPointFormats);
+ }
+
+ protected virtual TlsKeyExchange CreateRsaKeyExchange()
+ {
+ return new TlsRsaKeyExchange(mSupportedSignatureAlgorithms);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs b/bc-sharp-crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0ff732a97ce167b5eccd0be8ed0d54ac0165b853
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs
@@ -0,0 +1,93 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class DefaultTlsSignerCredentials
+ : AbstractTlsSignerCredentials
+ {
+ protected readonly TlsContext mContext;
+ protected readonly Certificate mCertificate;
+ protected readonly AsymmetricKeyParameter mPrivateKey;
+ protected readonly SignatureAndHashAlgorithm mSignatureAndHashAlgorithm;
+
+ protected readonly TlsSigner mSigner;
+
+ public DefaultTlsSignerCredentials(TlsContext context, Certificate certificate, AsymmetricKeyParameter privateKey)
+ : this(context, certificate, privateKey, null)
+ {
+ }
+
+ public DefaultTlsSignerCredentials(TlsContext context, Certificate certificate, AsymmetricKeyParameter privateKey,
+ SignatureAndHashAlgorithm signatureAndHashAlgorithm)
+ {
+ if (certificate == null)
+ throw new ArgumentNullException("certificate");
+ if (certificate.IsEmpty)
+ throw new ArgumentException("cannot be empty", "clientCertificate");
+ if (privateKey == null)
+ throw new ArgumentNullException("privateKey");
+ if (!privateKey.IsPrivate)
+ throw new ArgumentException("must be private", "privateKey");
+ if (TlsUtilities.IsTlsV12(context) && signatureAndHashAlgorithm == null)
+ throw new ArgumentException("cannot be null for (D)TLS 1.2+", "signatureAndHashAlgorithm");
+
+ if (privateKey is RsaKeyParameters)
+ {
+ mSigner = new TlsRsaSigner();
+ }
+ else if (privateKey is DsaPrivateKeyParameters)
+ {
+ mSigner = new TlsDssSigner();
+ }
+ else if (privateKey is ECPrivateKeyParameters)
+ {
+ mSigner = new TlsECDsaSigner();
+ }
+ else
+ {
+ throw new ArgumentException("type not supported: " + Platform.GetTypeName(privateKey), "privateKey");
+ }
+
+ this.mSigner.Init(context);
+
+ this.mContext = context;
+ this.mCertificate = certificate;
+ this.mPrivateKey = privateKey;
+ this.mSignatureAndHashAlgorithm = signatureAndHashAlgorithm;
+ }
+
+ public override Certificate Certificate
+ {
+ get { return mCertificate; }
+ }
+
+ ///
+ public override byte[] GenerateCertificateSignature(byte[] hash)
+ {
+ try
+ {
+ if (TlsUtilities.IsTlsV12(mContext))
+ {
+ return mSigner.GenerateRawSignature(mSignatureAndHashAlgorithm, mPrivateKey, hash);
+ }
+ else
+ {
+ return mSigner.GenerateRawSignature(mPrivateKey, hash);
+ }
+ }
+ catch (CryptoException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error, e);
+ }
+ }
+
+ public override SignatureAndHashAlgorithm SignatureAndHashAlgorithm
+ {
+ get { return mSignatureAndHashAlgorithm; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DefaultTlsSrpGroupVerifier.cs b/bc-sharp-crypto/src/crypto/tls/DefaultTlsSrpGroupVerifier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cc933bff92a087acd0a654d9cedd5e9245d657f9
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DefaultTlsSrpGroupVerifier.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Agreement.Srp;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class DefaultTlsSrpGroupVerifier
+ : TlsSrpGroupVerifier
+ {
+ protected static readonly IList DefaultGroups = Platform.CreateArrayList();
+
+ static DefaultTlsSrpGroupVerifier()
+ {
+ DefaultGroups.Add(Srp6StandardGroups.rfc5054_1024);
+ DefaultGroups.Add(Srp6StandardGroups.rfc5054_1536);
+ DefaultGroups.Add(Srp6StandardGroups.rfc5054_2048);
+ DefaultGroups.Add(Srp6StandardGroups.rfc5054_3072);
+ DefaultGroups.Add(Srp6StandardGroups.rfc5054_4096);
+ DefaultGroups.Add(Srp6StandardGroups.rfc5054_6144);
+ DefaultGroups.Add(Srp6StandardGroups.rfc5054_8192);
+ }
+
+ // Vector is (SRP6GroupParameters)
+ protected readonly IList mGroups;
+
+ /**
+ * Accept only the group parameters specified in RFC 5054 Appendix A.
+ */
+ public DefaultTlsSrpGroupVerifier()
+ : this(DefaultGroups)
+ {
+ }
+
+ /**
+ * Specify a custom set of acceptable group parameters.
+ *
+ * @param groups a {@link Vector} of acceptable {@link SRP6GroupParameters}
+ */
+ public DefaultTlsSrpGroupVerifier(IList groups)
+ {
+ this.mGroups = groups;
+ }
+
+ public virtual bool Accept(Srp6GroupParameters group)
+ {
+ foreach (Srp6GroupParameters entry in mGroups)
+ {
+ if (AreGroupsEqual(group, entry))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected virtual bool AreGroupsEqual(Srp6GroupParameters a, Srp6GroupParameters b)
+ {
+ return a == b || (AreParametersEqual(a.N, b.N) && AreParametersEqual(a.G, b.G));
+ }
+
+ protected virtual bool AreParametersEqual(BigInteger a, BigInteger b)
+ {
+ return a == b || a.Equals(b);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DeferredHash.cs b/bc-sharp-crypto/src/crypto/tls/DeferredHash.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f402f26d2574fa8db230f7077ffb75896f3212d9
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DeferredHash.cs
@@ -0,0 +1,201 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * Buffers input until the hash algorithm is determined.
+ */
+ internal class DeferredHash
+ : TlsHandshakeHash
+ {
+ protected const int BUFFERING_HASH_LIMIT = 4;
+
+ protected TlsContext mContext;
+
+ private DigestInputBuffer mBuf;
+ private IDictionary mHashes;
+ private int mPrfHashAlgorithm;
+
+ internal DeferredHash()
+ {
+ this.mBuf = new DigestInputBuffer();
+ this.mHashes = Platform.CreateHashtable();
+ this.mPrfHashAlgorithm = -1;
+ }
+
+ private DeferredHash(byte prfHashAlgorithm, IDigest prfHash)
+ {
+ this.mBuf = null;
+ this.mHashes = Platform.CreateHashtable();
+ this.mPrfHashAlgorithm = prfHashAlgorithm;
+ mHashes[prfHashAlgorithm] = prfHash;
+ }
+
+ public virtual void Init(TlsContext context)
+ {
+ this.mContext = context;
+ }
+
+ public virtual TlsHandshakeHash NotifyPrfDetermined()
+ {
+ int prfAlgorithm = mContext.SecurityParameters.PrfAlgorithm;
+ if (prfAlgorithm == PrfAlgorithm.tls_prf_legacy)
+ {
+ CombinedHash legacyHash = new CombinedHash();
+ legacyHash.Init(mContext);
+ mBuf.UpdateDigest(legacyHash);
+ return legacyHash.NotifyPrfDetermined();
+ }
+
+ this.mPrfHashAlgorithm = TlsUtilities.GetHashAlgorithmForPrfAlgorithm(prfAlgorithm);
+
+ CheckTrackingHash((byte)mPrfHashAlgorithm);
+
+ return this;
+ }
+
+ public virtual void TrackHashAlgorithm(byte hashAlgorithm)
+ {
+ if (mBuf == null)
+ throw new InvalidOperationException("Too late to track more hash algorithms");
+
+ CheckTrackingHash(hashAlgorithm);
+ }
+
+ public virtual void SealHashAlgorithms()
+ {
+ CheckStopBuffering();
+ }
+
+ public virtual TlsHandshakeHash StopTracking()
+ {
+ byte prfHashAlgorithm = (byte)mPrfHashAlgorithm;
+ IDigest prfHash = TlsUtilities.CloneHash(prfHashAlgorithm, (IDigest)mHashes[prfHashAlgorithm]);
+ if (mBuf != null)
+ {
+ mBuf.UpdateDigest(prfHash);
+ }
+ DeferredHash result = new DeferredHash(prfHashAlgorithm, prfHash);
+ result.Init(mContext);
+ return result;
+ }
+
+ public virtual IDigest ForkPrfHash()
+ {
+ CheckStopBuffering();
+
+ byte prfHashAlgorithm = (byte)mPrfHashAlgorithm;
+ if (mBuf != null)
+ {
+ IDigest prfHash = TlsUtilities.CreateHash(prfHashAlgorithm);
+ mBuf.UpdateDigest(prfHash);
+ return prfHash;
+ }
+
+ return TlsUtilities.CloneHash(prfHashAlgorithm, (IDigest)mHashes[prfHashAlgorithm]);
+ }
+
+ public virtual byte[] GetFinalHash(byte hashAlgorithm)
+ {
+ IDigest d = (IDigest)mHashes[hashAlgorithm];
+ if (d == null)
+ throw new InvalidOperationException("HashAlgorithm." + HashAlgorithm.GetText(hashAlgorithm) + " is not being tracked");
+
+ d = TlsUtilities.CloneHash(hashAlgorithm, d);
+ if (mBuf != null)
+ {
+ mBuf.UpdateDigest(d);
+ }
+
+ return DigestUtilities.DoFinal(d);
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { throw new InvalidOperationException("Use Fork() to get a definite IDigest"); }
+ }
+
+ public virtual int GetByteLength()
+ {
+ throw new InvalidOperationException("Use Fork() to get a definite IDigest");
+ }
+
+ public virtual int GetDigestSize()
+ {
+ throw new InvalidOperationException("Use Fork() to get a definite IDigest");
+ }
+
+ public virtual void Update(byte input)
+ {
+ if (mBuf != null)
+ {
+ mBuf.WriteByte(input);
+ return;
+ }
+
+ foreach (IDigest hash in mHashes.Values)
+ {
+ hash.Update(input);
+ }
+ }
+
+ public virtual void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ if (mBuf != null)
+ {
+ mBuf.Write(input, inOff, len);
+ return;
+ }
+
+ foreach (IDigest hash in mHashes.Values)
+ {
+ hash.BlockUpdate(input, inOff, len);
+ }
+ }
+
+ public virtual int DoFinal(byte[] output, int outOff)
+ {
+ throw new InvalidOperationException("Use Fork() to get a definite IDigest");
+ }
+
+ public virtual void Reset()
+ {
+ if (mBuf != null)
+ {
+ mBuf.SetLength(0);
+ return;
+ }
+
+ foreach (IDigest hash in mHashes.Values)
+ {
+ hash.Reset();
+ }
+ }
+
+ protected virtual void CheckStopBuffering()
+ {
+ if (mBuf != null && mHashes.Count <= BUFFERING_HASH_LIMIT)
+ {
+ foreach (IDigest hash in mHashes.Values)
+ {
+ mBuf.UpdateDigest(hash);
+ }
+
+ this.mBuf = null;
+ }
+ }
+
+ protected virtual void CheckTrackingHash(byte hashAlgorithm)
+ {
+ if (!mHashes.Contains(hashAlgorithm))
+ {
+ IDigest hash = TlsUtilities.CreateHash(hashAlgorithm);
+ mHashes[hashAlgorithm] = hash;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DigestInputBuffer.cs b/bc-sharp-crypto/src/crypto/tls/DigestInputBuffer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4435b40a5b38a1b19779c085b9bde970e96f0b47
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DigestInputBuffer.cs
@@ -0,0 +1,37 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ internal class DigestInputBuffer
+ : MemoryStream
+ {
+ internal void UpdateDigest(IDigest d)
+ {
+ Streams.WriteBufTo(this, new DigStream(d));
+ }
+
+ private class DigStream
+ : BaseOutputStream
+ {
+ private readonly IDigest d;
+
+ internal DigStream(IDigest d)
+ {
+ this.d = d;
+ }
+
+ public override void WriteByte(byte b)
+ {
+ d.Update(b);
+ }
+
+ public override void Write(byte[] buf, int off, int len)
+ {
+ d.BlockUpdate(buf, off, len);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DigitallySigned.cs b/bc-sharp-crypto/src/crypto/tls/DigitallySigned.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8b7344fd98916ced272e748afe383bfea878d7ee
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DigitallySigned.cs
@@ -0,0 +1,70 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class DigitallySigned
+ {
+ protected readonly SignatureAndHashAlgorithm mAlgorithm;
+ protected readonly byte[] mSignature;
+
+ public DigitallySigned(SignatureAndHashAlgorithm algorithm, byte[] signature)
+ {
+ if (signature == null)
+ throw new ArgumentNullException("signature");
+
+ this.mAlgorithm = algorithm;
+ this.mSignature = signature;
+ }
+
+ /**
+ * @return a {@link SignatureAndHashAlgorithm} (or null before TLS 1.2).
+ */
+ public virtual SignatureAndHashAlgorithm Algorithm
+ {
+ get { return mAlgorithm; }
+ }
+
+ public virtual byte[] Signature
+ {
+ get { return mSignature; }
+ }
+
+ /**
+ * Encode this {@link DigitallySigned} to a {@link Stream}.
+ *
+ * @param output
+ * the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ if (mAlgorithm != null)
+ {
+ mAlgorithm.Encode(output);
+ }
+ TlsUtilities.WriteOpaque16(mSignature, output);
+ }
+
+ /**
+ * Parse a {@link DigitallySigned} from a {@link Stream}.
+ *
+ * @param context
+ * the {@link TlsContext} of the current connection.
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link DigitallySigned} object.
+ * @throws IOException
+ */
+ public static DigitallySigned Parse(TlsContext context, Stream input)
+ {
+ SignatureAndHashAlgorithm algorithm = null;
+ if (TlsUtilities.IsTlsV12(context))
+ {
+ algorithm = SignatureAndHashAlgorithm.Parse(input);
+ }
+ byte[] signature = TlsUtilities.ReadOpaque16(input);
+ return new DigitallySigned(algorithm, signature);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DtlsClientProtocol.cs b/bc-sharp-crypto/src/crypto/tls/DtlsClientProtocol.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ae6e6a5731b82e1605ee3dbdeb8f9ee99d4ca768
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DtlsClientProtocol.cs
@@ -0,0 +1,857 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class DtlsClientProtocol
+ : DtlsProtocol
+ {
+ public DtlsClientProtocol(SecureRandom secureRandom)
+ : base(secureRandom)
+ {
+ }
+
+ public virtual DtlsTransport Connect(TlsClient client, DatagramTransport transport)
+ {
+ if (client == null)
+ throw new ArgumentNullException("client");
+ if (transport == null)
+ throw new ArgumentNullException("transport");
+
+ SecurityParameters securityParameters = new SecurityParameters();
+ securityParameters.entity = ConnectionEnd.client;
+
+ ClientHandshakeState state = new ClientHandshakeState();
+ state.client = client;
+ state.clientContext = new TlsClientContextImpl(mSecureRandom, securityParameters);
+
+ securityParameters.clientRandom = TlsProtocol.CreateRandomBlock(client.ShouldUseGmtUnixTime(),
+ state.clientContext.NonceRandomGenerator);
+
+ client.Init(state.clientContext);
+
+ DtlsRecordLayer recordLayer = new DtlsRecordLayer(transport, state.clientContext, client, ContentType.handshake);
+
+ TlsSession sessionToResume = state.client.GetSessionToResume();
+ if (sessionToResume != null && sessionToResume.IsResumable)
+ {
+ SessionParameters sessionParameters = sessionToResume.ExportSessionParameters();
+ if (sessionParameters != null)
+ {
+ state.tlsSession = sessionToResume;
+ state.sessionParameters = sessionParameters;
+ }
+ }
+
+ try
+ {
+ return ClientHandshake(state, recordLayer);
+ }
+ catch (TlsFatalAlert fatalAlert)
+ {
+ AbortClientHandshake(state, recordLayer, fatalAlert.AlertDescription);
+ throw fatalAlert;
+ }
+ catch (IOException e)
+ {
+ AbortClientHandshake(state, recordLayer, AlertDescription.internal_error);
+ throw e;
+ }
+ catch (Exception e)
+ {
+ AbortClientHandshake(state, recordLayer, AlertDescription.internal_error);
+ throw new TlsFatalAlert(AlertDescription.internal_error, e);
+ }
+ finally
+ {
+ securityParameters.Clear();
+ }
+ }
+
+ internal virtual void AbortClientHandshake(ClientHandshakeState state, DtlsRecordLayer recordLayer, byte alertDescription)
+ {
+ recordLayer.Fail(alertDescription);
+ InvalidateSession(state);
+ }
+
+ internal virtual DtlsTransport ClientHandshake(ClientHandshakeState state, DtlsRecordLayer recordLayer)
+ {
+ SecurityParameters securityParameters = state.clientContext.SecurityParameters;
+ DtlsReliableHandshake handshake = new DtlsReliableHandshake(state.clientContext, recordLayer);
+
+ byte[] clientHelloBody = GenerateClientHello(state, state.client);
+
+ recordLayer.SetWriteVersion(ProtocolVersion.DTLSv10);
+
+ handshake.SendMessage(HandshakeType.client_hello, clientHelloBody);
+
+ DtlsReliableHandshake.Message serverMessage = handshake.ReceiveMessage();
+
+ while (serverMessage.Type == HandshakeType.hello_verify_request)
+ {
+ ProtocolVersion recordLayerVersion = recordLayer.ReadVersion;
+ ProtocolVersion client_version = state.clientContext.ClientVersion;
+
+ /*
+ * RFC 6347 4.2.1 DTLS 1.2 server implementations SHOULD use DTLS version 1.0 regardless of
+ * the version of TLS that is expected to be negotiated. DTLS 1.2 and 1.0 clients MUST use
+ * the version solely to indicate packet formatting (which is the same in both DTLS 1.2 and
+ * 1.0) and not as part of version negotiation.
+ */
+ if (!recordLayerVersion.IsEqualOrEarlierVersionOf(client_version))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ recordLayer.ReadVersion = null;
+
+ byte[] cookie = ProcessHelloVerifyRequest(state, serverMessage.Body);
+ byte[] patched = PatchClientHelloWithCookie(clientHelloBody, cookie);
+
+ handshake.ResetHandshakeMessagesDigest();
+ handshake.SendMessage(HandshakeType.client_hello, patched);
+
+ serverMessage = handshake.ReceiveMessage();
+ }
+
+ if (serverMessage.Type == HandshakeType.server_hello)
+ {
+ ProtocolVersion recordLayerVersion = recordLayer.ReadVersion;
+ ReportServerVersion(state, recordLayerVersion);
+ recordLayer.SetWriteVersion(recordLayerVersion);
+
+ ProcessServerHello(state, serverMessage.Body);
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ handshake.NotifyHelloComplete();
+
+ ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.maxFragmentLength);
+
+ if (state.resumedSession)
+ {
+ securityParameters.masterSecret = Arrays.Clone(state.sessionParameters.MasterSecret);
+ recordLayer.InitPendingEpoch(state.client.GetCipher());
+
+ // NOTE: Calculated exclusive of the actual Finished message from the server
+ byte[] resExpectedServerVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.server_finished,
+ TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
+ ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished), resExpectedServerVerifyData);
+
+ // NOTE: Calculated exclusive of the Finished message itself
+ byte[] resClientVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.client_finished,
+ TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
+ handshake.SendMessage(HandshakeType.finished, resClientVerifyData);
+
+ handshake.Finish();
+
+ state.clientContext.SetResumableSession(state.tlsSession);
+
+ state.client.NotifyHandshakeComplete();
+
+ return new DtlsTransport(recordLayer);
+ }
+
+ InvalidateSession(state);
+
+ if (state.selectedSessionID.Length > 0)
+ {
+ state.tlsSession = new TlsSessionImpl(state.selectedSessionID, null);
+ }
+
+ serverMessage = handshake.ReceiveMessage();
+
+ if (serverMessage.Type == HandshakeType.supplemental_data)
+ {
+ ProcessServerSupplementalData(state, serverMessage.Body);
+ serverMessage = handshake.ReceiveMessage();
+ }
+ else
+ {
+ state.client.ProcessServerSupplementalData(null);
+ }
+
+ state.keyExchange = state.client.GetKeyExchange();
+ state.keyExchange.Init(state.clientContext);
+
+ Certificate serverCertificate = null;
+
+ if (serverMessage.Type == HandshakeType.certificate)
+ {
+ serverCertificate = ProcessServerCertificate(state, serverMessage.Body);
+ serverMessage = handshake.ReceiveMessage();
+ }
+ else
+ {
+ // Okay, Certificate is optional
+ state.keyExchange.SkipServerCredentials();
+ }
+
+ // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
+ if (serverCertificate == null || serverCertificate.IsEmpty)
+ {
+ state.allowCertificateStatus = false;
+ }
+
+ if (serverMessage.Type == HandshakeType.certificate_status)
+ {
+ ProcessCertificateStatus(state, serverMessage.Body);
+ serverMessage = handshake.ReceiveMessage();
+ }
+ else
+ {
+ // Okay, CertificateStatus is optional
+ }
+
+ if (serverMessage.Type == HandshakeType.server_key_exchange)
+ {
+ ProcessServerKeyExchange(state, serverMessage.Body);
+ serverMessage = handshake.ReceiveMessage();
+ }
+ else
+ {
+ // Okay, ServerKeyExchange is optional
+ state.keyExchange.SkipServerKeyExchange();
+ }
+
+ if (serverMessage.Type == HandshakeType.certificate_request)
+ {
+ ProcessCertificateRequest(state, serverMessage.Body);
+
+ /*
+ * TODO Give the client a chance to immediately select the CertificateVerify hash
+ * algorithm here to avoid tracking the other hash algorithms unnecessarily?
+ */
+ TlsUtilities.TrackHashAlgorithms(handshake.HandshakeHash,
+ state.certificateRequest.SupportedSignatureAlgorithms);
+
+ serverMessage = handshake.ReceiveMessage();
+ }
+ else
+ {
+ // Okay, CertificateRequest is optional
+ }
+
+ if (serverMessage.Type == HandshakeType.server_hello_done)
+ {
+ if (serverMessage.Body.Length != 0)
+ {
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ }
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ handshake.HandshakeHash.SealHashAlgorithms();
+
+ IList clientSupplementalData = state.client.GetClientSupplementalData();
+ if (clientSupplementalData != null)
+ {
+ byte[] supplementalDataBody = GenerateSupplementalData(clientSupplementalData);
+ handshake.SendMessage(HandshakeType.supplemental_data, supplementalDataBody);
+ }
+
+ if (state.certificateRequest != null)
+ {
+ state.clientCredentials = state.authentication.GetClientCredentials(state.certificateRequest);
+
+ /*
+ * RFC 5246 If no suitable certificate is available, the client MUST send a certificate
+ * message containing no certificates.
+ *
+ * NOTE: In previous RFCs, this was SHOULD instead of MUST.
+ */
+ Certificate clientCertificate = null;
+ if (state.clientCredentials != null)
+ {
+ clientCertificate = state.clientCredentials.Certificate;
+ }
+ if (clientCertificate == null)
+ {
+ clientCertificate = Certificate.EmptyChain;
+ }
+
+ byte[] certificateBody = GenerateCertificate(clientCertificate);
+ handshake.SendMessage(HandshakeType.certificate, certificateBody);
+ }
+
+ if (state.clientCredentials != null)
+ {
+ state.keyExchange.ProcessClientCredentials(state.clientCredentials);
+ }
+ else
+ {
+ state.keyExchange.SkipClientCredentials();
+ }
+
+ byte[] clientKeyExchangeBody = GenerateClientKeyExchange(state);
+ handshake.SendMessage(HandshakeType.client_key_exchange, clientKeyExchangeBody);
+
+ TlsHandshakeHash prepareFinishHash = handshake.PrepareToFinish();
+ securityParameters.sessionHash = TlsProtocol.GetCurrentPrfHash(state.clientContext, prepareFinishHash, null);
+
+ TlsProtocol.EstablishMasterSecret(state.clientContext, state.keyExchange);
+ recordLayer.InitPendingEpoch(state.client.GetCipher());
+
+ if (state.clientCredentials != null && state.clientCredentials is TlsSignerCredentials)
+ {
+ TlsSignerCredentials signerCredentials = (TlsSignerCredentials)state.clientCredentials;
+
+ /*
+ * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
+ */
+ SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
+ state.clientContext, signerCredentials);
+
+ byte[] hash;
+ if (signatureAndHashAlgorithm == null)
+ {
+ hash = securityParameters.SessionHash;
+ }
+ else
+ {
+ hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash);
+ }
+
+ byte[] signature = signerCredentials.GenerateCertificateSignature(hash);
+ DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature);
+ byte[] certificateVerifyBody = GenerateCertificateVerify(state, certificateVerify);
+ handshake.SendMessage(HandshakeType.certificate_verify, certificateVerifyBody);
+ }
+
+ // NOTE: Calculated exclusive of the Finished message itself
+ byte[] clientVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.client_finished,
+ TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
+ handshake.SendMessage(HandshakeType.finished, clientVerifyData);
+
+ if (state.expectSessionTicket)
+ {
+ serverMessage = handshake.ReceiveMessage();
+ if (serverMessage.Type == HandshakeType.session_ticket)
+ {
+ ProcessNewSessionTicket(state, serverMessage.Body);
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ }
+
+ // NOTE: Calculated exclusive of the actual Finished message from the server
+ byte[] expectedServerVerifyData = TlsUtilities.CalculateVerifyData(state.clientContext, ExporterLabel.server_finished,
+ TlsProtocol.GetCurrentPrfHash(state.clientContext, handshake.HandshakeHash, null));
+ ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished), expectedServerVerifyData);
+
+ handshake.Finish();
+
+ if (state.tlsSession != null)
+ {
+ state.sessionParameters = new SessionParameters.Builder()
+ .SetCipherSuite(securityParameters.CipherSuite)
+ .SetCompressionAlgorithm(securityParameters.CompressionAlgorithm)
+ .SetMasterSecret(securityParameters.MasterSecret)
+ .SetPeerCertificate(serverCertificate)
+ .SetPskIdentity(securityParameters.PskIdentity)
+ .SetSrpIdentity(securityParameters.SrpIdentity)
+ // TODO Consider filtering extensions that aren't relevant to resumed sessions
+ .SetServerExtensions(state.serverExtensions)
+ .Build();
+
+ state.tlsSession = TlsUtilities.ImportSession(state.tlsSession.SessionID, state.sessionParameters);
+
+ state.clientContext.SetResumableSession(state.tlsSession);
+ }
+
+ state.client.NotifyHandshakeComplete();
+
+ return new DtlsTransport(recordLayer);
+ }
+
+ protected virtual byte[] GenerateCertificateVerify(ClientHandshakeState state, DigitallySigned certificateVerify)
+ {
+ MemoryStream buf = new MemoryStream();
+ certificateVerify.Encode(buf);
+ return buf.ToArray();
+ }
+
+ protected virtual byte[] GenerateClientHello(ClientHandshakeState state, TlsClient client)
+ {
+ MemoryStream buf = new MemoryStream();
+
+ ProtocolVersion client_version = client.ClientVersion;
+ if (!client_version.IsDtls)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ TlsClientContextImpl context = state.clientContext;
+
+ context.SetClientVersion(client_version);
+ TlsUtilities.WriteVersion(client_version, buf);
+
+ SecurityParameters securityParameters = context.SecurityParameters;
+ buf.Write(securityParameters.ClientRandom, 0, securityParameters.ClientRandom.Length);
+
+ // Session ID
+ byte[] session_id = TlsUtilities.EmptyBytes;
+ if (state.tlsSession != null)
+ {
+ session_id = state.tlsSession.SessionID;
+ if (session_id == null || session_id.Length > 32)
+ {
+ session_id = TlsUtilities.EmptyBytes;
+ }
+ }
+ TlsUtilities.WriteOpaque8(session_id, buf);
+
+ // Cookie
+ TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf);
+
+ bool fallback = client.IsFallback;
+
+ /*
+ * Cipher suites
+ */
+ state.offeredCipherSuites = client.GetCipherSuites();
+
+ // Integer -> byte[]
+ state.clientExtensions = client.GetClientExtensions();
+
+ // Cipher Suites (and SCSV)
+ {
+ /*
+ * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
+ * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
+ * ClientHello. Including both is NOT RECOMMENDED.
+ */
+ byte[] renegExtData = TlsUtilities.GetExtensionData(state.clientExtensions, ExtensionType.renegotiation_info);
+ bool noRenegExt = (null == renegExtData);
+
+ bool noRenegSCSV = !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
+
+ if (noRenegExt && noRenegSCSV)
+ {
+ // TODO Consider whether to default to a client extension instead
+ state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
+ }
+
+ /*
+ * RFC 7507 4. If a client sends a ClientHello.client_version containing a lower value
+ * than the latest (highest-valued) version supported by the client, it SHOULD include
+ * the TLS_FALLBACK_SCSV cipher suite value in ClientHello.cipher_suites [..]. (The
+ * client SHOULD put TLS_FALLBACK_SCSV after all cipher suites that it actually intends
+ * to negotiate.)
+ */
+ if (fallback && !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV))
+ {
+ state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV);
+ }
+
+ TlsUtilities.WriteUint16ArrayWithUint16Length(state.offeredCipherSuites, buf);
+ }
+
+ // TODO Add support for compression
+ // Compression methods
+ // state.offeredCompressionMethods = client.getCompressionMethods();
+ state.offeredCompressionMethods = new byte[]{ CompressionMethod.cls_null };
+
+ TlsUtilities.WriteUint8ArrayWithUint8Length(state.offeredCompressionMethods, buf);
+
+ // Extensions
+ if (state.clientExtensions != null)
+ {
+ TlsProtocol.WriteExtensions(buf, state.clientExtensions);
+ }
+
+ return buf.ToArray();
+ }
+
+ protected virtual byte[] GenerateClientKeyExchange(ClientHandshakeState state)
+ {
+ MemoryStream buf = new MemoryStream();
+ state.keyExchange.GenerateClientKeyExchange(buf);
+ return buf.ToArray();
+ }
+
+ protected virtual void InvalidateSession(ClientHandshakeState state)
+ {
+ if (state.sessionParameters != null)
+ {
+ state.sessionParameters.Clear();
+ state.sessionParameters = null;
+ }
+
+ if (state.tlsSession != null)
+ {
+ state.tlsSession.Invalidate();
+ state.tlsSession = null;
+ }
+ }
+
+ protected virtual void ProcessCertificateRequest(ClientHandshakeState state, byte[] body)
+ {
+ if (state.authentication == null)
+ {
+ /*
+ * RFC 2246 7.4.4. It is a fatal handshake_failure alert for an anonymous server to
+ * request client identification.
+ */
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+
+ MemoryStream buf = new MemoryStream(body, false);
+
+ state.certificateRequest = CertificateRequest.Parse(state.clientContext, buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ state.keyExchange.ValidateCertificateRequest(state.certificateRequest);
+ }
+
+ protected virtual void ProcessCertificateStatus(ClientHandshakeState state, byte[] body)
+ {
+ if (!state.allowCertificateStatus)
+ {
+ /*
+ * RFC 3546 3.6. If a server returns a "CertificateStatus" message, then the
+ * server MUST have included an extension of type "status_request" with empty
+ * "extension_data" in the extended server hello..
+ */
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ MemoryStream buf = new MemoryStream(body, false);
+
+ state.certificateStatus = CertificateStatus.Parse(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ // TODO[RFC 3546] Figure out how to provide this to the client/authentication.
+ }
+
+ protected virtual byte[] ProcessHelloVerifyRequest(ClientHandshakeState state, byte[] body)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+
+ ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
+ byte[] cookie = TlsUtilities.ReadOpaque8(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ // TODO Seems this behaviour is not yet in line with OpenSSL for DTLS 1.2
+ // reportServerVersion(state, server_version);
+ if (!server_version.IsEqualOrEarlierVersionOf(state.clientContext.ClientVersion))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ /*
+ * RFC 6347 This specification increases the cookie size limit to 255 bytes for greater
+ * future flexibility. The limit remains 32 for previous versions of DTLS.
+ */
+ if (!ProtocolVersion.DTLSv12.IsEqualOrEarlierVersionOf(server_version) && cookie.Length > 32)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ return cookie;
+ }
+
+ protected virtual void ProcessNewSessionTicket(ClientHandshakeState state, byte[] body)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+
+ NewSessionTicket newSessionTicket = NewSessionTicket.Parse(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ state.client.NotifyNewSessionTicket(newSessionTicket);
+ }
+
+ protected virtual Certificate ProcessServerCertificate(ClientHandshakeState state, byte[] body)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+
+ Certificate serverCertificate = Certificate.Parse(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ state.keyExchange.ProcessServerCertificate(serverCertificate);
+ state.authentication = state.client.GetAuthentication();
+ state.authentication.NotifyServerCertificate(serverCertificate);
+
+ return serverCertificate;
+ }
+
+ protected virtual void ProcessServerHello(ClientHandshakeState state, byte[] body)
+ {
+ SecurityParameters securityParameters = state.clientContext.SecurityParameters;
+
+ MemoryStream buf = new MemoryStream(body, false);
+
+ {
+ ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
+ ReportServerVersion(state, server_version);
+ }
+
+ securityParameters.serverRandom = TlsUtilities.ReadFully(32, buf);
+
+ state.selectedSessionID = TlsUtilities.ReadOpaque8(buf);
+ if (state.selectedSessionID.Length > 32)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ state.client.NotifySessionID(state.selectedSessionID);
+ state.resumedSession = state.selectedSessionID.Length > 0 && state.tlsSession != null
+ && Arrays.AreEqual(state.selectedSessionID, state.tlsSession.SessionID);
+
+ int selectedCipherSuite = TlsUtilities.ReadUint16(buf);
+ if (!Arrays.Contains(state.offeredCipherSuites, selectedCipherSuite)
+ || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
+ || CipherSuite.IsScsv(selectedCipherSuite)
+ || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, state.clientContext.ServerVersion))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ ValidateSelectedCipherSuite(selectedCipherSuite, AlertDescription.illegal_parameter);
+ state.client.NotifySelectedCipherSuite(selectedCipherSuite);
+
+ byte selectedCompressionMethod = TlsUtilities.ReadUint8(buf);
+ if (!Arrays.Contains(state.offeredCompressionMethods, selectedCompressionMethod))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ state.client.NotifySelectedCompressionMethod(selectedCompressionMethod);
+
+ /*
+ * RFC3546 2.2 The extended server hello message format MAY be sent in place of the server
+ * hello message when the client has requested extended functionality via the extended
+ * client hello message specified in Section 2.1. ... Note that the extended server hello
+ * message is only sent in response to an extended client hello message. This prevents the
+ * possibility that the extended server hello message could "break" existing TLS 1.0
+ * clients.
+ */
+
+ /*
+ * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
+ * extensions appearing in the client hello, and send a server hello containing no
+ * extensions.
+ */
+
+ // Integer -> byte[]
+ state.serverExtensions = TlsProtocol.ReadExtensions(buf);
+
+ /*
+ * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an
+ * extended client hello message. However, see RFC 5746 exception below. We always include
+ * the SCSV, so an Extended Server Hello is always allowed.
+ */
+ if (state.serverExtensions != null)
+ {
+ foreach (int extType in state.serverExtensions.Keys)
+ {
+ /*
+ * RFC 5746 3.6. Note that sending a "renegotiation_info" extension in response to a
+ * ClientHello containing only the SCSV is an explicit exception to the prohibition
+ * in RFC 5246, Section 7.4.1.4, on the server sending unsolicited extensions and is
+ * only allowed because the client is signaling its willingness to receive the
+ * extension via the TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
+ */
+ if (extType == ExtensionType.renegotiation_info)
+ continue;
+
+ /*
+ * RFC 5246 7.4.1.4 An extension type MUST NOT appear in the ServerHello unless the
+ * same extension type appeared in the corresponding ClientHello. If a client
+ * receives an extension type in ServerHello that it did not request in the
+ * associated ClientHello, it MUST abort the handshake with an unsupported_extension
+ * fatal alert.
+ */
+ if (null == TlsUtilities.GetExtensionData(state.clientExtensions, extType))
+ throw new TlsFatalAlert(AlertDescription.unsupported_extension);
+
+ /*
+ * RFC 3546 2.3. If [...] the older session is resumed, then the server MUST ignore
+ * extensions appearing in the client hello, and send a server hello containing no
+ * extensions[.]
+ */
+ if (state.resumedSession)
+ {
+ // TODO[compat-gnutls] GnuTLS test server sends server extensions e.g. ec_point_formats
+ // TODO[compat-openssl] OpenSSL test server sends server extensions e.g. ec_point_formats
+ // TODO[compat-polarssl] PolarSSL test server sends server extensions e.g. ec_point_formats
+ //throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+ }
+
+ /*
+ * RFC 5746 3.4. Client Behavior: Initial Handshake
+ */
+ {
+ /*
+ * When a ServerHello is received, the client MUST check if it includes the
+ * "renegotiation_info" extension:
+ */
+ byte[] renegExtData = TlsUtilities.GetExtensionData(state.serverExtensions, ExtensionType.renegotiation_info);
+ if (renegExtData != null)
+ {
+ /*
+ * If the extension is present, set the secure_renegotiation flag to TRUE. The
+ * client MUST then verify that the length of the "renegotiated_connection"
+ * field is zero, and if it is not, MUST abort the handshake (by sending a fatal
+ * handshake_failure alert).
+ */
+ state.secure_renegotiation = true;
+
+ if (!Arrays.ConstantTimeAreEqual(renegExtData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+ }
+
+ // TODO[compat-gnutls] GnuTLS test server fails to send renegotiation_info extension when resuming
+ state.client.NotifySecureRenegotiation(state.secure_renegotiation);
+
+ IDictionary sessionClientExtensions = state.clientExtensions, sessionServerExtensions = state.serverExtensions;
+ if (state.resumedSession)
+ {
+ if (selectedCipherSuite != state.sessionParameters.CipherSuite
+ || selectedCompressionMethod != state.sessionParameters.CompressionAlgorithm)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ sessionClientExtensions = null;
+ sessionServerExtensions = state.sessionParameters.ReadServerExtensions();
+ }
+
+ securityParameters.cipherSuite = selectedCipherSuite;
+ securityParameters.compressionAlgorithm = selectedCompressionMethod;
+
+ if (sessionServerExtensions != null)
+ {
+ {
+ /*
+ * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client
+ * and then selects a stream or Authenticated Encryption with Associated Data (AEAD)
+ * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the
+ * client.
+ */
+ bool serverSentEncryptThenMAC = TlsExtensionsUtilities.HasEncryptThenMacExtension(sessionServerExtensions);
+ if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(securityParameters.CipherSuite))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ securityParameters.encryptThenMac = serverSentEncryptThenMAC;
+ }
+
+ securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);
+
+ securityParameters.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.resumedSession,
+ sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter);
+
+ securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(sessionServerExtensions);
+
+ /*
+ * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be
+ * sent in a session resumption handshake.
+ */
+ state.allowCertificateStatus = !state.resumedSession
+ && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.status_request,
+ AlertDescription.illegal_parameter);
+
+ state.expectSessionTicket = !state.resumedSession
+ && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.session_ticket,
+ AlertDescription.illegal_parameter);
+ }
+
+ /*
+ * TODO[session-hash]
+ *
+ * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes
+ * that do not use the extended master secret [..]. (and see 5.2, 5.3)
+ */
+
+ if (sessionClientExtensions != null)
+ {
+ state.client.ProcessServerExtensions(sessionServerExtensions);
+ }
+
+ securityParameters.prfAlgorithm = TlsProtocol.GetPrfAlgorithm(state.clientContext,
+ securityParameters.CipherSuite);
+
+ /*
+ * RFC 5246 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has
+ * a verify_data_length equal to 12. This includes all existing cipher suites.
+ */
+ securityParameters.verifyDataLength = 12;
+ }
+
+ protected virtual void ProcessServerKeyExchange(ClientHandshakeState state, byte[] body)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+
+ state.keyExchange.ProcessServerKeyExchange(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+ }
+
+ protected virtual void ProcessServerSupplementalData(ClientHandshakeState state, byte[] body)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+ IList serverSupplementalData = TlsProtocol.ReadSupplementalDataMessage(buf);
+ state.client.ProcessServerSupplementalData(serverSupplementalData);
+ }
+
+ protected virtual void ReportServerVersion(ClientHandshakeState state, ProtocolVersion server_version)
+ {
+ TlsClientContextImpl clientContext = state.clientContext;
+ ProtocolVersion currentServerVersion = clientContext.ServerVersion;
+ if (null == currentServerVersion)
+ {
+ clientContext.SetServerVersion(server_version);
+ state.client.NotifyServerVersion(server_version);
+ }
+ else if (!currentServerVersion.Equals(server_version))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+
+ protected static byte[] PatchClientHelloWithCookie(byte[] clientHelloBody, byte[] cookie)
+ {
+ int sessionIDPos = 34;
+ int sessionIDLength = TlsUtilities.ReadUint8(clientHelloBody, sessionIDPos);
+
+ int cookieLengthPos = sessionIDPos + 1 + sessionIDLength;
+ int cookiePos = cookieLengthPos + 1;
+
+ byte[] patched = new byte[clientHelloBody.Length + cookie.Length];
+ Array.Copy(clientHelloBody, 0, patched, 0, cookieLengthPos);
+ TlsUtilities.CheckUint8(cookie.Length);
+ TlsUtilities.WriteUint8((byte)cookie.Length, patched, cookieLengthPos);
+ Array.Copy(cookie, 0, patched, cookiePos, cookie.Length);
+ Array.Copy(clientHelloBody, cookiePos, patched, cookiePos + cookie.Length, clientHelloBody.Length - cookiePos);
+
+ return patched;
+ }
+
+ protected internal class ClientHandshakeState
+ {
+ internal TlsClient client = null;
+ internal TlsClientContextImpl clientContext = null;
+ internal TlsSession tlsSession = null;
+ internal SessionParameters sessionParameters = null;
+ internal SessionParameters.Builder sessionParametersBuilder = null;
+ internal int[] offeredCipherSuites = null;
+ internal byte[] offeredCompressionMethods = null;
+ internal IDictionary clientExtensions = null;
+ internal IDictionary serverExtensions = null;
+ internal byte[] selectedSessionID = null;
+ internal bool resumedSession = false;
+ internal bool secure_renegotiation = false;
+ internal bool allowCertificateStatus = false;
+ internal bool expectSessionTicket = false;
+ internal TlsKeyExchange keyExchange = null;
+ internal TlsAuthentication authentication = null;
+ internal CertificateStatus certificateStatus = null;
+ internal CertificateRequest certificateRequest = null;
+ internal TlsCredentials clientCredentials = null;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DtlsEpoch.cs b/bc-sharp-crypto/src/crypto/tls/DtlsEpoch.cs
new file mode 100644
index 0000000000000000000000000000000000000000..91fffa5e12f2ae3557eba7807f8db9e9820edb90
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DtlsEpoch.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ internal class DtlsEpoch
+ {
+ private readonly DtlsReplayWindow mReplayWindow = new DtlsReplayWindow();
+
+ private readonly int mEpoch;
+ private readonly TlsCipher mCipher;
+
+ private long mSequenceNumber = 0;
+
+ internal DtlsEpoch(int epoch, TlsCipher cipher)
+ {
+ if (epoch < 0)
+ throw new ArgumentException("must be >= 0", "epoch");
+ if (cipher == null)
+ throw new ArgumentNullException("cipher");
+
+ this.mEpoch = epoch;
+ this.mCipher = cipher;
+ }
+
+ internal long AllocateSequenceNumber()
+ {
+ // TODO Check for overflow
+ return mSequenceNumber++;
+ }
+
+ internal TlsCipher Cipher
+ {
+ get { return mCipher; }
+ }
+
+ internal int Epoch
+ {
+ get { return mEpoch; }
+ }
+
+ internal DtlsReplayWindow ReplayWindow
+ {
+ get { return mReplayWindow; }
+ }
+
+ internal long SequenceNumber
+ {
+ get { return mSequenceNumber; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DtlsHandshakeRetransmit.cs b/bc-sharp-crypto/src/crypto/tls/DtlsHandshakeRetransmit.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8bfae78b19cc2f7e7f77aaf3ffa4c67aac927580
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DtlsHandshakeRetransmit.cs
@@ -0,0 +1,11 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ interface DtlsHandshakeRetransmit
+ {
+ ///
+ void ReceivedHandshakeRecord(int epoch, byte[] buf, int off, int len);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DtlsProtocol.cs b/bc-sharp-crypto/src/crypto/tls/DtlsProtocol.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e4ebd436c30069235135c99da72d9a0c2f90cd34
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DtlsProtocol.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class DtlsProtocol
+ {
+ protected readonly SecureRandom mSecureRandom;
+
+ protected DtlsProtocol(SecureRandom secureRandom)
+ {
+ if (secureRandom == null)
+ throw new ArgumentNullException("secureRandom");
+
+ this.mSecureRandom = secureRandom;
+ }
+
+ ///
+ protected virtual void ProcessFinished(byte[] body, byte[] expected_verify_data)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+
+ byte[] verify_data = TlsUtilities.ReadFully(expected_verify_data.Length, buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ if (!Arrays.ConstantTimeAreEqual(expected_verify_data, verify_data))
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+
+ ///
+ internal static void ApplyMaxFragmentLengthExtension(DtlsRecordLayer recordLayer, short maxFragmentLength)
+ {
+ if (maxFragmentLength >= 0)
+ {
+ if (!MaxFragmentLength.IsValid((byte)maxFragmentLength))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ int plainTextLimit = 1 << (8 + maxFragmentLength);
+ recordLayer.SetPlaintextLimit(plainTextLimit);
+ }
+ }
+
+ ///
+ protected static short EvaluateMaxFragmentLengthExtension(bool resumedSession, IDictionary clientExtensions,
+ IDictionary serverExtensions, byte alertDescription)
+ {
+ short maxFragmentLength = TlsExtensionsUtilities.GetMaxFragmentLengthExtension(serverExtensions);
+ if (maxFragmentLength >= 0)
+ {
+ if (!MaxFragmentLength.IsValid((byte)maxFragmentLength)
+ || (!resumedSession && maxFragmentLength != TlsExtensionsUtilities
+ .GetMaxFragmentLengthExtension(clientExtensions)))
+ {
+ throw new TlsFatalAlert(alertDescription);
+ }
+ }
+ return maxFragmentLength;
+ }
+
+ ///
+ protected static byte[] GenerateCertificate(Certificate certificate)
+ {
+ MemoryStream buf = new MemoryStream();
+ certificate.Encode(buf);
+ return buf.ToArray();
+ }
+
+ ///
+ protected static byte[] GenerateSupplementalData(IList supplementalData)
+ {
+ MemoryStream buf = new MemoryStream();
+ TlsProtocol.WriteSupplementalData(buf, supplementalData);
+ return buf.ToArray();
+ }
+
+ ///
+ protected static void ValidateSelectedCipherSuite(int selectedCipherSuite, byte alertDescription)
+ {
+ switch (TlsUtilities.GetEncryptionAlgorithm(selectedCipherSuite))
+ {
+ case EncryptionAlgorithm.RC4_40:
+ case EncryptionAlgorithm.RC4_128:
+ throw new TlsFatalAlert(alertDescription);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DtlsReassembler.cs b/bc-sharp-crypto/src/crypto/tls/DtlsReassembler.cs
new file mode 100644
index 0000000000000000000000000000000000000000..11fe609cfd241976d27defea66f66b2230aa234d
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DtlsReassembler.cs
@@ -0,0 +1,125 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ class DtlsReassembler
+ {
+ private readonly byte mMsgType;
+ private readonly byte[] mBody;
+
+ private readonly IList mMissing = Platform.CreateArrayList();
+
+ internal DtlsReassembler(byte msg_type, int length)
+ {
+ this.mMsgType = msg_type;
+ this.mBody = new byte[length];
+ this.mMissing.Add(new Range(0, length));
+ }
+
+ internal byte MsgType
+ {
+ get { return mMsgType; }
+ }
+
+ internal byte[] GetBodyIfComplete()
+ {
+ return mMissing.Count == 0 ? mBody : null;
+ }
+
+ internal void ContributeFragment(byte msg_type, int length, byte[] buf, int off, int fragment_offset,
+ int fragment_length)
+ {
+ int fragment_end = fragment_offset + fragment_length;
+
+ if (this.mMsgType != msg_type || this.mBody.Length != length || fragment_end > length)
+ {
+ return;
+ }
+
+ if (fragment_length == 0)
+ {
+ // NOTE: Empty messages still require an empty fragment to complete it
+ if (fragment_offset == 0 && mMissing.Count > 0)
+ {
+ Range firstRange = (Range)mMissing[0];
+ if (firstRange.End == 0)
+ {
+ mMissing.RemoveAt(0);
+ }
+ }
+ return;
+ }
+
+ for (int i = 0; i < mMissing.Count; ++i)
+ {
+ Range range = (Range)mMissing[i];
+ if (range.Start >= fragment_end)
+ {
+ break;
+ }
+ if (range.End > fragment_offset)
+ {
+
+ int copyStart = System.Math.Max(range.Start, fragment_offset);
+ int copyEnd = System.Math.Min(range.End, fragment_end);
+ int copyLength = copyEnd - copyStart;
+
+ Array.Copy(buf, off + copyStart - fragment_offset, mBody, copyStart,
+ copyLength);
+
+ if (copyStart == range.Start)
+ {
+ if (copyEnd == range.End)
+ {
+ mMissing.RemoveAt(i--);
+ }
+ else
+ {
+ range.Start = copyEnd;
+ }
+ }
+ else
+ {
+ if (copyEnd != range.End)
+ {
+ mMissing.Insert(++i, new Range(copyEnd, range.End));
+ }
+ range.End = copyStart;
+ }
+ }
+ }
+ }
+
+ internal void Reset()
+ {
+ this.mMissing.Clear();
+ this.mMissing.Add(new Range(0, mBody.Length));
+ }
+
+ private class Range
+ {
+ private int mStart, mEnd;
+
+ internal Range(int start, int end)
+ {
+ this.mStart = start;
+ this.mEnd = end;
+ }
+
+ public int Start
+ {
+ get { return mStart; }
+ set { this.mStart = value; }
+ }
+
+ public int End
+ {
+ get { return mEnd; }
+ set { this.mEnd = value; }
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DtlsRecordLayer.cs b/bc-sharp-crypto/src/crypto/tls/DtlsRecordLayer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..39e018810eb95c30de5932d9d3aa202a729c4f4b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DtlsRecordLayer.cs
@@ -0,0 +1,530 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ internal class DtlsRecordLayer
+ : DatagramTransport
+ {
+ private const int RECORD_HEADER_LENGTH = 13;
+ private const int MAX_FRAGMENT_LENGTH = 1 << 14;
+ private const long TCP_MSL = 1000L * 60 * 2;
+ private const long RETRANSMIT_TIMEOUT = TCP_MSL * 2;
+
+ private readonly DatagramTransport mTransport;
+ private readonly TlsContext mContext;
+ private readonly TlsPeer mPeer;
+
+ private readonly ByteQueue mRecordQueue = new ByteQueue();
+
+ private volatile bool mClosed = false;
+ private volatile bool mFailed = false;
+ private volatile ProtocolVersion mReadVersion = null, mWriteVersion = null;
+ private volatile bool mInHandshake;
+ private volatile int mPlaintextLimit;
+ private DtlsEpoch mCurrentEpoch, mPendingEpoch;
+ private DtlsEpoch mReadEpoch, mWriteEpoch;
+
+ private DtlsHandshakeRetransmit mRetransmit = null;
+ private DtlsEpoch mRetransmitEpoch = null;
+ private long mRetransmitExpiry = 0;
+
+ internal DtlsRecordLayer(DatagramTransport transport, TlsContext context, TlsPeer peer, byte contentType)
+ {
+ this.mTransport = transport;
+ this.mContext = context;
+ this.mPeer = peer;
+
+ this.mInHandshake = true;
+
+ this.mCurrentEpoch = new DtlsEpoch(0, new TlsNullCipher(context));
+ this.mPendingEpoch = null;
+ this.mReadEpoch = mCurrentEpoch;
+ this.mWriteEpoch = mCurrentEpoch;
+
+ SetPlaintextLimit(MAX_FRAGMENT_LENGTH);
+ }
+
+ internal virtual void SetPlaintextLimit(int plaintextLimit)
+ {
+ this.mPlaintextLimit = plaintextLimit;
+ }
+
+ internal virtual int ReadEpoch
+ {
+ get { return mReadEpoch.Epoch; }
+ }
+
+ internal virtual ProtocolVersion ReadVersion
+ {
+ get { return mReadVersion; }
+ set { this.mReadVersion = value; }
+ }
+
+ internal virtual void SetWriteVersion(ProtocolVersion writeVersion)
+ {
+ this.mWriteVersion = writeVersion;
+ }
+
+ internal virtual void InitPendingEpoch(TlsCipher pendingCipher)
+ {
+ if (mPendingEpoch != null)
+ throw new InvalidOperationException();
+
+ /*
+ * TODO "In order to ensure that any given sequence/epoch pair is unique, implementations
+ * MUST NOT allow the same epoch value to be reused within two times the TCP maximum segment
+ * lifetime."
+ */
+
+ // TODO Check for overflow
+ this.mPendingEpoch = new DtlsEpoch(mWriteEpoch.Epoch + 1, pendingCipher);
+ }
+
+ internal virtual void HandshakeSuccessful(DtlsHandshakeRetransmit retransmit)
+ {
+ if (mReadEpoch == mCurrentEpoch || mWriteEpoch == mCurrentEpoch)
+ {
+ // TODO
+ throw new InvalidOperationException();
+ }
+
+ if (retransmit != null)
+ {
+ this.mRetransmit = retransmit;
+ this.mRetransmitEpoch = mCurrentEpoch;
+ this.mRetransmitExpiry = DateTimeUtilities.CurrentUnixMs() + RETRANSMIT_TIMEOUT;
+ }
+
+ this.mInHandshake = false;
+ this.mCurrentEpoch = mPendingEpoch;
+ this.mPendingEpoch = null;
+ }
+
+ internal virtual void ResetWriteEpoch()
+ {
+ if (mRetransmitEpoch != null)
+ {
+ this.mWriteEpoch = mRetransmitEpoch;
+ }
+ else
+ {
+ this.mWriteEpoch = mCurrentEpoch;
+ }
+ }
+
+ public virtual int GetReceiveLimit()
+ {
+ return System.Math.Min(this.mPlaintextLimit,
+ mReadEpoch.Cipher.GetPlaintextLimit(mTransport.GetReceiveLimit() - RECORD_HEADER_LENGTH));
+ }
+
+ public virtual int GetSendLimit()
+ {
+ return System.Math.Min(this.mPlaintextLimit,
+ mWriteEpoch.Cipher.GetPlaintextLimit(mTransport.GetSendLimit() - RECORD_HEADER_LENGTH));
+ }
+
+ public virtual int Receive(byte[] buf, int off, int len, int waitMillis)
+ {
+ byte[] record = null;
+
+ for (;;)
+ {
+ int receiveLimit = System.Math.Min(len, GetReceiveLimit()) + RECORD_HEADER_LENGTH;
+ if (record == null || record.Length < receiveLimit)
+ {
+ record = new byte[receiveLimit];
+ }
+
+ try
+ {
+ if (mRetransmit != null && DateTimeUtilities.CurrentUnixMs() > mRetransmitExpiry)
+ {
+ mRetransmit = null;
+ mRetransmitEpoch = null;
+ }
+
+ int received = ReceiveRecord(record, 0, receiveLimit, waitMillis);
+ if (received < 0)
+ {
+ return received;
+ }
+ if (received < RECORD_HEADER_LENGTH)
+ {
+ continue;
+ }
+ int length = TlsUtilities.ReadUint16(record, 11);
+ if (received != (length + RECORD_HEADER_LENGTH))
+ {
+ continue;
+ }
+
+ byte type = TlsUtilities.ReadUint8(record, 0);
+
+ // TODO Support user-specified custom protocols?
+ switch (type)
+ {
+ case ContentType.alert:
+ case ContentType.application_data:
+ case ContentType.change_cipher_spec:
+ case ContentType.handshake:
+ case ContentType.heartbeat:
+ break;
+ default:
+ // TODO Exception?
+ continue;
+ }
+
+ int epoch = TlsUtilities.ReadUint16(record, 3);
+
+ DtlsEpoch recordEpoch = null;
+ if (epoch == mReadEpoch.Epoch)
+ {
+ recordEpoch = mReadEpoch;
+ }
+ else if (type == ContentType.handshake && mRetransmitEpoch != null
+ && epoch == mRetransmitEpoch.Epoch)
+ {
+ recordEpoch = mRetransmitEpoch;
+ }
+
+ if (recordEpoch == null)
+ {
+ continue;
+ }
+
+ long seq = TlsUtilities.ReadUint48(record, 5);
+ if (recordEpoch.ReplayWindow.ShouldDiscard(seq))
+ {
+ continue;
+ }
+
+ ProtocolVersion version = TlsUtilities.ReadVersion(record, 1);
+ if (!version.IsDtls)
+ {
+ continue;
+ }
+
+ if (mReadVersion != null && !mReadVersion.Equals(version))
+ {
+ continue;
+ }
+
+ byte[] plaintext = recordEpoch.Cipher.DecodeCiphertext(
+ GetMacSequenceNumber(recordEpoch.Epoch, seq), type, record, RECORD_HEADER_LENGTH,
+ received - RECORD_HEADER_LENGTH);
+
+ recordEpoch.ReplayWindow.ReportAuthenticated(seq);
+
+ if (plaintext.Length > this.mPlaintextLimit)
+ {
+ continue;
+ }
+
+ if (mReadVersion == null)
+ {
+ mReadVersion = version;
+ }
+
+ switch (type)
+ {
+ case ContentType.alert:
+ {
+ if (plaintext.Length == 2)
+ {
+ byte alertLevel = plaintext[0];
+ byte alertDescription = plaintext[1];
+
+ mPeer.NotifyAlertReceived(alertLevel, alertDescription);
+
+ if (alertLevel == AlertLevel.fatal)
+ {
+ Failed();
+ throw new TlsFatalAlert(alertDescription);
+ }
+
+ // TODO Can close_notify be a fatal alert?
+ if (alertDescription == AlertDescription.close_notify)
+ {
+ CloseTransport();
+ }
+ }
+
+ continue;
+ }
+ case ContentType.application_data:
+ {
+ if (mInHandshake)
+ {
+ // TODO Consider buffering application data for new epoch that arrives
+ // out-of-order with the Finished message
+ continue;
+ }
+ break;
+ }
+ case ContentType.change_cipher_spec:
+ {
+ // Implicitly receive change_cipher_spec and change to pending cipher state
+
+ for (int i = 0; i < plaintext.Length; ++i)
+ {
+ byte message = TlsUtilities.ReadUint8(plaintext, i);
+ if (message != ChangeCipherSpec.change_cipher_spec)
+ {
+ continue;
+ }
+
+ if (mPendingEpoch != null)
+ {
+ mReadEpoch = mPendingEpoch;
+ }
+ }
+
+ continue;
+ }
+ case ContentType.handshake:
+ {
+ if (!mInHandshake)
+ {
+ if (mRetransmit != null)
+ {
+ mRetransmit.ReceivedHandshakeRecord(epoch, plaintext, 0, plaintext.Length);
+ }
+
+ // TODO Consider support for HelloRequest
+ continue;
+ }
+ break;
+ }
+ case ContentType.heartbeat:
+ {
+ // TODO[RFC 6520]
+ continue;
+ }
+ }
+
+ /*
+ * NOTE: If we receive any non-handshake data in the new epoch implies the peer has
+ * received our final flight.
+ */
+ if (!mInHandshake && mRetransmit != null)
+ {
+ this.mRetransmit = null;
+ this.mRetransmitEpoch = null;
+ }
+
+ Array.Copy(plaintext, 0, buf, off, plaintext.Length);
+ return plaintext.Length;
+ }
+ catch (IOException e)
+ {
+ // NOTE: Assume this is a timeout for the moment
+ throw e;
+ }
+ }
+ }
+
+ ///
+ public virtual void Send(byte[] buf, int off, int len)
+ {
+ byte contentType = ContentType.application_data;
+
+ if (this.mInHandshake || this.mWriteEpoch == this.mRetransmitEpoch)
+ {
+ contentType = ContentType.handshake;
+
+ byte handshakeType = TlsUtilities.ReadUint8(buf, off);
+ if (handshakeType == HandshakeType.finished)
+ {
+ DtlsEpoch nextEpoch = null;
+ if (this.mInHandshake)
+ {
+ nextEpoch = mPendingEpoch;
+ }
+ else if (this.mWriteEpoch == this.mRetransmitEpoch)
+ {
+ nextEpoch = mCurrentEpoch;
+ }
+
+ if (nextEpoch == null)
+ {
+ // TODO
+ throw new InvalidOperationException();
+ }
+
+ // Implicitly send change_cipher_spec and change to pending cipher state
+
+ // TODO Send change_cipher_spec and finished records in single datagram?
+ byte[] data = new byte[]{ 1 };
+ SendRecord(ContentType.change_cipher_spec, data, 0, data.Length);
+
+ mWriteEpoch = nextEpoch;
+ }
+ }
+
+ SendRecord(contentType, buf, off, len);
+ }
+
+ public virtual void Close()
+ {
+ if (!mClosed)
+ {
+ if (mInHandshake)
+ {
+ Warn(AlertDescription.user_canceled, "User canceled handshake");
+ }
+ CloseTransport();
+ }
+ }
+
+ internal virtual void Failed()
+ {
+ if (!mClosed)
+ {
+ mFailed = true;
+
+ CloseTransport();
+ }
+ }
+
+ internal virtual void Fail(byte alertDescription)
+ {
+ if (!mClosed)
+ {
+ try
+ {
+ RaiseAlert(AlertLevel.fatal, alertDescription, null, null);
+ }
+ catch (Exception)
+ {
+ // Ignore
+ }
+
+ mFailed = true;
+
+ CloseTransport();
+ }
+ }
+
+ internal virtual void Warn(byte alertDescription, string message)
+ {
+ RaiseAlert(AlertLevel.warning, alertDescription, message, null);
+ }
+
+ private void CloseTransport()
+ {
+ if (!mClosed)
+ {
+ /*
+ * RFC 5246 7.2.1. Unless some other fatal alert has been transmitted, each party is
+ * required to send a close_notify alert before closing the write side of the
+ * connection. The other party MUST respond with a close_notify alert of its own and
+ * close down the connection immediately, discarding any pending writes.
+ */
+
+ try
+ {
+ if (!mFailed)
+ {
+ Warn(AlertDescription.close_notify, null);
+ }
+ mTransport.Close();
+ }
+ catch (Exception)
+ {
+ // Ignore
+ }
+
+ mClosed = true;
+ }
+ }
+
+ private void RaiseAlert(byte alertLevel, byte alertDescription, string message, Exception cause)
+ {
+ mPeer.NotifyAlertRaised(alertLevel, alertDescription, message, cause);
+
+ byte[] error = new byte[2];
+ error[0] = (byte)alertLevel;
+ error[1] = (byte)alertDescription;
+
+ SendRecord(ContentType.alert, error, 0, 2);
+ }
+
+ private int ReceiveRecord(byte[] buf, int off, int len, int waitMillis)
+ {
+ if (mRecordQueue.Available > 0)
+ {
+ int length = 0;
+ if (mRecordQueue.Available >= RECORD_HEADER_LENGTH)
+ {
+ byte[] lengthBytes = new byte[2];
+ mRecordQueue.Read(lengthBytes, 0, 2, 11);
+ length = TlsUtilities.ReadUint16(lengthBytes, 0);
+ }
+
+ int received = System.Math.Min(mRecordQueue.Available, RECORD_HEADER_LENGTH + length);
+ mRecordQueue.RemoveData(buf, off, received, 0);
+ return received;
+ }
+
+ {
+ int received = mTransport.Receive(buf, off, len, waitMillis);
+ if (received >= RECORD_HEADER_LENGTH)
+ {
+ int fragmentLength = TlsUtilities.ReadUint16(buf, off + 11);
+ int recordLength = RECORD_HEADER_LENGTH + fragmentLength;
+ if (received > recordLength)
+ {
+ mRecordQueue.AddData(buf, off + recordLength, received - recordLength);
+ received = recordLength;
+ }
+ }
+ return received;
+ }
+ }
+
+ private void SendRecord(byte contentType, byte[] buf, int off, int len)
+ {
+ // Never send anything until a valid ClientHello has been received
+ if (mWriteVersion == null)
+ return;
+
+ if (len > this.mPlaintextLimit)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ /*
+ * RFC 5246 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert,
+ * or ChangeCipherSpec content types.
+ */
+ if (len < 1 && contentType != ContentType.application_data)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ int recordEpoch = mWriteEpoch.Epoch;
+ long recordSequenceNumber = mWriteEpoch.AllocateSequenceNumber();
+
+ byte[] ciphertext = mWriteEpoch.Cipher.EncodePlaintext(
+ GetMacSequenceNumber(recordEpoch, recordSequenceNumber), contentType, buf, off, len);
+
+ // TODO Check the ciphertext length?
+
+ byte[] record = new byte[ciphertext.Length + RECORD_HEADER_LENGTH];
+ TlsUtilities.WriteUint8(contentType, record, 0);
+ ProtocolVersion version = mWriteVersion;
+ TlsUtilities.WriteVersion(version, record, 1);
+ TlsUtilities.WriteUint16(recordEpoch, record, 3);
+ TlsUtilities.WriteUint48(recordSequenceNumber, record, 5);
+ TlsUtilities.WriteUint16(ciphertext.Length, record, 11);
+ Array.Copy(ciphertext, 0, record, RECORD_HEADER_LENGTH, ciphertext.Length);
+
+ mTransport.Send(record, 0, record.Length);
+ }
+
+ private static long GetMacSequenceNumber(int epoch, long sequence_number)
+ {
+ return ((epoch & 0xFFFFFFFFL) << 48) | sequence_number;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DtlsReliableHandshake.cs b/bc-sharp-crypto/src/crypto/tls/DtlsReliableHandshake.cs
new file mode 100644
index 0000000000000000000000000000000000000000..396ea7483815aa1155a490635b43747fb7a61b74
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DtlsReliableHandshake.cs
@@ -0,0 +1,434 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ internal class DtlsReliableHandshake
+ {
+ private const int MaxReceiveAhead = 16;
+ private const int MessageHeaderLength = 12;
+
+ private readonly DtlsRecordLayer mRecordLayer;
+
+ private TlsHandshakeHash mHandshakeHash;
+
+ private IDictionary mCurrentInboundFlight = Platform.CreateHashtable();
+ private IDictionary mPreviousInboundFlight = null;
+ private IList mOutboundFlight = Platform.CreateArrayList();
+ private bool mSending = true;
+
+ private int mMessageSeq = 0, mNextReceiveSeq = 0;
+
+ internal DtlsReliableHandshake(TlsContext context, DtlsRecordLayer transport)
+ {
+ this.mRecordLayer = transport;
+ this.mHandshakeHash = new DeferredHash();
+ this.mHandshakeHash.Init(context);
+ }
+
+ internal void NotifyHelloComplete()
+ {
+ this.mHandshakeHash = mHandshakeHash.NotifyPrfDetermined();
+ }
+
+ internal TlsHandshakeHash HandshakeHash
+ {
+ get { return mHandshakeHash; }
+ }
+
+ internal TlsHandshakeHash PrepareToFinish()
+ {
+ TlsHandshakeHash result = mHandshakeHash;
+ this.mHandshakeHash = mHandshakeHash.StopTracking();
+ return result;
+ }
+
+ internal void SendMessage(byte msg_type, byte[] body)
+ {
+ TlsUtilities.CheckUint24(body.Length);
+
+ if (!mSending)
+ {
+ CheckInboundFlight();
+ mSending = true;
+ mOutboundFlight.Clear();
+ }
+
+ Message message = new Message(mMessageSeq++, msg_type, body);
+
+ mOutboundFlight.Add(message);
+
+ WriteMessage(message);
+ UpdateHandshakeMessagesDigest(message);
+ }
+
+ internal byte[] ReceiveMessageBody(byte msg_type)
+ {
+ Message message = ReceiveMessage();
+ if (message.Type != msg_type)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ return message.Body;
+ }
+
+ internal Message ReceiveMessage()
+ {
+ if (mSending)
+ {
+ mSending = false;
+ PrepareInboundFlight(Platform.CreateHashtable());
+ }
+
+ byte[] buf = null;
+
+ // TODO Check the conditions under which we should reset this
+ int readTimeoutMillis = 1000;
+
+ for (;;)
+ {
+ try
+ {
+ for (;;)
+ {
+ Message pending = GetPendingMessage();
+ if (pending != null)
+ return pending;
+
+ int receiveLimit = mRecordLayer.GetReceiveLimit();
+ if (buf == null || buf.Length < receiveLimit)
+ {
+ buf = new byte[receiveLimit];
+ }
+
+ int received = mRecordLayer.Receive(buf, 0, receiveLimit, readTimeoutMillis);
+ if (received < 0)
+ break;
+
+ bool resentOutbound = ProcessRecord(MaxReceiveAhead, mRecordLayer.ReadEpoch, buf, 0, received);
+ if (resentOutbound)
+ {
+ readTimeoutMillis = BackOff(readTimeoutMillis);
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ // NOTE: Assume this is a timeout for the moment
+ }
+
+ ResendOutboundFlight();
+ readTimeoutMillis = BackOff(readTimeoutMillis);
+ }
+ }
+
+ internal void Finish()
+ {
+ DtlsHandshakeRetransmit retransmit = null;
+ if (!mSending)
+ {
+ CheckInboundFlight();
+ }
+ else
+ {
+ PrepareInboundFlight(null);
+
+ if (mPreviousInboundFlight != null)
+ {
+ /*
+ * RFC 6347 4.2.4. In addition, for at least twice the default MSL defined for [TCP],
+ * when in the FINISHED state, the node that transmits the last flight (the server in an
+ * ordinary handshake or the client in a resumed handshake) MUST respond to a retransmit
+ * of the peer's last flight with a retransmit of the last flight.
+ */
+ retransmit = new Retransmit(this);
+ }
+ }
+
+ mRecordLayer.HandshakeSuccessful(retransmit);
+ }
+
+ internal void ResetHandshakeMessagesDigest()
+ {
+ mHandshakeHash.Reset();
+ }
+
+ private int BackOff(int timeoutMillis)
+ {
+ /*
+ * TODO[DTLS] implementations SHOULD back off handshake packet size during the
+ * retransmit backoff.
+ */
+ return System.Math.Min(timeoutMillis * 2, 60000);
+ }
+
+ /**
+ * Check that there are no "extra" messages left in the current inbound flight
+ */
+ private void CheckInboundFlight()
+ {
+ foreach (int key in mCurrentInboundFlight.Keys)
+ {
+ if (key >= mNextReceiveSeq)
+ {
+ // TODO Should this be considered an error?
+ }
+ }
+ }
+
+ private Message GetPendingMessage()
+ {
+ DtlsReassembler next = (DtlsReassembler)mCurrentInboundFlight[mNextReceiveSeq];
+ if (next != null)
+ {
+ byte[] body = next.GetBodyIfComplete();
+ if (body != null)
+ {
+ mPreviousInboundFlight = null;
+ return UpdateHandshakeMessagesDigest(new Message(mNextReceiveSeq++, next.MsgType, body));
+ }
+ }
+ return null;
+ }
+
+ private void PrepareInboundFlight(IDictionary nextFlight)
+ {
+ ResetAll(mCurrentInboundFlight);
+ mPreviousInboundFlight = mCurrentInboundFlight;
+ mCurrentInboundFlight = nextFlight;
+ }
+
+ private bool ProcessRecord(int windowSize, int epoch, byte[] buf, int off, int len)
+ {
+ bool checkPreviousFlight = false;
+
+ while (len >= MessageHeaderLength)
+ {
+ int fragment_length = TlsUtilities.ReadUint24(buf, off + 9);
+ int message_length = fragment_length + MessageHeaderLength;
+ if (len < message_length)
+ {
+ // NOTE: Truncated message - ignore it
+ break;
+ }
+
+ int length = TlsUtilities.ReadUint24(buf, off + 1);
+ int fragment_offset = TlsUtilities.ReadUint24(buf, off + 6);
+ if (fragment_offset + fragment_length > length)
+ {
+ // NOTE: Malformed fragment - ignore it and the rest of the record
+ break;
+ }
+
+ /*
+ * NOTE: This very simple epoch check will only work until we want to support
+ * renegotiation (and we're not likely to do that anyway).
+ */
+ byte msg_type = TlsUtilities.ReadUint8(buf, off + 0);
+ int expectedEpoch = msg_type == HandshakeType.finished ? 1 : 0;
+ if (epoch != expectedEpoch)
+ {
+ break;
+ }
+
+ int message_seq = TlsUtilities.ReadUint16(buf, off + 4);
+ if (message_seq >= (mNextReceiveSeq + windowSize))
+ {
+ // NOTE: Too far ahead - ignore
+ }
+ else if (message_seq >= mNextReceiveSeq)
+ {
+ DtlsReassembler reassembler = (DtlsReassembler)mCurrentInboundFlight[message_seq];
+ if (reassembler == null)
+ {
+ reassembler = new DtlsReassembler(msg_type, length);
+ mCurrentInboundFlight[message_seq] = reassembler;
+ }
+
+ reassembler.ContributeFragment(msg_type, length, buf, off + MessageHeaderLength, fragment_offset,
+ fragment_length);
+ }
+ else if (mPreviousInboundFlight != null)
+ {
+ /*
+ * NOTE: If we receive the previous flight of incoming messages in full again,
+ * retransmit our last flight
+ */
+
+ DtlsReassembler reassembler = (DtlsReassembler)mPreviousInboundFlight[message_seq];
+ if (reassembler != null)
+ {
+ reassembler.ContributeFragment(msg_type, length, buf, off + MessageHeaderLength, fragment_offset,
+ fragment_length);
+ checkPreviousFlight = true;
+ }
+ }
+
+ off += message_length;
+ len -= message_length;
+ }
+
+ bool result = checkPreviousFlight && CheckAll(mPreviousInboundFlight);
+ if (result)
+ {
+ ResendOutboundFlight();
+ ResetAll(mPreviousInboundFlight);
+ }
+ return result;
+ }
+
+ private void ResendOutboundFlight()
+ {
+ mRecordLayer.ResetWriteEpoch();
+ for (int i = 0; i < mOutboundFlight.Count; ++i)
+ {
+ WriteMessage((Message)mOutboundFlight[i]);
+ }
+ }
+
+ private Message UpdateHandshakeMessagesDigest(Message message)
+ {
+ if (message.Type != HandshakeType.hello_request)
+ {
+ byte[] body = message.Body;
+ byte[] buf = new byte[MessageHeaderLength];
+ TlsUtilities.WriteUint8(message.Type, buf, 0);
+ TlsUtilities.WriteUint24(body.Length, buf, 1);
+ TlsUtilities.WriteUint16(message.Seq, buf, 4);
+ TlsUtilities.WriteUint24(0, buf, 6);
+ TlsUtilities.WriteUint24(body.Length, buf, 9);
+ mHandshakeHash.BlockUpdate(buf, 0, buf.Length);
+ mHandshakeHash.BlockUpdate(body, 0, body.Length);
+ }
+ return message;
+ }
+
+ private void WriteMessage(Message message)
+ {
+ int sendLimit = mRecordLayer.GetSendLimit();
+ int fragmentLimit = sendLimit - MessageHeaderLength;
+
+ // TODO Support a higher minimum fragment size?
+ if (fragmentLimit < 1)
+ {
+ // TODO Should we be throwing an exception here?
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ int length = message.Body.Length;
+
+ // NOTE: Must still send a fragment if body is empty
+ int fragment_offset = 0;
+ do
+ {
+ int fragment_length = System.Math.Min(length - fragment_offset, fragmentLimit);
+ WriteHandshakeFragment(message, fragment_offset, fragment_length);
+ fragment_offset += fragment_length;
+ }
+ while (fragment_offset < length);
+ }
+
+ private void WriteHandshakeFragment(Message message, int fragment_offset, int fragment_length)
+ {
+ RecordLayerBuffer fragment = new RecordLayerBuffer(MessageHeaderLength + fragment_length);
+ TlsUtilities.WriteUint8(message.Type, fragment);
+ TlsUtilities.WriteUint24(message.Body.Length, fragment);
+ TlsUtilities.WriteUint16(message.Seq, fragment);
+ TlsUtilities.WriteUint24(fragment_offset, fragment);
+ TlsUtilities.WriteUint24(fragment_length, fragment);
+ fragment.Write(message.Body, fragment_offset, fragment_length);
+
+ fragment.SendToRecordLayer(mRecordLayer);
+ }
+
+ private static bool CheckAll(IDictionary inboundFlight)
+ {
+ foreach (DtlsReassembler r in inboundFlight.Values)
+ {
+ if (r.GetBodyIfComplete() == null)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static void ResetAll(IDictionary inboundFlight)
+ {
+ foreach (DtlsReassembler r in inboundFlight.Values)
+ {
+ r.Reset();
+ }
+ }
+
+ internal class Message
+ {
+ private readonly int mMessageSeq;
+ private readonly byte mMsgType;
+ private readonly byte[] mBody;
+
+ internal Message(int message_seq, byte msg_type, byte[] body)
+ {
+ this.mMessageSeq = message_seq;
+ this.mMsgType = msg_type;
+ this.mBody = body;
+ }
+
+ public int Seq
+ {
+ get { return mMessageSeq; }
+ }
+
+ public byte Type
+ {
+ get { return mMsgType; }
+ }
+
+ public byte[] Body
+ {
+ get { return mBody; }
+ }
+ }
+
+ internal class RecordLayerBuffer
+ : MemoryStream
+ {
+ internal RecordLayerBuffer(int size)
+ : base(size)
+ {
+ }
+
+ internal void SendToRecordLayer(DtlsRecordLayer recordLayer)
+ {
+#if PORTABLE
+ byte[] buf = ToArray();
+ int bufLen = buf.Length;
+#else
+ byte[] buf = GetBuffer();
+ int bufLen = (int)Length;
+#endif
+
+ recordLayer.Send(buf, 0, bufLen);
+ Platform.Dispose(this);
+ }
+ }
+
+ internal class Retransmit
+ : DtlsHandshakeRetransmit
+ {
+ private readonly DtlsReliableHandshake mOuter;
+
+ internal Retransmit(DtlsReliableHandshake outer)
+ {
+ this.mOuter = outer;
+ }
+
+ public void ReceivedHandshakeRecord(int epoch, byte[] buf, int off, int len)
+ {
+ mOuter.ProcessRecord(0, epoch, buf, off, len);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DtlsReplayWindow.cs b/bc-sharp-crypto/src/crypto/tls/DtlsReplayWindow.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ea18e805e0cece9c2e06c4be8a651f4eaaa6c9b5
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DtlsReplayWindow.cs
@@ -0,0 +1,85 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * RFC 4347 4.1.2.5 Anti-replay
+ *
+ * Support fast rejection of duplicate records by maintaining a sliding receive window
+ */
+ internal class DtlsReplayWindow
+ {
+ private const long VALID_SEQ_MASK = 0x0000FFFFFFFFFFFFL;
+
+ private const long WINDOW_SIZE = 64L;
+
+ private long mLatestConfirmedSeq = -1;
+ private long mBitmap = 0;
+
+ /**
+ * Check whether a received record with the given sequence number should be rejected as a duplicate.
+ *
+ * @param seq the 48-bit DTLSPlainText.sequence_number field of a received record.
+ * @return true if the record should be discarded without further processing.
+ */
+ internal bool ShouldDiscard(long seq)
+ {
+ if ((seq & VALID_SEQ_MASK) != seq)
+ return true;
+
+ if (seq <= mLatestConfirmedSeq)
+ {
+ long diff = mLatestConfirmedSeq - seq;
+ if (diff >= WINDOW_SIZE)
+ return true;
+ if ((mBitmap & (1L << (int)diff)) != 0)
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Report that a received record with the given sequence number passed authentication checks.
+ *
+ * @param seq the 48-bit DTLSPlainText.sequence_number field of an authenticated record.
+ */
+ internal void ReportAuthenticated(long seq)
+ {
+ if ((seq & VALID_SEQ_MASK) != seq)
+ throw new ArgumentException("out of range", "seq");
+
+ if (seq <= mLatestConfirmedSeq)
+ {
+ long diff = mLatestConfirmedSeq - seq;
+ if (diff < WINDOW_SIZE)
+ {
+ mBitmap |= (1L << (int)diff);
+ }
+ }
+ else
+ {
+ long diff = seq - mLatestConfirmedSeq;
+ if (diff >= WINDOW_SIZE)
+ {
+ mBitmap = 1;
+ }
+ else
+ {
+ mBitmap <<= (int)diff;
+ mBitmap |= 1;
+ }
+ mLatestConfirmedSeq = seq;
+ }
+ }
+
+ /**
+ * When a new epoch begins, sequence numbers begin again at 0
+ */
+ internal void Reset()
+ {
+ mLatestConfirmedSeq = -1;
+ mBitmap = 0;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DtlsServerProtocol.cs b/bc-sharp-crypto/src/crypto/tls/DtlsServerProtocol.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3032269d1db57b4f411d4178ba0820f1158c042f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DtlsServerProtocol.cs
@@ -0,0 +1,696 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class DtlsServerProtocol
+ : DtlsProtocol
+ {
+ protected bool mVerifyRequests = true;
+
+ public DtlsServerProtocol(SecureRandom secureRandom)
+ : base(secureRandom)
+ {
+ }
+
+ public virtual bool VerifyRequests
+ {
+ get { return mVerifyRequests; }
+ set { this.mVerifyRequests = value; }
+ }
+
+ public virtual DtlsTransport Accept(TlsServer server, DatagramTransport transport)
+ {
+ if (server == null)
+ throw new ArgumentNullException("server");
+ if (transport == null)
+ throw new ArgumentNullException("transport");
+
+ SecurityParameters securityParameters = new SecurityParameters();
+ securityParameters.entity = ConnectionEnd.server;
+
+ ServerHandshakeState state = new ServerHandshakeState();
+ state.server = server;
+ state.serverContext = new TlsServerContextImpl(mSecureRandom, securityParameters);
+
+ securityParameters.serverRandom = TlsProtocol.CreateRandomBlock(server.ShouldUseGmtUnixTime(),
+ state.serverContext.NonceRandomGenerator);
+
+ server.Init(state.serverContext);
+
+ DtlsRecordLayer recordLayer = new DtlsRecordLayer(transport, state.serverContext, server, ContentType.handshake);
+
+ // TODO Need to handle sending of HelloVerifyRequest without entering a full connection
+
+ try
+ {
+ return ServerHandshake(state, recordLayer);
+ }
+ catch (TlsFatalAlert fatalAlert)
+ {
+ AbortServerHandshake(state, recordLayer, fatalAlert.AlertDescription);
+ throw fatalAlert;
+ }
+ catch (IOException e)
+ {
+ AbortServerHandshake(state, recordLayer, AlertDescription.internal_error);
+ throw e;
+ }
+ catch (Exception e)
+ {
+ AbortServerHandshake(state, recordLayer, AlertDescription.internal_error);
+ throw new TlsFatalAlert(AlertDescription.internal_error, e);
+ }
+ finally
+ {
+ securityParameters.Clear();
+ }
+ }
+
+ internal virtual void AbortServerHandshake(ServerHandshakeState state, DtlsRecordLayer recordLayer, byte alertDescription)
+ {
+ recordLayer.Fail(alertDescription);
+ InvalidateSession(state);
+ }
+
+ internal virtual DtlsTransport ServerHandshake(ServerHandshakeState state, DtlsRecordLayer recordLayer)
+ {
+ SecurityParameters securityParameters = state.serverContext.SecurityParameters;
+ DtlsReliableHandshake handshake = new DtlsReliableHandshake(state.serverContext, recordLayer);
+
+ DtlsReliableHandshake.Message clientMessage = handshake.ReceiveMessage();
+
+ // NOTE: DTLSRecordLayer requires any DTLS version, we don't otherwise constrain this
+ //ProtocolVersion recordLayerVersion = recordLayer.ReadVersion;
+
+ if (clientMessage.Type == HandshakeType.client_hello)
+ {
+ ProcessClientHello(state, clientMessage.Body);
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ {
+ byte[] serverHelloBody = GenerateServerHello(state);
+
+ ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.maxFragmentLength);
+
+ ProtocolVersion recordLayerVersion = state.serverContext.ServerVersion;
+ recordLayer.ReadVersion = recordLayerVersion;
+ recordLayer.SetWriteVersion(recordLayerVersion);
+
+ handshake.SendMessage(HandshakeType.server_hello, serverHelloBody);
+ }
+
+ handshake.NotifyHelloComplete();
+
+ IList serverSupplementalData = state.server.GetServerSupplementalData();
+ if (serverSupplementalData != null)
+ {
+ byte[] supplementalDataBody = GenerateSupplementalData(serverSupplementalData);
+ handshake.SendMessage(HandshakeType.supplemental_data, supplementalDataBody);
+ }
+
+ state.keyExchange = state.server.GetKeyExchange();
+ state.keyExchange.Init(state.serverContext);
+
+ state.serverCredentials = state.server.GetCredentials();
+
+ Certificate serverCertificate = null;
+
+ if (state.serverCredentials == null)
+ {
+ state.keyExchange.SkipServerCredentials();
+ }
+ else
+ {
+ state.keyExchange.ProcessServerCredentials(state.serverCredentials);
+
+ serverCertificate = state.serverCredentials.Certificate;
+ byte[] certificateBody = GenerateCertificate(serverCertificate);
+ handshake.SendMessage(HandshakeType.certificate, certificateBody);
+ }
+
+ // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
+ if (serverCertificate == null || serverCertificate.IsEmpty)
+ {
+ state.allowCertificateStatus = false;
+ }
+
+ if (state.allowCertificateStatus)
+ {
+ CertificateStatus certificateStatus = state.server.GetCertificateStatus();
+ if (certificateStatus != null)
+ {
+ byte[] certificateStatusBody = GenerateCertificateStatus(state, certificateStatus);
+ handshake.SendMessage(HandshakeType.certificate_status, certificateStatusBody);
+ }
+ }
+
+ byte[] serverKeyExchange = state.keyExchange.GenerateServerKeyExchange();
+ if (serverKeyExchange != null)
+ {
+ handshake.SendMessage(HandshakeType.server_key_exchange, serverKeyExchange);
+ }
+
+ if (state.serverCredentials != null)
+ {
+ state.certificateRequest = state.server.GetCertificateRequest();
+ if (state.certificateRequest != null)
+ {
+ if (TlsUtilities.IsTlsV12(state.serverContext) != (state.certificateRequest.SupportedSignatureAlgorithms != null))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ state.keyExchange.ValidateCertificateRequest(state.certificateRequest);
+
+ byte[] certificateRequestBody = GenerateCertificateRequest(state, state.certificateRequest);
+ handshake.SendMessage(HandshakeType.certificate_request, certificateRequestBody);
+
+ TlsUtilities.TrackHashAlgorithms(handshake.HandshakeHash,
+ state.certificateRequest.SupportedSignatureAlgorithms);
+ }
+ }
+
+ handshake.SendMessage(HandshakeType.server_hello_done, TlsUtilities.EmptyBytes);
+
+ handshake.HandshakeHash.SealHashAlgorithms();
+
+ clientMessage = handshake.ReceiveMessage();
+
+ if (clientMessage.Type == HandshakeType.supplemental_data)
+ {
+ ProcessClientSupplementalData(state, clientMessage.Body);
+ clientMessage = handshake.ReceiveMessage();
+ }
+ else
+ {
+ state.server.ProcessClientSupplementalData(null);
+ }
+
+ if (state.certificateRequest == null)
+ {
+ state.keyExchange.SkipClientCredentials();
+ }
+ else
+ {
+ if (clientMessage.Type == HandshakeType.certificate)
+ {
+ ProcessClientCertificate(state, clientMessage.Body);
+ clientMessage = handshake.ReceiveMessage();
+ }
+ else
+ {
+ if (TlsUtilities.IsTlsV12(state.serverContext))
+ {
+ /*
+ * RFC 5246 If no suitable certificate is available, the client MUST send a
+ * certificate message containing no certificates.
+ *
+ * NOTE: In previous RFCs, this was SHOULD instead of MUST.
+ */
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ NotifyClientCertificate(state, Certificate.EmptyChain);
+ }
+ }
+
+ if (clientMessage.Type == HandshakeType.client_key_exchange)
+ {
+ ProcessClientKeyExchange(state, clientMessage.Body);
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ TlsHandshakeHash prepareFinishHash = handshake.PrepareToFinish();
+ securityParameters.sessionHash = TlsProtocol.GetCurrentPrfHash(state.serverContext, prepareFinishHash, null);
+
+ TlsProtocol.EstablishMasterSecret(state.serverContext, state.keyExchange);
+ recordLayer.InitPendingEpoch(state.server.GetCipher());
+
+ /*
+ * RFC 5246 7.4.8 This message is only sent following a client certificate that has signing
+ * capability (i.e., all certificates except those containing fixed Diffie-Hellman
+ * parameters).
+ */
+ if (ExpectCertificateVerifyMessage(state))
+ {
+ byte[] certificateVerifyBody = handshake.ReceiveMessageBody(HandshakeType.certificate_verify);
+ ProcessCertificateVerify(state, certificateVerifyBody, prepareFinishHash);
+ }
+
+ // NOTE: Calculated exclusive of the actual Finished message from the client
+ byte[] expectedClientVerifyData = TlsUtilities.CalculateVerifyData(state.serverContext, ExporterLabel.client_finished,
+ TlsProtocol.GetCurrentPrfHash(state.serverContext, handshake.HandshakeHash, null));
+ ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished), expectedClientVerifyData);
+
+ if (state.expectSessionTicket)
+ {
+ NewSessionTicket newSessionTicket = state.server.GetNewSessionTicket();
+ byte[] newSessionTicketBody = GenerateNewSessionTicket(state, newSessionTicket);
+ handshake.SendMessage(HandshakeType.session_ticket, newSessionTicketBody);
+ }
+
+ // NOTE: Calculated exclusive of the Finished message itself
+ byte[] serverVerifyData = TlsUtilities.CalculateVerifyData(state.serverContext, ExporterLabel.server_finished,
+ TlsProtocol.GetCurrentPrfHash(state.serverContext, handshake.HandshakeHash, null));
+ handshake.SendMessage(HandshakeType.finished, serverVerifyData);
+
+ handshake.Finish();
+
+ state.server.NotifyHandshakeComplete();
+
+ return new DtlsTransport(recordLayer);
+ }
+
+ protected virtual void InvalidateSession(ServerHandshakeState state)
+ {
+ if (state.sessionParameters != null)
+ {
+ state.sessionParameters.Clear();
+ state.sessionParameters = null;
+ }
+
+ if (state.tlsSession != null)
+ {
+ state.tlsSession.Invalidate();
+ state.tlsSession = null;
+ }
+ }
+
+ protected virtual byte[] GenerateCertificateRequest(ServerHandshakeState state, CertificateRequest certificateRequest)
+ {
+ MemoryStream buf = new MemoryStream();
+ certificateRequest.Encode(buf);
+ return buf.ToArray();
+ }
+
+ protected virtual byte[] GenerateCertificateStatus(ServerHandshakeState state, CertificateStatus certificateStatus)
+ {
+ MemoryStream buf = new MemoryStream();
+ certificateStatus.Encode(buf);
+ return buf.ToArray();
+ }
+
+ protected virtual byte[] GenerateNewSessionTicket(ServerHandshakeState state, NewSessionTicket newSessionTicket)
+ {
+ MemoryStream buf = new MemoryStream();
+ newSessionTicket.Encode(buf);
+ return buf.ToArray();
+ }
+
+ protected virtual byte[] GenerateServerHello(ServerHandshakeState state)
+ {
+ SecurityParameters securityParameters = state.serverContext.SecurityParameters;
+
+ MemoryStream buf = new MemoryStream();
+
+ {
+ ProtocolVersion server_version = state.server.GetServerVersion();
+ if (!server_version.IsEqualOrEarlierVersionOf(state.serverContext.ClientVersion))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ // TODO Read RFCs for guidance on the expected record layer version number
+ // recordStream.setReadVersion(server_version);
+ // recordStream.setWriteVersion(server_version);
+ // recordStream.setRestrictReadVersion(true);
+ state.serverContext.SetServerVersion(server_version);
+
+ TlsUtilities.WriteVersion(state.serverContext.ServerVersion, buf);
+ }
+
+ buf.Write(securityParameters.ServerRandom, 0, securityParameters.ServerRandom.Length);
+
+ /*
+ * The server may return an empty session_id to indicate that the session will not be cached
+ * and therefore cannot be resumed.
+ */
+ TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf);
+
+ int selectedCipherSuite = state.server.GetSelectedCipherSuite();
+ if (!Arrays.Contains(state.offeredCipherSuites, selectedCipherSuite)
+ || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
+ || CipherSuite.IsScsv(selectedCipherSuite)
+ || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, state.serverContext.ServerVersion))
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ ValidateSelectedCipherSuite(selectedCipherSuite, AlertDescription.internal_error);
+ securityParameters.cipherSuite = selectedCipherSuite;
+
+ byte selectedCompressionMethod = state.server.GetSelectedCompressionMethod();
+ if (!Arrays.Contains(state.offeredCompressionMethods, selectedCompressionMethod))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ securityParameters.compressionAlgorithm = selectedCompressionMethod;
+
+ TlsUtilities.WriteUint16(selectedCipherSuite, buf);
+ TlsUtilities.WriteUint8(selectedCompressionMethod, buf);
+
+ state.serverExtensions = state.server.GetServerExtensions();
+
+ /*
+ * RFC 5746 3.6. Server Behavior: Initial Handshake
+ */
+ if (state.secure_renegotiation)
+ {
+ byte[] renegExtData = TlsUtilities.GetExtensionData(state.serverExtensions, ExtensionType.renegotiation_info);
+ bool noRenegExt = (null == renegExtData);
+
+ if (noRenegExt)
+ {
+ /*
+ * Note that sending a "renegotiation_info" extension in response to a ClientHello
+ * containing only the SCSV is an explicit exception to the prohibition in RFC 5246,
+ * Section 7.4.1.4, on the server sending unsolicited extensions and is only allowed
+ * because the client is signaling its willingness to receive the extension via the
+ * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
+ */
+
+ /*
+ * If the secure_renegotiation flag is set to TRUE, the server MUST include an empty
+ * "renegotiation_info" extension in the ServerHello message.
+ */
+ state.serverExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(state.serverExtensions);
+ state.serverExtensions[ExtensionType.renegotiation_info] = TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
+ }
+ }
+
+ if (securityParameters.extendedMasterSecret)
+ {
+ state.serverExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(state.serverExtensions);
+ TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.serverExtensions);
+ }
+
+ /*
+ * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
+ * extensions appearing in the client hello, and send a server hello containing no
+ * extensions.
+ */
+
+ if (state.serverExtensions != null)
+ {
+ securityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(state.serverExtensions);
+
+ securityParameters.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.resumedSession,
+ state.clientExtensions, state.serverExtensions, AlertDescription.internal_error);
+
+ securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(state.serverExtensions);
+
+ /*
+ * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
+ * a session resumption handshake.
+ */
+ state.allowCertificateStatus = !state.resumedSession
+ && TlsUtilities.HasExpectedEmptyExtensionData(state.serverExtensions, ExtensionType.status_request,
+ AlertDescription.internal_error);
+
+ state.expectSessionTicket = !state.resumedSession
+ && TlsUtilities.HasExpectedEmptyExtensionData(state.serverExtensions, ExtensionType.session_ticket,
+ AlertDescription.internal_error);
+
+ TlsProtocol.WriteExtensions(buf, state.serverExtensions);
+ }
+
+ securityParameters.prfAlgorithm = TlsProtocol.GetPrfAlgorithm(state.serverContext,
+ securityParameters.CipherSuite);
+
+ /*
+ * RFC 5246 7.4.9. Any cipher suite which does not explicitly specify verify_data_length
+ * has a verify_data_length equal to 12. This includes all existing cipher suites.
+ */
+ securityParameters.verifyDataLength = 12;
+
+ return buf.ToArray();
+ }
+
+ protected virtual void NotifyClientCertificate(ServerHandshakeState state, Certificate clientCertificate)
+ {
+ if (state.certificateRequest == null)
+ throw new InvalidOperationException();
+
+ if (state.clientCertificate != null)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ state.clientCertificate = clientCertificate;
+
+ if (clientCertificate.IsEmpty)
+ {
+ state.keyExchange.SkipClientCredentials();
+ }
+ else
+ {
+
+ /*
+ * TODO RFC 5246 7.4.6. If the certificate_authorities list in the certificate request
+ * message was non-empty, one of the certificates in the certificate chain SHOULD be
+ * issued by one of the listed CAs.
+ */
+
+ state.clientCertificateType = TlsUtilities.GetClientCertificateType(clientCertificate,
+ state.serverCredentials.Certificate);
+
+ state.keyExchange.ProcessClientCertificate(clientCertificate);
+ }
+
+ /*
+ * RFC 5246 7.4.6. If the client does not send any certificates, the server MAY at its
+ * discretion either continue the handshake without client authentication, or respond with a
+ * fatal handshake_failure alert. Also, if some aspect of the certificate chain was
+ * unacceptable (e.g., it was not signed by a known, trusted CA), the server MAY at its
+ * discretion either continue the handshake (considering the client unauthenticated) or send
+ * a fatal alert.
+ */
+ state.server.NotifyClientCertificate(clientCertificate);
+ }
+
+ protected virtual void ProcessClientCertificate(ServerHandshakeState state, byte[] body)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+
+ Certificate clientCertificate = Certificate.Parse(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ NotifyClientCertificate(state, clientCertificate);
+ }
+
+ protected virtual void ProcessCertificateVerify(ServerHandshakeState state, byte[] body, TlsHandshakeHash prepareFinishHash)
+ {
+ if (state.certificateRequest == null)
+ throw new InvalidOperationException();
+
+ MemoryStream buf = new MemoryStream(body, false);
+
+ TlsServerContextImpl context = state.serverContext;
+ DigitallySigned clientCertificateVerify = DigitallySigned.Parse(context, buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ // Verify the CertificateVerify message contains a correct signature.
+ try
+ {
+ SignatureAndHashAlgorithm signatureAlgorithm = clientCertificateVerify.Algorithm;
+
+ byte[] hash;
+ if (TlsUtilities.IsTlsV12(context))
+ {
+ TlsUtilities.VerifySupportedSignatureAlgorithm(state.certificateRequest.SupportedSignatureAlgorithms, signatureAlgorithm);
+ hash = prepareFinishHash.GetFinalHash(signatureAlgorithm.Hash);
+ }
+ else
+ {
+ hash = context.SecurityParameters.SessionHash;
+ }
+
+ X509CertificateStructure x509Cert = state.clientCertificate.GetCertificateAt(0);
+ SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+ AsymmetricKeyParameter publicKey = PublicKeyFactory.CreateKey(keyInfo);
+
+ TlsSigner tlsSigner = TlsUtilities.CreateTlsSigner((byte)state.clientCertificateType);
+ tlsSigner.Init(context);
+ if (!tlsSigner.VerifyRawSignature(signatureAlgorithm, clientCertificateVerify.Signature, publicKey, hash))
+ throw new TlsFatalAlert(AlertDescription.decrypt_error);
+ }
+ catch (TlsFatalAlert e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new TlsFatalAlert(AlertDescription.decrypt_error, e);
+ }
+ }
+
+ protected virtual void ProcessClientHello(ServerHandshakeState state, byte[] body)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+
+ // TODO Read RFCs for guidance on the expected record layer version number
+ ProtocolVersion client_version = TlsUtilities.ReadVersion(buf);
+ if (!client_version.IsDtls)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ /*
+ * Read the client random
+ */
+ byte[] client_random = TlsUtilities.ReadFully(32, buf);
+
+ byte[] sessionID = TlsUtilities.ReadOpaque8(buf);
+ if (sessionID.Length > 32)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ // TODO RFC 4347 has the cookie length restricted to 32, but not in RFC 6347
+ byte[] cookie = TlsUtilities.ReadOpaque8(buf);
+
+ int cipher_suites_length = TlsUtilities.ReadUint16(buf);
+ if (cipher_suites_length < 2 || (cipher_suites_length & 1) != 0)
+ {
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ }
+
+ /*
+ * NOTE: "If the session_id field is not empty (implying a session resumption request) this
+ * vector must include at least the cipher_suite from that session."
+ */
+ state.offeredCipherSuites = TlsUtilities.ReadUint16Array(cipher_suites_length / 2, buf);
+
+ int compression_methods_length = TlsUtilities.ReadUint8(buf);
+ if (compression_methods_length < 1)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ state.offeredCompressionMethods = TlsUtilities.ReadUint8Array(compression_methods_length, buf);
+
+ /*
+ * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
+ * extensions appearing in the client hello, and send a server hello containing no
+ * extensions.
+ */
+ state.clientExtensions = TlsProtocol.ReadExtensions(buf);
+
+ TlsServerContextImpl context = state.serverContext;
+ SecurityParameters securityParameters = context.SecurityParameters;
+
+ /*
+ * TODO[session-hash]
+ *
+ * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes
+ * that do not use the extended master secret [..]. (and see 5.2, 5.3)
+ */
+ securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(state.clientExtensions);
+
+ context.SetClientVersion(client_version);
+
+ state.server.NotifyClientVersion(client_version);
+ state.server.NotifyFallback(Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV));
+
+ securityParameters.clientRandom = client_random;
+
+ state.server.NotifyOfferedCipherSuites(state.offeredCipherSuites);
+ state.server.NotifyOfferedCompressionMethods(state.offeredCompressionMethods);
+
+ /*
+ * RFC 5746 3.6. Server Behavior: Initial Handshake
+ */
+ {
+ /*
+ * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
+ * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
+ * ClientHello. Including both is NOT RECOMMENDED.
+ */
+
+ /*
+ * When a ClientHello is received, the server MUST check if it includes the
+ * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. If it does, set the secure_renegotiation flag
+ * to TRUE.
+ */
+ if (Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV))
+ {
+ state.secure_renegotiation = true;
+ }
+
+ /*
+ * The server MUST check if the "renegotiation_info" extension is included in the
+ * ClientHello.
+ */
+ byte[] renegExtData = TlsUtilities.GetExtensionData(state.clientExtensions, ExtensionType.renegotiation_info);
+ if (renegExtData != null)
+ {
+ /*
+ * If the extension is present, set secure_renegotiation flag to TRUE. The
+ * server MUST then verify that the length of the "renegotiated_connection"
+ * field is zero, and if it is not, MUST abort the handshake.
+ */
+ state.secure_renegotiation = true;
+
+ if (!Arrays.ConstantTimeAreEqual(renegExtData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+ }
+
+ state.server.NotifySecureRenegotiation(state.secure_renegotiation);
+
+ if (state.clientExtensions != null)
+ {
+ // NOTE: Validates the padding extension data, if present
+ TlsExtensionsUtilities.GetPaddingExtension(state.clientExtensions);
+
+ state.server.ProcessClientExtensions(state.clientExtensions);
+ }
+ }
+
+ protected virtual void ProcessClientKeyExchange(ServerHandshakeState state, byte[] body)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+
+ state.keyExchange.ProcessClientKeyExchange(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+ }
+
+ protected virtual void ProcessClientSupplementalData(ServerHandshakeState state, byte[] body)
+ {
+ MemoryStream buf = new MemoryStream(body, false);
+ IList clientSupplementalData = TlsProtocol.ReadSupplementalDataMessage(buf);
+ state.server.ProcessClientSupplementalData(clientSupplementalData);
+ }
+
+ protected virtual bool ExpectCertificateVerifyMessage(ServerHandshakeState state)
+ {
+ return state.clientCertificateType >= 0 && TlsUtilities.HasSigningCapability((byte)state.clientCertificateType);
+ }
+
+ protected internal class ServerHandshakeState
+ {
+ internal TlsServer server = null;
+ internal TlsServerContextImpl serverContext = null;
+ internal TlsSession tlsSession = null;
+ internal SessionParameters sessionParameters = null;
+ internal SessionParameters.Builder sessionParametersBuilder = null;
+ internal int[] offeredCipherSuites = null;
+ internal byte[] offeredCompressionMethods = null;
+ internal IDictionary clientExtensions = null;
+ internal IDictionary serverExtensions = null;
+ internal bool resumedSession = false;
+ internal bool secure_renegotiation = false;
+ internal bool allowCertificateStatus = false;
+ internal bool expectSessionTicket = false;
+ internal TlsKeyExchange keyExchange = null;
+ internal TlsCredentials serverCredentials = null;
+ internal CertificateRequest certificateRequest = null;
+ internal short clientCertificateType = -1;
+ internal Certificate clientCertificate = null;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/DtlsTransport.cs b/bc-sharp-crypto/src/crypto/tls/DtlsTransport.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5c607336b0f7b9893292c29fee35a09be4a8b93a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/DtlsTransport.cs
@@ -0,0 +1,77 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class DtlsTransport
+ : DatagramTransport
+ {
+ private readonly DtlsRecordLayer mRecordLayer;
+
+ internal DtlsTransport(DtlsRecordLayer recordLayer)
+ {
+ this.mRecordLayer = recordLayer;
+ }
+
+ public virtual int GetReceiveLimit()
+ {
+ return mRecordLayer.GetReceiveLimit();
+ }
+
+ public virtual int GetSendLimit()
+ {
+ return mRecordLayer.GetSendLimit();
+ }
+
+ public virtual int Receive(byte[] buf, int off, int len, int waitMillis)
+ {
+ try
+ {
+ return mRecordLayer.Receive(buf, off, len, waitMillis);
+ }
+ catch (TlsFatalAlert fatalAlert)
+ {
+ mRecordLayer.Fail(fatalAlert.AlertDescription);
+ throw fatalAlert;
+ }
+ catch (IOException e)
+ {
+ mRecordLayer.Fail(AlertDescription.internal_error);
+ throw e;
+ }
+ catch (Exception e)
+ {
+ mRecordLayer.Fail(AlertDescription.internal_error);
+ throw new TlsFatalAlert(AlertDescription.internal_error, e);
+ }
+ }
+
+ public virtual void Send(byte[] buf, int off, int len)
+ {
+ try
+ {
+ mRecordLayer.Send(buf, off, len);
+ }
+ catch (TlsFatalAlert fatalAlert)
+ {
+ mRecordLayer.Fail(fatalAlert.AlertDescription);
+ throw fatalAlert;
+ }
+ catch (IOException e)
+ {
+ mRecordLayer.Fail(AlertDescription.internal_error);
+ throw e;
+ }
+ catch (Exception e)
+ {
+ mRecordLayer.Fail(AlertDescription.internal_error);
+ throw new TlsFatalAlert(AlertDescription.internal_error, e);
+ }
+ }
+
+ public virtual void Close()
+ {
+ mRecordLayer.Close();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/ECBasisType.cs b/bc-sharp-crypto/src/crypto/tls/ECBasisType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5416e17c0700b4b95b98aba7278246e4a70bbc34
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/ECBasisType.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// RFC 4492 5.4. (Errata ID: 2389)
+ public abstract class ECBasisType
+ {
+ public const byte ec_basis_trinomial = 1;
+ public const byte ec_basis_pentanomial = 2;
+
+ public static bool IsValid(byte ecBasisType)
+ {
+ return ecBasisType >= ec_basis_trinomial && ecBasisType <= ec_basis_pentanomial;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/ECCurveType.cs b/bc-sharp-crypto/src/crypto/tls/ECCurveType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1b352e9c437a93d26cdf728ffca30ad5488dc85f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/ECCurveType.cs
@@ -0,0 +1,29 @@
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ ///
+ /// RFC 4492 5.4
+ ///
+ public abstract class ECCurveType
+ {
+ /**
+ * Indicates the elliptic curve domain parameters are conveyed verbosely, and the
+ * underlying finite field is a prime field.
+ */
+ public const byte explicit_prime = 1;
+
+ /**
+ * Indicates the elliptic curve domain parameters are conveyed verbosely, and the
+ * underlying finite field is a characteristic-2 field.
+ */
+ public const byte explicit_char2 = 2;
+
+ /**
+ * Indicates that a named curve is used. This option SHOULD be used when applicable.
+ */
+ public const byte named_curve = 3;
+
+ /*
+ * Values 248 through 255 are reserved for private use.
+ */
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/ECPointFormat.cs b/bc-sharp-crypto/src/crypto/tls/ECPointFormat.cs
new file mode 100644
index 0000000000000000000000000000000000000000..21b0fdd976bff57022dc846bdbc7e0f0289463f7
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/ECPointFormat.cs
@@ -0,0 +1,16 @@
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ ///
+ /// RFC 4492 5.1.2
+ ///
+ public abstract class ECPointFormat
+ {
+ public const byte uncompressed = 0;
+ public const byte ansiX962_compressed_prime = 1;
+ public const byte ansiX962_compressed_char2 = 2;
+
+ /*
+ * reserved (248..255)
+ */
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/EncryptionAlgorithm.cs b/bc-sharp-crypto/src/crypto/tls/EncryptionAlgorithm.cs
new file mode 100644
index 0000000000000000000000000000000000000000..45eef18e37c61f1d66b2a86db52a59e1a18dd82e
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/EncryptionAlgorithm.cs
@@ -0,0 +1,69 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// RFC 2246
+ ///
+ /// Note that the values here are implementation-specific and arbitrary. It is recommended not to
+ /// depend on the particular values (e.g. serialization).
+ ///
+ public abstract class EncryptionAlgorithm
+ {
+ public const int NULL = 0;
+ public const int RC4_40 = 1;
+ public const int RC4_128 = 2;
+ public const int RC2_CBC_40 = 3;
+ public const int IDEA_CBC = 4;
+ public const int DES40_CBC = 5;
+ public const int DES_CBC = 6;
+ public const int cls_3DES_EDE_CBC = 7;
+
+ /*
+ * RFC 3268
+ */
+ public const int AES_128_CBC = 8;
+ public const int AES_256_CBC = 9;
+
+ /*
+ * RFC 5289
+ */
+ public const int AES_128_GCM = 10;
+ public const int AES_256_GCM = 11;
+
+ /*
+ * RFC 4132
+ */
+ public const int CAMELLIA_128_CBC = 12;
+ public const int CAMELLIA_256_CBC = 13;
+
+ /*
+ * RFC 4162
+ */
+ public const int SEED_CBC = 14;
+
+ /*
+ * RFC 6655
+ */
+ public const int AES_128_CCM = 15;
+ public const int AES_128_CCM_8 = 16;
+ public const int AES_256_CCM = 17;
+ public const int AES_256_CCM_8 = 18;
+
+ /*
+ * RFC 6367
+ */
+ public const int CAMELLIA_128_GCM = 19;
+ public const int CAMELLIA_256_GCM = 20;
+
+ /*
+ * RFC 7905
+ */
+ public const int CHACHA20_POLY1305 = 21;
+
+ /*
+ * draft-zauner-tls-aes-ocb-04
+ */
+ public const int AES_128_OCB_TAGLEN96 = 103;
+ public const int AES_256_OCB_TAGLEN96 = 104;
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/ExporterLabel.cs b/bc-sharp-crypto/src/crypto/tls/ExporterLabel.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5970769d78bd8ffe89956549c939b61e5b991070
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/ExporterLabel.cs
@@ -0,0 +1,37 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// RFC 5705
+ public abstract class ExporterLabel
+ {
+ /*
+ * RFC 5246
+ */
+ public const string client_finished = "client finished";
+ public const string server_finished = "server finished";
+ public const string master_secret = "master secret";
+ public const string key_expansion = "key expansion";
+
+ /*
+ * RFC 5216
+ */
+ public const string client_EAP_encryption = "client EAP encryption";
+
+ /*
+ * RFC 5281
+ */
+ public const string ttls_keying_material = "ttls keying material";
+ public const string ttls_challenge = "ttls challenge";
+
+ /*
+ * RFC 5764
+ */
+ public const string dtls_srtp = "EXTRACTOR-dtls_srtp";
+
+ /*
+ * draft-ietf-tls-session-hash-04
+ */
+ public static readonly string extended_master_secret = "extended master secret";
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/ExtensionType.cs b/bc-sharp-crypto/src/crypto/tls/ExtensionType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f17210b807da05a38ca5b3862819eaaad947133b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/ExtensionType.cs
@@ -0,0 +1,128 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class ExtensionType
+ {
+ /*
+ * RFC 2546 2.3.
+ */
+ public const int server_name = 0;
+ public const int max_fragment_length = 1;
+ public const int client_certificate_url = 2;
+ public const int trusted_ca_keys = 3;
+ public const int truncated_hmac = 4;
+ public const int status_request = 5;
+
+ /*
+ * RFC 4681
+ */
+ public const int user_mapping = 6;
+
+ /*
+ * RFC 5878
+ */
+ public const int client_authz = 7;
+ public const int server_authz = 8;
+
+ /*
+ * RFC RFC6091
+ */
+ public const int cert_type = 9;
+
+ /*
+ * draft-ietf-tls-negotiated-ff-dhe-10
+ */
+ public const int supported_groups = 10;
+
+ /*
+ * RFC 4492 5.1.
+ */
+ [Obsolete("Use 'supported_groups' instead")]
+ public const int elliptic_curves = supported_groups;
+ public const int ec_point_formats = 11;
+
+ /*
+ * RFC 5054 2.8.1.
+ */
+ public const int srp = 12;
+
+ /*
+ * RFC 5246 7.4.1.4.
+ */
+ public const int signature_algorithms = 13;
+
+ /*
+ * RFC 5764 9.
+ */
+ public const int use_srtp = 14;
+
+ /*
+ * RFC 6520 6.
+ */
+ public const int heartbeat = 15;
+
+ /*
+ * RFC 7301
+ */
+ public const int application_layer_protocol_negotiation = 16;
+
+ /*
+ * RFC 6961
+ */
+ public const int status_request_v2 = 17;
+
+ /*
+ * RFC 6962
+ */
+ public const int signed_certificate_timestamp = 18;
+
+ /*
+ * RFC 7250
+ */
+ public const int client_certificate_type = 19;
+ public const int server_certificate_type = 20;
+
+ /*
+ * RFC 7685
+ */
+ public const int padding = 21;
+
+ /*
+ * RFC 7366
+ */
+ public const int encrypt_then_mac = 22;
+
+ /*
+ * RFC 7627
+ */
+ public const int extended_master_secret = 23;
+
+ /*
+ * draft-ietf-tokbind-negotiation-08
+ */
+ public static readonly int DRAFT_token_binding = 24;
+
+ /*
+ * RFC 7924
+ */
+ public const int cached_info = 25;
+
+ /*
+ * RFC 5077 7.
+ */
+ public const int session_ticket = 35;
+
+ /*
+ * draft-ietf-tls-negotiated-ff-dhe-01
+ *
+ * WARNING: Placeholder value; the real value is TBA
+ */
+ public static readonly int negotiated_ff_dhe_groups = 101;
+
+ /*
+ * RFC 5746 3.2.
+ */
+ public const int renegotiation_info = 0xff01;
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/FiniteFieldDheGroup.cs b/bc-sharp-crypto/src/crypto/tls/FiniteFieldDheGroup.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4375049416acff90432f03c8e85aca0dbc81e307
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/FiniteFieldDheGroup.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /*
+ * draft-ietf-tls-negotiated-ff-dhe-01
+ */
+ public abstract class FiniteFieldDheGroup
+ {
+ public const byte ffdhe2432 = 0;
+ public const byte ffdhe3072 = 1;
+ public const byte ffdhe4096 = 2;
+ public const byte ffdhe6144 = 3;
+ public const byte ffdhe8192 = 4;
+
+ public static bool IsValid(byte group)
+ {
+ return group >= ffdhe2432 && group <= ffdhe8192;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/HandshakeType.cs b/bc-sharp-crypto/src/crypto/tls/HandshakeType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e63042ac3461853d1789f7410e221b4bd4599656
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/HandshakeType.cs
@@ -0,0 +1,40 @@
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class HandshakeType
+ {
+ /*
+ * RFC 2246 7.4
+ */
+ public const byte hello_request = 0;
+ public const byte client_hello = 1;
+ public const byte server_hello = 2;
+ public const byte certificate = 11;
+ public const byte server_key_exchange = 12;
+ public const byte certificate_request = 13;
+ public const byte server_hello_done = 14;
+ public const byte certificate_verify = 15;
+ public const byte client_key_exchange = 16;
+ public const byte finished = 20;
+
+ /*
+ * RFC 3546 2.4
+ */
+ public const byte certificate_url = 21;
+ public const byte certificate_status = 22;
+
+ /*
+ * (DTLS) RFC 4347 4.3.2
+ */
+ public const byte hello_verify_request = 3;
+
+ /*
+ * RFC 4680
+ */
+ public const byte supplemental_data = 23;
+
+ /*
+ * RFC 5077
+ */
+ public const byte session_ticket = 4;
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/HashAlgorithm.cs b/bc-sharp-crypto/src/crypto/tls/HashAlgorithm.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0f38e2d7c3704c3ac2a9083b2492afd4e9f6d126
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/HashAlgorithm.cs
@@ -0,0 +1,49 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// RFC 5246 7.4.1.4.1
+ public abstract class HashAlgorithm
+ {
+ public const byte none = 0;
+ public const byte md5 = 1;
+ public const byte sha1 = 2;
+ public const byte sha224 = 3;
+ public const byte sha256 = 4;
+ public const byte sha384 = 5;
+ public const byte sha512 = 6;
+
+ public static string GetName(byte hashAlgorithm)
+ {
+ switch (hashAlgorithm)
+ {
+ case none:
+ return "none";
+ case md5:
+ return "md5";
+ case sha1:
+ return "sha1";
+ case sha224:
+ return "sha224";
+ case sha256:
+ return "sha256";
+ case sha384:
+ return "sha384";
+ case sha512:
+ return "sha512";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ public static string GetText(byte hashAlgorithm)
+ {
+ return GetName(hashAlgorithm) + "(" + hashAlgorithm + ")";
+ }
+
+ public static bool IsPrivate(byte hashAlgorithm)
+ {
+ return 224 <= hashAlgorithm && hashAlgorithm <= 255;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/HeartbeatExtension.cs b/bc-sharp-crypto/src/crypto/tls/HeartbeatExtension.cs
new file mode 100644
index 0000000000000000000000000000000000000000..04983726662118e8372be3abe2e566b8970fa141
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/HeartbeatExtension.cs
@@ -0,0 +1,52 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class HeartbeatExtension
+ {
+ protected readonly byte mMode;
+
+ public HeartbeatExtension(byte mode)
+ {
+ if (!HeartbeatMode.IsValid(mode))
+ throw new ArgumentException("not a valid HeartbeatMode value", "mode");
+
+ this.mMode = mode;
+ }
+
+ public virtual byte Mode
+ {
+ get { return mMode; }
+ }
+
+ /**
+ * Encode this {@link HeartbeatExtension} to a {@link Stream}.
+ *
+ * @param output
+ * the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ TlsUtilities.WriteUint8(mMode, output);
+ }
+
+ /**
+ * Parse a {@link HeartbeatExtension} from a {@link Stream}.
+ *
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link HeartbeatExtension} object.
+ * @throws IOException
+ */
+ public static HeartbeatExtension Parse(Stream input)
+ {
+ byte mode = TlsUtilities.ReadUint8(input);
+ if (!HeartbeatMode.IsValid(mode))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ return new HeartbeatExtension(mode);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/HeartbeatMessage.cs b/bc-sharp-crypto/src/crypto/tls/HeartbeatMessage.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3f22f7e1d8c222411513dd664cb5d8d48e7b926a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/HeartbeatMessage.cs
@@ -0,0 +1,109 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class HeartbeatMessage
+ {
+ protected readonly byte mType;
+ protected readonly byte[] mPayload;
+ protected readonly int mPaddingLength;
+
+ public HeartbeatMessage(byte type, byte[] payload, int paddingLength)
+ {
+ if (!HeartbeatMessageType.IsValid(type))
+ throw new ArgumentException("not a valid HeartbeatMessageType value", "type");
+ if (payload == null || payload.Length >= (1 << 16))
+ throw new ArgumentException("must have length < 2^16", "payload");
+ if (paddingLength < 16)
+ throw new ArgumentException("must be at least 16", "paddingLength");
+
+ this.mType = type;
+ this.mPayload = payload;
+ this.mPaddingLength = paddingLength;
+ }
+
+ /**
+ * Encode this {@link HeartbeatMessage} to a {@link Stream}.
+ *
+ * @param output
+ * the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(TlsContext context, Stream output)
+ {
+ TlsUtilities.WriteUint8(mType, output);
+
+ TlsUtilities.CheckUint16(mPayload.Length);
+ TlsUtilities.WriteUint16(mPayload.Length, output);
+ output.Write(mPayload, 0, mPayload.Length);
+
+ byte[] padding = new byte[mPaddingLength];
+ context.NonceRandomGenerator.NextBytes(padding);
+ output.Write(padding, 0, padding.Length);
+ }
+
+ /**
+ * Parse a {@link HeartbeatMessage} from a {@link Stream}.
+ *
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link HeartbeatMessage} object.
+ * @throws IOException
+ */
+ public static HeartbeatMessage Parse(Stream input)
+ {
+ byte type = TlsUtilities.ReadUint8(input);
+ if (!HeartbeatMessageType.IsValid(type))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ int payload_length = TlsUtilities.ReadUint16(input);
+
+ PayloadBuffer buf = new PayloadBuffer();
+ Streams.PipeAll(input, buf);
+
+ byte[] payload = buf.ToTruncatedByteArray(payload_length);
+ if (payload == null)
+ {
+ /*
+ * RFC 6520 4. If the payload_length of a received HeartbeatMessage is too large, the
+ * received HeartbeatMessage MUST be discarded silently.
+ */
+ return null;
+ }
+
+ TlsUtilities.CheckUint16(buf.Length);
+ int padding_length = (int)buf.Length - payload.Length;
+
+ /*
+ * RFC 6520 4. The padding of a received HeartbeatMessage message MUST be ignored
+ */
+ return new HeartbeatMessage(type, payload, padding_length);
+ }
+
+ internal class PayloadBuffer
+ : MemoryStream
+ {
+ internal byte[] ToTruncatedByteArray(int payloadLength)
+ {
+ /*
+ * RFC 6520 4. The padding_length MUST be at least 16.
+ */
+ int minimumCount = payloadLength + 16;
+ if (Length < minimumCount)
+ return null;
+
+#if PORTABLE
+ byte[] buf = ToArray();
+#else
+ byte[] buf = GetBuffer();
+#endif
+
+ return Arrays.CopyOf(buf, payloadLength);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/HeartbeatMessageType.cs b/bc-sharp-crypto/src/crypto/tls/HeartbeatMessageType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..57a4b86be14b9cc5ee9b113b0c4179cf58071ce0
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/HeartbeatMessageType.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /*
+ * RFC 6520 3.
+ */
+ public abstract class HeartbeatMessageType
+ {
+ public const byte heartbeat_request = 1;
+ public const byte heartbeat_response = 2;
+
+ public static bool IsValid(byte heartbeatMessageType)
+ {
+ return heartbeatMessageType >= heartbeat_request && heartbeatMessageType <= heartbeat_response;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/HeartbeatMode.cs b/bc-sharp-crypto/src/crypto/tls/HeartbeatMode.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f1570a84d02c32a149cfafb0c55aa488b36f9e3d
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/HeartbeatMode.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /*
+ * RFC 6520
+ */
+ public abstract class HeartbeatMode
+ {
+ public const byte peer_allowed_to_send = 1;
+ public const byte peer_not_allowed_to_send = 2;
+
+ public static bool IsValid(byte heartbeatMode)
+ {
+ return heartbeatMode >= peer_allowed_to_send && heartbeatMode <= peer_not_allowed_to_send;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/KeyExchangeAlgorithm.cs b/bc-sharp-crypto/src/crypto/tls/KeyExchangeAlgorithm.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9b1b3ba5eee85dbe0c6ca98e948313cfafb55086
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/KeyExchangeAlgorithm.cs
@@ -0,0 +1,54 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// RFC 2246
+ ///
+ /// Note that the values here are implementation-specific and arbitrary. It is recommended not to
+ /// depend on the particular values (e.g. serialization).
+ ///
+ public abstract class KeyExchangeAlgorithm
+ {
+ public const int NULL = 0;
+ public const int RSA = 1;
+ public const int RSA_EXPORT = 2;
+ public const int DHE_DSS = 3;
+ public const int DHE_DSS_EXPORT = 4;
+ public const int DHE_RSA = 5;
+ public const int DHE_RSA_EXPORT = 6;
+ public const int DH_DSS = 7;
+ public const int DH_DSS_EXPORT = 8;
+ public const int DH_RSA = 9;
+ public const int DH_RSA_EXPORT = 10;
+ public const int DH_anon = 11;
+ public const int DH_anon_EXPORT = 12;
+
+ /*
+ * RFC 4279
+ */
+ public const int PSK = 13;
+ public const int DHE_PSK = 14;
+ public const int RSA_PSK = 15;
+
+ /*
+ * RFC 4429
+ */
+ public const int ECDH_ECDSA = 16;
+ public const int ECDHE_ECDSA = 17;
+ public const int ECDH_RSA = 18;
+ public const int ECDHE_RSA = 19;
+ public const int ECDH_anon = 20;
+
+ /*
+ * RFC 5054
+ */
+ public const int SRP = 21;
+ public const int SRP_DSS = 22;
+ public const int SRP_RSA = 23;
+
+ /*
+ * RFC 5489
+ */
+ public const int ECDHE_PSK = 24;
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/MacAlgorithm.cs b/bc-sharp-crypto/src/crypto/tls/MacAlgorithm.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e4aa88de637b3768dd04ae8fc51566d0787708d5
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/MacAlgorithm.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// RFC 2246
+ ///
+ /// Note that the values here are implementation-specific and arbitrary. It is recommended not to
+ /// depend on the particular values (e.g. serialization).
+ ///
+ public abstract class MacAlgorithm
+ {
+ public const int cls_null = 0;
+ public const int md5 = 1;
+ public const int sha = 2;
+
+ /*
+ * RFC 5246
+ */
+ public const int hmac_md5 = md5;
+ public const int hmac_sha1 = sha;
+ public const int hmac_sha256 = 3;
+ public const int hmac_sha384 = 4;
+ public const int hmac_sha512 = 5;
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/MaxFragmentLength.cs b/bc-sharp-crypto/src/crypto/tls/MaxFragmentLength.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5b10b35dd950b5558ec941486cfd870df2c72e4a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/MaxFragmentLength.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class MaxFragmentLength
+ {
+ /*
+ * RFC 3546 3.2.
+ */
+ public const byte pow2_9 = 1;
+ public const byte pow2_10 = 2;
+ public const byte pow2_11 = 3;
+ public const byte pow2_12 = 4;
+
+ public static bool IsValid(byte maxFragmentLength)
+ {
+ return maxFragmentLength >= pow2_9 && maxFragmentLength <= pow2_12;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/NameType.cs b/bc-sharp-crypto/src/crypto/tls/NameType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..78216421549a822eee01e4b2ef6fa0d0fea81f70
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/NameType.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class NameType
+ {
+ /*
+ * RFC 3546 3.1.
+ */
+ public const byte host_name = 0;
+
+ public static bool IsValid(byte nameType)
+ {
+ return nameType == host_name;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/NamedCurve.cs b/bc-sharp-crypto/src/crypto/tls/NamedCurve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b8aa0ecded3a4316ed0ed7811d9fea019b179156
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/NamedCurve.cs
@@ -0,0 +1,77 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ ///
+ /// RFC 4492 5.1.1
+ /// The named curves defined here are those specified in SEC 2 [13]. Note that many of
+ /// these curves are also recommended in ANSI X9.62 [7] and FIPS 186-2 [11]. Values 0xFE00
+ /// through 0xFEFF are reserved for private use. Values 0xFF01 and 0xFF02 indicate that the
+ /// client supports arbitrary prime and characteristic-2 curves, respectively (the curve
+ /// parameters must be encoded explicitly in ECParameters).
+ ///
+ public abstract class NamedCurve
+ {
+ public const int sect163k1 = 1;
+ public const int sect163r1 = 2;
+ public const int sect163r2 = 3;
+ public const int sect193r1 = 4;
+ public const int sect193r2 = 5;
+ public const int sect233k1 = 6;
+ public const int sect233r1 = 7;
+ public const int sect239k1 = 8;
+ public const int sect283k1 = 9;
+ public const int sect283r1 = 10;
+ public const int sect409k1 = 11;
+ public const int sect409r1 = 12;
+ public const int sect571k1 = 13;
+ public const int sect571r1 = 14;
+ public const int secp160k1 = 15;
+ public const int secp160r1 = 16;
+ public const int secp160r2 = 17;
+ public const int secp192k1 = 18;
+ public const int secp192r1 = 19;
+ public const int secp224k1 = 20;
+ public const int secp224r1 = 21;
+ public const int secp256k1 = 22;
+ public const int secp256r1 = 23;
+ public const int secp384r1 = 24;
+ public const int secp521r1 = 25;
+
+ /*
+ * RFC 7027
+ */
+ public const int brainpoolP256r1 = 26;
+ public const int brainpoolP384r1 = 27;
+ public const int brainpoolP512r1 = 28;
+
+ /*
+ * reserved (0xFE00..0xFEFF)
+ */
+
+ public const int arbitrary_explicit_prime_curves = 0xFF01;
+ public const int arbitrary_explicit_char2_curves = 0xFF02;
+
+ public static bool IsValid(int namedCurve)
+ {
+ return (namedCurve >= sect163k1 && namedCurve <= brainpoolP512r1)
+ || (namedCurve >= arbitrary_explicit_prime_curves && namedCurve <= arbitrary_explicit_char2_curves);
+ }
+
+ public static bool RefersToASpecificNamedCurve(int namedCurve)
+ {
+ switch (namedCurve)
+ {
+ case arbitrary_explicit_prime_curves:
+ case arbitrary_explicit_char2_curves:
+ return false;
+ default:
+ return true;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/NewSessionTicket.cs b/bc-sharp-crypto/src/crypto/tls/NewSessionTicket.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a84026b8c0dfe663bcb0acd7edae5f3dd98a5790
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/NewSessionTicket.cs
@@ -0,0 +1,53 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class NewSessionTicket
+ {
+ protected readonly long mTicketLifetimeHint;
+ protected readonly byte[] mTicket;
+
+ public NewSessionTicket(long ticketLifetimeHint, byte[] ticket)
+ {
+ this.mTicketLifetimeHint = ticketLifetimeHint;
+ this.mTicket = ticket;
+ }
+
+ public virtual long TicketLifetimeHint
+ {
+ get { return mTicketLifetimeHint; }
+ }
+
+ public virtual byte[] Ticket
+ {
+ get { return mTicket; }
+ }
+
+ /**
+ * Encode this {@link NewSessionTicket} to a {@link Stream}.
+ *
+ * @param output the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ TlsUtilities.WriteUint32(mTicketLifetimeHint, output);
+ TlsUtilities.WriteOpaque16(mTicket, output);
+ }
+
+ /**
+ * Parse a {@link NewSessionTicket} from a {@link Stream}.
+ *
+ * @param input the {@link Stream} to parse from.
+ * @return a {@link NewSessionTicket} object.
+ * @throws IOException
+ */
+ public static NewSessionTicket Parse(Stream input)
+ {
+ long ticketLifetimeHint = TlsUtilities.ReadUint32(input);
+ byte[] ticket = TlsUtilities.ReadOpaque16(input);
+ return new NewSessionTicket(ticketLifetimeHint, ticket);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/OcspStatusRequest.cs b/bc-sharp-crypto/src/crypto/tls/OcspStatusRequest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d9203a3c44a4344a8920294c11dd45e25ba043f5
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/OcspStatusRequest.cs
@@ -0,0 +1,131 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * RFC 3546 3.6
+ */
+ public class OcspStatusRequest
+ {
+ protected readonly IList mResponderIDList;
+ protected readonly X509Extensions mRequestExtensions;
+
+ /**
+ * @param responderIDList
+ * an {@link IList} of {@link ResponderID}, specifying the list of trusted OCSP
+ * responders. An empty list has the special meaning that the responders are
+ * implicitly known to the server - e.g., by prior arrangement.
+ * @param requestExtensions
+ * OCSP request extensions. A null value means that there are no extensions.
+ */
+ public OcspStatusRequest(IList responderIDList, X509Extensions requestExtensions)
+ {
+ this.mResponderIDList = responderIDList;
+ this.mRequestExtensions = requestExtensions;
+ }
+
+ /**
+ * @return an {@link IList} of {@link ResponderID}
+ */
+ public virtual IList ResponderIDList
+ {
+ get { return mResponderIDList; }
+ }
+
+ /**
+ * @return OCSP request extensions
+ */
+ public virtual X509Extensions RequestExtensions
+ {
+ get { return mRequestExtensions; }
+ }
+
+ /**
+ * Encode this {@link OcspStatusRequest} to a {@link Stream}.
+ *
+ * @param output
+ * the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ if (mResponderIDList == null || mResponderIDList.Count < 1)
+ {
+ TlsUtilities.WriteUint16(0, output);
+ }
+ else
+ {
+ MemoryStream buf = new MemoryStream();
+ for (int i = 0; i < mResponderIDList.Count; ++i)
+ {
+ ResponderID responderID = (ResponderID)mResponderIDList[i];
+ byte[] derEncoding = responderID.GetEncoded(Asn1Encodable.Der);
+ TlsUtilities.WriteOpaque16(derEncoding, buf);
+ }
+ TlsUtilities.CheckUint16(buf.Length);
+ TlsUtilities.WriteUint16((int)buf.Length, output);
+ Streams.WriteBufTo(buf, output);
+ }
+
+ if (mRequestExtensions == null)
+ {
+ TlsUtilities.WriteUint16(0, output);
+ }
+ else
+ {
+ byte[] derEncoding = mRequestExtensions.GetEncoded(Asn1Encodable.Der);
+ TlsUtilities.CheckUint16(derEncoding.Length);
+ TlsUtilities.WriteUint16(derEncoding.Length, output);
+ output.Write(derEncoding, 0, derEncoding.Length);
+ }
+ }
+
+ /**
+ * Parse a {@link OcspStatusRequest} from a {@link Stream}.
+ *
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return an {@link OcspStatusRequest} object.
+ * @throws IOException
+ */
+ public static OcspStatusRequest Parse(Stream input)
+ {
+ IList responderIDList = Platform.CreateArrayList();
+ {
+ int length = TlsUtilities.ReadUint16(input);
+ if (length > 0)
+ {
+ byte[] data = TlsUtilities.ReadFully(length, input);
+ MemoryStream buf = new MemoryStream(data, false);
+ do
+ {
+ byte[] derEncoding = TlsUtilities.ReadOpaque16(buf);
+ ResponderID responderID = ResponderID.GetInstance(TlsUtilities.ReadDerObject(derEncoding));
+ responderIDList.Add(responderID);
+ }
+ while (buf.Position < buf.Length);
+ }
+ }
+
+ X509Extensions requestExtensions = null;
+ {
+ int length = TlsUtilities.ReadUint16(input);
+ if (length > 0)
+ {
+ byte[] derEncoding = TlsUtilities.ReadFully(length, input);
+ requestExtensions = X509Extensions.GetInstance(TlsUtilities.ReadDerObject(derEncoding));
+ }
+ }
+
+ return new OcspStatusRequest(responderIDList, requestExtensions);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/PrfAlgorithm.cs b/bc-sharp-crypto/src/crypto/tls/PrfAlgorithm.cs
new file mode 100644
index 0000000000000000000000000000000000000000..871241bd2122f56a725835e6a136afeb9f4a8112
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/PrfAlgorithm.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// RFC 5246
+ ///
+ /// Note that the values here are implementation-specific and arbitrary. It is recommended not to
+ /// depend on the particular values (e.g. serialization).
+ ///
+ public abstract class PrfAlgorithm
+ {
+ /*
+ * Placeholder to refer to the legacy TLS algorithm
+ */
+ public const int tls_prf_legacy = 0;
+
+ public const int tls_prf_sha256 = 1;
+
+ /*
+ * Implied by RFC 5288
+ */
+ public const int tls_prf_sha384 = 2;
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/ProtocolVersion.cs b/bc-sharp-crypto/src/crypto/tls/ProtocolVersion.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b0d55183a3425e846821c582a2c56d13047f5274
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/ProtocolVersion.cs
@@ -0,0 +1,159 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public sealed class ProtocolVersion
+ {
+ public static readonly ProtocolVersion SSLv3 = new ProtocolVersion(0x0300, "SSL 3.0");
+ public static readonly ProtocolVersion TLSv10 = new ProtocolVersion(0x0301, "TLS 1.0");
+ public static readonly ProtocolVersion TLSv11 = new ProtocolVersion(0x0302, "TLS 1.1");
+ public static readonly ProtocolVersion TLSv12 = new ProtocolVersion(0x0303, "TLS 1.2");
+ public static readonly ProtocolVersion DTLSv10 = new ProtocolVersion(0xFEFF, "DTLS 1.0");
+ public static readonly ProtocolVersion DTLSv12 = new ProtocolVersion(0xFEFD, "DTLS 1.2");
+
+ private readonly int version;
+ private readonly String name;
+
+ private ProtocolVersion(int v, String name)
+ {
+ this.version = v & 0xffff;
+ this.name = name;
+ }
+
+ public int FullVersion
+ {
+ get { return version; }
+ }
+
+ public int MajorVersion
+ {
+ get { return version >> 8; }
+ }
+
+ public int MinorVersion
+ {
+ get { return version & 0xff; }
+ }
+
+ public bool IsDtls
+ {
+ get { return MajorVersion == 0xFE; }
+ }
+
+ public bool IsSsl
+ {
+ get { return this == SSLv3; }
+ }
+
+ public bool IsTls
+ {
+ get { return MajorVersion == 0x03; }
+ }
+
+ public ProtocolVersion GetEquivalentTLSVersion()
+ {
+ if (!IsDtls)
+ {
+ return this;
+ }
+ if (this == DTLSv10)
+ {
+ return TLSv11;
+ }
+ return TLSv12;
+ }
+
+ public bool IsEqualOrEarlierVersionOf(ProtocolVersion version)
+ {
+ if (MajorVersion != version.MajorVersion)
+ {
+ return false;
+ }
+ int diffMinorVersion = version.MinorVersion - MinorVersion;
+ return IsDtls ? diffMinorVersion <= 0 : diffMinorVersion >= 0;
+ }
+
+ public bool IsLaterVersionOf(ProtocolVersion version)
+ {
+ if (MajorVersion != version.MajorVersion)
+ {
+ return false;
+ }
+ int diffMinorVersion = version.MinorVersion - MinorVersion;
+ return IsDtls ? diffMinorVersion > 0 : diffMinorVersion < 0;
+ }
+
+ public override bool Equals(object other)
+ {
+ return this == other || (other is ProtocolVersion && Equals((ProtocolVersion)other));
+ }
+
+ public bool Equals(ProtocolVersion other)
+ {
+ return other != null && this.version == other.version;
+ }
+
+ public override int GetHashCode()
+ {
+ return version;
+ }
+
+ ///
+ public static ProtocolVersion Get(int major, int minor)
+ {
+ switch (major)
+ {
+ case 0x03:
+ {
+ switch (minor)
+ {
+ case 0x00:
+ return SSLv3;
+ case 0x01:
+ return TLSv10;
+ case 0x02:
+ return TLSv11;
+ case 0x03:
+ return TLSv12;
+ }
+ return GetUnknownVersion(major, minor, "TLS");
+ }
+ case 0xFE:
+ {
+ switch (minor)
+ {
+ case 0xFF:
+ return DTLSv10;
+ case 0xFE:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ case 0xFD:
+ return DTLSv12;
+ }
+ return GetUnknownVersion(major, minor, "DTLS");
+ }
+ default:
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+ }
+
+ public override string ToString()
+ {
+ return name;
+ }
+
+ private static ProtocolVersion GetUnknownVersion(int major, int minor, string prefix)
+ {
+ TlsUtilities.CheckUint8(major);
+ TlsUtilities.CheckUint8(minor);
+
+ int v = (major << 8) | minor;
+ String hex = Platform.ToUpperInvariant(Convert.ToString(0x10000 | v, 16).Substring(1));
+ return new ProtocolVersion(v, prefix + " 0x" + hex);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/PskTlsClient.cs b/bc-sharp-crypto/src/crypto/tls/PskTlsClient.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2ef80dcfd873710ed4d40ceb4b733266ebf2d458
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/PskTlsClient.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class PskTlsClient
+ : AbstractTlsClient
+ {
+ protected TlsPskIdentity mPskIdentity;
+
+ public PskTlsClient(TlsPskIdentity pskIdentity)
+ : this(new DefaultTlsCipherFactory(), pskIdentity)
+ {
+ }
+
+ public PskTlsClient(TlsCipherFactory cipherFactory, TlsPskIdentity pskIdentity)
+ : base(cipherFactory)
+ {
+ this.mPskIdentity = pskIdentity;
+ }
+
+ public override int[] GetCipherSuites()
+ {
+ return new int[]
+ {
+ CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA
+ };
+ }
+
+ public override TlsKeyExchange GetKeyExchange()
+ {
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
+
+ switch (keyExchangeAlgorithm)
+ {
+ case KeyExchangeAlgorithm.DHE_PSK:
+ case KeyExchangeAlgorithm.ECDHE_PSK:
+ case KeyExchangeAlgorithm.PSK:
+ case KeyExchangeAlgorithm.RSA_PSK:
+ return CreatePskKeyExchange(keyExchangeAlgorithm);
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocol implementation verifies that the
+ * server-selected cipher suite was in the list of client-offered cipher suites, so if
+ * we now can't produce an implementation, we shouldn't have offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public override TlsAuthentication GetAuthentication()
+ {
+ /*
+ * Note: This method is not called unless a server certificate is sent, which may be the
+ * case e.g. for RSA_PSK key exchange.
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ protected virtual TlsKeyExchange CreatePskKeyExchange(int keyExchange)
+ {
+ return new TlsPskKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mPskIdentity, null, null, mNamedCurves,
+ mClientECPointFormats, mServerECPointFormats);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/PskTlsServer.cs b/bc-sharp-crypto/src/crypto/tls/PskTlsServer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b0fb67c04b0fbe8e445c57202e4562586c7727f3
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/PskTlsServer.cs
@@ -0,0 +1,93 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class PskTlsServer
+ : AbstractTlsServer
+ {
+ protected TlsPskIdentityManager mPskIdentityManager;
+
+ public PskTlsServer(TlsPskIdentityManager pskIdentityManager)
+ : this(new DefaultTlsCipherFactory(), pskIdentityManager)
+ {
+ }
+
+ public PskTlsServer(TlsCipherFactory cipherFactory, TlsPskIdentityManager pskIdentityManager)
+ : base(cipherFactory)
+ {
+ this.mPskIdentityManager = pskIdentityManager;
+ }
+
+ protected virtual TlsEncryptionCredentials GetRsaEncryptionCredentials()
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ protected virtual DHParameters GetDHParameters()
+ {
+ return DHStandardGroups.rfc7919_ffdhe2048;
+ }
+
+ protected override int[] GetCipherSuites()
+ {
+ return new int[]
+ {
+ CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
+ CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA
+ };
+ }
+
+ public override TlsCredentials GetCredentials()
+ {
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
+
+ switch (keyExchangeAlgorithm)
+ {
+ case KeyExchangeAlgorithm.DHE_PSK:
+ case KeyExchangeAlgorithm.ECDHE_PSK:
+ case KeyExchangeAlgorithm.PSK:
+ return null;
+
+ case KeyExchangeAlgorithm.RSA_PSK:
+ return GetRsaEncryptionCredentials();
+
+ default:
+ /* Note: internal error here; selected a key exchange we don't implement! */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public override TlsKeyExchange GetKeyExchange()
+ {
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
+
+ switch (keyExchangeAlgorithm)
+ {
+ case KeyExchangeAlgorithm.DHE_PSK:
+ case KeyExchangeAlgorithm.ECDHE_PSK:
+ case KeyExchangeAlgorithm.PSK:
+ case KeyExchangeAlgorithm.RSA_PSK:
+ return CreatePskKeyExchange(keyExchangeAlgorithm);
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocol implementation verifies that the
+ * server-selected cipher suite was in the list of client-offered cipher suites, so if
+ * we now can't produce an implementation, we shouldn't have offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ protected virtual TlsKeyExchange CreatePskKeyExchange(int keyExchange)
+ {
+ return new TlsPskKeyExchange(keyExchange, mSupportedSignatureAlgorithms, null, mPskIdentityManager,
+ GetDHParameters(), mNamedCurves, mClientECPointFormats, mServerECPointFormats);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/RecordStream.cs b/bc-sharp-crypto/src/crypto/tls/RecordStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5d556ad0660b968f736b84ea6d822175b5d51402
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/RecordStream.cs
@@ -0,0 +1,412 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// An implementation of the TLS 1.0/1.1/1.2 record layer, allowing downgrade to SSLv3.
+ internal class RecordStream
+ {
+ private const int DEFAULT_PLAINTEXT_LIMIT = (1 << 14);
+
+ internal const int TLS_HEADER_SIZE = 5;
+ internal const int TLS_HEADER_TYPE_OFFSET = 0;
+ internal const int TLS_HEADER_VERSION_OFFSET = 1;
+ internal const int TLS_HEADER_LENGTH_OFFSET = 3;
+
+ private TlsProtocol mHandler;
+ private Stream mInput;
+ private Stream mOutput;
+ private TlsCompression mPendingCompression = null, mReadCompression = null, mWriteCompression = null;
+ private TlsCipher mPendingCipher = null, mReadCipher = null, mWriteCipher = null;
+ private SequenceNumber mReadSeqNo = new SequenceNumber(), mWriteSeqNo = new SequenceNumber();
+ private MemoryStream mBuffer = new MemoryStream();
+
+ private TlsHandshakeHash mHandshakeHash = null;
+ private readonly BaseOutputStream mHandshakeHashUpdater;
+
+ private ProtocolVersion mReadVersion = null, mWriteVersion = null;
+ private bool mRestrictReadVersion = true;
+
+ private int mPlaintextLimit, mCompressedLimit, mCiphertextLimit;
+
+ internal RecordStream(TlsProtocol handler, Stream input, Stream output)
+ {
+ this.mHandler = handler;
+ this.mInput = input;
+ this.mOutput = output;
+ this.mReadCompression = new TlsNullCompression();
+ this.mWriteCompression = this.mReadCompression;
+ this.mHandshakeHashUpdater = new HandshakeHashUpdateStream(this);
+ }
+
+ internal virtual void Init(TlsContext context)
+ {
+ this.mReadCipher = new TlsNullCipher(context);
+ this.mWriteCipher = this.mReadCipher;
+ this.mHandshakeHash = new DeferredHash();
+ this.mHandshakeHash.Init(context);
+
+ SetPlaintextLimit(DEFAULT_PLAINTEXT_LIMIT);
+ }
+
+ internal virtual int GetPlaintextLimit()
+ {
+ return mPlaintextLimit;
+ }
+
+ internal virtual void SetPlaintextLimit(int plaintextLimit)
+ {
+ this.mPlaintextLimit = plaintextLimit;
+ this.mCompressedLimit = this.mPlaintextLimit + 1024;
+ this.mCiphertextLimit = this.mCompressedLimit + 1024;
+ }
+
+ internal virtual ProtocolVersion ReadVersion
+ {
+ get { return mReadVersion; }
+ set { this.mReadVersion = value; }
+ }
+
+ internal virtual void SetWriteVersion(ProtocolVersion writeVersion)
+ {
+ this.mWriteVersion = writeVersion;
+ }
+
+ /**
+ * RFC 5246 E.1. "Earlier versions of the TLS specification were not fully clear on what the
+ * record layer version number (TLSPlaintext.version) should contain when sending ClientHello
+ * (i.e., before it is known which version of the protocol will be employed). Thus, TLS servers
+ * compliant with this specification MUST accept any value {03,XX} as the record layer version
+ * number for ClientHello."
+ */
+ internal virtual void SetRestrictReadVersion(bool enabled)
+ {
+ this.mRestrictReadVersion = enabled;
+ }
+
+ internal virtual void SetPendingConnectionState(TlsCompression tlsCompression, TlsCipher tlsCipher)
+ {
+ this.mPendingCompression = tlsCompression;
+ this.mPendingCipher = tlsCipher;
+ }
+
+ internal virtual void SentWriteCipherSpec()
+ {
+ if (mPendingCompression == null || mPendingCipher == null)
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+
+ this.mWriteCompression = this.mPendingCompression;
+ this.mWriteCipher = this.mPendingCipher;
+ this.mWriteSeqNo = new SequenceNumber();
+ }
+
+ internal virtual void ReceivedReadCipherSpec()
+ {
+ if (mPendingCompression == null || mPendingCipher == null)
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+
+ this.mReadCompression = this.mPendingCompression;
+ this.mReadCipher = this.mPendingCipher;
+ this.mReadSeqNo = new SequenceNumber();
+ }
+
+ internal virtual void FinaliseHandshake()
+ {
+ if (mReadCompression != mPendingCompression || mWriteCompression != mPendingCompression
+ || mReadCipher != mPendingCipher || mWriteCipher != mPendingCipher)
+ {
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+ this.mPendingCompression = null;
+ this.mPendingCipher = null;
+ }
+
+ internal virtual void CheckRecordHeader(byte[] recordHeader)
+ {
+ byte type = TlsUtilities.ReadUint8(recordHeader, TLS_HEADER_TYPE_OFFSET);
+
+ /*
+ * RFC 5246 6. If a TLS implementation receives an unexpected record type, it MUST send an
+ * unexpected_message alert.
+ */
+ CheckType(type, AlertDescription.unexpected_message);
+
+ if (!mRestrictReadVersion)
+ {
+ int version = TlsUtilities.ReadVersionRaw(recordHeader, TLS_HEADER_VERSION_OFFSET);
+ if ((version & 0xffffff00) != 0x0300)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ else
+ {
+ ProtocolVersion version = TlsUtilities.ReadVersion(recordHeader, TLS_HEADER_VERSION_OFFSET);
+ if (mReadVersion == null)
+ {
+ // Will be set later in 'readRecord'
+ }
+ else if (!version.Equals(mReadVersion))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+
+ int length = TlsUtilities.ReadUint16(recordHeader, TLS_HEADER_LENGTH_OFFSET);
+
+ CheckLength(length, mCiphertextLimit, AlertDescription.record_overflow);
+ }
+
+ internal virtual bool ReadRecord()
+ {
+ byte[] recordHeader = TlsUtilities.ReadAllOrNothing(TLS_HEADER_SIZE, mInput);
+ if (recordHeader == null)
+ return false;
+
+ byte type = TlsUtilities.ReadUint8(recordHeader, TLS_HEADER_TYPE_OFFSET);
+
+ /*
+ * RFC 5246 6. If a TLS implementation receives an unexpected record type, it MUST send an
+ * unexpected_message alert.
+ */
+ CheckType(type, AlertDescription.unexpected_message);
+
+ if (!mRestrictReadVersion)
+ {
+ int version = TlsUtilities.ReadVersionRaw(recordHeader, TLS_HEADER_VERSION_OFFSET);
+ if ((version & 0xffffff00) != 0x0300)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ else
+ {
+ ProtocolVersion version = TlsUtilities.ReadVersion(recordHeader, TLS_HEADER_VERSION_OFFSET);
+ if (mReadVersion == null)
+ {
+ mReadVersion = version;
+ }
+ else if (!version.Equals(mReadVersion))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+
+ int length = TlsUtilities.ReadUint16(recordHeader, TLS_HEADER_LENGTH_OFFSET);
+
+ CheckLength(length, mCiphertextLimit, AlertDescription.record_overflow);
+
+ byte[] plaintext = DecodeAndVerify(type, mInput, length);
+ mHandler.ProcessRecord(type, plaintext, 0, plaintext.Length);
+ return true;
+ }
+
+ internal virtual byte[] DecodeAndVerify(byte type, Stream input, int len)
+ {
+ byte[] buf = TlsUtilities.ReadFully(len, input);
+
+ long seqNo = mReadSeqNo.NextValue(AlertDescription.unexpected_message);
+ byte[] decoded = mReadCipher.DecodeCiphertext(seqNo, type, buf, 0, buf.Length);
+
+ CheckLength(decoded.Length, mCompressedLimit, AlertDescription.record_overflow);
+
+ /*
+ * TODO 5246 6.2.2. Implementation note: Decompression functions are responsible for
+ * ensuring that messages cannot cause internal buffer overflows.
+ */
+ Stream cOut = mReadCompression.Decompress(mBuffer);
+ if (cOut != mBuffer)
+ {
+ cOut.Write(decoded, 0, decoded.Length);
+ cOut.Flush();
+ decoded = GetBufferContents();
+ }
+
+ /*
+ * RFC 5246 6.2.2. If the decompression function encounters a TLSCompressed.fragment that
+ * would decompress to a length in excess of 2^14 bytes, it should report a fatal
+ * decompression failure error.
+ */
+ CheckLength(decoded.Length, mPlaintextLimit, AlertDescription.decompression_failure);
+
+ /*
+ * RFC 5246 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert,
+ * or ChangeCipherSpec content types.
+ */
+ if (decoded.Length < 1 && type != ContentType.application_data)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ return decoded;
+ }
+
+ internal virtual void WriteRecord(byte type, byte[] plaintext, int plaintextOffset, int plaintextLength)
+ {
+ // Never send anything until a valid ClientHello has been received
+ if (mWriteVersion == null)
+ return;
+
+ /*
+ * RFC 5246 6. Implementations MUST NOT send record types not defined in this document
+ * unless negotiated by some extension.
+ */
+ CheckType(type, AlertDescription.internal_error);
+
+ /*
+ * RFC 5246 6.2.1 The length should not exceed 2^14.
+ */
+ CheckLength(plaintextLength, mPlaintextLimit, AlertDescription.internal_error);
+
+ /*
+ * RFC 5246 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert,
+ * or ChangeCipherSpec content types.
+ */
+ if (plaintextLength < 1 && type != ContentType.application_data)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ Stream cOut = mWriteCompression.Compress(mBuffer);
+
+ long seqNo = mWriteSeqNo.NextValue(AlertDescription.internal_error);
+
+ byte[] ciphertext;
+ if (cOut == mBuffer)
+ {
+ ciphertext = mWriteCipher.EncodePlaintext(seqNo, type, plaintext, plaintextOffset, plaintextLength);
+ }
+ else
+ {
+ cOut.Write(plaintext, plaintextOffset, plaintextLength);
+ cOut.Flush();
+ byte[] compressed = GetBufferContents();
+
+ /*
+ * RFC 5246 6.2.2. Compression must be lossless and may not increase the content length
+ * by more than 1024 bytes.
+ */
+ CheckLength(compressed.Length, plaintextLength + 1024, AlertDescription.internal_error);
+
+ ciphertext = mWriteCipher.EncodePlaintext(seqNo, type, compressed, 0, compressed.Length);
+ }
+
+ /*
+ * RFC 5246 6.2.3. The length may not exceed 2^14 + 2048.
+ */
+ CheckLength(ciphertext.Length, mCiphertextLimit, AlertDescription.internal_error);
+
+ byte[] record = new byte[ciphertext.Length + TLS_HEADER_SIZE];
+ TlsUtilities.WriteUint8(type, record, TLS_HEADER_TYPE_OFFSET);
+ TlsUtilities.WriteVersion(mWriteVersion, record, TLS_HEADER_VERSION_OFFSET);
+ TlsUtilities.WriteUint16(ciphertext.Length, record, TLS_HEADER_LENGTH_OFFSET);
+ Array.Copy(ciphertext, 0, record, TLS_HEADER_SIZE, ciphertext.Length);
+ mOutput.Write(record, 0, record.Length);
+ mOutput.Flush();
+ }
+
+ internal virtual void NotifyHelloComplete()
+ {
+ this.mHandshakeHash = mHandshakeHash.NotifyPrfDetermined();
+ }
+
+ internal virtual TlsHandshakeHash HandshakeHash
+ {
+ get { return mHandshakeHash; }
+ }
+
+ internal virtual Stream HandshakeHashUpdater
+ {
+ get { return mHandshakeHashUpdater; }
+ }
+
+ internal virtual TlsHandshakeHash PrepareToFinish()
+ {
+ TlsHandshakeHash result = mHandshakeHash;
+ this.mHandshakeHash = mHandshakeHash.StopTracking();
+ return result;
+ }
+
+ internal virtual void SafeClose()
+ {
+ try
+ {
+ Platform.Dispose(mInput);
+ }
+ catch (IOException)
+ {
+ }
+
+ try
+ {
+ Platform.Dispose(mOutput);
+ }
+ catch (IOException)
+ {
+ }
+ }
+
+ internal virtual void Flush()
+ {
+ mOutput.Flush();
+ }
+
+ private byte[] GetBufferContents()
+ {
+ byte[] contents = mBuffer.ToArray();
+ mBuffer.SetLength(0);
+ return contents;
+ }
+
+ private static void CheckType(byte type, byte alertDescription)
+ {
+ switch (type)
+ {
+ case ContentType.application_data:
+ case ContentType.alert:
+ case ContentType.change_cipher_spec:
+ case ContentType.handshake:
+ //case ContentType.heartbeat:
+ break;
+ default:
+ throw new TlsFatalAlert(alertDescription);
+ }
+ }
+
+ private static void CheckLength(int length, int limit, byte alertDescription)
+ {
+ if (length > limit)
+ throw new TlsFatalAlert(alertDescription);
+ }
+
+ private class HandshakeHashUpdateStream
+ : BaseOutputStream
+ {
+ private readonly RecordStream mOuter;
+ public HandshakeHashUpdateStream(RecordStream mOuter)
+ {
+ this.mOuter = mOuter;
+ }
+
+ public override void Write(byte[] buf, int off, int len)
+ {
+ mOuter.mHandshakeHash.BlockUpdate(buf, off, len);
+ }
+ }
+
+ private class SequenceNumber
+ {
+ private long value = 0L;
+ private bool exhausted = false;
+
+ internal long NextValue(byte alertDescription)
+ {
+ if (exhausted)
+ {
+ throw new TlsFatalAlert(alertDescription);
+ }
+ long result = value;
+ if (++value == 0)
+ {
+ exhausted = true;
+ }
+ return result;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/SecurityParameters.cs b/bc-sharp-crypto/src/crypto/tls/SecurityParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3b851587d54b4393e8a862c622bf2c13a354f270
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/SecurityParameters.cs
@@ -0,0 +1,103 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class SecurityParameters
+ {
+ internal int entity = -1;
+ internal int cipherSuite = -1;
+ internal byte compressionAlgorithm = CompressionMethod.cls_null;
+ internal int prfAlgorithm = -1;
+ internal int verifyDataLength = -1;
+ internal byte[] masterSecret = null;
+ internal byte[] clientRandom = null;
+ internal byte[] serverRandom = null;
+ internal byte[] sessionHash = null;
+ internal byte[] pskIdentity = null;
+ internal byte[] srpIdentity = null;
+
+ // TODO Keep these internal, since it's maybe not the ideal place for them
+ internal short maxFragmentLength = -1;
+ internal bool truncatedHMac = false;
+ internal bool encryptThenMac = false;
+ internal bool extendedMasterSecret = false;
+
+ internal virtual void Clear()
+ {
+ if (this.masterSecret != null)
+ {
+ Arrays.Fill(this.masterSecret, (byte)0);
+ this.masterSecret = null;
+ }
+ }
+
+ /**
+ * @return {@link ConnectionEnd}
+ */
+ public virtual int Entity
+ {
+ get { return entity; }
+ }
+
+ /**
+ * @return {@link CipherSuite}
+ */
+ public virtual int CipherSuite
+ {
+ get { return cipherSuite; }
+ }
+
+ /**
+ * @return {@link CompressionMethod}
+ */
+ public byte CompressionAlgorithm
+ {
+ get { return compressionAlgorithm; }
+ }
+
+ /**
+ * @return {@link PRFAlgorithm}
+ */
+ public virtual int PrfAlgorithm
+ {
+ get { return prfAlgorithm; }
+ }
+
+ public virtual int VerifyDataLength
+ {
+ get { return verifyDataLength; }
+ }
+
+ public virtual byte[] MasterSecret
+ {
+ get { return masterSecret; }
+ }
+
+ public virtual byte[] ClientRandom
+ {
+ get { return clientRandom; }
+ }
+
+ public virtual byte[] ServerRandom
+ {
+ get { return serverRandom; }
+ }
+
+ public virtual byte[] SessionHash
+ {
+ get { return sessionHash; }
+ }
+
+ public virtual byte[] PskIdentity
+ {
+ get { return pskIdentity; }
+ }
+
+ public virtual byte[] SrpIdentity
+ {
+ get { return srpIdentity; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/ServerDHParams.cs b/bc-sharp-crypto/src/crypto/tls/ServerDHParams.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b09262771cda3b0b01c7f053afeb26e2cb7db2dc
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/ServerDHParams.cs
@@ -0,0 +1,61 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class ServerDHParams
+ {
+ protected readonly DHPublicKeyParameters mPublicKey;
+
+ public ServerDHParams(DHPublicKeyParameters publicKey)
+ {
+ if (publicKey == null)
+ throw new ArgumentNullException("publicKey");
+
+ this.mPublicKey = publicKey;
+ }
+
+ public virtual DHPublicKeyParameters PublicKey
+ {
+ get { return mPublicKey; }
+ }
+
+ /**
+ * Encode this {@link ServerDHParams} to a {@link Stream}.
+ *
+ * @param output
+ * the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ DHParameters dhParameters = mPublicKey.Parameters;
+ BigInteger Ys = mPublicKey.Y;
+
+ TlsDHUtilities.WriteDHParameter(dhParameters.P, output);
+ TlsDHUtilities.WriteDHParameter(dhParameters.G, output);
+ TlsDHUtilities.WriteDHParameter(Ys, output);
+ }
+
+ /**
+ * Parse a {@link ServerDHParams} from a {@link Stream}.
+ *
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link ServerDHParams} object.
+ * @throws IOException
+ */
+ public static ServerDHParams Parse(Stream input)
+ {
+ BigInteger p = TlsDHUtilities.ReadDHParameter(input);
+ BigInteger g = TlsDHUtilities.ReadDHParameter(input);
+ BigInteger Ys = TlsDHUtilities.ReadDHParameter(input);
+
+ return new ServerDHParams(
+ TlsDHUtilities.ValidateDHPublicKey(new DHPublicKeyParameters(Ys, new DHParameters(p, g))));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/ServerName.cs b/bc-sharp-crypto/src/crypto/tls/ServerName.cs
new file mode 100644
index 0000000000000000000000000000000000000000..508c2ddbcccb216a4493c54c562c1e170094b8e2
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/ServerName.cs
@@ -0,0 +1,105 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class ServerName
+ {
+ protected readonly byte mNameType;
+ protected readonly object mName;
+
+ public ServerName(byte nameType, object name)
+ {
+ if (!IsCorrectType(nameType, name))
+ throw new ArgumentException("not an instance of the correct type", "name");
+
+ this.mNameType = nameType;
+ this.mName = name;
+ }
+
+ public virtual byte NameType
+ {
+ get { return mNameType; }
+ }
+
+ public virtual object Name
+ {
+ get { return mName; }
+ }
+
+ public virtual string GetHostName()
+ {
+ if (!IsCorrectType(Tls.NameType.host_name, mName))
+ throw new InvalidOperationException("'name' is not a HostName string");
+
+ return (string)mName;
+ }
+
+ /**
+ * Encode this {@link ServerName} to a {@link Stream}.
+ *
+ * @param output
+ * the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ TlsUtilities.WriteUint8(mNameType, output);
+
+ switch (mNameType)
+ {
+ case Tls.NameType.host_name:
+ byte[] asciiEncoding = Strings.ToAsciiByteArray((string)mName);
+ if (asciiEncoding.Length < 1)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ TlsUtilities.WriteOpaque16(asciiEncoding, output);
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ /**
+ * Parse a {@link ServerName} from a {@link Stream}.
+ *
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link ServerName} object.
+ * @throws IOException
+ */
+ public static ServerName Parse(Stream input)
+ {
+ byte name_type = TlsUtilities.ReadUint8(input);
+ object name;
+
+ switch (name_type)
+ {
+ case Tls.NameType.host_name:
+ {
+ byte[] asciiEncoding = TlsUtilities.ReadOpaque16(input);
+ if (asciiEncoding.Length < 1)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ name = Strings.FromAsciiByteArray(asciiEncoding);
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ }
+
+ return new ServerName(name_type, name);
+ }
+
+ protected static bool IsCorrectType(byte nameType, object name)
+ {
+ switch (nameType)
+ {
+ case Tls.NameType.host_name:
+ return name is string;
+ default:
+ throw new ArgumentException("unsupported value", "name");
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/ServerNameList.cs b/bc-sharp-crypto/src/crypto/tls/ServerNameList.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ed4e59359192356a2feb2141ee99565fe800d996
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/ServerNameList.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class ServerNameList
+ {
+ protected readonly IList mServerNameList;
+
+ /**
+ * @param serverNameList an {@link IList} of {@link ServerName}.
+ */
+ public ServerNameList(IList serverNameList)
+ {
+ if (serverNameList == null)
+ throw new ArgumentNullException("serverNameList");
+
+ this.mServerNameList = serverNameList;
+ }
+
+ /**
+ * @return an {@link IList} of {@link ServerName}.
+ */
+ public virtual IList ServerNames
+ {
+ get { return mServerNameList; }
+ }
+
+ /**
+ * Encode this {@link ServerNameList} to a {@link Stream}.
+ *
+ * @param output
+ * the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ MemoryStream buf = new MemoryStream();
+
+ byte[] nameTypesSeen = TlsUtilities.EmptyBytes;
+ foreach (ServerName entry in ServerNames)
+ {
+ nameTypesSeen = CheckNameType(nameTypesSeen, entry.NameType);
+ if (nameTypesSeen == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ entry.Encode(buf);
+ }
+
+ TlsUtilities.CheckUint16(buf.Length);
+ TlsUtilities.WriteUint16((int)buf.Length, output);
+ Streams.WriteBufTo(buf, output);
+ }
+
+ /**
+ * Parse a {@link ServerNameList} from a {@link Stream}.
+ *
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link ServerNameList} object.
+ * @throws IOException
+ */
+ public static ServerNameList Parse(Stream input)
+ {
+ int length = TlsUtilities.ReadUint16(input);
+ if (length < 1)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ byte[] data = TlsUtilities.ReadFully(length, input);
+
+ MemoryStream buf = new MemoryStream(data, false);
+
+ byte[] nameTypesSeen = TlsUtilities.EmptyBytes;
+ IList server_name_list = Platform.CreateArrayList();
+ while (buf.Position < buf.Length)
+ {
+ ServerName entry = ServerName.Parse(buf);
+
+ nameTypesSeen = CheckNameType(nameTypesSeen, entry.NameType);
+ if (nameTypesSeen == null)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ server_name_list.Add(entry);
+ }
+
+ return new ServerNameList(server_name_list);
+ }
+
+ private static byte[] CheckNameType(byte[] nameTypesSeen, byte nameType)
+ {
+ /*
+ * RFC 6066 3. The ServerNameList MUST NOT contain more than one name of the same
+ * name_type.
+ */
+ if (!NameType.IsValid(nameType) || Arrays.Contains(nameTypesSeen, nameType))
+ return null;
+
+ return Arrays.Append(nameTypesSeen, nameType);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/ServerOnlyTlsAuthentication.cs b/bc-sharp-crypto/src/crypto/tls/ServerOnlyTlsAuthentication.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4858897098a8ec8dac903251fac06e6123f958c7
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/ServerOnlyTlsAuthentication.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class ServerOnlyTlsAuthentication
+ : TlsAuthentication
+ {
+ public abstract void NotifyServerCertificate(Certificate serverCertificate);
+
+ public TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
+ {
+ return null;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/ServerSrpParams.cs b/bc-sharp-crypto/src/crypto/tls/ServerSrpParams.cs
new file mode 100644
index 0000000000000000000000000000000000000000..556ac531034f8135a82776db0555e1b81146cafd
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/ServerSrpParams.cs
@@ -0,0 +1,75 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class ServerSrpParams
+ {
+ protected BigInteger m_N, m_g, m_B;
+ protected byte[] m_s;
+
+ public ServerSrpParams(BigInteger N, BigInteger g, byte[] s, BigInteger B)
+ {
+ this.m_N = N;
+ this.m_g = g;
+ this.m_s = Arrays.Clone(s);
+ this.m_B = B;
+ }
+
+ public virtual BigInteger B
+ {
+ get { return m_B; }
+ }
+
+ public virtual BigInteger G
+ {
+ get { return m_g; }
+ }
+
+ public virtual BigInteger N
+ {
+ get { return m_N; }
+ }
+
+ public virtual byte[] S
+ {
+ get { return m_s; }
+ }
+
+ /**
+ * Encode this {@link ServerSRPParams} to an {@link OutputStream}.
+ *
+ * @param output
+ * the {@link OutputStream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ TlsSrpUtilities.WriteSrpParameter(m_N, output);
+ TlsSrpUtilities.WriteSrpParameter(m_g, output);
+ TlsUtilities.WriteOpaque8(m_s, output);
+ TlsSrpUtilities.WriteSrpParameter(m_B, output);
+ }
+
+ /**
+ * Parse a {@link ServerSRPParams} from an {@link InputStream}.
+ *
+ * @param input
+ * the {@link InputStream} to parse from.
+ * @return a {@link ServerSRPParams} object.
+ * @throws IOException
+ */
+ public static ServerSrpParams Parse(Stream input)
+ {
+ BigInteger N = TlsSrpUtilities.ReadSrpParameter(input);
+ BigInteger g = TlsSrpUtilities.ReadSrpParameter(input);
+ byte[] s = TlsUtilities.ReadOpaque8(input);
+ BigInteger B = TlsSrpUtilities.ReadSrpParameter(input);
+
+ return new ServerSrpParams(N, g, s, B);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/SessionParameters.cs b/bc-sharp-crypto/src/crypto/tls/SessionParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a1eb5f27c5ee09a41e551b23733d8d492604d8ee
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/SessionParameters.cs
@@ -0,0 +1,165 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public sealed class SessionParameters
+ {
+ public sealed class Builder
+ {
+ private int mCipherSuite = -1;
+ private short mCompressionAlgorithm = -1;
+ private byte[] mMasterSecret = null;
+ private Certificate mPeerCertificate = null;
+ private byte[] mPskIdentity = null;
+ private byte[] mSrpIdentity = null;
+ private byte[] mEncodedServerExtensions = null;
+
+ public Builder()
+ {
+ }
+
+ public SessionParameters Build()
+ {
+ Validate(this.mCipherSuite >= 0, "cipherSuite");
+ Validate(this.mCompressionAlgorithm >= 0, "compressionAlgorithm");
+ Validate(this.mMasterSecret != null, "masterSecret");
+ return new SessionParameters(mCipherSuite, (byte)mCompressionAlgorithm, mMasterSecret, mPeerCertificate,
+ mPskIdentity, mSrpIdentity, mEncodedServerExtensions);
+ }
+
+ public Builder SetCipherSuite(int cipherSuite)
+ {
+ this.mCipherSuite = cipherSuite;
+ return this;
+ }
+
+ public Builder SetCompressionAlgorithm(byte compressionAlgorithm)
+ {
+ this.mCompressionAlgorithm = compressionAlgorithm;
+ return this;
+ }
+
+ public Builder SetMasterSecret(byte[] masterSecret)
+ {
+ this.mMasterSecret = masterSecret;
+ return this;
+ }
+
+ public Builder SetPeerCertificate(Certificate peerCertificate)
+ {
+ this.mPeerCertificate = peerCertificate;
+ return this;
+ }
+
+ public Builder SetPskIdentity(byte[] pskIdentity)
+ {
+ this.mPskIdentity = pskIdentity;
+ return this;
+ }
+
+ public Builder SetSrpIdentity(byte[] srpIdentity)
+ {
+ this.mSrpIdentity = srpIdentity;
+ return this;
+ }
+
+ public Builder SetServerExtensions(IDictionary serverExtensions)
+ {
+ if (serverExtensions == null)
+ {
+ mEncodedServerExtensions = null;
+ }
+ else
+ {
+ MemoryStream buf = new MemoryStream();
+ TlsProtocol.WriteExtensions(buf, serverExtensions);
+ mEncodedServerExtensions = buf.ToArray();
+ }
+ return this;
+ }
+
+ private void Validate(bool condition, string parameter)
+ {
+ if (!condition)
+ throw new InvalidOperationException("Required session parameter '" + parameter + "' not configured");
+ }
+ }
+
+ private int mCipherSuite;
+ private byte mCompressionAlgorithm;
+ private byte[] mMasterSecret;
+ private Certificate mPeerCertificate;
+ private byte[] mPskIdentity;
+ private byte[] mSrpIdentity;
+ private byte[] mEncodedServerExtensions;
+
+ private SessionParameters(int cipherSuite, byte compressionAlgorithm, byte[] masterSecret,
+ Certificate peerCertificate, byte[] pskIdentity, byte[] srpIdentity, byte[] encodedServerExtensions)
+ {
+ this.mCipherSuite = cipherSuite;
+ this.mCompressionAlgorithm = compressionAlgorithm;
+ this.mMasterSecret = Arrays.Clone(masterSecret);
+ this.mPeerCertificate = peerCertificate;
+ this.mPskIdentity = Arrays.Clone(pskIdentity);
+ this.mSrpIdentity = Arrays.Clone(srpIdentity);
+ this.mEncodedServerExtensions = encodedServerExtensions;
+ }
+
+ public void Clear()
+ {
+ if (this.mMasterSecret != null)
+ {
+ Arrays.Fill(this.mMasterSecret, (byte)0);
+ }
+ }
+
+ public SessionParameters Copy()
+ {
+ return new SessionParameters(mCipherSuite, mCompressionAlgorithm, mMasterSecret, mPeerCertificate,
+ mPskIdentity, mSrpIdentity, mEncodedServerExtensions);
+ }
+
+ public int CipherSuite
+ {
+ get { return mCipherSuite; }
+ }
+
+ public byte CompressionAlgorithm
+ {
+ get { return mCompressionAlgorithm; }
+ }
+
+ public byte[] MasterSecret
+ {
+ get { return mMasterSecret; }
+ }
+
+ public Certificate PeerCertificate
+ {
+ get { return mPeerCertificate; }
+ }
+
+ public byte[] PskIdentity
+ {
+ get { return mPskIdentity; }
+ }
+
+ public byte[] SrpIdentity
+ {
+ get { return mSrpIdentity; }
+ }
+
+ public IDictionary ReadServerExtensions()
+ {
+ if (mEncodedServerExtensions == null)
+ return null;
+
+ MemoryStream buf = new MemoryStream(mEncodedServerExtensions, false);
+ return TlsProtocol.ReadExtensions(buf);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/SignatureAlgorithm.cs b/bc-sharp-crypto/src/crypto/tls/SignatureAlgorithm.cs
new file mode 100644
index 0000000000000000000000000000000000000000..35b961762874db3296180151da28c2d6aeea7e18
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/SignatureAlgorithm.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * RFC 5246 7.4.1.4.1 (in RFC 2246, there were no specific values assigned)
+ */
+ public abstract class SignatureAlgorithm
+ {
+ public const byte anonymous = 0;
+ public const byte rsa = 1;
+ public const byte dsa = 2;
+ public const byte ecdsa = 3;
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/SignatureAndHashAlgorithm.cs b/bc-sharp-crypto/src/crypto/tls/SignatureAndHashAlgorithm.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f74205b62b70499bc43c72245f562ba41ec0ca84
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/SignatureAndHashAlgorithm.cs
@@ -0,0 +1,94 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * RFC 5246 7.4.1.4.1
+ */
+ public class SignatureAndHashAlgorithm
+ {
+ protected readonly byte mHash;
+ protected readonly byte mSignature;
+
+ /**
+ * @param hash {@link HashAlgorithm}
+ * @param signature {@link SignatureAlgorithm}
+ */
+ public SignatureAndHashAlgorithm(byte hash, byte signature)
+ {
+ if (!TlsUtilities.IsValidUint8(hash))
+ {
+ throw new ArgumentException("should be a uint8", "hash");
+ }
+ if (!TlsUtilities.IsValidUint8(signature))
+ {
+ throw new ArgumentException("should be a uint8", "signature");
+ }
+ if (signature == SignatureAlgorithm.anonymous)
+ {
+ throw new ArgumentException("MUST NOT be \"anonymous\"", "signature");
+ }
+
+ this.mHash = hash;
+ this.mSignature = signature;
+ }
+
+ /**
+ * @return {@link HashAlgorithm}
+ */
+ public virtual byte Hash
+ {
+ get { return mHash; }
+ }
+
+ /**
+ * @return {@link SignatureAlgorithm}
+ */
+ public virtual byte Signature
+ {
+ get { return mSignature; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (!(obj is SignatureAndHashAlgorithm))
+ {
+ return false;
+ }
+ SignatureAndHashAlgorithm other = (SignatureAndHashAlgorithm)obj;
+ return other.Hash == Hash && other.Signature == Signature;
+ }
+
+ public override int GetHashCode()
+ {
+ return ((int)Hash << 16) | (int)Signature;
+ }
+
+ /**
+ * Encode this {@link SignatureAndHashAlgorithm} to a {@link Stream}.
+ *
+ * @param output the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ TlsUtilities.WriteUint8(Hash, output);
+ TlsUtilities.WriteUint8(Signature, output);
+ }
+
+ /**
+ * Parse a {@link SignatureAndHashAlgorithm} from a {@link Stream}.
+ *
+ * @param input the {@link Stream} to parse from.
+ * @return a {@link SignatureAndHashAlgorithm} object.
+ * @throws IOException
+ */
+ public static SignatureAndHashAlgorithm Parse(Stream input)
+ {
+ byte hash = TlsUtilities.ReadUint8(input);
+ byte signature = TlsUtilities.ReadUint8(input);
+ return new SignatureAndHashAlgorithm(hash, signature);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/SignerInputBuffer.cs b/bc-sharp-crypto/src/crypto/tls/SignerInputBuffer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7bc69624c6ca6afecbd1eb6bf728ba5411788277
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/SignerInputBuffer.cs
@@ -0,0 +1,37 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ internal class SignerInputBuffer
+ : MemoryStream
+ {
+ internal void UpdateSigner(ISigner s)
+ {
+ Streams.WriteBufTo(this, new SigStream(s));
+ }
+
+ private class SigStream
+ : BaseOutputStream
+ {
+ private readonly ISigner s;
+
+ internal SigStream(ISigner s)
+ {
+ this.s = s;
+ }
+
+ public override void WriteByte(byte b)
+ {
+ s.Update(b);
+ }
+
+ public override void Write(byte[] buf, int off, int len)
+ {
+ s.BlockUpdate(buf, off, len);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/SimulatedTlsSrpIdentityManager.cs b/bc-sharp-crypto/src/crypto/tls/SimulatedTlsSrpIdentityManager.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3e9737cd766e50e28c73e37b148edbf7cb381bec
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/SimulatedTlsSrpIdentityManager.cs
@@ -0,0 +1,69 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Agreement.Srp;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * An implementation of {@link TlsSRPIdentityManager} that simulates the existence of "unknown" identities
+ * to obscure the fact that there is no verifier for them.
+ */
+ public class SimulatedTlsSrpIdentityManager
+ : TlsSrpIdentityManager
+ {
+ private static readonly byte[] PREFIX_PASSWORD = Strings.ToByteArray("password");
+ private static readonly byte[] PREFIX_SALT = Strings.ToByteArray("salt");
+
+ /**
+ * Create a {@link SimulatedTlsSRPIdentityManager} that implements the algorithm from RFC 5054 2.5.1.3
+ *
+ * @param group the {@link SRP6GroupParameters} defining the group that SRP is operating in
+ * @param seedKey the secret "seed key" referred to in RFC 5054 2.5.1.3
+ * @return an instance of {@link SimulatedTlsSRPIdentityManager}
+ */
+ public static SimulatedTlsSrpIdentityManager GetRfc5054Default(Srp6GroupParameters group, byte[] seedKey)
+ {
+ Srp6VerifierGenerator verifierGenerator = new Srp6VerifierGenerator();
+ verifierGenerator.Init(group, TlsUtilities.CreateHash(HashAlgorithm.sha1));
+
+ HMac mac = new HMac(TlsUtilities.CreateHash(HashAlgorithm.sha1));
+ mac.Init(new KeyParameter(seedKey));
+
+ return new SimulatedTlsSrpIdentityManager(group, verifierGenerator, mac);
+ }
+
+ protected readonly Srp6GroupParameters mGroup;
+ protected readonly Srp6VerifierGenerator mVerifierGenerator;
+ protected readonly IMac mMac;
+
+ public SimulatedTlsSrpIdentityManager(Srp6GroupParameters group, Srp6VerifierGenerator verifierGenerator, IMac mac)
+ {
+ this.mGroup = group;
+ this.mVerifierGenerator = verifierGenerator;
+ this.mMac = mac;
+ }
+
+ public virtual TlsSrpLoginParameters GetLoginParameters(byte[] identity)
+ {
+ mMac.BlockUpdate(PREFIX_SALT, 0, PREFIX_SALT.Length);
+ mMac.BlockUpdate(identity, 0, identity.Length);
+
+ byte[] salt = new byte[mMac.GetMacSize()];
+ mMac.DoFinal(salt, 0);
+
+ mMac.BlockUpdate(PREFIX_PASSWORD, 0, PREFIX_PASSWORD.Length);
+ mMac.BlockUpdate(identity, 0, identity.Length);
+
+ byte[] password = new byte[mMac.GetMacSize()];
+ mMac.DoFinal(password, 0);
+
+ BigInteger verifier = mVerifierGenerator.GenerateVerifier(salt, identity, password);
+
+ return new TlsSrpLoginParameters(mGroup, verifier, salt);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/SrpTlsClient.cs b/bc-sharp-crypto/src/crypto/tls/SrpTlsClient.cs
new file mode 100644
index 0000000000000000000000000000000000000000..df1607751798ef0616c473844bc71303e792d73b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/SrpTlsClient.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class SrpTlsClient
+ : AbstractTlsClient
+ {
+ protected TlsSrpGroupVerifier mGroupVerifier;
+
+ protected byte[] mIdentity;
+ protected byte[] mPassword;
+
+ public SrpTlsClient(byte[] identity, byte[] password)
+ : this(new DefaultTlsCipherFactory(), new DefaultTlsSrpGroupVerifier(), identity, password)
+ {
+ }
+
+ public SrpTlsClient(TlsCipherFactory cipherFactory, byte[] identity, byte[] password)
+ : this(cipherFactory, new DefaultTlsSrpGroupVerifier(), identity, password)
+ {
+ }
+
+ public SrpTlsClient(TlsCipherFactory cipherFactory, TlsSrpGroupVerifier groupVerifier,
+ byte[] identity, byte[] password)
+ : base(cipherFactory)
+ {
+ this.mGroupVerifier = groupVerifier;
+ this.mIdentity = Arrays.Clone(identity);
+ this.mPassword = Arrays.Clone(password);
+ }
+
+ protected virtual bool RequireSrpServerExtension
+ {
+ // No explicit guidance in RFC 5054; by default an (empty) extension from server is optional
+ get { return false; }
+ }
+
+ public override int[] GetCipherSuites()
+ {
+ return new int[]
+ {
+ CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA
+ };
+ }
+
+ public override IDictionary GetClientExtensions()
+ {
+ IDictionary clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(base.GetClientExtensions());
+ TlsSrpUtilities.AddSrpExtension(clientExtensions, this.mIdentity);
+ return clientExtensions;
+ }
+
+ public override void ProcessServerExtensions(IDictionary serverExtensions)
+ {
+ if (!TlsUtilities.HasExpectedEmptyExtensionData(serverExtensions, ExtensionType.srp,
+ AlertDescription.illegal_parameter))
+ {
+ if (RequireSrpServerExtension)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ base.ProcessServerExtensions(serverExtensions);
+ }
+
+ public override TlsKeyExchange GetKeyExchange()
+ {
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
+
+ switch (keyExchangeAlgorithm)
+ {
+ case KeyExchangeAlgorithm.SRP:
+ case KeyExchangeAlgorithm.SRP_DSS:
+ case KeyExchangeAlgorithm.SRP_RSA:
+ return CreateSrpKeyExchange(keyExchangeAlgorithm);
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocol implementation verifies that the
+ * server-selected cipher suite was in the list of client-offered cipher suites, so if
+ * we now can't produce an implementation, we shouldn't have offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public override TlsAuthentication GetAuthentication()
+ {
+ /*
+ * Note: This method is not called unless a server certificate is sent, which may be the
+ * case e.g. for SRP_DSS or SRP_RSA key exchange.
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ protected virtual TlsKeyExchange CreateSrpKeyExchange(int keyExchange)
+ {
+ return new TlsSrpKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mGroupVerifier, mIdentity, mPassword);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/SrpTlsServer.cs b/bc-sharp-crypto/src/crypto/tls/SrpTlsServer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f97878380c08c25e909c782ff7bac24ceca3c53c
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/SrpTlsServer.cs
@@ -0,0 +1,121 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class SrpTlsServer
+ : AbstractTlsServer
+ {
+ protected TlsSrpIdentityManager mSrpIdentityManager;
+
+ protected byte[] mSrpIdentity = null;
+ protected TlsSrpLoginParameters mLoginParameters = null;
+
+ public SrpTlsServer(TlsSrpIdentityManager srpIdentityManager)
+ : this(new DefaultTlsCipherFactory(), srpIdentityManager)
+ {
+ }
+
+ public SrpTlsServer(TlsCipherFactory cipherFactory, TlsSrpIdentityManager srpIdentityManager)
+ : base(cipherFactory)
+ {
+ this.mSrpIdentityManager = srpIdentityManager;
+ }
+
+ protected virtual TlsSignerCredentials GetDsaSignerCredentials()
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ protected virtual TlsSignerCredentials GetRsaSignerCredentials()
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ protected override int[] GetCipherSuites()
+ {
+ return new int[]
+ {
+ CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA
+ };
+ }
+
+ public override void ProcessClientExtensions(IDictionary clientExtensions)
+ {
+ base.ProcessClientExtensions(clientExtensions);
+
+ this.mSrpIdentity = TlsSrpUtilities.GetSrpExtension(clientExtensions);
+ }
+
+ public override int GetSelectedCipherSuite()
+ {
+ int cipherSuite = base.GetSelectedCipherSuite();
+
+ if (TlsSrpUtilities.IsSrpCipherSuite(cipherSuite))
+ {
+ if (mSrpIdentity != null)
+ {
+ this.mLoginParameters = mSrpIdentityManager.GetLoginParameters(mSrpIdentity);
+ }
+
+ if (mLoginParameters == null)
+ throw new TlsFatalAlert(AlertDescription.unknown_psk_identity);
+ }
+
+ return cipherSuite;
+ }
+
+ public override TlsCredentials GetCredentials()
+ {
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
+
+ switch (keyExchangeAlgorithm)
+ {
+ case KeyExchangeAlgorithm.SRP:
+ return null;
+
+ case KeyExchangeAlgorithm.SRP_DSS:
+ return GetDsaSignerCredentials();
+
+ case KeyExchangeAlgorithm.SRP_RSA:
+ return GetRsaSignerCredentials();
+
+ default:
+ /* Note: internal error here; selected a key exchange we don't implement! */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public override TlsKeyExchange GetKeyExchange()
+ {
+ int keyExchangeAlgorithm = TlsUtilities.GetKeyExchangeAlgorithm(mSelectedCipherSuite);
+
+ switch (keyExchangeAlgorithm)
+ {
+ case KeyExchangeAlgorithm.SRP:
+ case KeyExchangeAlgorithm.SRP_DSS:
+ case KeyExchangeAlgorithm.SRP_RSA:
+ return CreateSrpKeyExchange(keyExchangeAlgorithm);
+
+ default:
+ /*
+ * Note: internal error here; the TlsProtocol implementation verifies that the
+ * server-selected cipher suite was in the list of client-offered cipher suites, so if
+ * we now can't produce an implementation, we shouldn't have offered it!
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ protected virtual TlsKeyExchange CreateSrpKeyExchange(int keyExchange)
+ {
+ return new TlsSrpKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mSrpIdentity, mLoginParameters);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/SrtpProtectionProfile.cs b/bc-sharp-crypto/src/crypto/tls/SrtpProtectionProfile.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6e9091bb9fbf4d277624c22bd4c94943e89a83ba
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/SrtpProtectionProfile.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class SrtpProtectionProfile
+ {
+ /*
+ * RFC 5764 4.1.2.
+ */
+ public const int SRTP_AES128_CM_HMAC_SHA1_80 = 0x0001;
+ public const int SRTP_AES128_CM_HMAC_SHA1_32 = 0x0002;
+ public const int SRTP_NULL_HMAC_SHA1_80 = 0x0005;
+ public const int SRTP_NULL_HMAC_SHA1_32 = 0x0006;
+
+ /*
+ * RFC 7714 14.2.
+ */
+ public const int SRTP_AEAD_AES_128_GCM = 0x0007;
+ public const int SRTP_AEAD_AES_256_GCM = 0x0008;
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/Ssl3Mac.cs b/bc-sharp-crypto/src/crypto/tls/Ssl3Mac.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8bdb342dc450dfe756e5ce78f3ca30bcc20ce00d
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/Ssl3Mac.cs
@@ -0,0 +1,110 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * HMAC implementation based on original internet draft for HMAC (RFC 2104)
+ *
+ * The difference is that padding is concatentated versus XORed with the key
+ *
+ * H(K + opad, H(K + ipad, text))
+ */
+ public class Ssl3Mac
+ : IMac
+ {
+ private const byte IPAD_BYTE = 0x36;
+ private const byte OPAD_BYTE = 0x5C;
+
+ internal static readonly byte[] IPAD = GenPad(IPAD_BYTE, 48);
+ internal static readonly byte[] OPAD = GenPad(OPAD_BYTE, 48);
+
+ private readonly IDigest digest;
+ private readonly int padLength;
+
+ private byte[] secret;
+
+ /**
+ * Base constructor for one of the standard digest algorithms that the byteLength of
+ * the algorithm is know for. Behaviour is undefined for digests other than MD5 or SHA1.
+ *
+ * @param digest the digest.
+ */
+ public Ssl3Mac(IDigest digest)
+ {
+ this.digest = digest;
+
+ if (digest.GetDigestSize() == 20)
+ {
+ this.padLength = 40;
+ }
+ else
+ {
+ this.padLength = 48;
+ }
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return digest.AlgorithmName + "/SSL3MAC"; }
+ }
+
+ public virtual void Init(ICipherParameters parameters)
+ {
+ secret = Arrays.Clone(((KeyParameter)parameters).GetKey());
+
+ Reset();
+ }
+
+ public virtual int GetMacSize()
+ {
+ return digest.GetDigestSize();
+ }
+
+ public virtual void Update(byte input)
+ {
+ digest.Update(input);
+ }
+
+ public virtual void BlockUpdate(byte[] input, int inOff, int len)
+ {
+ digest.BlockUpdate(input, inOff, len);
+ }
+
+ public virtual int DoFinal(byte[] output, int outOff)
+ {
+ byte[] tmp = new byte[digest.GetDigestSize()];
+ digest.DoFinal(tmp, 0);
+
+ digest.BlockUpdate(secret, 0, secret.Length);
+ digest.BlockUpdate(OPAD, 0, padLength);
+ digest.BlockUpdate(tmp, 0, tmp.Length);
+
+ int len = digest.DoFinal(output, outOff);
+
+ Reset();
+
+ return len;
+ }
+
+ /**
+ * Reset the mac generator.
+ */
+ public virtual void Reset()
+ {
+ digest.Reset();
+ digest.BlockUpdate(secret, 0, secret.Length);
+ digest.BlockUpdate(IPAD, 0, padLength);
+ }
+
+ private static byte[] GenPad(byte b, int count)
+ {
+ byte[] padding = new byte[count];
+ Arrays.Fill(padding, b);
+ return padding;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/SupplementalDataEntry.cs b/bc-sharp-crypto/src/crypto/tls/SupplementalDataEntry.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5adc4fa528dc13a473541e42bf671d46ac21b9fa
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/SupplementalDataEntry.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class SupplementalDataEntry
+ {
+ protected readonly int mDataType;
+ protected readonly byte[] mData;
+
+ public SupplementalDataEntry(int dataType, byte[] data)
+ {
+ this.mDataType = dataType;
+ this.mData = data;
+ }
+
+ public virtual int DataType
+ {
+ get { return mDataType; }
+ }
+
+ public virtual byte[] Data
+ {
+ get { return mData; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/SupplementalDataType.cs b/bc-sharp-crypto/src/crypto/tls/SupplementalDataType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..79511c50a6c911c3f541b860273afc62764d3ce0
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/SupplementalDataType.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// RFC 4680
+ public abstract class SupplementalDataType
+ {
+ /*
+ * RFC 4681
+ */
+ public const int user_mapping_data = 0;
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsAeadCipher.cs b/bc-sharp-crypto/src/crypto/tls/TlsAeadCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cc0575cf00cf70cb03aed874532d3a94cc9c8349
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsAeadCipher.cs
@@ -0,0 +1,249 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsAeadCipher
+ : TlsCipher
+ {
+ // TODO[draft-zauner-tls-aes-ocb-04] Apply data volume limit described in section 8.4
+
+ public const int NONCE_RFC5288 = 1;
+
+ /*
+ * draft-zauner-tls-aes-ocb-04 specifies the nonce construction from draft-ietf-tls-chacha20-poly1305-04
+ */
+ internal const int NONCE_DRAFT_CHACHA20_POLY1305 = 2;
+
+ protected readonly TlsContext context;
+ protected readonly int macSize;
+ // TODO SecurityParameters.record_iv_length
+ protected readonly int record_iv_length;
+
+ protected readonly IAeadBlockCipher encryptCipher;
+ protected readonly IAeadBlockCipher decryptCipher;
+
+ protected readonly byte[] encryptImplicitNonce, decryptImplicitNonce;
+
+ protected readonly int nonceMode;
+
+ ///
+ public TlsAeadCipher(TlsContext context, IAeadBlockCipher clientWriteCipher, IAeadBlockCipher serverWriteCipher,
+ int cipherKeySize, int macSize)
+ : this(context, clientWriteCipher, serverWriteCipher, cipherKeySize, macSize, NONCE_RFC5288)
+ {
+ }
+
+ ///
+ internal TlsAeadCipher(TlsContext context, IAeadBlockCipher clientWriteCipher, IAeadBlockCipher serverWriteCipher,
+ int cipherKeySize, int macSize, int nonceMode)
+ {
+ if (!TlsUtilities.IsTlsV12(context))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ this.nonceMode = nonceMode;
+
+ // TODO SecurityParameters.fixed_iv_length
+ int fixed_iv_length;
+
+ switch (nonceMode)
+ {
+ case NONCE_RFC5288:
+ fixed_iv_length = 4;
+ this.record_iv_length = 8;
+ break;
+ case NONCE_DRAFT_CHACHA20_POLY1305:
+ fixed_iv_length = 12;
+ this.record_iv_length = 0;
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ this.context = context;
+ this.macSize = macSize;
+
+ int key_block_size = (2 * cipherKeySize) + (2 * fixed_iv_length);
+
+ byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size);
+
+ int offset = 0;
+
+ KeyParameter client_write_key = new KeyParameter(key_block, offset, cipherKeySize);
+ offset += cipherKeySize;
+ KeyParameter server_write_key = new KeyParameter(key_block, offset, cipherKeySize);
+ offset += cipherKeySize;
+ byte[] client_write_IV = Arrays.CopyOfRange(key_block, offset, offset + fixed_iv_length);
+ offset += fixed_iv_length;
+ byte[] server_write_IV = Arrays.CopyOfRange(key_block, offset, offset + fixed_iv_length);
+ offset += fixed_iv_length;
+
+ if (offset != key_block_size)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ KeyParameter encryptKey, decryptKey;
+ if (context.IsServer)
+ {
+ this.encryptCipher = serverWriteCipher;
+ this.decryptCipher = clientWriteCipher;
+ this.encryptImplicitNonce = server_write_IV;
+ this.decryptImplicitNonce = client_write_IV;
+ encryptKey = server_write_key;
+ decryptKey = client_write_key;
+ }
+ else
+ {
+ this.encryptCipher = clientWriteCipher;
+ this.decryptCipher = serverWriteCipher;
+ this.encryptImplicitNonce = client_write_IV;
+ this.decryptImplicitNonce = server_write_IV;
+ encryptKey = client_write_key;
+ decryptKey = server_write_key;
+ }
+
+ byte[] dummyNonce = new byte[fixed_iv_length + record_iv_length];
+
+ this.encryptCipher.Init(true, new AeadParameters(encryptKey, 8 * macSize, dummyNonce));
+ this.decryptCipher.Init(false, new AeadParameters(decryptKey, 8 * macSize, dummyNonce));
+ }
+
+ public virtual int GetPlaintextLimit(int ciphertextLimit)
+ {
+ // TODO We ought to be able to ask the decryptCipher (independently of it's current state!)
+ return ciphertextLimit - macSize - record_iv_length;
+ }
+
+ ///
+ public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
+ {
+ byte[] nonce = new byte[encryptImplicitNonce.Length + record_iv_length];
+
+ switch (nonceMode)
+ {
+ case NONCE_RFC5288:
+ Array.Copy(encryptImplicitNonce, 0, nonce, 0, encryptImplicitNonce.Length);
+ // RFC 5288/6655: The nonce_explicit MAY be the 64-bit sequence number.
+ TlsUtilities.WriteUint64(seqNo, nonce, encryptImplicitNonce.Length);
+ break;
+ case NONCE_DRAFT_CHACHA20_POLY1305:
+ TlsUtilities.WriteUint64(seqNo, nonce, nonce.Length - 8);
+ for (int i = 0; i < encryptImplicitNonce.Length; ++i)
+ {
+ nonce[i] ^= encryptImplicitNonce[i];
+ }
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ int plaintextOffset = offset;
+ int plaintextLength = len;
+ int ciphertextLength = encryptCipher.GetOutputSize(plaintextLength);
+
+ byte[] output = new byte[record_iv_length + ciphertextLength];
+ if (record_iv_length != 0)
+ {
+ Array.Copy(nonce, nonce.Length - record_iv_length, output, 0, record_iv_length);
+ }
+ int outputPos = record_iv_length;
+
+ byte[] additionalData = GetAdditionalData(seqNo, type, plaintextLength);
+ AeadParameters parameters = new AeadParameters(null, 8 * macSize, nonce, additionalData);
+
+ try
+ {
+ encryptCipher.Init(true, parameters);
+ outputPos += encryptCipher.ProcessBytes(plaintext, plaintextOffset, plaintextLength, output, outputPos);
+ outputPos += encryptCipher.DoFinal(output, outputPos);
+ }
+ catch (Exception e)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error, e);
+ }
+
+ if (outputPos != output.Length)
+ {
+ // NOTE: Existing AEAD cipher implementations all give exact output lengths
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ return output;
+ }
+
+ ///
+ public virtual byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len)
+ {
+ if (GetPlaintextLimit(len) < 0)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ byte[] nonce = new byte[decryptImplicitNonce.Length + record_iv_length];
+
+ switch (nonceMode)
+ {
+ case NONCE_RFC5288:
+ Array.Copy(decryptImplicitNonce, 0, nonce, 0, decryptImplicitNonce.Length);
+ Array.Copy(ciphertext, offset, nonce, nonce.Length - record_iv_length, record_iv_length);
+ break;
+ case NONCE_DRAFT_CHACHA20_POLY1305:
+ TlsUtilities.WriteUint64(seqNo, nonce, nonce.Length - 8);
+ for (int i = 0; i < decryptImplicitNonce.Length; ++i)
+ {
+ nonce[i] ^= decryptImplicitNonce[i];
+ }
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ int ciphertextOffset = offset + record_iv_length;
+ int ciphertextLength = len - record_iv_length;
+ int plaintextLength = decryptCipher.GetOutputSize(ciphertextLength);
+
+ byte[] output = new byte[plaintextLength];
+ int outputPos = 0;
+
+ byte[] additionalData = GetAdditionalData(seqNo, type, plaintextLength);
+ AeadParameters parameters = new AeadParameters(null, 8 * macSize, nonce, additionalData);
+
+ try
+ {
+ decryptCipher.Init(false, parameters);
+ outputPos += decryptCipher.ProcessBytes(ciphertext, ciphertextOffset, ciphertextLength, output, outputPos);
+ outputPos += decryptCipher.DoFinal(output, outputPos);
+ }
+ catch (Exception e)
+ {
+ throw new TlsFatalAlert(AlertDescription.bad_record_mac, e);
+ }
+
+ if (outputPos != output.Length)
+ {
+ // NOTE: Existing AEAD cipher implementations all give exact output lengths
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ return output;
+ }
+
+ ///
+ protected virtual byte[] GetAdditionalData(long seqNo, byte type, int len)
+ {
+ /*
+ * additional_data = seq_num + TLSCompressed.type + TLSCompressed.version +
+ * TLSCompressed.length
+ */
+
+ byte[] additional_data = new byte[13];
+ TlsUtilities.WriteUint64(seqNo, additional_data, 0);
+ TlsUtilities.WriteUint8(type, additional_data, 8);
+ TlsUtilities.WriteVersion(context.ServerVersion, additional_data, 9);
+ TlsUtilities.WriteUint16(len, additional_data, 11);
+
+ return additional_data;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsAgreementCredentials.cs b/bc-sharp-crypto/src/crypto/tls/TlsAgreementCredentials.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7c64072e8705dea93b9f126b889f3dc900e0dbf1
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsAgreementCredentials.cs
@@ -0,0 +1,12 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsAgreementCredentials
+ : TlsCredentials
+ {
+ ///
+ byte[] GenerateAgreement(AsymmetricKeyParameter peerPublicKey);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsAuthentication.cs b/bc-sharp-crypto/src/crypto/tls/TlsAuthentication.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9aea5e4498ab0a61d3fc738807de50d2cc40abd4
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsAuthentication.cs
@@ -0,0 +1,31 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsAuthentication
+ {
+ ///
+ /// Called by the protocol handler to report the server certificate.
+ ///
+ ///
+ /// This method is responsible for certificate verification and validation
+ ///
+ /// The server received
+ ///
+ void NotifyServerCertificate(Certificate serverCertificate);
+
+ ///
+ /// Return client credentials in response to server's certificate request
+ ///
+ ///
+ /// A containing server certificate request details
+ ///
+ ///
+ /// A to be used for client authentication
+ /// (or null for no client authentication)
+ ///
+ ///
+ TlsCredentials GetClientCredentials(CertificateRequest certificateRequest);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsBlockCipher.cs b/bc-sharp-crypto/src/crypto/tls/TlsBlockCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..76b476a1828ac0726eedab1f9174c79061f7885a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsBlockCipher.cs
@@ -0,0 +1,395 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ ///
+ /// A generic TLS 1.0-1.2 / SSLv3 block cipher. This can be used for AES or 3DES for example.
+ ///
+ public class TlsBlockCipher
+ : TlsCipher
+ {
+ protected readonly TlsContext context;
+ protected readonly byte[] randomData;
+ protected readonly bool useExplicitIV;
+ protected readonly bool encryptThenMac;
+
+ protected readonly IBlockCipher encryptCipher;
+ protected readonly IBlockCipher decryptCipher;
+
+ protected readonly TlsMac mWriteMac;
+ protected readonly TlsMac mReadMac;
+
+ public virtual TlsMac WriteMac
+ {
+ get { return mWriteMac; }
+ }
+
+ public virtual TlsMac ReadMac
+ {
+ get { return mReadMac; }
+ }
+
+ ///
+ public TlsBlockCipher(TlsContext context, IBlockCipher clientWriteCipher, IBlockCipher serverWriteCipher,
+ IDigest clientWriteDigest, IDigest serverWriteDigest, int cipherKeySize)
+ {
+ this.context = context;
+
+ this.randomData = new byte[256];
+ context.NonceRandomGenerator.NextBytes(randomData);
+
+ this.useExplicitIV = TlsUtilities.IsTlsV11(context);
+ this.encryptThenMac = context.SecurityParameters.encryptThenMac;
+
+ int key_block_size = (2 * cipherKeySize) + clientWriteDigest.GetDigestSize()
+ + serverWriteDigest.GetDigestSize();
+
+ // From TLS 1.1 onwards, block ciphers don't need client_write_IV
+ if (!useExplicitIV)
+ {
+ key_block_size += clientWriteCipher.GetBlockSize() + serverWriteCipher.GetBlockSize();
+ }
+
+ byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size);
+
+ int offset = 0;
+
+ TlsMac clientWriteMac = new TlsMac(context, clientWriteDigest, key_block, offset,
+ clientWriteDigest.GetDigestSize());
+ offset += clientWriteDigest.GetDigestSize();
+ TlsMac serverWriteMac = new TlsMac(context, serverWriteDigest, key_block, offset,
+ serverWriteDigest.GetDigestSize());
+ offset += serverWriteDigest.GetDigestSize();
+
+ KeyParameter client_write_key = new KeyParameter(key_block, offset, cipherKeySize);
+ offset += cipherKeySize;
+ KeyParameter server_write_key = new KeyParameter(key_block, offset, cipherKeySize);
+ offset += cipherKeySize;
+
+ byte[] client_write_IV, server_write_IV;
+ if (useExplicitIV)
+ {
+ client_write_IV = new byte[clientWriteCipher.GetBlockSize()];
+ server_write_IV = new byte[serverWriteCipher.GetBlockSize()];
+ }
+ else
+ {
+ client_write_IV = Arrays.CopyOfRange(key_block, offset, offset + clientWriteCipher.GetBlockSize());
+ offset += clientWriteCipher.GetBlockSize();
+ server_write_IV = Arrays.CopyOfRange(key_block, offset, offset + serverWriteCipher.GetBlockSize());
+ offset += serverWriteCipher.GetBlockSize();
+ }
+
+ if (offset != key_block_size)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ ICipherParameters encryptParams, decryptParams;
+ if (context.IsServer)
+ {
+ this.mWriteMac = serverWriteMac;
+ this.mReadMac = clientWriteMac;
+ this.encryptCipher = serverWriteCipher;
+ this.decryptCipher = clientWriteCipher;
+ encryptParams = new ParametersWithIV(server_write_key, server_write_IV);
+ decryptParams = new ParametersWithIV(client_write_key, client_write_IV);
+ }
+ else
+ {
+ this.mWriteMac = clientWriteMac;
+ this.mReadMac = serverWriteMac;
+ this.encryptCipher = clientWriteCipher;
+ this.decryptCipher = serverWriteCipher;
+ encryptParams = new ParametersWithIV(client_write_key, client_write_IV);
+ decryptParams = new ParametersWithIV(server_write_key, server_write_IV);
+ }
+
+ this.encryptCipher.Init(true, encryptParams);
+ this.decryptCipher.Init(false, decryptParams);
+ }
+
+ public virtual int GetPlaintextLimit(int ciphertextLimit)
+ {
+ int blockSize = encryptCipher.GetBlockSize();
+ int macSize = mWriteMac.Size;
+
+ int plaintextLimit = ciphertextLimit;
+
+ // An explicit IV consumes 1 block
+ if (useExplicitIV)
+ {
+ plaintextLimit -= blockSize;
+ }
+
+ // Leave room for the MAC, and require block-alignment
+ if (encryptThenMac)
+ {
+ plaintextLimit -= macSize;
+ plaintextLimit -= plaintextLimit % blockSize;
+ }
+ else
+ {
+ plaintextLimit -= plaintextLimit % blockSize;
+ plaintextLimit -= macSize;
+ }
+
+ // Minimum 1 byte of padding
+ --plaintextLimit;
+
+ return plaintextLimit;
+ }
+
+ public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
+ {
+ int blockSize = encryptCipher.GetBlockSize();
+ int macSize = mWriteMac.Size;
+
+ ProtocolVersion version = context.ServerVersion;
+
+ int enc_input_length = len;
+ if (!encryptThenMac)
+ {
+ enc_input_length += macSize;
+ }
+
+ int padding_length = blockSize - 1 - (enc_input_length % blockSize);
+
+ /*
+ * Don't use variable-length padding with truncated MACs.
+ *
+ * See "Tag Size Does Matter: Attacks and Proofs for the TLS Record Protocol", Paterson,
+ * Ristenpart, Shrimpton.
+ */
+ if (encryptThenMac || !context.SecurityParameters.truncatedHMac)
+ {
+ // TODO[DTLS] Consider supporting in DTLS (without exceeding send limit though)
+ if (!version.IsDtls && !version.IsSsl)
+ {
+ // Add a random number of extra blocks worth of padding
+ int maxExtraPadBlocks = (255 - padding_length) / blockSize;
+ int actualExtraPadBlocks = ChooseExtraPadBlocks(context.SecureRandom, maxExtraPadBlocks);
+ padding_length += actualExtraPadBlocks * blockSize;
+ }
+ }
+
+ int totalSize = len + macSize + padding_length + 1;
+ if (useExplicitIV)
+ {
+ totalSize += blockSize;
+ }
+
+ byte[] outBuf = new byte[totalSize];
+ int outOff = 0;
+
+ if (useExplicitIV)
+ {
+ byte[] explicitIV = new byte[blockSize];
+ context.NonceRandomGenerator.NextBytes(explicitIV);
+
+ encryptCipher.Init(true, new ParametersWithIV(null, explicitIV));
+
+ Array.Copy(explicitIV, 0, outBuf, outOff, blockSize);
+ outOff += blockSize;
+ }
+
+ int blocks_start = outOff;
+
+ Array.Copy(plaintext, offset, outBuf, outOff, len);
+ outOff += len;
+
+ if (!encryptThenMac)
+ {
+ byte[] mac = mWriteMac.CalculateMac(seqNo, type, plaintext, offset, len);
+ Array.Copy(mac, 0, outBuf, outOff, mac.Length);
+ outOff += mac.Length;
+ }
+
+ for (int i = 0; i <= padding_length; i++)
+ {
+ outBuf[outOff++] = (byte)padding_length;
+ }
+
+ for (int i = blocks_start; i < outOff; i += blockSize)
+ {
+ encryptCipher.ProcessBlock(outBuf, i, outBuf, i);
+ }
+
+ if (encryptThenMac)
+ {
+ byte[] mac = mWriteMac.CalculateMac(seqNo, type, outBuf, 0, outOff);
+ Array.Copy(mac, 0, outBuf, outOff, mac.Length);
+ outOff += mac.Length;
+ }
+
+ // assert outBuf.length == outOff;
+
+ return outBuf;
+ }
+
+ ///
+ public virtual byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len)
+ {
+ int blockSize = decryptCipher.GetBlockSize();
+ int macSize = mReadMac.Size;
+
+ int minLen = blockSize;
+ if (encryptThenMac)
+ {
+ minLen += macSize;
+ }
+ else
+ {
+ minLen = System.Math.Max(minLen, macSize + 1);
+ }
+
+ if (useExplicitIV)
+ {
+ minLen += blockSize;
+ }
+
+ if (len < minLen)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ int blocks_length = len;
+ if (encryptThenMac)
+ {
+ blocks_length -= macSize;
+ }
+
+ if (blocks_length % blockSize != 0)
+ throw new TlsFatalAlert(AlertDescription.decryption_failed);
+
+ if (encryptThenMac)
+ {
+ int end = offset + len;
+ byte[] receivedMac = Arrays.CopyOfRange(ciphertext, end - macSize, end);
+ byte[] calculatedMac = mReadMac.CalculateMac(seqNo, type, ciphertext, offset, len - macSize);
+
+ bool badMacEtm = !Arrays.ConstantTimeAreEqual(calculatedMac, receivedMac);
+ if (badMacEtm)
+ {
+ /*
+ * RFC 7366 3. The MAC SHALL be evaluated before any further processing such as
+ * decryption is performed, and if the MAC verification fails, then processing SHALL
+ * terminate immediately. For TLS, a fatal bad_record_mac MUST be generated [2]. For
+ * DTLS, the record MUST be discarded, and a fatal bad_record_mac MAY be generated
+ * [4]. This immediate response to a bad MAC eliminates any timing channels that may
+ * be available through the use of manipulated packet data.
+ */
+ throw new TlsFatalAlert(AlertDescription.bad_record_mac);
+ }
+ }
+
+ if (useExplicitIV)
+ {
+ decryptCipher.Init(false, new ParametersWithIV(null, ciphertext, offset, blockSize));
+
+ offset += blockSize;
+ blocks_length -= blockSize;
+ }
+
+ for (int i = 0; i < blocks_length; i += blockSize)
+ {
+ decryptCipher.ProcessBlock(ciphertext, offset + i, ciphertext, offset + i);
+ }
+
+ // If there's anything wrong with the padding, this will return zero
+ int totalPad = CheckPaddingConstantTime(ciphertext, offset, blocks_length, blockSize, encryptThenMac ? 0 : macSize);
+ bool badMac = (totalPad == 0);
+
+ int dec_output_length = blocks_length - totalPad;
+
+ if (!encryptThenMac)
+ {
+ dec_output_length -= macSize;
+ int macInputLen = dec_output_length;
+ int macOff = offset + macInputLen;
+ byte[] receivedMac = Arrays.CopyOfRange(ciphertext, macOff, macOff + macSize);
+ byte[] calculatedMac = mReadMac.CalculateMacConstantTime(seqNo, type, ciphertext, offset, macInputLen,
+ blocks_length - macSize, randomData);
+
+ badMac |= !Arrays.ConstantTimeAreEqual(calculatedMac, receivedMac);
+ }
+
+ if (badMac)
+ throw new TlsFatalAlert(AlertDescription.bad_record_mac);
+
+ return Arrays.CopyOfRange(ciphertext, offset, offset + dec_output_length);
+ }
+
+ protected virtual int CheckPaddingConstantTime(byte[] buf, int off, int len, int blockSize, int macSize)
+ {
+ int end = off + len;
+ byte lastByte = buf[end - 1];
+ int padlen = lastByte & 0xff;
+ int totalPad = padlen + 1;
+
+ int dummyIndex = 0;
+ byte padDiff = 0;
+
+ if ((TlsUtilities.IsSsl(context) && totalPad > blockSize) || (macSize + totalPad > len))
+ {
+ totalPad = 0;
+ }
+ else
+ {
+ int padPos = end - totalPad;
+ do
+ {
+ padDiff |= (byte)(buf[padPos++] ^ lastByte);
+ }
+ while (padPos < end);
+
+ dummyIndex = totalPad;
+
+ if (padDiff != 0)
+ {
+ totalPad = 0;
+ }
+ }
+
+ // Run some extra dummy checks so the number of checks is always constant
+ {
+ byte[] dummyPad = randomData;
+ while (dummyIndex < 256)
+ {
+ padDiff |= (byte)(dummyPad[dummyIndex++] ^ lastByte);
+ }
+ // Ensure the above loop is not eliminated
+ dummyPad[0] ^= padDiff;
+ }
+
+ return totalPad;
+ }
+
+ protected virtual int ChooseExtraPadBlocks(SecureRandom r, int max)
+ {
+ // return r.NextInt(max + 1);
+
+ int x = r.NextInt();
+ int n = LowestBitSet(x);
+ return System.Math.Min(n, max);
+ }
+
+ protected virtual int LowestBitSet(int x)
+ {
+ if (x == 0)
+ return 32;
+
+ uint ux = (uint)x;
+ int n = 0;
+ while ((ux & 1U) == 0)
+ {
+ ++n;
+ ux >>= 1;
+ }
+ return n;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsCipher.cs b/bc-sharp-crypto/src/crypto/tls/TlsCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7bd8573ac2cc30e3caac7aee68ad33134beae831
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsCipher.cs
@@ -0,0 +1,16 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsCipher
+ {
+ int GetPlaintextLimit(int ciphertextLimit);
+
+ ///
+ byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len);
+
+ ///
+ byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsCipherFactory.cs b/bc-sharp-crypto/src/crypto/tls/TlsCipherFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4e1fe0eb98a7b51956911ea5def1077f3d4f5a44
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsCipherFactory.cs
@@ -0,0 +1,11 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsCipherFactory
+ {
+ ///
+ TlsCipher CreateCipher(TlsContext context, int encryptionAlgorithm, int macAlgorithm);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsClient.cs b/bc-sharp-crypto/src/crypto/tls/TlsClient.cs
new file mode 100644
index 0000000000000000000000000000000000000000..73f169054dfb46bd7f3a78aa6011600b6e87b001
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsClient.cs
@@ -0,0 +1,148 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsClient
+ : TlsPeer
+ {
+ ///
+ /// Called at the start of a new TLS session, before any other methods.
+ ///
+ ///
+ /// A
+ ///
+ void Init(TlsClientContext context);
+
+ /// Return the session this client wants to resume, if any.
+ /// Note that the peer's certificate chain for the session (if any) may need to be periodically revalidated.
+ ///
+ /// A representing the resumable session to be used for this connection,
+ /// or null to use a new session.
+ ///
+ TlsSession GetSessionToResume();
+
+ ///
+ /// Return the to use for the TLSPlaintext.version field prior to
+ /// receiving the server version. NOTE: This method is not called for DTLS.
+ ///
+ ///
+ /// See RFC 5246 E.1.: "TLS clients that wish to negotiate with older servers MAY send any value
+ /// {03,XX} as the record layer version number. Typical values would be {03,00}, the lowest
+ /// version number supported by the client, and the value of ClientHello.client_version. No
+ /// single value will guarantee interoperability with all old servers, but this is a complex
+ /// topic beyond the scope of this document."
+ ///
+ /// The to use.
+ ProtocolVersion ClientHelloRecordLayerVersion { get; }
+
+ ProtocolVersion ClientVersion { get; }
+
+ bool IsFallback { get; }
+
+ ///
+ /// Get the list of cipher suites that this client supports.
+ ///
+ ///
+ /// An array of values, each specifying a supported cipher suite.
+ ///
+ int[] GetCipherSuites();
+
+ ///
+ /// Get the list of compression methods that this client supports.
+ ///
+ ///
+ /// An array of values, each specifying a supported compression method.
+ ///
+ byte[] GetCompressionMethods();
+
+ ///
+ /// Get the (optional) table of client extensions to be included in (extended) client hello.
+ ///
+ ///
+ /// A (Int32 -> byte[]). May be null.
+ ///
+ ///
+ IDictionary GetClientExtensions();
+
+ ///
+ void NotifyServerVersion(ProtocolVersion selectedVersion);
+
+ ///
+ /// Notifies the client of the session_id sent in the ServerHello.
+ ///
+ /// An array of
+ void NotifySessionID(byte[] sessionID);
+
+ ///
+ /// Report the cipher suite that was selected by the server.
+ ///
+ ///
+ /// The protocol handler validates this value against the offered cipher suites
+ ///
+ ///
+ ///
+ /// A
+ ///
+ void NotifySelectedCipherSuite(int selectedCipherSuite);
+
+ ///
+ /// Report the compression method that was selected by the server.
+ ///
+ ///
+ /// The protocol handler validates this value against the offered compression methods
+ ///
+ ///
+ ///
+ /// A
+ ///
+ void NotifySelectedCompressionMethod(byte selectedCompressionMethod);
+
+ ///
+ /// Report the extensions from an extended server hello.
+ ///
+ ///
+ /// Will only be called if we returned a non-null result from .
+ ///
+ ///
+ /// A (Int32 -> byte[])
+ ///
+ void ProcessServerExtensions(IDictionary serverExtensions);
+
+ /// A list of
+ ///
+ void ProcessServerSupplementalData(IList serverSupplementalData);
+
+ ///
+ /// Return an implementation of to negotiate the key exchange
+ /// part of the protocol.
+ ///
+ ///
+ /// A
+ ///
+ ///
+ TlsKeyExchange GetKeyExchange();
+
+ ///
+ /// Return an implementation of to handle authentication
+ /// part of the protocol.
+ ///
+ ///
+ TlsAuthentication GetAuthentication();
+
+ /// A list of
+ ///
+ IList GetClientSupplementalData();
+
+ /// RFC 5077 3.3. NewSessionTicket Handshake Message
+ ///
+ /// This method will be called (only) when a NewSessionTicket handshake message is received. The
+ /// ticket is opaque to the client and clients MUST NOT examine the ticket under the assumption
+ /// that it complies with e.g. RFC 5077 4. Recommended Ticket Construction .
+ ///
+ /// The ticket
+ ///
+ void NotifyNewSessionTicket(NewSessionTicket newSessionTicket);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsClientContext.cs b/bc-sharp-crypto/src/crypto/tls/TlsClientContext.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b077d0aafba7f2d7197fb3dcc9c633b02d5d846c
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsClientContext.cs
@@ -0,0 +1,11 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsClientContext
+ : TlsContext
+ {
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsClientContextImpl.cs b/bc-sharp-crypto/src/crypto/tls/TlsClientContextImpl.cs
new file mode 100644
index 0000000000000000000000000000000000000000..674d6893739d91346aea7d81f254cc5e7a21f0e2
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsClientContextImpl.cs
@@ -0,0 +1,20 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ internal class TlsClientContextImpl
+ : AbstractTlsContext, TlsClientContext
+ {
+ internal TlsClientContextImpl(SecureRandom secureRandom, SecurityParameters securityParameters)
+ : base(secureRandom, securityParameters)
+ {
+ }
+
+ public override bool IsServer
+ {
+ get { return false; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsClientProtocol.cs b/bc-sharp-crypto/src/crypto/tls/TlsClientProtocol.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0ea84c05caa3f346975b413cbe3c37f9ebec4912
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsClientProtocol.cs
@@ -0,0 +1,912 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsClientProtocol
+ : TlsProtocol
+ {
+ protected TlsClient mTlsClient = null;
+ internal TlsClientContextImpl mTlsClientContext = null;
+
+ protected byte[] mSelectedSessionID = null;
+
+ protected TlsKeyExchange mKeyExchange = null;
+ protected TlsAuthentication mAuthentication = null;
+
+ protected CertificateStatus mCertificateStatus = null;
+ protected CertificateRequest mCertificateRequest = null;
+
+ /**
+ * Constructor for blocking mode.
+ * @param stream The bi-directional stream of data to/from the server
+ * @param secureRandom Random number generator for various cryptographic functions
+ */
+ public TlsClientProtocol(Stream stream, SecureRandom secureRandom)
+ : base(stream, secureRandom)
+ {
+ }
+
+ /**
+ * Constructor for blocking mode.
+ * @param input The stream of data from the server
+ * @param output The stream of data to the server
+ * @param secureRandom Random number generator for various cryptographic functions
+ */
+ public TlsClientProtocol(Stream input, Stream output, SecureRandom secureRandom)
+ : base(input, output, secureRandom)
+ {
+ }
+
+ /**
+ * Constructor for non-blocking mode.
+ *
+ * When data is received, use {@link #offerInput(java.nio.ByteBuffer)} to
+ * provide the received ciphertext, then use
+ * {@link #readInput(byte[], int, int)} to read the corresponding cleartext.
+ *
+ * Similarly, when data needs to be sent, use
+ * {@link #offerOutput(byte[], int, int)} to provide the cleartext, then use
+ * {@link #readOutput(byte[], int, int)} to get the corresponding
+ * ciphertext.
+ *
+ * @param secureRandom
+ * Random number generator for various cryptographic functions
+ */
+ public TlsClientProtocol(SecureRandom secureRandom)
+ : base(secureRandom)
+ {
+ }
+
+ /**
+ * Initiates a TLS handshake in the role of client.
+ *
+ * In blocking mode, this will not return until the handshake is complete.
+ * In non-blocking mode, use {@link TlsPeer#NotifyHandshakeComplete()} to
+ * receive a callback when the handshake is complete.
+ *
+ * @param tlsClient The {@link TlsClient} to use for the handshake.
+ * @throws IOException If in blocking mode and handshake was not successful.
+ */
+ public virtual void Connect(TlsClient tlsClient)
+ {
+ if (tlsClient == null)
+ throw new ArgumentNullException("tlsClient");
+ if (this.mTlsClient != null)
+ throw new InvalidOperationException("'Connect' can only be called once");
+
+ this.mTlsClient = tlsClient;
+
+ this.mSecurityParameters = new SecurityParameters();
+ this.mSecurityParameters.entity = ConnectionEnd.client;
+
+ this.mTlsClientContext = new TlsClientContextImpl(mSecureRandom, mSecurityParameters);
+
+ this.mSecurityParameters.clientRandom = CreateRandomBlock(tlsClient.ShouldUseGmtUnixTime(),
+ mTlsClientContext.NonceRandomGenerator);
+
+ this.mTlsClient.Init(mTlsClientContext);
+ this.mRecordStream.Init(mTlsClientContext);
+
+ TlsSession sessionToResume = tlsClient.GetSessionToResume();
+ if (sessionToResume != null && sessionToResume.IsResumable)
+ {
+ SessionParameters sessionParameters = sessionToResume.ExportSessionParameters();
+ if (sessionParameters != null)
+ {
+ this.mTlsSession = sessionToResume;
+ this.mSessionParameters = sessionParameters;
+ }
+ }
+
+ SendClientHelloMessage();
+ this.mConnectionState = CS_CLIENT_HELLO;
+
+ BlockForHandshake();
+ }
+
+ protected override void CleanupHandshake()
+ {
+ base.CleanupHandshake();
+
+ this.mSelectedSessionID = null;
+ this.mKeyExchange = null;
+ this.mAuthentication = null;
+ this.mCertificateStatus = null;
+ this.mCertificateRequest = null;
+ }
+
+ protected override TlsContext Context
+ {
+ get { return mTlsClientContext; }
+ }
+
+ internal override AbstractTlsContext ContextAdmin
+ {
+ get { return mTlsClientContext; }
+ }
+
+ protected override TlsPeer Peer
+ {
+ get { return mTlsClient; }
+ }
+
+ protected override void HandleHandshakeMessage(byte type, MemoryStream buf)
+ {
+ if (this.mResumedSession)
+ {
+ if (type != HandshakeType.finished || this.mConnectionState != CS_SERVER_HELLO)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ ProcessFinishedMessage(buf);
+ this.mConnectionState = CS_SERVER_FINISHED;
+
+ SendFinishedMessage();
+ this.mConnectionState = CS_CLIENT_FINISHED;
+
+ CompleteHandshake();
+ return;
+ }
+
+ switch (type)
+ {
+ case HandshakeType.certificate:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_SERVER_HELLO:
+ case CS_SERVER_SUPPLEMENTAL_DATA:
+ {
+ if (this.mConnectionState == CS_SERVER_HELLO)
+ {
+ HandleSupplementalData(null);
+ }
+
+ // Parse the Certificate message and Send to cipher suite
+
+ this.mPeerCertificate = Certificate.Parse(buf);
+
+ AssertEmpty(buf);
+
+ // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
+ if (this.mPeerCertificate == null || this.mPeerCertificate.IsEmpty)
+ {
+ this.mAllowCertificateStatus = false;
+ }
+
+ this.mKeyExchange.ProcessServerCertificate(this.mPeerCertificate);
+
+ this.mAuthentication = mTlsClient.GetAuthentication();
+ this.mAuthentication.NotifyServerCertificate(this.mPeerCertificate);
+
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ this.mConnectionState = CS_SERVER_CERTIFICATE;
+ break;
+ }
+ case HandshakeType.certificate_status:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_SERVER_CERTIFICATE:
+ {
+ if (!this.mAllowCertificateStatus)
+ {
+ /*
+ * RFC 3546 3.6. If a server returns a "CertificateStatus" message, then the
+ * server MUST have included an extension of type "status_request" with empty
+ * "extension_data" in the extended server hello..
+ */
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ this.mCertificateStatus = CertificateStatus.Parse(buf);
+
+ AssertEmpty(buf);
+
+ // TODO[RFC 3546] Figure out how to provide this to the client/authentication.
+
+ this.mConnectionState = CS_CERTIFICATE_STATUS;
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.finished:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_CLIENT_FINISHED:
+ case CS_SERVER_SESSION_TICKET:
+ {
+ if (this.mConnectionState == CS_CLIENT_FINISHED && this.mExpectSessionTicket)
+ {
+ /*
+ * RFC 5077 3.3. This message MUST be sent if the server included a
+ * SessionTicket extension in the ServerHello.
+ */
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ ProcessFinishedMessage(buf);
+ this.mConnectionState = CS_SERVER_FINISHED;
+
+ CompleteHandshake();
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.server_hello:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_CLIENT_HELLO:
+ {
+ ReceiveServerHelloMessage(buf);
+ this.mConnectionState = CS_SERVER_HELLO;
+
+ this.mRecordStream.NotifyHelloComplete();
+
+ ApplyMaxFragmentLengthExtension();
+
+ if (this.mResumedSession)
+ {
+ this.mSecurityParameters.masterSecret = Arrays.Clone(this.mSessionParameters.MasterSecret);
+ this.mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
+
+ SendChangeCipherSpecMessage();
+ }
+ else
+ {
+ InvalidateSession();
+
+ if (this.mSelectedSessionID.Length > 0)
+ {
+ this.mTlsSession = new TlsSessionImpl(this.mSelectedSessionID, null);
+ }
+ }
+
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.supplemental_data:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_SERVER_HELLO:
+ {
+ HandleSupplementalData(ReadSupplementalDataMessage(buf));
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.server_hello_done:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_SERVER_HELLO:
+ case CS_SERVER_SUPPLEMENTAL_DATA:
+ case CS_SERVER_CERTIFICATE:
+ case CS_CERTIFICATE_STATUS:
+ case CS_SERVER_KEY_EXCHANGE:
+ case CS_CERTIFICATE_REQUEST:
+ {
+ if (mConnectionState < CS_SERVER_SUPPLEMENTAL_DATA)
+ {
+ HandleSupplementalData(null);
+ }
+
+ if (mConnectionState < CS_SERVER_CERTIFICATE)
+ {
+ // There was no server certificate message; check it's OK
+ this.mKeyExchange.SkipServerCredentials();
+ this.mAuthentication = null;
+ }
+
+ if (mConnectionState < CS_SERVER_KEY_EXCHANGE)
+ {
+ // There was no server key exchange message; check it's OK
+ this.mKeyExchange.SkipServerKeyExchange();
+ }
+
+ AssertEmpty(buf);
+
+ this.mConnectionState = CS_SERVER_HELLO_DONE;
+
+ this.mRecordStream.HandshakeHash.SealHashAlgorithms();
+
+ IList clientSupplementalData = mTlsClient.GetClientSupplementalData();
+ if (clientSupplementalData != null)
+ {
+ SendSupplementalDataMessage(clientSupplementalData);
+ }
+ this.mConnectionState = CS_CLIENT_SUPPLEMENTAL_DATA;
+
+ TlsCredentials clientCreds = null;
+ if (mCertificateRequest == null)
+ {
+ this.mKeyExchange.SkipClientCredentials();
+ }
+ else
+ {
+ clientCreds = this.mAuthentication.GetClientCredentials(mCertificateRequest);
+
+ if (clientCreds == null)
+ {
+ this.mKeyExchange.SkipClientCredentials();
+
+ /*
+ * RFC 5246 If no suitable certificate is available, the client MUST Send a
+ * certificate message containing no certificates.
+ *
+ * NOTE: In previous RFCs, this was SHOULD instead of MUST.
+ */
+ SendCertificateMessage(Certificate.EmptyChain);
+ }
+ else
+ {
+ this.mKeyExchange.ProcessClientCredentials(clientCreds);
+
+ SendCertificateMessage(clientCreds.Certificate);
+ }
+ }
+
+ this.mConnectionState = CS_CLIENT_CERTIFICATE;
+
+ /*
+ * Send the client key exchange message, depending on the key exchange we are using
+ * in our CipherSuite.
+ */
+ SendClientKeyExchangeMessage();
+ this.mConnectionState = CS_CLIENT_KEY_EXCHANGE;
+
+ if (TlsUtilities.IsSsl(Context))
+ {
+ EstablishMasterSecret(Context, mKeyExchange);
+ }
+
+ TlsHandshakeHash prepareFinishHash = mRecordStream.PrepareToFinish();
+ this.mSecurityParameters.sessionHash = GetCurrentPrfHash(Context, prepareFinishHash, null);
+
+ if (!TlsUtilities.IsSsl(Context))
+ {
+ EstablishMasterSecret(Context, mKeyExchange);
+ }
+
+ mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
+
+ if (clientCreds != null && clientCreds is TlsSignerCredentials)
+ {
+ TlsSignerCredentials signerCredentials = (TlsSignerCredentials)clientCreds;
+
+ /*
+ * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
+ */
+ SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
+ Context, signerCredentials);
+
+ byte[] hash;
+ if (signatureAndHashAlgorithm == null)
+ {
+ hash = mSecurityParameters.SessionHash;
+ }
+ else
+ {
+ hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash);
+ }
+
+ byte[] signature = signerCredentials.GenerateCertificateSignature(hash);
+ DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature);
+ SendCertificateVerifyMessage(certificateVerify);
+
+ this.mConnectionState = CS_CERTIFICATE_VERIFY;
+ }
+
+ SendChangeCipherSpecMessage();
+ SendFinishedMessage();
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ this.mConnectionState = CS_CLIENT_FINISHED;
+ break;
+ }
+ case HandshakeType.server_key_exchange:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_SERVER_HELLO:
+ case CS_SERVER_SUPPLEMENTAL_DATA:
+ case CS_SERVER_CERTIFICATE:
+ case CS_CERTIFICATE_STATUS:
+ {
+ if (mConnectionState < CS_SERVER_SUPPLEMENTAL_DATA)
+ {
+ HandleSupplementalData(null);
+ }
+
+ if (mConnectionState < CS_SERVER_CERTIFICATE)
+ {
+ // There was no server certificate message; check it's OK
+ this.mKeyExchange.SkipServerCredentials();
+ this.mAuthentication = null;
+ }
+
+ this.mKeyExchange.ProcessServerKeyExchange(buf);
+
+ AssertEmpty(buf);
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ this.mConnectionState = CS_SERVER_KEY_EXCHANGE;
+ break;
+ }
+ case HandshakeType.certificate_request:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_SERVER_CERTIFICATE:
+ case CS_CERTIFICATE_STATUS:
+ case CS_SERVER_KEY_EXCHANGE:
+ {
+ if (this.mConnectionState != CS_SERVER_KEY_EXCHANGE)
+ {
+ // There was no server key exchange message; check it's OK
+ this.mKeyExchange.SkipServerKeyExchange();
+ }
+
+ if (this.mAuthentication == null)
+ {
+ /*
+ * RFC 2246 7.4.4. It is a fatal handshake_failure alert for an anonymous server
+ * to request client identification.
+ */
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+
+ this.mCertificateRequest = CertificateRequest.Parse(Context, buf);
+
+ AssertEmpty(buf);
+
+ this.mKeyExchange.ValidateCertificateRequest(this.mCertificateRequest);
+
+ /*
+ * TODO Give the client a chance to immediately select the CertificateVerify hash
+ * algorithm here to avoid tracking the other hash algorithms unnecessarily?
+ */
+ TlsUtilities.TrackHashAlgorithms(this.mRecordStream.HandshakeHash,
+ this.mCertificateRequest.SupportedSignatureAlgorithms);
+
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ this.mConnectionState = CS_CERTIFICATE_REQUEST;
+ break;
+ }
+ case HandshakeType.session_ticket:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_CLIENT_FINISHED:
+ {
+ if (!this.mExpectSessionTicket)
+ {
+ /*
+ * RFC 5077 3.3. This message MUST NOT be sent if the server did not include a
+ * SessionTicket extension in the ServerHello.
+ */
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ /*
+ * RFC 5077 3.4. If the client receives a session ticket from the server, then it
+ * discards any Session ID that was sent in the ServerHello.
+ */
+ InvalidateSession();
+
+ ReceiveNewSessionTicketMessage(buf);
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ this.mConnectionState = CS_SERVER_SESSION_TICKET;
+ break;
+ }
+ case HandshakeType.hello_request:
+ {
+ AssertEmpty(buf);
+
+ /*
+ * RFC 2246 7.4.1.1 Hello request This message will be ignored by the client if the
+ * client is currently negotiating a session. This message may be ignored by the client
+ * if it does not wish to renegotiate a session, or the client may, if it wishes,
+ * respond with a no_renegotiation alert.
+ */
+ if (this.mConnectionState == CS_END)
+ {
+ RefuseRenegotiation();
+ }
+ break;
+ }
+ case HandshakeType.client_hello:
+ case HandshakeType.client_key_exchange:
+ case HandshakeType.certificate_verify:
+ case HandshakeType.hello_verify_request:
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ }
+
+ protected virtual void HandleSupplementalData(IList serverSupplementalData)
+ {
+ this.mTlsClient.ProcessServerSupplementalData(serverSupplementalData);
+ this.mConnectionState = CS_SERVER_SUPPLEMENTAL_DATA;
+
+ this.mKeyExchange = mTlsClient.GetKeyExchange();
+ this.mKeyExchange.Init(Context);
+ }
+
+ protected virtual void ReceiveNewSessionTicketMessage(MemoryStream buf)
+ {
+ NewSessionTicket newSessionTicket = NewSessionTicket.Parse(buf);
+
+ AssertEmpty(buf);
+
+ mTlsClient.NotifyNewSessionTicket(newSessionTicket);
+ }
+
+ protected virtual void ReceiveServerHelloMessage(MemoryStream buf)
+ {
+ {
+ ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
+ if (server_version.IsDtls)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ // Check that this matches what the server is Sending in the record layer
+ if (!server_version.Equals(this.mRecordStream.ReadVersion))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ ProtocolVersion client_version = Context.ClientVersion;
+ if (!server_version.IsEqualOrEarlierVersionOf(client_version))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ this.mRecordStream.SetWriteVersion(server_version);
+ ContextAdmin.SetServerVersion(server_version);
+ this.mTlsClient.NotifyServerVersion(server_version);
+ }
+
+ /*
+ * Read the server random
+ */
+ this.mSecurityParameters.serverRandom = TlsUtilities.ReadFully(32, buf);
+
+ this.mSelectedSessionID = TlsUtilities.ReadOpaque8(buf);
+ if (this.mSelectedSessionID.Length > 32)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ this.mTlsClient.NotifySessionID(this.mSelectedSessionID);
+ this.mResumedSession = this.mSelectedSessionID.Length > 0 && this.mTlsSession != null
+ && Arrays.AreEqual(this.mSelectedSessionID, this.mTlsSession.SessionID);
+
+ /*
+ * Find out which CipherSuite the server has chosen and check that it was one of the offered
+ * ones, and is a valid selection for the negotiated version.
+ */
+ int selectedCipherSuite = TlsUtilities.ReadUint16(buf);
+ if (!Arrays.Contains(this.mOfferedCipherSuites, selectedCipherSuite)
+ || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
+ || CipherSuite.IsScsv(selectedCipherSuite)
+ || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ this.mTlsClient.NotifySelectedCipherSuite(selectedCipherSuite);
+
+ /*
+ * Find out which CompressionMethod the server has chosen and check that it was one of the
+ * offered ones.
+ */
+ byte selectedCompressionMethod = TlsUtilities.ReadUint8(buf);
+ if (!Arrays.Contains(this.mOfferedCompressionMethods, selectedCompressionMethod))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ this.mTlsClient.NotifySelectedCompressionMethod(selectedCompressionMethod);
+
+ /*
+ * RFC3546 2.2 The extended server hello message format MAY be sent in place of the server
+ * hello message when the client has requested extended functionality via the extended
+ * client hello message specified in Section 2.1. ... Note that the extended server hello
+ * message is only sent in response to an extended client hello message. This prevents the
+ * possibility that the extended server hello message could "break" existing TLS 1.0
+ * clients.
+ */
+ this.mServerExtensions = ReadExtensions(buf);
+
+ /*
+ * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an
+ * extended client hello message.
+ *
+ * However, see RFC 5746 exception below. We always include the SCSV, so an Extended Server
+ * Hello is always allowed.
+ */
+ if (this.mServerExtensions != null)
+ {
+ foreach (int extType in this.mServerExtensions.Keys)
+ {
+ /*
+ * RFC 5746 3.6. Note that Sending a "renegotiation_info" extension in response to a
+ * ClientHello containing only the SCSV is an explicit exception to the prohibition
+ * in RFC 5246, Section 7.4.1.4, on the server Sending unsolicited extensions and is
+ * only allowed because the client is signaling its willingness to receive the
+ * extension via the TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
+ */
+ if (extType == ExtensionType.renegotiation_info)
+ continue;
+
+ /*
+ * RFC 5246 7.4.1.4 An extension type MUST NOT appear in the ServerHello unless the
+ * same extension type appeared in the corresponding ClientHello. If a client
+ * receives an extension type in ServerHello that it did not request in the
+ * associated ClientHello, it MUST abort the handshake with an unsupported_extension
+ * fatal alert.
+ */
+ if (null == TlsUtilities.GetExtensionData(this.mClientExtensions, extType))
+ throw new TlsFatalAlert(AlertDescription.unsupported_extension);
+
+ /*
+ * RFC 3546 2.3. If [...] the older session is resumed, then the server MUST ignore
+ * extensions appearing in the client hello, and Send a server hello containing no
+ * extensions[.]
+ */
+ if (this.mResumedSession)
+ {
+ // TODO[compat-gnutls] GnuTLS test server Sends server extensions e.g. ec_point_formats
+ // TODO[compat-openssl] OpenSSL test server Sends server extensions e.g. ec_point_formats
+ // TODO[compat-polarssl] PolarSSL test server Sends server extensions e.g. ec_point_formats
+ // throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+ }
+
+ /*
+ * RFC 5746 3.4. Client Behavior: Initial Handshake
+ */
+ {
+ /*
+ * When a ServerHello is received, the client MUST check if it includes the
+ * "renegotiation_info" extension:
+ */
+ byte[] renegExtData = TlsUtilities.GetExtensionData(this.mServerExtensions, ExtensionType.renegotiation_info);
+ if (renegExtData != null)
+ {
+ /*
+ * If the extension is present, set the secure_renegotiation flag to TRUE. The
+ * client MUST then verify that the length of the "renegotiated_connection"
+ * field is zero, and if it is not, MUST abort the handshake (by Sending a fatal
+ * handshake_failure alert).
+ */
+ this.mSecureRenegotiation = true;
+
+ if (!Arrays.ConstantTimeAreEqual(renegExtData, CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+ }
+
+ // TODO[compat-gnutls] GnuTLS test server fails to Send renegotiation_info extension when resuming
+ this.mTlsClient.NotifySecureRenegotiation(this.mSecureRenegotiation);
+
+ IDictionary sessionClientExtensions = mClientExtensions, sessionServerExtensions = mServerExtensions;
+ if (this.mResumedSession)
+ {
+ if (selectedCipherSuite != this.mSessionParameters.CipherSuite
+ || selectedCompressionMethod != this.mSessionParameters.CompressionAlgorithm)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ sessionClientExtensions = null;
+ sessionServerExtensions = this.mSessionParameters.ReadServerExtensions();
+ }
+
+ this.mSecurityParameters.cipherSuite = selectedCipherSuite;
+ this.mSecurityParameters.compressionAlgorithm = selectedCompressionMethod;
+
+ if (sessionServerExtensions != null)
+ {
+ {
+ /*
+ * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client
+ * and then selects a stream or Authenticated Encryption with Associated Data (AEAD)
+ * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the
+ * client.
+ */
+ bool serverSentEncryptThenMAC = TlsExtensionsUtilities.HasEncryptThenMacExtension(sessionServerExtensions);
+ if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(selectedCipherSuite))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ this.mSecurityParameters.encryptThenMac = serverSentEncryptThenMAC;
+ }
+
+ this.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);
+
+ this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(sessionClientExtensions,
+ sessionServerExtensions, AlertDescription.illegal_parameter);
+
+ this.mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(sessionServerExtensions);
+
+ /*
+ * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
+ * a session resumption handshake.
+ */
+ this.mAllowCertificateStatus = !this.mResumedSession
+ && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.status_request,
+ AlertDescription.illegal_parameter);
+
+ this.mExpectSessionTicket = !this.mResumedSession
+ && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.session_ticket,
+ AlertDescription.illegal_parameter);
+ }
+
+ /*
+ * TODO[session-hash]
+ *
+ * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes
+ * that do not use the extended master secret [..]. (and see 5.2, 5.3)
+ */
+
+ if (sessionClientExtensions != null)
+ {
+ this.mTlsClient.ProcessServerExtensions(sessionServerExtensions);
+ }
+
+ this.mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, this.mSecurityParameters.CipherSuite);
+
+ /*
+ * RFC 5246 7.4.9. Any cipher suite which does not explicitly specify
+ * verify_data_length has a verify_data_length equal to 12. This includes all
+ * existing cipher suites.
+ */
+ this.mSecurityParameters.verifyDataLength = 12;
+ }
+
+ protected virtual void SendCertificateVerifyMessage(DigitallySigned certificateVerify)
+ {
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_verify);
+
+ certificateVerify.Encode(message);
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual void SendClientHelloMessage()
+ {
+ this.mRecordStream.SetWriteVersion(this.mTlsClient.ClientHelloRecordLayerVersion);
+
+ ProtocolVersion client_version = this.mTlsClient.ClientVersion;
+ if (client_version.IsDtls)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ ContextAdmin.SetClientVersion(client_version);
+
+ /*
+ * TODO RFC 5077 3.4. When presenting a ticket, the client MAY generate and include a
+ * Session ID in the TLS ClientHello.
+ */
+ byte[] session_id = TlsUtilities.EmptyBytes;
+ if (this.mTlsSession != null)
+ {
+ session_id = this.mTlsSession.SessionID;
+ if (session_id == null || session_id.Length > 32)
+ {
+ session_id = TlsUtilities.EmptyBytes;
+ }
+ }
+
+ bool fallback = this.mTlsClient.IsFallback;
+
+ this.mOfferedCipherSuites = this.mTlsClient.GetCipherSuites();
+
+ this.mOfferedCompressionMethods = this.mTlsClient.GetCompressionMethods();
+
+ if (session_id.Length > 0 && this.mSessionParameters != null)
+ {
+ if (!Arrays.Contains(this.mOfferedCipherSuites, mSessionParameters.CipherSuite)
+ || !Arrays.Contains(this.mOfferedCompressionMethods, mSessionParameters.CompressionAlgorithm))
+ {
+ session_id = TlsUtilities.EmptyBytes;
+ }
+ }
+
+ this.mClientExtensions = this.mTlsClient.GetClientExtensions();
+
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.client_hello);
+
+ TlsUtilities.WriteVersion(client_version, message);
+
+ message.Write(this.mSecurityParameters.ClientRandom);
+
+ TlsUtilities.WriteOpaque8(session_id, message);
+
+ // Cipher Suites (and SCSV)
+ {
+ /*
+ * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
+ * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
+ * ClientHello. Including both is NOT RECOMMENDED.
+ */
+ byte[] renegExtData = TlsUtilities.GetExtensionData(mClientExtensions, ExtensionType.renegotiation_info);
+ bool noRenegExt = (null == renegExtData);
+
+ bool noRenegScsv = !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
+
+ if (noRenegExt && noRenegScsv)
+ {
+ // TODO Consider whether to default to a client extension instead
+ // this.mClientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(this.mClientExtensions);
+ // this.mClientExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
+ this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
+ }
+
+ /*
+ * RFC 7507 4. If a client sends a ClientHello.client_version containing a lower value
+ * than the latest (highest-valued) version supported by the client, it SHOULD include
+ * the TLS_FALLBACK_SCSV cipher suite value in ClientHello.cipher_suites [..]. (The
+ * client SHOULD put TLS_FALLBACK_SCSV after all cipher suites that it actually intends
+ * to negotiate.)
+ */
+ if (fallback && !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV))
+ {
+ this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV);
+ }
+
+ TlsUtilities.WriteUint16ArrayWithUint16Length(mOfferedCipherSuites, message);
+ }
+
+ TlsUtilities.WriteUint8ArrayWithUint8Length(mOfferedCompressionMethods, message);
+
+ if (mClientExtensions != null)
+ {
+ WriteExtensions(message, mClientExtensions);
+ }
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual void SendClientKeyExchangeMessage()
+ {
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.client_key_exchange);
+
+ this.mKeyExchange.GenerateClientKeyExchange(message);
+
+ message.WriteToRecordStream(this);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsCompression.cs b/bc-sharp-crypto/src/crypto/tls/TlsCompression.cs
new file mode 100644
index 0000000000000000000000000000000000000000..177d64b7eae691e894659844e5aebc4bae063729
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsCompression.cs
@@ -0,0 +1,12 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsCompression
+ {
+ Stream Compress(Stream output);
+
+ Stream Decompress(Stream output);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsContext.cs b/bc-sharp-crypto/src/crypto/tls/TlsContext.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d066723fc7bace37177a56068e6b8dcdcc32c2b5
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsContext.cs
@@ -0,0 +1,45 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Prng;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsContext
+ {
+ IRandomGenerator NonceRandomGenerator { get; }
+
+ SecureRandom SecureRandom { get; }
+
+ SecurityParameters SecurityParameters { get; }
+
+ bool IsServer { get; }
+
+ ProtocolVersion ClientVersion { get; }
+
+ ProtocolVersion ServerVersion { get; }
+
+ /**
+ * Used to get the resumable session, if any, used by this connection. Only available after the
+ * handshake has successfully completed.
+ *
+ * @return A {@link TlsSession} representing the resumable session used by this connection, or
+ * null if no resumable session available.
+ * @see TlsPeer#NotifyHandshakeComplete()
+ */
+ TlsSession ResumableSession { get; }
+
+ object UserObject { get; set; }
+
+ /**
+ * Export keying material according to RFC 5705: "Keying Material Exporters for TLS".
+ *
+ * @param asciiLabel indicates which application will use the exported keys.
+ * @param context_value allows the application using the exporter to mix its own data with the TLS PRF for
+ * the exporter output.
+ * @param length the number of bytes to generate
+ * @return a pseudorandom bit string of 'length' bytes generated from the master_secret.
+ */
+ byte[] ExportKeyingMaterial(string asciiLabel, byte[] context_value, int length);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsCredentials.cs b/bc-sharp-crypto/src/crypto/tls/TlsCredentials.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5c5f1c02e9b3ef03b2dd5c22cab3fade29097562
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsCredentials.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsCredentials
+ {
+ Certificate Certificate { get; }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsDHKeyExchange.cs b/bc-sharp-crypto/src/crypto/tls/TlsDHKeyExchange.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d179068bb5b42f7a4e499b511fa6c1e579130d8b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsDHKeyExchange.cs
@@ -0,0 +1,259 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// (D)TLS DH key exchange.
+ public class TlsDHKeyExchange
+ : AbstractTlsKeyExchange
+ {
+ protected TlsSigner mTlsSigner;
+ protected DHParameters mDHParameters;
+
+ protected AsymmetricKeyParameter mServerPublicKey;
+ protected TlsAgreementCredentials mAgreementCredentials;
+
+ protected DHPrivateKeyParameters mDHAgreePrivateKey;
+ protected DHPublicKeyParameters mDHAgreePublicKey;
+
+ public TlsDHKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, DHParameters dhParameters)
+ : base(keyExchange, supportedSignatureAlgorithms)
+ {
+ switch (keyExchange)
+ {
+ case KeyExchangeAlgorithm.DH_anon:
+ case KeyExchangeAlgorithm.DH_RSA:
+ case KeyExchangeAlgorithm.DH_DSS:
+ this.mTlsSigner = null;
+ break;
+ case KeyExchangeAlgorithm.DHE_RSA:
+ this.mTlsSigner = new TlsRsaSigner();
+ break;
+ case KeyExchangeAlgorithm.DHE_DSS:
+ this.mTlsSigner = new TlsDssSigner();
+ break;
+ default:
+ throw new InvalidOperationException("unsupported key exchange algorithm");
+ }
+
+ this.mDHParameters = dhParameters;
+ }
+
+ public override void Init(TlsContext context)
+ {
+ base.Init(context);
+
+ if (this.mTlsSigner != null)
+ {
+ this.mTlsSigner.Init(context);
+ }
+ }
+
+ public override void SkipServerCredentials()
+ {
+ if (mKeyExchange != KeyExchangeAlgorithm.DH_anon)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public override void ProcessServerCertificate(Certificate serverCertificate)
+ {
+ if (mKeyExchange == KeyExchangeAlgorithm.DH_anon)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ if (serverCertificate.IsEmpty)
+ throw new TlsFatalAlert(AlertDescription.bad_certificate);
+
+ X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
+
+ SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+ try
+ {
+ this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo);
+ }
+ catch (Exception e)
+ {
+ throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
+ }
+
+ if (mTlsSigner == null)
+ {
+ try
+ {
+ this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey((DHPublicKeyParameters)this.mServerPublicKey);
+ this.mDHParameters = ValidateDHParameters(mDHAgreePublicKey.Parameters);
+ }
+ catch (InvalidCastException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
+ }
+
+ TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement);
+ }
+ else
+ {
+ if (!mTlsSigner.IsValidPublicKey(this.mServerPublicKey))
+ {
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+ }
+
+ TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
+ }
+
+ base.ProcessServerCertificate(serverCertificate);
+ }
+
+ public override bool RequiresServerKeyExchange
+ {
+ get
+ {
+ switch (mKeyExchange)
+ {
+ case KeyExchangeAlgorithm.DH_anon:
+ case KeyExchangeAlgorithm.DHE_DSS:
+ case KeyExchangeAlgorithm.DHE_RSA:
+ return true;
+ default:
+ return false;
+ }
+ }
+ }
+
+ public override byte[] GenerateServerKeyExchange()
+ {
+ if (!RequiresServerKeyExchange)
+ return null;
+
+ // DH_anon is handled here, DHE_* in a subclass
+
+ MemoryStream buf = new MemoryStream();
+ this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom,
+ this.mDHParameters, buf);
+ return buf.ToArray();
+ }
+
+ public override void ProcessServerKeyExchange(Stream input)
+ {
+ if (!RequiresServerKeyExchange)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ // DH_anon is handled here, DHE_* in a subclass
+
+ ServerDHParams dhParams = ServerDHParams.Parse(input);
+
+ this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(dhParams.PublicKey);
+ this.mDHParameters = ValidateDHParameters(mDHAgreePublicKey.Parameters);
+ }
+
+ public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
+ {
+ if (mKeyExchange == KeyExchangeAlgorithm.DH_anon)
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+
+ byte[] types = certificateRequest.CertificateTypes;
+ for (int i = 0; i < types.Length; ++i)
+ {
+ switch (types[i])
+ {
+ case ClientCertificateType.rsa_sign:
+ case ClientCertificateType.dss_sign:
+ case ClientCertificateType.rsa_fixed_dh:
+ case ClientCertificateType.dss_fixed_dh:
+ case ClientCertificateType.ecdsa_sign:
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+ }
+
+ public override void ProcessClientCredentials(TlsCredentials clientCredentials)
+ {
+ if (mKeyExchange == KeyExchangeAlgorithm.DH_anon)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ if (clientCredentials is TlsAgreementCredentials)
+ {
+ // TODO Validate client cert has matching parameters (see 'areCompatibleParameters')?
+
+ this.mAgreementCredentials = (TlsAgreementCredentials)clientCredentials;
+ }
+ else if (clientCredentials is TlsSignerCredentials)
+ {
+ // OK
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public override void GenerateClientKeyExchange(Stream output)
+ {
+ /*
+ * RFC 2246 7.4.7.2 If the client certificate already contains a suitable Diffie-Hellman
+ * key, then Yc is implicit and does not need to be sent again. In this case, the Client Key
+ * Exchange message will be sent, but will be empty.
+ */
+ if (mAgreementCredentials == null)
+ {
+ this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom,
+ mDHParameters, output);
+ }
+ }
+
+ public override void ProcessClientCertificate(Certificate clientCertificate)
+ {
+ if (mKeyExchange == KeyExchangeAlgorithm.DH_anon)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ // TODO Extract the public key
+ // TODO If the certificate is 'fixed', take the public key as dhAgreePublicKey
+ }
+
+ public override void ProcessClientKeyExchange(Stream input)
+ {
+ if (mDHAgreePublicKey != null)
+ {
+ // For dss_fixed_dh and rsa_fixed_dh, the key arrived in the client certificate
+ return;
+ }
+
+ BigInteger Yc = TlsDHUtilities.ReadDHParameter(input);
+
+ this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(new DHPublicKeyParameters(Yc, mDHParameters));
+ }
+
+ public override byte[] GeneratePremasterSecret()
+ {
+ if (mAgreementCredentials != null)
+ {
+ return mAgreementCredentials.GenerateAgreement(mDHAgreePublicKey);
+ }
+
+ if (mDHAgreePrivateKey != null)
+ {
+ return TlsDHUtilities.CalculateDHBasicAgreement(mDHAgreePublicKey, mDHAgreePrivateKey);
+ }
+
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ protected virtual int MinimumPrimeBits
+ {
+ get { return 1024; }
+ }
+
+ protected virtual DHParameters ValidateDHParameters(DHParameters parameters)
+ {
+ if (parameters.P.BitLength < MinimumPrimeBits)
+ throw new TlsFatalAlert(AlertDescription.insufficient_security);
+
+ return TlsDHUtilities.ValidateDHParameters(parameters);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsDHUtilities.cs b/bc-sharp-crypto/src/crypto/tls/TlsDHUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6df61cbed35d238246f674a9e4f29e44515f9344
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsDHUtilities.cs
@@ -0,0 +1,462 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class TlsDHUtilities
+ {
+ internal static readonly BigInteger Two = BigInteger.Two;
+
+ /*
+ * TODO[draft-ietf-tls-negotiated-ff-dhe-01] Move these groups to DHStandardGroups once reaches RFC
+ */
+ private static BigInteger FromHex(String hex)
+ {
+ return new BigInteger(1, Hex.Decode(hex));
+ }
+
+ private static DHParameters FromSafeP(String hexP)
+ {
+ BigInteger p = FromHex(hexP), q = p.ShiftRight(1);
+ return new DHParameters(p, Two, q);
+ }
+
+ private static readonly string draft_ffdhe2432_p =
+ "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1"
+ + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9"
+ + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561"
+ + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935"
+ + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735"
+ + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB"
+ + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19"
+ + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61"
+ + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73"
+ + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA"
+ + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238"
+ + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C"
+ + "AEFE13098533C8B3FFFFFFFFFFFFFFFF";
+ internal static readonly DHParameters draft_ffdhe2432 = FromSafeP(draft_ffdhe2432_p);
+
+ private static readonly string draft_ffdhe3072_p =
+ "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1"
+ + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9"
+ + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561"
+ + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935"
+ + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735"
+ + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB"
+ + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19"
+ + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61"
+ + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73"
+ + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA"
+ + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238"
+ + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C"
+ + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3"
+ + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D"
+ + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF"
+ + "3C1B20EE3FD59D7C25E41D2B66C62E37FFFFFFFFFFFFFFFF";
+ internal static readonly DHParameters draft_ffdhe3072 = FromSafeP(draft_ffdhe3072_p);
+
+ private static readonly string draft_ffdhe4096_p =
+ "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1"
+ + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9"
+ + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561"
+ + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935"
+ + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735"
+ + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB"
+ + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19"
+ + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61"
+ + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73"
+ + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA"
+ + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238"
+ + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C"
+ + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3"
+ + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D"
+ + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF"
+ + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB"
+ + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004"
+ + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832"
+ + "A907600A918130C46DC778F971AD0038092999A333CB8B7A"
+ + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF"
+ + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E655F6A"
+ + "FFFFFFFFFFFFFFFF";
+ internal static readonly DHParameters draft_ffdhe4096 = FromSafeP(draft_ffdhe4096_p);
+
+ private static readonly string draft_ffdhe6144_p =
+ "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1"
+ + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9"
+ + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561"
+ + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935"
+ + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735"
+ + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB"
+ + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19"
+ + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61"
+ + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73"
+ + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA"
+ + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238"
+ + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C"
+ + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3"
+ + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D"
+ + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF"
+ + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB"
+ + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004"
+ + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832"
+ + "A907600A918130C46DC778F971AD0038092999A333CB8B7A"
+ + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF"
+ + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902"
+ + "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6"
+ + "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A"
+ + "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477"
+ + "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3"
+ + "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4"
+ + "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6"
+ + "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C"
+ + "D72B03746AE77F5E62292C311562A846505DC82DB854338A"
+ + "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04"
+ + "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1"
+ + "A41D570D7938DAD4A40E329CD0E40E65FFFFFFFFFFFFFFFF";
+ internal static readonly DHParameters draft_ffdhe6144 = FromSafeP(draft_ffdhe6144_p);
+
+ private static readonly string draft_ffdhe8192_p =
+ "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1"
+ + "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9"
+ + "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561"
+ + "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935"
+ + "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735"
+ + "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB"
+ + "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19"
+ + "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61"
+ + "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73"
+ + "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA"
+ + "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238"
+ + "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C"
+ + "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3"
+ + "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D"
+ + "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF"
+ + "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB"
+ + "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004"
+ + "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832"
+ + "A907600A918130C46DC778F971AD0038092999A333CB8B7A"
+ + "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF"
+ + "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902"
+ + "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6"
+ + "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A"
+ + "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477"
+ + "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3"
+ + "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4"
+ + "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6"
+ + "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C"
+ + "D72B03746AE77F5E62292C311562A846505DC82DB854338A"
+ + "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04"
+ + "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1"
+ + "A41D570D7938DAD4A40E329CCFF46AAA36AD004CF600C838"
+ + "1E425A31D951AE64FDB23FCEC9509D43687FEB69EDD1CC5E"
+ + "0B8CC3BDF64B10EF86B63142A3AB8829555B2F747C932665"
+ + "CB2C0F1CC01BD70229388839D2AF05E454504AC78B758282"
+ + "2846C0BA35C35F5C59160CC046FD8251541FC68C9C86B022"
+ + "BB7099876A460E7451A8A93109703FEE1C217E6C3826E52C"
+ + "51AA691E0E423CFC99E9E31650C1217B624816CDAD9A95F9"
+ + "D5B8019488D9C0A0A1FE3075A577E23183F81D4A3F2FA457"
+ + "1EFC8CE0BA8A4FE8B6855DFE72B0A66EDED2FBABFBE58A30"
+ + "FAFABE1C5D71A87E2F741EF8C1FE86FEA6BBFDE530677F0D"
+ + "97D11D49F7A8443D0822E506A9F4614E011E2A94838FF88C"
+ + "D68C8BB7C5C6424CFFFFFFFFFFFFFFFF";
+ internal static readonly DHParameters draft_ffdhe8192 = FromSafeP(draft_ffdhe8192_p);
+
+
+ public static void AddNegotiatedDheGroupsClientExtension(IDictionary extensions, byte[] dheGroups)
+ {
+ extensions[ExtensionType.negotiated_ff_dhe_groups] = CreateNegotiatedDheGroupsClientExtension(dheGroups);
+ }
+
+ public static void AddNegotiatedDheGroupsServerExtension(IDictionary extensions, byte dheGroup)
+ {
+ extensions[ExtensionType.negotiated_ff_dhe_groups] = CreateNegotiatedDheGroupsServerExtension(dheGroup);
+ }
+
+ public static byte[] GetNegotiatedDheGroupsClientExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.negotiated_ff_dhe_groups);
+ return extensionData == null ? null : ReadNegotiatedDheGroupsClientExtension(extensionData);
+ }
+
+ public static short GetNegotiatedDheGroupsServerExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.negotiated_ff_dhe_groups);
+ return extensionData == null ? (short)-1 : (short)ReadNegotiatedDheGroupsServerExtension(extensionData);
+ }
+
+ public static byte[] CreateNegotiatedDheGroupsClientExtension(byte[] dheGroups)
+ {
+ if (dheGroups == null || dheGroups.Length < 1 || dheGroups.Length > 255)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ return TlsUtilities.EncodeUint8ArrayWithUint8Length(dheGroups);
+ }
+
+ public static byte[] CreateNegotiatedDheGroupsServerExtension(byte dheGroup)
+ {
+ return TlsUtilities.EncodeUint8(dheGroup);
+ }
+
+ public static byte[] ReadNegotiatedDheGroupsClientExtension(byte[] extensionData)
+ {
+ byte[] dheGroups = TlsUtilities.DecodeUint8ArrayWithUint8Length(extensionData);
+ if (dheGroups.Length < 1)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ return dheGroups;
+ }
+
+ public static byte ReadNegotiatedDheGroupsServerExtension(byte[] extensionData)
+ {
+ return TlsUtilities.DecodeUint8(extensionData);
+ }
+
+ public static DHParameters GetParametersForDHEGroup(short dheGroup)
+ {
+ switch (dheGroup)
+ {
+ case FiniteFieldDheGroup.ffdhe2432:
+ return draft_ffdhe2432;
+ case FiniteFieldDheGroup.ffdhe3072:
+ return draft_ffdhe3072;
+ case FiniteFieldDheGroup.ffdhe4096:
+ return draft_ffdhe4096;
+ case FiniteFieldDheGroup.ffdhe6144:
+ return draft_ffdhe6144;
+ case FiniteFieldDheGroup.ffdhe8192:
+ return draft_ffdhe8192;
+ default:
+ return null;
+ }
+ }
+
+ public static bool ContainsDheCipherSuites(int[] cipherSuites)
+ {
+ for (int i = 0; i < cipherSuites.Length; ++i)
+ {
+ if (IsDheCipherSuite(cipherSuites[i]))
+ return true;
+ }
+ return false;
+ }
+
+ public static bool IsDheCipherSuite(int cipherSuite)
+ {
+ switch (cipherSuite)
+ {
+ /*
+ * RFC 2246
+ */
+ case CipherSuite.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_DES_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_DES_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+
+ /*
+ * RFC 3268
+ */
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+
+ /*
+ * RFC 5932
+ */
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+
+ /*
+ * RFC 4162
+ */
+ case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA:
+
+ /*
+ * RFC 4279
+ */
+ case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
+
+ /*
+ * RFC 4785
+ */
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA:
+
+ /*
+ * RFC 5246
+ */
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+
+ /*
+ * RFC 5288
+ */
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+
+ /*
+ * RFC 5487
+ */
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384:
+
+ /*
+ * RFC 6367
+ */
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+
+ /*
+ * RFC 6655
+ */
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
+
+ /*
+ * draft-ietf-tls-chacha20-poly1305-04
+ */
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+
+ /*
+ * draft-zauner-tls-aes-ocb-04
+ */
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB:
+
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ public static bool AreCompatibleParameters(DHParameters a, DHParameters b)
+ {
+ return a.P.Equals(b.P) && a.G.Equals(b.G)
+ && (a.Q == null || b.Q == null || a.Q.Equals(b.Q));
+ }
+
+ public static byte[] CalculateDHBasicAgreement(DHPublicKeyParameters publicKey,
+ DHPrivateKeyParameters privateKey)
+ {
+ DHBasicAgreement basicAgreement = new DHBasicAgreement();
+ basicAgreement.Init(privateKey);
+ BigInteger agreementValue = basicAgreement.CalculateAgreement(publicKey);
+
+ /*
+ * RFC 5246 8.1.2. Leading bytes of Z that contain all zero bits are stripped before it is
+ * used as the pre_master_secret.
+ */
+ return BigIntegers.AsUnsignedByteArray(agreementValue);
+ }
+
+ public static AsymmetricCipherKeyPair GenerateDHKeyPair(SecureRandom random, DHParameters dhParams)
+ {
+ DHBasicKeyPairGenerator dhGen = new DHBasicKeyPairGenerator();
+ dhGen.Init(new DHKeyGenerationParameters(random, dhParams));
+ return dhGen.GenerateKeyPair();
+ }
+
+ public static DHPrivateKeyParameters GenerateEphemeralClientKeyExchange(SecureRandom random,
+ DHParameters dhParams, Stream output)
+ {
+ AsymmetricCipherKeyPair kp = GenerateDHKeyPair(random, dhParams);
+
+ DHPublicKeyParameters dhPublic = (DHPublicKeyParameters)kp.Public;
+ WriteDHParameter(dhPublic.Y, output);
+
+ return (DHPrivateKeyParameters)kp.Private;
+ }
+
+ public static DHPrivateKeyParameters GenerateEphemeralServerKeyExchange(SecureRandom random,
+ DHParameters dhParams, Stream output)
+ {
+ AsymmetricCipherKeyPair kp = GenerateDHKeyPair(random, dhParams);
+
+ DHPublicKeyParameters dhPublic = (DHPublicKeyParameters)kp.Public;
+ new ServerDHParams(dhPublic).Encode(output);
+
+ return (DHPrivateKeyParameters)kp.Private;
+ }
+
+ public static DHParameters ValidateDHParameters(DHParameters parameters)
+ {
+ BigInteger p = parameters.P;
+ BigInteger g = parameters.G;
+
+ if (!p.IsProbablePrime(2))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ if (g.CompareTo(Two) < 0 || g.CompareTo(p.Subtract(Two)) > 0)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+
+ return parameters;
+ }
+
+ public static DHPublicKeyParameters ValidateDHPublicKey(DHPublicKeyParameters key)
+ {
+ DHParameters parameters = ValidateDHParameters(key.Parameters);
+
+ BigInteger Y = key.Y;
+ if (Y.CompareTo(Two) < 0 || Y.CompareTo(parameters.P.Subtract(Two)) > 0)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ // TODO See RFC 2631 for more discussion of Diffie-Hellman validation
+
+ return key;
+ }
+
+ public static BigInteger ReadDHParameter(Stream input)
+ {
+ return new BigInteger(1, TlsUtilities.ReadOpaque16(input));
+ }
+
+ public static void WriteDHParameter(BigInteger x, Stream output)
+ {
+ TlsUtilities.WriteOpaque16(BigIntegers.AsUnsignedByteArray(x), output);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsDeflateCompression.cs b/bc-sharp-crypto/src/crypto/tls/TlsDeflateCompression.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9e1152908cb8f11987362fdcf76a92d3cc6cc140
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsDeflateCompression.cs
@@ -0,0 +1,68 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.Zlib;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsDeflateCompression : TlsCompression
+ {
+ public const int LEVEL_NONE = JZlib.Z_NO_COMPRESSION;
+ public const int LEVEL_FASTEST = JZlib.Z_BEST_SPEED;
+ public const int LEVEL_SMALLEST = JZlib.Z_BEST_COMPRESSION;
+ public const int LEVEL_DEFAULT = JZlib.Z_DEFAULT_COMPRESSION;
+
+ protected readonly ZStream zIn, zOut;
+
+ public TlsDeflateCompression()
+ : this(LEVEL_DEFAULT)
+ {
+ }
+
+ public TlsDeflateCompression(int level)
+ {
+ this.zIn = new ZStream();
+ this.zIn.inflateInit();
+
+ this.zOut = new ZStream();
+ this.zOut.deflateInit(level);
+ }
+
+ public virtual Stream Compress(Stream output)
+ {
+ return new DeflateOutputStream(output, zOut, true);
+ }
+
+ public virtual Stream Decompress(Stream output)
+ {
+ return new DeflateOutputStream(output, zIn, false);
+ }
+
+ protected class DeflateOutputStream : ZOutputStream
+ {
+ public DeflateOutputStream(Stream output, ZStream z, bool compress)
+ : base(output, z)
+ {
+ this.compress = compress;
+
+ /*
+ * See discussion at http://www.bolet.org/~pornin/deflate-flush.html .
+ */
+ this.FlushMode = JZlib.Z_SYNC_FLUSH;
+ }
+
+ public override void Flush()
+ {
+ /*
+ * TODO The inflateSyncPoint doesn't appear to work the way I hoped at the moment.
+ * In any case, we may like to accept PARTIAL_FLUSH input, not just SYNC_FLUSH.
+ * It's not clear how to check this in the Inflater.
+ */
+ //if (!this.compress && (z == null || z.istate == null || z.istate.inflateSyncPoint(z) <= 0))
+ //{
+ // throw new TlsFatalAlert(AlertDescription.decompression_failure);
+ //}
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsDheKeyExchange.cs b/bc-sharp-crypto/src/crypto/tls/TlsDheKeyExchange.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cdd629247bb7b5311fd9939c9f67f087410e1668
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsDheKeyExchange.cs
@@ -0,0 +1,94 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsDheKeyExchange
+ : TlsDHKeyExchange
+ {
+ protected TlsSignerCredentials mServerCredentials = null;
+
+ public TlsDheKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, DHParameters dhParameters)
+ : base(keyExchange, supportedSignatureAlgorithms, dhParameters)
+ {
+ }
+
+ public override void ProcessServerCredentials(TlsCredentials serverCredentials)
+ {
+ if (!(serverCredentials is TlsSignerCredentials))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ ProcessServerCertificate(serverCredentials.Certificate);
+
+ this.mServerCredentials = (TlsSignerCredentials)serverCredentials;
+ }
+
+ public override byte[] GenerateServerKeyExchange()
+ {
+ if (this.mDHParameters == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ DigestInputBuffer buf = new DigestInputBuffer();
+
+ this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom,
+ this.mDHParameters, buf);
+
+ /*
+ * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
+ */
+ SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
+ mContext, mServerCredentials);
+
+ IDigest d = TlsUtilities.CreateHash(signatureAndHashAlgorithm);
+
+ SecurityParameters securityParameters = mContext.SecurityParameters;
+ d.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
+ d.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
+ buf.UpdateDigest(d);
+
+ byte[] hash = DigestUtilities.DoFinal(d);
+
+ byte[] signature = mServerCredentials.GenerateCertificateSignature(hash);
+
+ DigitallySigned signed_params = new DigitallySigned(signatureAndHashAlgorithm, signature);
+ signed_params.Encode(buf);
+
+ return buf.ToArray();
+ }
+
+ public override void ProcessServerKeyExchange(Stream input)
+ {
+ SecurityParameters securityParameters = mContext.SecurityParameters;
+
+ SignerInputBuffer buf = new SignerInputBuffer();
+ Stream teeIn = new TeeInputStream(input, buf);
+
+ ServerDHParams dhParams = ServerDHParams.Parse(teeIn);
+
+ DigitallySigned signed_params = ParseSignature(input);
+
+ ISigner signer = InitVerifyer(mTlsSigner, signed_params.Algorithm, securityParameters);
+ buf.UpdateSigner(signer);
+ if (!signer.VerifySignature(signed_params.Signature))
+ throw new TlsFatalAlert(AlertDescription.decrypt_error);
+
+ this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(dhParams.PublicKey);
+ this.mDHParameters = ValidateDHParameters(mDHAgreePublicKey.Parameters);
+ }
+
+ protected virtual ISigner InitVerifyer(TlsSigner tlsSigner, SignatureAndHashAlgorithm algorithm,
+ SecurityParameters securityParameters)
+ {
+ ISigner signer = tlsSigner.CreateVerifyer(algorithm, this.mServerPublicKey);
+ signer.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
+ signer.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
+ return signer;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsDsaSigner.cs b/bc-sharp-crypto/src/crypto/tls/TlsDsaSigner.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f0c1e9451400539f43ffd901d12eb479980e623e
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsDsaSigner.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class TlsDsaSigner
+ : AbstractTlsSigner
+ {
+ public override byte[] GenerateRawSignature(SignatureAndHashAlgorithm algorithm,
+ AsymmetricKeyParameter privateKey, byte[] hash)
+ {
+ ISigner signer = MakeSigner(algorithm, true, true,
+ new ParametersWithRandom(privateKey, this.mContext.SecureRandom));
+ if (algorithm == null)
+ {
+ // Note: Only use the SHA1 part of the (MD5/SHA1) hash
+ signer.BlockUpdate(hash, 16, 20);
+ }
+ else
+ {
+ signer.BlockUpdate(hash, 0, hash.Length);
+ }
+ return signer.GenerateSignature();
+ }
+
+ public override bool VerifyRawSignature(SignatureAndHashAlgorithm algorithm, byte[] sigBytes,
+ AsymmetricKeyParameter publicKey, byte[] hash)
+ {
+ ISigner signer = MakeSigner(algorithm, true, false, publicKey);
+ if (algorithm == null)
+ {
+ // Note: Only use the SHA1 part of the (MD5/SHA1) hash
+ signer.BlockUpdate(hash, 16, 20);
+ }
+ else
+ {
+ signer.BlockUpdate(hash, 0, hash.Length);
+ }
+ return signer.VerifySignature(sigBytes);
+ }
+
+ public override ISigner CreateSigner(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter privateKey)
+ {
+ return MakeSigner(algorithm, false, true, privateKey);
+ }
+
+ public override ISigner CreateVerifyer(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter publicKey)
+ {
+ return MakeSigner(algorithm, false, false, publicKey);
+ }
+
+ protected virtual ICipherParameters MakeInitParameters(bool forSigning, ICipherParameters cp)
+ {
+ return cp;
+ }
+
+ protected virtual ISigner MakeSigner(SignatureAndHashAlgorithm algorithm, bool raw, bool forSigning,
+ ICipherParameters cp)
+ {
+ if ((algorithm != null) != TlsUtilities.IsTlsV12(mContext))
+ throw new InvalidOperationException();
+
+ if (algorithm != null && algorithm.Signature != SignatureAlgorithm)
+ throw new InvalidOperationException();
+
+ byte hashAlgorithm = algorithm == null ? HashAlgorithm.sha1 : algorithm.Hash;
+ IDigest d = raw ? new NullDigest() : TlsUtilities.CreateHash(hashAlgorithm);
+
+ ISigner s = new DsaDigestSigner(CreateDsaImpl(hashAlgorithm), d);
+ s.Init(forSigning, MakeInitParameters(forSigning, cp));
+ return s;
+ }
+
+ protected abstract byte SignatureAlgorithm { get; }
+
+ protected abstract IDsa CreateDsaImpl(byte hashAlgorithm);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsDssSigner.cs b/bc-sharp-crypto/src/crypto/tls/TlsDssSigner.cs
new file mode 100644
index 0000000000000000000000000000000000000000..707ef3853037cd2372d19e462097f09ecff8b8ad
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsDssSigner.cs
@@ -0,0 +1,26 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsDssSigner
+ : TlsDsaSigner
+ {
+ public override bool IsValidPublicKey(AsymmetricKeyParameter publicKey)
+ {
+ return publicKey is DsaPublicKeyParameters;
+ }
+
+ protected override IDsa CreateDsaImpl(byte hashAlgorithm)
+ {
+ return new DsaSigner(new HMacDsaKCalculator(TlsUtilities.CreateHash(hashAlgorithm)));
+ }
+
+ protected override byte SignatureAlgorithm
+ {
+ get { return Tls.SignatureAlgorithm.dsa; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsECDHKeyExchange.cs b/bc-sharp-crypto/src/crypto/tls/TlsECDHKeyExchange.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c508fb993242c4b0eeb6bd2fab38cb9c522cd12f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsECDHKeyExchange.cs
@@ -0,0 +1,252 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// (D)TLS ECDH key exchange (see RFC 4492).
+ public class TlsECDHKeyExchange
+ : AbstractTlsKeyExchange
+ {
+ protected TlsSigner mTlsSigner;
+ protected int[] mNamedCurves;
+ protected byte[] mClientECPointFormats, mServerECPointFormats;
+
+ protected AsymmetricKeyParameter mServerPublicKey;
+ protected TlsAgreementCredentials mAgreementCredentials;
+
+ protected ECPrivateKeyParameters mECAgreePrivateKey;
+ protected ECPublicKeyParameters mECAgreePublicKey;
+
+ public TlsECDHKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, int[] namedCurves,
+ byte[] clientECPointFormats, byte[] serverECPointFormats)
+ : base(keyExchange, supportedSignatureAlgorithms)
+ {
+ switch (keyExchange)
+ {
+ case KeyExchangeAlgorithm.ECDHE_RSA:
+ this.mTlsSigner = new TlsRsaSigner();
+ break;
+ case KeyExchangeAlgorithm.ECDHE_ECDSA:
+ this.mTlsSigner = new TlsECDsaSigner();
+ break;
+ case KeyExchangeAlgorithm.ECDH_anon:
+ case KeyExchangeAlgorithm.ECDH_RSA:
+ case KeyExchangeAlgorithm.ECDH_ECDSA:
+ this.mTlsSigner = null;
+ break;
+ default:
+ throw new InvalidOperationException("unsupported key exchange algorithm");
+ }
+
+ this.mNamedCurves = namedCurves;
+ this.mClientECPointFormats = clientECPointFormats;
+ this.mServerECPointFormats = serverECPointFormats;
+ }
+
+ public override void Init(TlsContext context)
+ {
+ base.Init(context);
+
+ if (this.mTlsSigner != null)
+ {
+ this.mTlsSigner.Init(context);
+ }
+ }
+
+ public override void SkipServerCredentials()
+ {
+ if (mKeyExchange != KeyExchangeAlgorithm.ECDH_anon)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public override void ProcessServerCertificate(Certificate serverCertificate)
+ {
+ if (mKeyExchange == KeyExchangeAlgorithm.ECDH_anon)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ if (serverCertificate.IsEmpty)
+ throw new TlsFatalAlert(AlertDescription.bad_certificate);
+
+ X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
+
+ SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+ try
+ {
+ this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo);
+ }
+ catch (Exception e)
+ {
+ throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
+ }
+
+ if (mTlsSigner == null)
+ {
+ try
+ {
+ this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey((ECPublicKeyParameters) this.mServerPublicKey);
+ }
+ catch (InvalidCastException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
+ }
+
+ TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement);
+ }
+ else
+ {
+ if (!mTlsSigner.IsValidPublicKey(this.mServerPublicKey))
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+
+ TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
+ }
+
+ base.ProcessServerCertificate(serverCertificate);
+ }
+
+ public override bool RequiresServerKeyExchange
+ {
+ get
+ {
+ switch (mKeyExchange)
+ {
+ case KeyExchangeAlgorithm.ECDH_anon:
+ case KeyExchangeAlgorithm.ECDHE_ECDSA:
+ case KeyExchangeAlgorithm.ECDHE_RSA:
+ return true;
+ default:
+ return false;
+ }
+ }
+ }
+
+ public override byte[] GenerateServerKeyExchange()
+ {
+ if (!RequiresServerKeyExchange)
+ return null;
+
+ // ECDH_anon is handled here, ECDHE_* in a subclass
+
+ MemoryStream buf = new MemoryStream();
+ this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom, mNamedCurves,
+ mClientECPointFormats, buf);
+ return buf.ToArray();
+ }
+
+ public override void ProcessServerKeyExchange(Stream input)
+ {
+ if (!RequiresServerKeyExchange)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ // ECDH_anon is handled here, ECDHE_* in a subclass
+
+ ECDomainParameters curve_params = TlsEccUtilities.ReadECParameters(mNamedCurves, mClientECPointFormats, input);
+
+ byte[] point = TlsUtilities.ReadOpaque8(input);
+
+ this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
+ mClientECPointFormats, curve_params, point));
+ }
+
+ public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
+ {
+ if (mKeyExchange == KeyExchangeAlgorithm.ECDH_anon)
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+
+ /*
+ * RFC 4492 3. [...] The ECDSA_fixed_ECDH and RSA_fixed_ECDH mechanisms are usable with
+ * ECDH_ECDSA and ECDH_RSA. Their use with ECDHE_ECDSA and ECDHE_RSA is prohibited because
+ * the use of a long-term ECDH client key would jeopardize the forward secrecy property of
+ * these algorithms.
+ */
+ byte[] types = certificateRequest.CertificateTypes;
+ for (int i = 0; i < types.Length; ++i)
+ {
+ switch (types[i])
+ {
+ case ClientCertificateType.rsa_sign:
+ case ClientCertificateType.dss_sign:
+ case ClientCertificateType.ecdsa_sign:
+ case ClientCertificateType.rsa_fixed_ecdh:
+ case ClientCertificateType.ecdsa_fixed_ecdh:
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+ }
+
+ public override void ProcessClientCredentials(TlsCredentials clientCredentials)
+ {
+ if (mKeyExchange == KeyExchangeAlgorithm.ECDH_anon)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ if (clientCredentials is TlsAgreementCredentials)
+ {
+ // TODO Validate client cert has matching parameters (see 'TlsEccUtilities.AreOnSameCurve')?
+
+ this.mAgreementCredentials = (TlsAgreementCredentials)clientCredentials;
+ }
+ else if (clientCredentials is TlsSignerCredentials)
+ {
+ // OK
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public override void GenerateClientKeyExchange(Stream output)
+ {
+ if (mAgreementCredentials == null)
+ {
+ this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom,
+ mServerECPointFormats, mECAgreePublicKey.Parameters, output);
+ }
+ }
+
+ public override void ProcessClientCertificate(Certificate clientCertificate)
+ {
+ if (mKeyExchange == KeyExchangeAlgorithm.ECDH_anon)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ // TODO Extract the public key
+ // TODO If the certificate is 'fixed', take the public key as mECAgreeClientPublicKey
+ }
+
+ public override void ProcessClientKeyExchange(Stream input)
+ {
+ if (mECAgreePublicKey != null)
+ {
+ // For ecdsa_fixed_ecdh and rsa_fixed_ecdh, the key arrived in the client certificate
+ return;
+ }
+
+ byte[] point = TlsUtilities.ReadOpaque8(input);
+
+ ECDomainParameters curve_params = this.mECAgreePrivateKey.Parameters;
+
+ this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
+ mServerECPointFormats, curve_params, point));
+ }
+
+ public override byte[] GeneratePremasterSecret()
+ {
+ if (mAgreementCredentials != null)
+ {
+ return mAgreementCredentials.GenerateAgreement(mECAgreePublicKey);
+ }
+
+ if (mECAgreePrivateKey != null)
+ {
+ return TlsEccUtilities.CalculateECDHBasicAgreement(mECAgreePublicKey, mECAgreePrivateKey);
+ }
+
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsECDheKeyExchange.cs b/bc-sharp-crypto/src/crypto/tls/TlsECDheKeyExchange.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e0553b3f0717be6840f8b0d1cbdb682fd1d4d58a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsECDheKeyExchange.cs
@@ -0,0 +1,131 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// (D)TLS ECDHE key exchange (see RFC 4492).
+ public class TlsECDheKeyExchange
+ : TlsECDHKeyExchange
+ {
+ protected TlsSignerCredentials mServerCredentials = null;
+
+ public TlsECDheKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, int[] namedCurves,
+ byte[] clientECPointFormats, byte[] serverECPointFormats)
+ : base(keyExchange, supportedSignatureAlgorithms, namedCurves, clientECPointFormats, serverECPointFormats)
+ {
+ }
+
+ public override void ProcessServerCredentials(TlsCredentials serverCredentials)
+ {
+ if (!(serverCredentials is TlsSignerCredentials))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ ProcessServerCertificate(serverCredentials.Certificate);
+
+ this.mServerCredentials = (TlsSignerCredentials)serverCredentials;
+ }
+
+ public override byte[] GenerateServerKeyExchange()
+ {
+ DigestInputBuffer buf = new DigestInputBuffer();
+
+ this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom, mNamedCurves,
+ mClientECPointFormats, buf);
+
+ /*
+ * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
+ */
+ SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
+ mContext, mServerCredentials);
+
+ IDigest d = TlsUtilities.CreateHash(signatureAndHashAlgorithm);
+
+ SecurityParameters securityParameters = mContext.SecurityParameters;
+ d.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
+ d.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
+ buf.UpdateDigest(d);
+
+ byte[] hash = DigestUtilities.DoFinal(d);
+
+ byte[] signature = mServerCredentials.GenerateCertificateSignature(hash);
+
+ DigitallySigned signed_params = new DigitallySigned(signatureAndHashAlgorithm, signature);
+ signed_params.Encode(buf);
+
+ return buf.ToArray();
+ }
+
+ public override void ProcessServerKeyExchange(Stream input)
+ {
+ SecurityParameters securityParameters = mContext.SecurityParameters;
+
+ SignerInputBuffer buf = new SignerInputBuffer();
+ Stream teeIn = new TeeInputStream(input, buf);
+
+ ECDomainParameters curve_params = TlsEccUtilities.ReadECParameters(mNamedCurves, mClientECPointFormats, teeIn);
+
+ byte[] point = TlsUtilities.ReadOpaque8(teeIn);
+
+ DigitallySigned signed_params = ParseSignature(input);
+
+ ISigner signer = InitVerifyer(mTlsSigner, signed_params.Algorithm, securityParameters);
+ buf.UpdateSigner(signer);
+ if (!signer.VerifySignature(signed_params.Signature))
+ throw new TlsFatalAlert(AlertDescription.decrypt_error);
+
+ this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
+ mClientECPointFormats, curve_params, point));
+ }
+
+ public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
+ {
+ /*
+ * RFC 4492 3. [...] The ECDSA_fixed_ECDH and RSA_fixed_ECDH mechanisms are usable with
+ * ECDH_ECDSA and ECDH_RSA. Their use with ECDHE_ECDSA and ECDHE_RSA is prohibited because
+ * the use of a long-term ECDH client key would jeopardize the forward secrecy property of
+ * these algorithms.
+ */
+ byte[] types = certificateRequest.CertificateTypes;
+ for (int i = 0; i < types.Length; ++i)
+ {
+ switch (types[i])
+ {
+ case ClientCertificateType.rsa_sign:
+ case ClientCertificateType.dss_sign:
+ case ClientCertificateType.ecdsa_sign:
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+ }
+
+ public override void ProcessClientCredentials(TlsCredentials clientCredentials)
+ {
+ if (clientCredentials is TlsSignerCredentials)
+ {
+ // OK
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ protected virtual ISigner InitVerifyer(TlsSigner tlsSigner, SignatureAndHashAlgorithm algorithm,
+ SecurityParameters securityParameters)
+ {
+ ISigner signer = tlsSigner.CreateVerifyer(algorithm, this.mServerPublicKey);
+ signer.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
+ signer.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
+ return signer;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsECDsaSigner.cs b/bc-sharp-crypto/src/crypto/tls/TlsECDsaSigner.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fa9d0b71482e1476395cccd58fdb6c76b3764a02
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsECDsaSigner.cs
@@ -0,0 +1,26 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsECDsaSigner
+ : TlsDsaSigner
+ {
+ public override bool IsValidPublicKey(AsymmetricKeyParameter publicKey)
+ {
+ return publicKey is ECPublicKeyParameters;
+ }
+
+ protected override IDsa CreateDsaImpl(byte hashAlgorithm)
+ {
+ return new ECDsaSigner(new HMacDsaKCalculator(TlsUtilities.CreateHash(hashAlgorithm)));
+ }
+
+ protected override byte SignatureAlgorithm
+ {
+ get { return Tls.SignatureAlgorithm.ecdsa; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsEccUtilities.cs b/bc-sharp-crypto/src/crypto/tls/TlsEccUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fb31e1b07de41a2c8c9dbab5934d0f2226c971c3
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsEccUtilities.cs
@@ -0,0 +1,705 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.EC;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.Field;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class TlsEccUtilities
+ {
+ private static readonly string[] CurveNames = new string[] { "sect163k1", "sect163r1", "sect163r2", "sect193r1",
+ "sect193r2", "sect233k1", "sect233r1", "sect239k1", "sect283k1", "sect283r1", "sect409k1", "sect409r1",
+ "sect571k1", "sect571r1", "secp160k1", "secp160r1", "secp160r2", "secp192k1", "secp192r1", "secp224k1",
+ "secp224r1", "secp256k1", "secp256r1", "secp384r1", "secp521r1",
+ "brainpoolP256r1", "brainpoolP384r1", "brainpoolP512r1"};
+
+ public static void AddSupportedEllipticCurvesExtension(IDictionary extensions, int[] namedCurves)
+ {
+ extensions[ExtensionType.elliptic_curves] = CreateSupportedEllipticCurvesExtension(namedCurves);
+ }
+
+ public static void AddSupportedPointFormatsExtension(IDictionary extensions, byte[] ecPointFormats)
+ {
+ extensions[ExtensionType.ec_point_formats] = CreateSupportedPointFormatsExtension(ecPointFormats);
+ }
+
+ public static int[] GetSupportedEllipticCurvesExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.elliptic_curves);
+ return extensionData == null ? null : ReadSupportedEllipticCurvesExtension(extensionData);
+ }
+
+ public static byte[] GetSupportedPointFormatsExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.ec_point_formats);
+ return extensionData == null ? null : ReadSupportedPointFormatsExtension(extensionData);
+ }
+
+ public static byte[] CreateSupportedEllipticCurvesExtension(int[] namedCurves)
+ {
+ if (namedCurves == null || namedCurves.Length < 1)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ return TlsUtilities.EncodeUint16ArrayWithUint16Length(namedCurves);
+ }
+
+ public static byte[] CreateSupportedPointFormatsExtension(byte[] ecPointFormats)
+ {
+ if (ecPointFormats == null || !Arrays.Contains(ecPointFormats, ECPointFormat.uncompressed))
+ {
+ /*
+ * RFC 4492 5.1. If the Supported Point Formats Extension is indeed sent, it MUST
+ * contain the value 0 (uncompressed) as one of the items in the list of point formats.
+ */
+
+ // NOTE: We add it at the end (lowest preference)
+ ecPointFormats = Arrays.Append(ecPointFormats, ECPointFormat.uncompressed);
+ }
+
+ return TlsUtilities.EncodeUint8ArrayWithUint8Length(ecPointFormats);
+ }
+
+ public static int[] ReadSupportedEllipticCurvesExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ MemoryStream buf = new MemoryStream(extensionData, false);
+
+ int length = TlsUtilities.ReadUint16(buf);
+ if (length < 2 || (length & 1) != 0)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ int[] namedCurves = TlsUtilities.ReadUint16Array(length / 2, buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ return namedCurves;
+ }
+
+ public static byte[] ReadSupportedPointFormatsExtension(byte[] extensionData)
+ {
+ byte[] ecPointFormats = TlsUtilities.DecodeUint8ArrayWithUint8Length(extensionData);
+ if (!Arrays.Contains(ecPointFormats, ECPointFormat.uncompressed))
+ {
+ /*
+ * RFC 4492 5.1. If the Supported Point Formats Extension is indeed sent, it MUST
+ * contain the value 0 (uncompressed) as one of the items in the list of point formats.
+ */
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ return ecPointFormats;
+ }
+
+ public static string GetNameOfNamedCurve(int namedCurve)
+ {
+ return IsSupportedNamedCurve(namedCurve) ? CurveNames[namedCurve - 1] : null;
+ }
+
+ public static ECDomainParameters GetParametersForNamedCurve(int namedCurve)
+ {
+ string curveName = GetNameOfNamedCurve(namedCurve);
+ if (curveName == null)
+ return null;
+
+ // Parameters are lazily created the first time a particular curve is accessed
+
+ X9ECParameters ecP = CustomNamedCurves.GetByName(curveName);
+ if (ecP == null)
+ {
+ ecP = ECNamedCurveTable.GetByName(curveName);
+ if (ecP == null)
+ return null;
+ }
+
+ // It's a bit inefficient to do this conversion every time
+ return new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());
+ }
+
+ public static bool HasAnySupportedNamedCurves()
+ {
+ return CurveNames.Length > 0;
+ }
+
+ public static bool ContainsEccCipherSuites(int[] cipherSuites)
+ {
+ for (int i = 0; i < cipherSuites.Length; ++i)
+ {
+ if (IsEccCipherSuite(cipherSuites[i]))
+ return true;
+ }
+ return false;
+ }
+
+ public static bool IsEccCipherSuite(int cipherSuite)
+ {
+ switch (cipherSuite)
+ {
+ /*
+ * RFC 4492
+ */
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
+
+ /*
+ * RFC 5289
+ */
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+
+ /*
+ * RFC 5489
+ */
+ case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA:
+
+ /*
+ * RFC 6367
+ */
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+
+ case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+
+ /*
+ * RFC 7251
+ */
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
+
+ /*
+ * draft-ietf-tls-chacha20-poly1305-04
+ */
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+
+ /*
+ * draft-zauner-tls-aes-ocb-04
+ */
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB:
+
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ public static bool AreOnSameCurve(ECDomainParameters a, ECDomainParameters b)
+ {
+ return a != null && a.Equals(b);
+ }
+
+ public static bool IsSupportedNamedCurve(int namedCurve)
+ {
+ return (namedCurve > 0 && namedCurve <= CurveNames.Length);
+ }
+
+ public static bool IsCompressionPreferred(byte[] ecPointFormats, byte compressionFormat)
+ {
+ if (ecPointFormats == null)
+ return false;
+
+ for (int i = 0; i < ecPointFormats.Length; ++i)
+ {
+ byte ecPointFormat = ecPointFormats[i];
+ if (ecPointFormat == ECPointFormat.uncompressed)
+ return false;
+ if (ecPointFormat == compressionFormat)
+ return true;
+ }
+ return false;
+ }
+
+ public static byte[] SerializeECFieldElement(int fieldSize, BigInteger x)
+ {
+ return BigIntegers.AsUnsignedByteArray((fieldSize + 7) / 8, x);
+ }
+
+ public static byte[] SerializeECPoint(byte[] ecPointFormats, ECPoint point)
+ {
+ ECCurve curve = point.Curve;
+
+ /*
+ * RFC 4492 5.7. ...an elliptic curve point in uncompressed or compressed format. Here, the
+ * format MUST conform to what the server has requested through a Supported Point Formats
+ * Extension if this extension was used, and MUST be uncompressed if this extension was not
+ * used.
+ */
+ bool compressed = false;
+ if (ECAlgorithms.IsFpCurve(curve))
+ {
+ compressed = IsCompressionPreferred(ecPointFormats, ECPointFormat.ansiX962_compressed_prime);
+ }
+ else if (ECAlgorithms.IsF2mCurve(curve))
+ {
+ compressed = IsCompressionPreferred(ecPointFormats, ECPointFormat.ansiX962_compressed_char2);
+ }
+ return point.GetEncoded(compressed);
+ }
+
+ public static byte[] SerializeECPublicKey(byte[] ecPointFormats, ECPublicKeyParameters keyParameters)
+ {
+ return SerializeECPoint(ecPointFormats, keyParameters.Q);
+ }
+
+ public static BigInteger DeserializeECFieldElement(int fieldSize, byte[] encoding)
+ {
+ int requiredLength = (fieldSize + 7) / 8;
+ if (encoding.Length != requiredLength)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ return new BigInteger(1, encoding);
+ }
+
+ public static ECPoint DeserializeECPoint(byte[] ecPointFormats, ECCurve curve, byte[] encoding)
+ {
+ if (encoding == null || encoding.Length < 1)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ byte actualFormat;
+ switch (encoding[0])
+ {
+ case 0x02: // compressed
+ case 0x03: // compressed
+ {
+ if (ECAlgorithms.IsF2mCurve(curve))
+ {
+ actualFormat = ECPointFormat.ansiX962_compressed_char2;
+ }
+ else if (ECAlgorithms.IsFpCurve(curve))
+ {
+ actualFormat = ECPointFormat.ansiX962_compressed_prime;
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ break;
+ }
+ case 0x04: // uncompressed
+ {
+ actualFormat = ECPointFormat.uncompressed;
+ break;
+ }
+ case 0x00: // infinity
+ case 0x06: // hybrid
+ case 0x07: // hybrid
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ if (actualFormat != ECPointFormat.uncompressed
+ && (ecPointFormats == null || !Arrays.Contains(ecPointFormats, actualFormat)))
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ return curve.DecodePoint(encoding);
+ }
+
+ public static ECPublicKeyParameters DeserializeECPublicKey(byte[] ecPointFormats, ECDomainParameters curve_params,
+ byte[] encoding)
+ {
+ try
+ {
+ ECPoint Y = DeserializeECPoint(ecPointFormats, curve_params.Curve, encoding);
+ return new ECPublicKeyParameters(Y, curve_params);
+ }
+ catch (Exception e)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
+ }
+ }
+
+ public static byte[] CalculateECDHBasicAgreement(ECPublicKeyParameters publicKey, ECPrivateKeyParameters privateKey)
+ {
+ ECDHBasicAgreement basicAgreement = new ECDHBasicAgreement();
+ basicAgreement.Init(privateKey);
+ BigInteger agreementValue = basicAgreement.CalculateAgreement(publicKey);
+
+ /*
+ * RFC 4492 5.10. Note that this octet string (Z in IEEE 1363 terminology) as output by
+ * FE2OSP, the Field Element to Octet String Conversion Primitive, has constant length for
+ * any given field; leading zeros found in this octet string MUST NOT be truncated.
+ */
+ return BigIntegers.AsUnsignedByteArray(basicAgreement.GetFieldSize(), agreementValue);
+ }
+
+ public static AsymmetricCipherKeyPair GenerateECKeyPair(SecureRandom random, ECDomainParameters ecParams)
+ {
+ ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
+ keyPairGenerator.Init(new ECKeyGenerationParameters(ecParams, random));
+ return keyPairGenerator.GenerateKeyPair();
+ }
+
+ public static ECPrivateKeyParameters GenerateEphemeralClientKeyExchange(SecureRandom random, byte[] ecPointFormats,
+ ECDomainParameters ecParams, Stream output)
+ {
+ AsymmetricCipherKeyPair kp = GenerateECKeyPair(random, ecParams);
+
+ ECPublicKeyParameters ecPublicKey = (ECPublicKeyParameters)kp.Public;
+ WriteECPoint(ecPointFormats, ecPublicKey.Q, output);
+
+ return (ECPrivateKeyParameters)kp.Private;
+ }
+
+ // TODO Refactor around ServerECDHParams before making this public
+ internal static ECPrivateKeyParameters GenerateEphemeralServerKeyExchange(SecureRandom random, int[] namedCurves,
+ byte[] ecPointFormats, Stream output)
+ {
+ /* First we try to find a supported named curve from the client's list. */
+ int namedCurve = -1;
+ if (namedCurves == null)
+ {
+ // TODO Let the peer choose the default named curve
+ namedCurve = NamedCurve.secp256r1;
+ }
+ else
+ {
+ for (int i = 0; i < namedCurves.Length; ++i)
+ {
+ int entry = namedCurves[i];
+ if (NamedCurve.IsValid(entry) && IsSupportedNamedCurve(entry))
+ {
+ namedCurve = entry;
+ break;
+ }
+ }
+ }
+
+ ECDomainParameters ecParams = null;
+ if (namedCurve >= 0)
+ {
+ ecParams = GetParametersForNamedCurve(namedCurve);
+ }
+ else
+ {
+ /* If no named curves are suitable, check if the client supports explicit curves. */
+ if (Arrays.Contains(namedCurves, NamedCurve.arbitrary_explicit_prime_curves))
+ {
+ ecParams = GetParametersForNamedCurve(NamedCurve.secp256r1);
+ }
+ else if (Arrays.Contains(namedCurves, NamedCurve.arbitrary_explicit_char2_curves))
+ {
+ ecParams = GetParametersForNamedCurve(NamedCurve.sect283r1);
+ }
+ }
+
+ if (ecParams == null)
+ {
+ /*
+ * NOTE: We shouldn't have negotiated ECDHE key exchange since we apparently can't find
+ * a suitable curve.
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ if (namedCurve < 0)
+ {
+ WriteExplicitECParameters(ecPointFormats, ecParams, output);
+ }
+ else
+ {
+ WriteNamedECParameters(namedCurve, output);
+ }
+
+ return GenerateEphemeralClientKeyExchange(random, ecPointFormats, ecParams, output);
+ }
+
+ public static ECPublicKeyParameters ValidateECPublicKey(ECPublicKeyParameters key)
+ {
+ // TODO Check RFC 4492 for validation
+ return key;
+ }
+
+ public static int ReadECExponent(int fieldSize, Stream input)
+ {
+ BigInteger K = ReadECParameter(input);
+ if (K.BitLength < 32)
+ {
+ int k = K.IntValue;
+ if (k > 0 && k < fieldSize)
+ {
+ return k;
+ }
+ }
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ public static BigInteger ReadECFieldElement(int fieldSize, Stream input)
+ {
+ return DeserializeECFieldElement(fieldSize, TlsUtilities.ReadOpaque8(input));
+ }
+
+ public static BigInteger ReadECParameter(Stream input)
+ {
+ // TODO Are leading zeroes okay here?
+ return new BigInteger(1, TlsUtilities.ReadOpaque8(input));
+ }
+
+ public static ECDomainParameters ReadECParameters(int[] namedCurves, byte[] ecPointFormats, Stream input)
+ {
+ try
+ {
+ byte curveType = TlsUtilities.ReadUint8(input);
+
+ switch (curveType)
+ {
+ case ECCurveType.explicit_prime:
+ {
+ CheckNamedCurve(namedCurves, NamedCurve.arbitrary_explicit_prime_curves);
+
+ BigInteger prime_p = ReadECParameter(input);
+ BigInteger a = ReadECFieldElement(prime_p.BitLength, input);
+ BigInteger b = ReadECFieldElement(prime_p.BitLength, input);
+ byte[] baseEncoding = TlsUtilities.ReadOpaque8(input);
+ BigInteger order = ReadECParameter(input);
+ BigInteger cofactor = ReadECParameter(input);
+ ECCurve curve = new FpCurve(prime_p, a, b, order, cofactor);
+ ECPoint basePoint = DeserializeECPoint(ecPointFormats, curve, baseEncoding);
+ return new ECDomainParameters(curve, basePoint, order, cofactor);
+ }
+ case ECCurveType.explicit_char2:
+ {
+ CheckNamedCurve(namedCurves, NamedCurve.arbitrary_explicit_char2_curves);
+
+ int m = TlsUtilities.ReadUint16(input);
+ byte basis = TlsUtilities.ReadUint8(input);
+ if (!ECBasisType.IsValid(basis))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ int k1 = ReadECExponent(m, input), k2 = -1, k3 = -1;
+ if (basis == ECBasisType.ec_basis_pentanomial)
+ {
+ k2 = ReadECExponent(m, input);
+ k3 = ReadECExponent(m, input);
+ }
+
+ BigInteger a = ReadECFieldElement(m, input);
+ BigInteger b = ReadECFieldElement(m, input);
+ byte[] baseEncoding = TlsUtilities.ReadOpaque8(input);
+ BigInteger order = ReadECParameter(input);
+ BigInteger cofactor = ReadECParameter(input);
+
+ ECCurve curve = (basis == ECBasisType.ec_basis_pentanomial)
+ ? new F2mCurve(m, k1, k2, k3, a, b, order, cofactor)
+ : new F2mCurve(m, k1, a, b, order, cofactor);
+
+ ECPoint basePoint = DeserializeECPoint(ecPointFormats, curve, baseEncoding);
+
+ return new ECDomainParameters(curve, basePoint, order, cofactor);
+ }
+ case ECCurveType.named_curve:
+ {
+ int namedCurve = TlsUtilities.ReadUint16(input);
+ if (!NamedCurve.RefersToASpecificNamedCurve(namedCurve))
+ {
+ /*
+ * RFC 4492 5.4. All those values of NamedCurve are allowed that refer to a
+ * specific curve. Values of NamedCurve that indicate support for a class of
+ * explicitly defined curves are not allowed here [...].
+ */
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ CheckNamedCurve(namedCurves, namedCurve);
+
+ return GetParametersForNamedCurve(namedCurve);
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
+ }
+ }
+
+ private static void CheckNamedCurve(int[] namedCurves, int namedCurve)
+ {
+ if (namedCurves != null && !Arrays.Contains(namedCurves, namedCurve))
+ {
+ /*
+ * RFC 4492 4. [...] servers MUST NOT negotiate the use of an ECC cipher suite
+ * unless they can complete the handshake while respecting the choice of curves
+ * and compression techniques specified by the client.
+ */
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+
+ public static void WriteECExponent(int k, Stream output)
+ {
+ BigInteger K = BigInteger.ValueOf(k);
+ WriteECParameter(K, output);
+ }
+
+ public static void WriteECFieldElement(ECFieldElement x, Stream output)
+ {
+ TlsUtilities.WriteOpaque8(x.GetEncoded(), output);
+ }
+
+ public static void WriteECFieldElement(int fieldSize, BigInteger x, Stream output)
+ {
+ TlsUtilities.WriteOpaque8(SerializeECFieldElement(fieldSize, x), output);
+ }
+
+ public static void WriteECParameter(BigInteger x, Stream output)
+ {
+ TlsUtilities.WriteOpaque8(BigIntegers.AsUnsignedByteArray(x), output);
+ }
+
+ public static void WriteExplicitECParameters(byte[] ecPointFormats, ECDomainParameters ecParameters,
+ Stream output)
+ {
+ ECCurve curve = ecParameters.Curve;
+
+ if (ECAlgorithms.IsFpCurve(curve))
+ {
+ TlsUtilities.WriteUint8(ECCurveType.explicit_prime, output);
+
+ WriteECParameter(curve.Field.Characteristic, output);
+ }
+ else if (ECAlgorithms.IsF2mCurve(curve))
+ {
+ IPolynomialExtensionField field = (IPolynomialExtensionField)curve.Field;
+ int[] exponents = field.MinimalPolynomial.GetExponentsPresent();
+
+ TlsUtilities.WriteUint8(ECCurveType.explicit_char2, output);
+
+ int m = exponents[exponents.Length - 1];
+ TlsUtilities.CheckUint16(m);
+ TlsUtilities.WriteUint16(m, output);
+
+ if (exponents.Length == 3)
+ {
+ TlsUtilities.WriteUint8(ECBasisType.ec_basis_trinomial, output);
+ WriteECExponent(exponents[1], output);
+ }
+ else if (exponents.Length == 5)
+ {
+ TlsUtilities.WriteUint8(ECBasisType.ec_basis_pentanomial, output);
+ WriteECExponent(exponents[1], output);
+ WriteECExponent(exponents[2], output);
+ WriteECExponent(exponents[3], output);
+ }
+ else
+ {
+ throw new ArgumentException("Only trinomial and pentomial curves are supported");
+ }
+ }
+ else
+ {
+ throw new ArgumentException("'ecParameters' not a known curve type");
+ }
+
+ WriteECFieldElement(curve.A, output);
+ WriteECFieldElement(curve.B, output);
+ TlsUtilities.WriteOpaque8(SerializeECPoint(ecPointFormats, ecParameters.G), output);
+ WriteECParameter(ecParameters.N, output);
+ WriteECParameter(ecParameters.H, output);
+ }
+
+ public static void WriteECPoint(byte[] ecPointFormats, ECPoint point, Stream output)
+ {
+ TlsUtilities.WriteOpaque8(SerializeECPoint(ecPointFormats, point), output);
+ }
+
+ public static void WriteNamedECParameters(int namedCurve, Stream output)
+ {
+ if (!NamedCurve.RefersToASpecificNamedCurve(namedCurve))
+ {
+ /*
+ * RFC 4492 5.4. All those values of NamedCurve are allowed that refer to a specific
+ * curve. Values of NamedCurve that indicate support for a class of explicitly defined
+ * curves are not allowed here [...].
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ TlsUtilities.WriteUint8(ECCurveType.named_curve, output);
+ TlsUtilities.CheckUint16(namedCurve);
+ TlsUtilities.WriteUint16(namedCurve, output);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsEncryptionCredentials.cs b/bc-sharp-crypto/src/crypto/tls/TlsEncryptionCredentials.cs
new file mode 100644
index 0000000000000000000000000000000000000000..52f007006c526365d3b24bd8aab11f09e360c7ba
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsEncryptionCredentials.cs
@@ -0,0 +1,12 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsEncryptionCredentials
+ : TlsCredentials
+ {
+ ///
+ byte[] DecryptPreMasterSecret(byte[] encryptedPreMasterSecret);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsException.cs b/bc-sharp-crypto/src/crypto/tls/TlsException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cea9e3e77ba15e156337ccff644ea02c6114ec6c
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsException.cs
@@ -0,0 +1,14 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsException
+ : IOException
+ {
+ public TlsException(string message, Exception cause)
+ : base(message, cause)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsExtensionsUtilities.cs b/bc-sharp-crypto/src/crypto/tls/TlsExtensionsUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4b3d9e0c5336081ef8e038fb1b7b9c842263be57
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsExtensionsUtilities.cs
@@ -0,0 +1,368 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class TlsExtensionsUtilities
+ {
+ public static IDictionary EnsureExtensionsInitialised(IDictionary extensions)
+ {
+ return extensions == null ? Platform.CreateHashtable() : extensions;
+ }
+
+ ///
+ public static void AddClientCertificateTypeExtensionClient(IDictionary extensions, byte[] certificateTypes)
+ {
+ extensions[ExtensionType.client_certificate_type] = CreateCertificateTypeExtensionClient(certificateTypes);
+ }
+
+ ///
+ public static void AddClientCertificateTypeExtensionServer(IDictionary extensions, byte certificateType)
+ {
+ extensions[ExtensionType.client_certificate_type] = CreateCertificateTypeExtensionServer(certificateType);
+ }
+
+ public static void AddEncryptThenMacExtension(IDictionary extensions)
+ {
+ extensions[ExtensionType.encrypt_then_mac] = CreateEncryptThenMacExtension();
+ }
+
+ public static void AddExtendedMasterSecretExtension(IDictionary extensions)
+ {
+ extensions[ExtensionType.extended_master_secret] = CreateExtendedMasterSecretExtension();
+ }
+
+ ///
+ public static void AddHeartbeatExtension(IDictionary extensions, HeartbeatExtension heartbeatExtension)
+ {
+ extensions[ExtensionType.heartbeat] = CreateHeartbeatExtension(heartbeatExtension);
+ }
+
+ ///
+ public static void AddMaxFragmentLengthExtension(IDictionary extensions, byte maxFragmentLength)
+ {
+ extensions[ExtensionType.max_fragment_length] = CreateMaxFragmentLengthExtension(maxFragmentLength);
+ }
+
+ ///
+ public static void AddPaddingExtension(IDictionary extensions, int dataLength)
+ {
+ extensions[ExtensionType.padding] = CreatePaddingExtension(dataLength);
+ }
+
+ ///
+ public static void AddServerCertificateTypeExtensionClient(IDictionary extensions, byte[] certificateTypes)
+ {
+ extensions[ExtensionType.server_certificate_type] = CreateCertificateTypeExtensionClient(certificateTypes);
+ }
+
+ ///
+ public static void AddServerCertificateTypeExtensionServer(IDictionary extensions, byte certificateType)
+ {
+ extensions[ExtensionType.server_certificate_type] = CreateCertificateTypeExtensionServer(certificateType);
+ }
+
+ ///
+ public static void AddServerNameExtension(IDictionary extensions, ServerNameList serverNameList)
+ {
+ extensions[ExtensionType.server_name] = CreateServerNameExtension(serverNameList);
+ }
+
+ ///
+ public static void AddStatusRequestExtension(IDictionary extensions, CertificateStatusRequest statusRequest)
+ {
+ extensions[ExtensionType.status_request] = CreateStatusRequestExtension(statusRequest);
+ }
+
+ public static void AddTruncatedHMacExtension(IDictionary extensions)
+ {
+ extensions[ExtensionType.truncated_hmac] = CreateTruncatedHMacExtension();
+ }
+
+ ///
+ public static byte[] GetClientCertificateTypeExtensionClient(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.client_certificate_type);
+ return extensionData == null ? null : ReadCertificateTypeExtensionClient(extensionData);
+ }
+
+ ///
+ public static short GetClientCertificateTypeExtensionServer(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.client_certificate_type);
+ return extensionData == null ? (short)-1 : (short)ReadCertificateTypeExtensionServer(extensionData);
+ }
+
+ ///
+ public static HeartbeatExtension GetHeartbeatExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.heartbeat);
+ return extensionData == null ? null : ReadHeartbeatExtension(extensionData);
+ }
+
+ ///
+ public static short GetMaxFragmentLengthExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.max_fragment_length);
+ return extensionData == null ? (short)-1 : (short)ReadMaxFragmentLengthExtension(extensionData);
+ }
+
+ ///
+ public static int GetPaddingExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.padding);
+ return extensionData == null ? -1 : ReadPaddingExtension(extensionData);
+ }
+
+ ///
+ public static byte[] GetServerCertificateTypeExtensionClient(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.server_certificate_type);
+ return extensionData == null ? null : ReadCertificateTypeExtensionClient(extensionData);
+ }
+
+ ///
+ public static short GetServerCertificateTypeExtensionServer(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.server_certificate_type);
+ return extensionData == null ? (short)-1 : (short)ReadCertificateTypeExtensionServer(extensionData);
+ }
+
+ ///
+ public static ServerNameList GetServerNameExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.server_name);
+ return extensionData == null ? null : ReadServerNameExtension(extensionData);
+ }
+
+ ///
+ public static CertificateStatusRequest GetStatusRequestExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.status_request);
+ return extensionData == null ? null : ReadStatusRequestExtension(extensionData);
+ }
+
+ ///
+ public static bool HasEncryptThenMacExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.encrypt_then_mac);
+ return extensionData == null ? false : ReadEncryptThenMacExtension(extensionData);
+ }
+
+ ///
+ public static bool HasExtendedMasterSecretExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.extended_master_secret);
+ return extensionData == null ? false : ReadExtendedMasterSecretExtension(extensionData);
+ }
+
+ ///
+ public static bool HasTruncatedHMacExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.truncated_hmac);
+ return extensionData == null ? false : ReadTruncatedHMacExtension(extensionData);
+ }
+
+ ///
+ public static byte[] CreateCertificateTypeExtensionClient(byte[] certificateTypes)
+ {
+ if (certificateTypes == null || certificateTypes.Length < 1 || certificateTypes.Length > 255)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ return TlsUtilities.EncodeUint8ArrayWithUint8Length(certificateTypes);
+ }
+
+ ///
+ public static byte[] CreateCertificateTypeExtensionServer(byte certificateType)
+ {
+ return TlsUtilities.EncodeUint8(certificateType);
+ }
+
+ public static byte[] CreateEmptyExtensionData()
+ {
+ return TlsUtilities.EmptyBytes;
+ }
+
+ public static byte[] CreateEncryptThenMacExtension()
+ {
+ return CreateEmptyExtensionData();
+ }
+
+ public static byte[] CreateExtendedMasterSecretExtension()
+ {
+ return CreateEmptyExtensionData();
+ }
+
+ ///
+ public static byte[] CreateHeartbeatExtension(HeartbeatExtension heartbeatExtension)
+ {
+ if (heartbeatExtension == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ MemoryStream buf = new MemoryStream();
+
+ heartbeatExtension.Encode(buf);
+
+ return buf.ToArray();
+ }
+
+ ///
+ public static byte[] CreateMaxFragmentLengthExtension(byte maxFragmentLength)
+ {
+ return TlsUtilities.EncodeUint8(maxFragmentLength);
+ }
+
+ ///
+ public static byte[] CreatePaddingExtension(int dataLength)
+ {
+ TlsUtilities.CheckUint16(dataLength);
+ return new byte[dataLength];
+ }
+
+ ///
+ public static byte[] CreateServerNameExtension(ServerNameList serverNameList)
+ {
+ if (serverNameList == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ MemoryStream buf = new MemoryStream();
+
+ serverNameList.Encode(buf);
+
+ return buf.ToArray();
+ }
+
+ ///
+ public static byte[] CreateStatusRequestExtension(CertificateStatusRequest statusRequest)
+ {
+ if (statusRequest == null)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ MemoryStream buf = new MemoryStream();
+
+ statusRequest.Encode(buf);
+
+ return buf.ToArray();
+ }
+
+ public static byte[] CreateTruncatedHMacExtension()
+ {
+ return CreateEmptyExtensionData();
+ }
+
+ ///
+ private static bool ReadEmptyExtensionData(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ if (extensionData.Length != 0)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ return true;
+ }
+
+ ///
+ public static byte[] ReadCertificateTypeExtensionClient(byte[] extensionData)
+ {
+ byte[] certificateTypes = TlsUtilities.DecodeUint8ArrayWithUint8Length(extensionData);
+ if (certificateTypes.Length < 1)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ return certificateTypes;
+ }
+
+ ///
+ public static byte ReadCertificateTypeExtensionServer(byte[] extensionData)
+ {
+ return TlsUtilities.DecodeUint8(extensionData);
+ }
+
+ ///
+ public static bool ReadEncryptThenMacExtension(byte[] extensionData)
+ {
+ return ReadEmptyExtensionData(extensionData);
+ }
+
+ ///
+ public static bool ReadExtendedMasterSecretExtension(byte[] extensionData)
+ {
+ return ReadEmptyExtensionData(extensionData);
+ }
+
+ ///
+ public static HeartbeatExtension ReadHeartbeatExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ MemoryStream buf = new MemoryStream(extensionData, false);
+
+ HeartbeatExtension heartbeatExtension = HeartbeatExtension.Parse(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ return heartbeatExtension;
+ }
+
+ ///
+ public static byte ReadMaxFragmentLengthExtension(byte[] extensionData)
+ {
+ return TlsUtilities.DecodeUint8(extensionData);
+ }
+
+ ///
+ public static int ReadPaddingExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ for (int i = 0; i < extensionData.Length; ++i)
+ {
+ if (extensionData[i] != 0)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ return extensionData.Length;
+ }
+
+ ///
+ public static ServerNameList ReadServerNameExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ MemoryStream buf = new MemoryStream(extensionData, false);
+
+ ServerNameList serverNameList = ServerNameList.Parse(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ return serverNameList;
+ }
+
+ ///
+ public static CertificateStatusRequest ReadStatusRequestExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ MemoryStream buf = new MemoryStream(extensionData, false);
+
+ CertificateStatusRequest statusRequest = CertificateStatusRequest.Parse(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ return statusRequest;
+ }
+
+ ///
+ public static bool ReadTruncatedHMacExtension(byte[] extensionData)
+ {
+ return ReadEmptyExtensionData(extensionData);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsFatalAlert.cs b/bc-sharp-crypto/src/crypto/tls/TlsFatalAlert.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6f189817976526b09f7a336ad20d2968ae427e74
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsFatalAlert.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsFatalAlert
+ : TlsException
+ {
+ private readonly byte alertDescription;
+
+ public TlsFatalAlert(byte alertDescription)
+ : this(alertDescription, null)
+ {
+ }
+
+ public TlsFatalAlert(byte alertDescription, Exception alertCause)
+ : base(Tls.AlertDescription.GetText(alertDescription), alertCause)
+ {
+ this.alertDescription = alertDescription;
+ }
+
+ public virtual byte AlertDescription
+ {
+ get { return alertDescription; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsFatalAlertReceived.cs b/bc-sharp-crypto/src/crypto/tls/TlsFatalAlertReceived.cs
new file mode 100644
index 0000000000000000000000000000000000000000..044fc802726c8ccfb5aefca377cdb623adc02981
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsFatalAlertReceived.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsFatalAlertReceived
+ : TlsException
+ {
+ private readonly byte alertDescription;
+
+ public TlsFatalAlertReceived(byte alertDescription)
+ : base(Tls.AlertDescription.GetText(alertDescription), null)
+ {
+ this.alertDescription = alertDescription;
+ }
+
+ public virtual byte AlertDescription
+ {
+ get { return alertDescription; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsHandshakeHash.cs b/bc-sharp-crypto/src/crypto/tls/TlsHandshakeHash.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7118d97696bf74fe3d724394e544b38b3e5704a8
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsHandshakeHash.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsHandshakeHash
+ : IDigest
+ {
+ void Init(TlsContext context);
+
+ TlsHandshakeHash NotifyPrfDetermined();
+
+ void TrackHashAlgorithm(byte hashAlgorithm);
+
+ void SealHashAlgorithms();
+
+ TlsHandshakeHash StopTracking();
+
+ IDigest ForkPrfHash();
+
+ byte[] GetFinalHash(byte hashAlgorithm);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsKeyExchange.cs b/bc-sharp-crypto/src/crypto/tls/TlsKeyExchange.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6731f6f63b06f8c4afb214a3bda4d0ef5641c311
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsKeyExchange.cs
@@ -0,0 +1,54 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ ///
+ /// A generic interface for key exchange implementations in (D)TLS.
+ ///
+ public interface TlsKeyExchange
+ {
+ void Init(TlsContext context);
+
+ ///
+ void SkipServerCredentials();
+
+ ///
+ void ProcessServerCredentials(TlsCredentials serverCredentials);
+
+ ///
+ void ProcessServerCertificate(Certificate serverCertificate);
+
+ bool RequiresServerKeyExchange { get; }
+
+ ///
+ byte[] GenerateServerKeyExchange();
+
+ ///
+ void SkipServerKeyExchange();
+
+ ///
+ void ProcessServerKeyExchange(Stream input);
+
+ ///
+ void ValidateCertificateRequest(CertificateRequest certificateRequest);
+
+ ///
+ void SkipClientCredentials();
+
+ ///
+ void ProcessClientCredentials(TlsCredentials clientCredentials);
+
+ ///
+ void ProcessClientCertificate(Certificate clientCertificate);
+
+ ///
+ void GenerateClientKeyExchange(Stream output);
+
+ ///
+ void ProcessClientKeyExchange(Stream input);
+
+ ///
+ byte[] GeneratePremasterSecret();
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsMac.cs b/bc-sharp-crypto/src/crypto/tls/TlsMac.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a80319a1704898952bb8dd3f434a7fbd449b1112
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsMac.cs
@@ -0,0 +1,173 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ ///
+ /// A generic TLS MAC implementation, acting as an HMAC based on some underlying Digest.
+ ///
+ public class TlsMac
+ {
+ protected readonly TlsContext context;
+ protected readonly byte[] secret;
+ protected readonly IMac mac;
+ protected readonly int digestBlockSize;
+ protected readonly int digestOverhead;
+ protected readonly int macLength;
+
+ /**
+ * Generate a new instance of an TlsMac.
+ *
+ * @param context the TLS client context
+ * @param digest The digest to use.
+ * @param key A byte-array where the key for this MAC is located.
+ * @param keyOff The number of bytes to skip, before the key starts in the buffer.
+ * @param keyLen The length of the key.
+ */
+ public TlsMac(TlsContext context, IDigest digest, byte[] key, int keyOff, int keyLen)
+ {
+ this.context = context;
+
+ KeyParameter keyParameter = new KeyParameter(key, keyOff, keyLen);
+
+ this.secret = Arrays.Clone(keyParameter.GetKey());
+
+ // TODO This should check the actual algorithm, not rely on the engine type
+ if (digest is LongDigest)
+ {
+ this.digestBlockSize = 128;
+ this.digestOverhead = 16;
+ }
+ else
+ {
+ this.digestBlockSize = 64;
+ this.digestOverhead = 8;
+ }
+
+ if (TlsUtilities.IsSsl(context))
+ {
+ this.mac = new Ssl3Mac(digest);
+
+ // TODO This should check the actual algorithm, not assume based on the digest size
+ if (digest.GetDigestSize() == 20)
+ {
+ /*
+ * NOTE: When SHA-1 is used with the SSL 3.0 MAC, the secret + input pad is not
+ * digest block-aligned.
+ */
+ this.digestOverhead = 4;
+ }
+ }
+ else
+ {
+ this.mac = new HMac(digest);
+
+ // NOTE: The input pad for HMAC is always a full digest block
+ }
+
+ this.mac.Init(keyParameter);
+
+ this.macLength = mac.GetMacSize();
+ if (context.SecurityParameters.truncatedHMac)
+ {
+ this.macLength = System.Math.Min(this.macLength, 10);
+ }
+ }
+
+ /**
+ * @return the MAC write secret
+ */
+ public virtual byte[] MacSecret
+ {
+ get { return this.secret; }
+ }
+
+ /**
+ * @return The output length of this MAC.
+ */
+ public virtual int Size
+ {
+ get { return macLength; }
+ }
+
+ /**
+ * Calculate the MAC for some given data.
+ *
+ * @param type The message type of the message.
+ * @param message A byte-buffer containing the message.
+ * @param offset The number of bytes to skip, before the message starts.
+ * @param length The length of the message.
+ * @return A new byte-buffer containing the MAC value.
+ */
+ public virtual byte[] CalculateMac(long seqNo, byte type, byte[] message, int offset, int length)
+ {
+ ProtocolVersion serverVersion = context.ServerVersion;
+ bool isSsl = serverVersion.IsSsl;
+
+ byte[] macHeader = new byte[isSsl ? 11 : 13];
+ TlsUtilities.WriteUint64(seqNo, macHeader, 0);
+ TlsUtilities.WriteUint8(type, macHeader, 8);
+ if (!isSsl)
+ {
+ TlsUtilities.WriteVersion(serverVersion, macHeader, 9);
+ }
+ TlsUtilities.WriteUint16(length, macHeader, macHeader.Length - 2);
+
+ mac.BlockUpdate(macHeader, 0, macHeader.Length);
+ mac.BlockUpdate(message, offset, length);
+
+ return Truncate(MacUtilities.DoFinal(mac));
+ }
+
+ public virtual byte[] CalculateMacConstantTime(long seqNo, byte type, byte[] message, int offset, int length,
+ int fullLength, byte[] dummyData)
+ {
+ /*
+ * Actual MAC only calculated on 'length' bytes...
+ */
+ byte[] result = CalculateMac(seqNo, type, message, offset, length);
+
+ /*
+ * ...but ensure a constant number of complete digest blocks are processed (as many as would
+ * be needed for 'fullLength' bytes of input).
+ */
+ int headerLength = TlsUtilities.IsSsl(context) ? 11 : 13;
+
+ // How many extra full blocks do we need to calculate?
+ int extra = GetDigestBlockCount(headerLength + fullLength) - GetDigestBlockCount(headerLength + length);
+
+ while (--extra >= 0)
+ {
+ mac.BlockUpdate(dummyData, 0, digestBlockSize);
+ }
+
+ // One more byte in case the implementation is "lazy" about processing blocks
+ mac.Update(dummyData[0]);
+ mac.Reset();
+
+ return result;
+ }
+
+ protected virtual int GetDigestBlockCount(int inputLength)
+ {
+ // NOTE: This calculation assumes a minimum of 1 pad byte
+ return (inputLength + digestOverhead) / digestBlockSize;
+ }
+
+ protected virtual byte[] Truncate(byte[] bs)
+ {
+ if (bs.Length <= macLength)
+ {
+ return bs;
+ }
+
+ return Arrays.CopyOf(bs, macLength);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsNoCloseNotifyException.cs b/bc-sharp-crypto/src/crypto/tls/TlsNoCloseNotifyException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0bafd820bfdf50500912354d993a5646c2028590
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsNoCloseNotifyException.cs
@@ -0,0 +1,23 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ ///
+ /// This exception will be thrown(only) when the connection is closed by the peer without sending a
+ /// close_notify
warning alert.
+ ///
+ ///
+ /// If this happens, the TLS protocol cannot rule out truncation of the connection data (potentially
+ /// malicious). It may be possible to check for truncation via some property of a higher level protocol
+ /// built upon TLS, e.g.the Content-Length header for HTTPS.
+ ///
+ public class TlsNoCloseNotifyException
+ : EndOfStreamException
+ {
+ public TlsNoCloseNotifyException()
+ : base("No close_notify alert received before connection closed")
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsNullCipher.cs b/bc-sharp-crypto/src/crypto/tls/TlsNullCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f30ace24f41b78f888ca486d6d2ab1bcc800e3c5
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsNullCipher.cs
@@ -0,0 +1,118 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ ///
+ /// A NULL CipherSuite, with optional MAC.
+ ///
+ public class TlsNullCipher
+ : TlsCipher
+ {
+ protected readonly TlsContext context;
+
+ protected readonly TlsMac writeMac;
+ protected readonly TlsMac readMac;
+
+ public TlsNullCipher(TlsContext context)
+ {
+ this.context = context;
+ this.writeMac = null;
+ this.readMac = null;
+ }
+
+ ///
+ public TlsNullCipher(TlsContext context, IDigest clientWriteDigest, IDigest serverWriteDigest)
+ {
+ if ((clientWriteDigest == null) != (serverWriteDigest == null))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ this.context = context;
+
+ TlsMac clientWriteMac = null, serverWriteMac = null;
+
+ if (clientWriteDigest != null)
+ {
+ int key_block_size = clientWriteDigest.GetDigestSize()
+ + serverWriteDigest.GetDigestSize();
+ byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size);
+
+ int offset = 0;
+
+ clientWriteMac = new TlsMac(context, clientWriteDigest, key_block, offset,
+ clientWriteDigest.GetDigestSize());
+ offset += clientWriteDigest.GetDigestSize();
+
+ serverWriteMac = new TlsMac(context, serverWriteDigest, key_block, offset,
+ serverWriteDigest.GetDigestSize());
+ offset += serverWriteDigest.GetDigestSize();
+
+ if (offset != key_block_size)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ if (context.IsServer)
+ {
+ writeMac = serverWriteMac;
+ readMac = clientWriteMac;
+ }
+ else
+ {
+ writeMac = clientWriteMac;
+ readMac = serverWriteMac;
+ }
+ }
+
+ public virtual int GetPlaintextLimit(int ciphertextLimit)
+ {
+ int result = ciphertextLimit;
+ if (writeMac != null)
+ {
+ result -= writeMac.Size;
+ }
+ return result;
+ }
+
+ ///
+ public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
+ {
+ if (writeMac == null)
+ {
+ return Arrays.CopyOfRange(plaintext, offset, offset + len);
+ }
+
+ byte[] mac = writeMac.CalculateMac(seqNo, type, plaintext, offset, len);
+ byte[] ciphertext = new byte[len + mac.Length];
+ Array.Copy(plaintext, offset, ciphertext, 0, len);
+ Array.Copy(mac, 0, ciphertext, len, mac.Length);
+ return ciphertext;
+ }
+
+ ///
+ public virtual byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len)
+ {
+ if (readMac == null)
+ {
+ return Arrays.CopyOfRange(ciphertext, offset, offset + len);
+ }
+
+ int macSize = readMac.Size;
+ if (len < macSize)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ int macInputLen = len - macSize;
+
+ byte[] receivedMac = Arrays.CopyOfRange(ciphertext, offset + macInputLen, offset + len);
+ byte[] computedMac = readMac.CalculateMac(seqNo, type, ciphertext, offset, macInputLen);
+
+ if (!Arrays.ConstantTimeAreEqual(receivedMac, computedMac))
+ throw new TlsFatalAlert(AlertDescription.bad_record_mac);
+
+ return Arrays.CopyOfRange(ciphertext, offset, offset + macInputLen);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsNullCompression.cs b/bc-sharp-crypto/src/crypto/tls/TlsNullCompression.cs
new file mode 100644
index 0000000000000000000000000000000000000000..45f8fc708334b8a16096d2adf2ea1f0a9db8de1d
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsNullCompression.cs
@@ -0,0 +1,19 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsNullCompression
+ : TlsCompression
+ {
+ public virtual Stream Compress(Stream output)
+ {
+ return output;
+ }
+
+ public virtual Stream Decompress(Stream output)
+ {
+ return output;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsPeer.cs b/bc-sharp-crypto/src/crypto/tls/TlsPeer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1ae41a41a36e6bb0c55d7018dcb07614e5ce59a3
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsPeer.cs
@@ -0,0 +1,62 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsPeer
+ {
+ ///
+ /// draft-mathewson-no-gmtunixtime-00 2. "If existing users of a TLS implementation may rely on
+ /// gmt_unix_time containing the current time, we recommend that implementors MAY provide the
+ /// ability to set gmt_unix_time as an option only, off by default."
+ ///
+ ///
+ /// true
if the current time should be used in the gmt_unix_time field of
+ /// Random, or false
if gmt_unix_time should contain a cryptographically
+ /// random value.
+ ///
+ bool ShouldUseGmtUnixTime();
+
+ ///
+ /// Report whether the server supports secure renegotiation
+ ///
+ ///
+ /// The protocol handler automatically processes the relevant extensions
+ ///
+ ///
+ /// A , true if the server supports secure renegotiation
+ ///
+ ///
+ void NotifySecureRenegotiation(bool secureRenegotiation);
+
+ ///
+ /// Return an implementation of to handle record compression.
+ ///
+ /// A
+ ///
+ TlsCompression GetCompression();
+
+ ///
+ /// Return an implementation of to use for encryption/decryption.
+ ///
+ /// A
+ ///
+ TlsCipher GetCipher();
+
+ /// This method will be called when an alert is raised by the protocol.
+ ///
+ ///
+ /// A human-readable message explaining what caused this alert. May be null.
+ /// The Exception that caused this alert to be raised. May be null.
+ void NotifyAlertRaised(byte alertLevel, byte alertDescription, string message, Exception cause);
+
+ /// This method will be called when an alert is received from the remote peer.
+ ///
+ ///
+ void NotifyAlertReceived(byte alertLevel, byte alertDescription);
+
+ /// Notifies the peer that the handshake has been successfully completed.
+ ///
+ void NotifyHandshakeComplete();
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsProtocol.cs b/bc-sharp-crypto/src/crypto/tls/TlsProtocol.cs
new file mode 100644
index 0000000000000000000000000000000000000000..72151d414eab3b6f3c1828bdc105b631b373a1a9
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsProtocol.cs
@@ -0,0 +1,1450 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Prng;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class TlsProtocol
+ {
+ /*
+ * Our Connection states
+ */
+ protected const short CS_START = 0;
+ protected const short CS_CLIENT_HELLO = 1;
+ protected const short CS_SERVER_HELLO = 2;
+ protected const short CS_SERVER_SUPPLEMENTAL_DATA = 3;
+ protected const short CS_SERVER_CERTIFICATE = 4;
+ protected const short CS_CERTIFICATE_STATUS = 5;
+ protected const short CS_SERVER_KEY_EXCHANGE = 6;
+ protected const short CS_CERTIFICATE_REQUEST = 7;
+ protected const short CS_SERVER_HELLO_DONE = 8;
+ protected const short CS_CLIENT_SUPPLEMENTAL_DATA = 9;
+ protected const short CS_CLIENT_CERTIFICATE = 10;
+ protected const short CS_CLIENT_KEY_EXCHANGE = 11;
+ protected const short CS_CERTIFICATE_VERIFY = 12;
+ protected const short CS_CLIENT_FINISHED = 13;
+ protected const short CS_SERVER_SESSION_TICKET = 14;
+ protected const short CS_SERVER_FINISHED = 15;
+ protected const short CS_END = 16;
+
+ /*
+ * Different modes to handle the known IV weakness
+ */
+ protected const short ADS_MODE_1_Nsub1 = 0; // 1/n-1 record splitting
+ protected const short ADS_MODE_0_N = 1; // 0/n record splitting
+ protected const short ADS_MODE_0_N_FIRSTONLY = 2; // 0/n record splitting on first data fragment only
+
+ /*
+ * Queues for data from some protocols.
+ */
+ private ByteQueue mApplicationDataQueue = new ByteQueue(0);
+ private ByteQueue mAlertQueue = new ByteQueue(2);
+ private ByteQueue mHandshakeQueue = new ByteQueue(0);
+ // private ByteQueue mHeartbeatQueue = new ByteQueue();
+
+ /*
+ * The Record Stream we use
+ */
+ internal RecordStream mRecordStream;
+ protected SecureRandom mSecureRandom;
+
+ private TlsStream mTlsStream = null;
+
+ private volatile bool mClosed = false;
+ private volatile bool mFailedWithError = false;
+ private volatile bool mAppDataReady = false;
+ private volatile bool mAppDataSplitEnabled = true;
+ private volatile int mAppDataSplitMode = ADS_MODE_1_Nsub1;
+ private byte[] mExpectedVerifyData = null;
+
+ protected TlsSession mTlsSession = null;
+ protected SessionParameters mSessionParameters = null;
+ protected SecurityParameters mSecurityParameters = null;
+ protected Certificate mPeerCertificate = null;
+
+ protected int[] mOfferedCipherSuites = null;
+ protected byte[] mOfferedCompressionMethods = null;
+ protected IDictionary mClientExtensions = null;
+ protected IDictionary mServerExtensions = null;
+
+ protected short mConnectionState = CS_START;
+ protected bool mResumedSession = false;
+ protected bool mReceivedChangeCipherSpec = false;
+ protected bool mSecureRenegotiation = false;
+ protected bool mAllowCertificateStatus = false;
+ protected bool mExpectSessionTicket = false;
+
+ protected bool mBlocking = true;
+ protected ByteQueueStream mInputBuffers = null;
+ protected ByteQueueStream mOutputBuffer = null;
+
+ public TlsProtocol(Stream stream, SecureRandom secureRandom)
+ : this(stream, stream, secureRandom)
+ {
+ }
+
+ public TlsProtocol(Stream input, Stream output, SecureRandom secureRandom)
+ {
+ this.mRecordStream = new RecordStream(this, input, output);
+ this.mSecureRandom = secureRandom;
+ }
+
+ public TlsProtocol(SecureRandom secureRandom)
+ {
+ this.mBlocking = false;
+ this.mInputBuffers = new ByteQueueStream();
+ this.mOutputBuffer = new ByteQueueStream();
+ this.mRecordStream = new RecordStream(this, mInputBuffers, mOutputBuffer);
+ this.mSecureRandom = secureRandom;
+ }
+
+ protected abstract TlsContext Context { get; }
+
+ internal abstract AbstractTlsContext ContextAdmin { get; }
+
+ protected abstract TlsPeer Peer { get; }
+
+ protected virtual void HandleAlertMessage(byte alertLevel, byte alertDescription)
+ {
+ Peer.NotifyAlertReceived(alertLevel, alertDescription);
+
+ if (alertLevel == AlertLevel.warning)
+ {
+ HandleAlertWarningMessage(alertDescription);
+ }
+ else
+ {
+ HandleFailure();
+
+ throw new TlsFatalAlertReceived(alertDescription);
+ }
+ }
+
+ protected virtual void HandleAlertWarningMessage(byte alertDescription)
+ {
+ /*
+ * RFC 5246 7.2.1. The other party MUST respond with a close_notify alert of its own
+ * and close down the connection immediately, discarding any pending writes.
+ */
+ if (alertDescription == AlertDescription.close_notify)
+ {
+ if (!mAppDataReady)
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+
+ HandleClose(false);
+ }
+ }
+
+ protected virtual void HandleChangeCipherSpecMessage()
+ {
+ }
+
+ protected virtual void HandleClose(bool user_canceled)
+ {
+ if (!mClosed)
+ {
+ this.mClosed = true;
+
+ if (user_canceled && !mAppDataReady)
+ {
+ RaiseAlertWarning(AlertDescription.user_canceled, "User canceled handshake");
+ }
+
+ RaiseAlertWarning(AlertDescription.close_notify, "Connection closed");
+
+ mRecordStream.SafeClose();
+
+ if (!mAppDataReady)
+ {
+ CleanupHandshake();
+ }
+ }
+ }
+
+ protected virtual void HandleException(byte alertDescription, string message, Exception cause)
+ {
+ if (!mClosed)
+ {
+ RaiseAlertFatal(alertDescription, message, cause);
+
+ HandleFailure();
+ }
+ }
+
+ protected virtual void HandleFailure()
+ {
+ this.mClosed = true;
+ this.mFailedWithError = true;
+
+ /*
+ * RFC 2246 7.2.1. The session becomes unresumable if any connection is terminated
+ * without proper close_notify messages with level equal to warning.
+ */
+ // TODO This isn't quite in the right place. Also, as of TLS 1.1 the above is obsolete.
+ InvalidateSession();
+
+ mRecordStream.SafeClose();
+
+ if (!mAppDataReady)
+ {
+ CleanupHandshake();
+ }
+ }
+
+ protected abstract void HandleHandshakeMessage(byte type, MemoryStream buf);
+
+ protected virtual void ApplyMaxFragmentLengthExtension()
+ {
+ if (mSecurityParameters.maxFragmentLength >= 0)
+ {
+ if (!MaxFragmentLength.IsValid((byte)mSecurityParameters.maxFragmentLength))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ int plainTextLimit = 1 << (8 + mSecurityParameters.maxFragmentLength);
+ mRecordStream.SetPlaintextLimit(plainTextLimit);
+ }
+ }
+
+ protected virtual void CheckReceivedChangeCipherSpec(bool expected)
+ {
+ if (expected != mReceivedChangeCipherSpec)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ protected virtual void CleanupHandshake()
+ {
+ if (this.mExpectedVerifyData != null)
+ {
+ Arrays.Fill(this.mExpectedVerifyData, (byte)0);
+ this.mExpectedVerifyData = null;
+ }
+
+ this.mSecurityParameters.Clear();
+ this.mPeerCertificate = null;
+
+ this.mOfferedCipherSuites = null;
+ this.mOfferedCompressionMethods = null;
+ this.mClientExtensions = null;
+ this.mServerExtensions = null;
+
+ this.mResumedSession = false;
+ this.mReceivedChangeCipherSpec = false;
+ this.mSecureRenegotiation = false;
+ this.mAllowCertificateStatus = false;
+ this.mExpectSessionTicket = false;
+ }
+
+ protected virtual void BlockForHandshake()
+ {
+ if (mBlocking)
+ {
+ while (this.mConnectionState != CS_END)
+ {
+ if (this.mClosed)
+ {
+ // NOTE: Any close during the handshake should have raised an exception.
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ SafeReadRecord();
+ }
+ }
+ }
+
+ protected virtual void CompleteHandshake()
+ {
+ try
+ {
+ this.mConnectionState = CS_END;
+
+ this.mAlertQueue.Shrink();
+ this.mHandshakeQueue.Shrink();
+
+ this.mRecordStream.FinaliseHandshake();
+
+ this.mAppDataSplitEnabled = !TlsUtilities.IsTlsV11(Context);
+
+ /*
+ * If this was an initial handshake, we are now ready to send and receive application data.
+ */
+ if (!mAppDataReady)
+ {
+ this.mAppDataReady = true;
+
+ if (mBlocking)
+ {
+ this.mTlsStream = new TlsStream(this);
+ }
+ }
+
+ if (this.mTlsSession != null)
+ {
+ if (this.mSessionParameters == null)
+ {
+ this.mSessionParameters = new SessionParameters.Builder()
+ .SetCipherSuite(this.mSecurityParameters.CipherSuite)
+ .SetCompressionAlgorithm(this.mSecurityParameters.CompressionAlgorithm)
+ .SetMasterSecret(this.mSecurityParameters.MasterSecret)
+ .SetPeerCertificate(this.mPeerCertificate)
+ .SetPskIdentity(this.mSecurityParameters.PskIdentity)
+ .SetSrpIdentity(this.mSecurityParameters.SrpIdentity)
+ // TODO Consider filtering extensions that aren't relevant to resumed sessions
+ .SetServerExtensions(this.mServerExtensions)
+ .Build();
+
+ this.mTlsSession = new TlsSessionImpl(this.mTlsSession.SessionID, this.mSessionParameters);
+ }
+
+ ContextAdmin.SetResumableSession(this.mTlsSession);
+ }
+
+ Peer.NotifyHandshakeComplete();
+ }
+ finally
+ {
+ CleanupHandshake();
+ }
+ }
+
+ protected internal void ProcessRecord(byte protocol, byte[] buf, int off, int len)
+ {
+ /*
+ * Have a look at the protocol type, and add it to the correct queue.
+ */
+ switch (protocol)
+ {
+ case ContentType.alert:
+ {
+ mAlertQueue.AddData(buf, off, len);
+ ProcessAlertQueue();
+ break;
+ }
+ case ContentType.application_data:
+ {
+ if (!mAppDataReady)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ mApplicationDataQueue.AddData(buf, off, len);
+ ProcessApplicationDataQueue();
+ break;
+ }
+ case ContentType.change_cipher_spec:
+ {
+ ProcessChangeCipherSpec(buf, off, len);
+ break;
+ }
+ case ContentType.handshake:
+ {
+ if (mHandshakeQueue.Available > 0)
+ {
+ mHandshakeQueue.AddData(buf, off, len);
+ ProcessHandshakeQueue(mHandshakeQueue);
+ }
+ else
+ {
+ ByteQueue tmpQueue = new ByteQueue(buf, off, len);
+ ProcessHandshakeQueue(tmpQueue);
+ int remaining = tmpQueue.Available;
+ if (remaining > 0)
+ {
+ mHandshakeQueue.AddData(buf, off + len - remaining, remaining);
+ }
+ }
+ break;
+ }
+ //case ContentType.heartbeat:
+ //{
+ // if (!mAppDataReady)
+ // throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ // // TODO[RFC 6520]
+ // //mHeartbeatQueue.AddData(buf, offset, len);
+ // //ProcessHeartbeat();
+ // break;
+ //}
+ default:
+ // Record type should already have been checked
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ private void ProcessHandshakeQueue(ByteQueue queue)
+ {
+ while (queue.Available >= 4)
+ {
+ /*
+ * We need the first 4 bytes, they contain type and length of the message.
+ */
+ byte[] beginning = new byte[4];
+ queue.Read(beginning, 0, 4, 0);
+ byte type = TlsUtilities.ReadUint8(beginning, 0);
+ int length = TlsUtilities.ReadUint24(beginning, 1);
+ int totalLength = 4 + length;
+
+ /*
+ * Check if we have enough bytes in the buffer to read the full message.
+ */
+ if (queue.Available < totalLength)
+ break;
+
+ CheckReceivedChangeCipherSpec(mConnectionState == CS_END || type == HandshakeType.finished);
+
+ /*
+ * RFC 2246 7.4.9. The value handshake_messages includes all handshake messages
+ * starting at client hello up to, but not including, this finished message.
+ * [..] Note: [Also,] Hello Request messages are omitted from handshake hashes.
+ */
+ switch (type)
+ {
+ case HandshakeType.hello_request:
+ break;
+ case HandshakeType.finished:
+ default:
+ {
+ TlsContext ctx = Context;
+ if (type == HandshakeType.finished
+ && this.mExpectedVerifyData == null
+ && ctx.SecurityParameters.MasterSecret != null)
+ {
+ this.mExpectedVerifyData = CreateVerifyData(!ctx.IsServer);
+ }
+
+ queue.CopyTo(mRecordStream.HandshakeHashUpdater, totalLength);
+ break;
+ }
+ }
+
+ queue.RemoveData(4);
+
+ MemoryStream buf = queue.ReadFrom(length);
+
+ /*
+ * Now, parse the message.
+ */
+ HandleHandshakeMessage(type, buf);
+ }
+ }
+
+ private void ProcessApplicationDataQueue()
+ {
+ /*
+ * There is nothing we need to do here.
+ *
+ * This function could be used for callbacks when application data arrives in the future.
+ */
+ }
+
+ private void ProcessAlertQueue()
+ {
+ while (mAlertQueue.Available >= 2)
+ {
+ /*
+ * An alert is always 2 bytes. Read the alert.
+ */
+ byte[] alert = mAlertQueue.RemoveData(2, 0);
+ byte alertLevel = alert[0];
+ byte alertDescription = alert[1];
+
+ HandleAlertMessage(alertLevel, alertDescription);
+ }
+ }
+
+ /**
+ * This method is called, when a change cipher spec message is received.
+ *
+ * @throws IOException If the message has an invalid content or the handshake is not in the correct
+ * state.
+ */
+ private void ProcessChangeCipherSpec(byte[] buf, int off, int len)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ byte message = TlsUtilities.ReadUint8(buf, off + i);
+
+ if (message != ChangeCipherSpec.change_cipher_spec)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ if (this.mReceivedChangeCipherSpec
+ || mAlertQueue.Available > 0
+ || mHandshakeQueue.Available > 0)
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ mRecordStream.ReceivedReadCipherSpec();
+
+ this.mReceivedChangeCipherSpec = true;
+
+ HandleChangeCipherSpecMessage();
+ }
+ }
+
+ protected internal virtual int ApplicationDataAvailable()
+ {
+ return mApplicationDataQueue.Available;
+ }
+
+ /**
+ * Read data from the network. The method will return immediately, if there is still some data
+ * left in the buffer, or block until some application data has been read from the network.
+ *
+ * @param buf The buffer where the data will be copied to.
+ * @param offset The position where the data will be placed in the buffer.
+ * @param len The maximum number of bytes to read.
+ * @return The number of bytes read.
+ * @throws IOException If something goes wrong during reading data.
+ */
+ protected internal virtual int ReadApplicationData(byte[] buf, int offset, int len)
+ {
+ if (len < 1)
+ return 0;
+
+ while (mApplicationDataQueue.Available == 0)
+ {
+ if (this.mClosed)
+ {
+ if (this.mFailedWithError)
+ throw new IOException("Cannot read application data on failed TLS connection");
+
+ if (!mAppDataReady)
+ throw new InvalidOperationException("Cannot read application data until initial handshake completed.");
+
+ return 0;
+ }
+
+ SafeReadRecord();
+ }
+
+ len = System.Math.Min(len, mApplicationDataQueue.Available);
+ mApplicationDataQueue.RemoveData(buf, offset, len, 0);
+ return len;
+ }
+
+ protected virtual void SafeCheckRecordHeader(byte[] recordHeader)
+ {
+ try
+ {
+ mRecordStream.CheckRecordHeader(recordHeader);
+ }
+ catch (TlsFatalAlert e)
+ {
+ HandleException(e.AlertDescription, "Failed to read record", e);
+ throw e;
+ }
+ catch (IOException e)
+ {
+ HandleException(AlertDescription.internal_error, "Failed to read record", e);
+ throw e;
+ }
+ catch (Exception e)
+ {
+ HandleException(AlertDescription.internal_error, "Failed to read record", e);
+ throw new TlsFatalAlert(AlertDescription.internal_error, e);
+ }
+ }
+
+ protected virtual void SafeReadRecord()
+ {
+ try
+ {
+ if (mRecordStream.ReadRecord())
+ return;
+
+ if (!mAppDataReady)
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+ catch (TlsFatalAlertReceived e)
+ {
+ // Connection failure already handled at source
+ throw e;
+ }
+ catch (TlsFatalAlert e)
+ {
+ HandleException(e.AlertDescription, "Failed to read record", e);
+ throw e;
+ }
+ catch (IOException e)
+ {
+ HandleException(AlertDescription.internal_error, "Failed to read record", e);
+ throw e;
+ }
+ catch (Exception e)
+ {
+ HandleException(AlertDescription.internal_error, "Failed to read record", e);
+ throw new TlsFatalAlert(AlertDescription.internal_error, e);
+ }
+
+ HandleFailure();
+
+ throw new TlsNoCloseNotifyException();
+ }
+
+ protected virtual void SafeWriteRecord(byte type, byte[] buf, int offset, int len)
+ {
+ try
+ {
+ mRecordStream.WriteRecord(type, buf, offset, len);
+ }
+ catch (TlsFatalAlert e)
+ {
+ HandleException(e.AlertDescription, "Failed to write record", e);
+ throw e;
+ }
+ catch (IOException e)
+ {
+ HandleException(AlertDescription.internal_error, "Failed to write record", e);
+ throw e;
+ }
+ catch (Exception e)
+ {
+ HandleException(AlertDescription.internal_error, "Failed to write record", e);
+ throw new TlsFatalAlert(AlertDescription.internal_error, e);
+ }
+ }
+
+ /**
+ * Send some application data to the remote system.
+ *
+ * The method will handle fragmentation internally.
+ *
+ * @param buf The buffer with the data.
+ * @param offset The position in the buffer where the data is placed.
+ * @param len The length of the data.
+ * @throws IOException If something goes wrong during sending.
+ */
+ protected internal virtual void WriteData(byte[] buf, int offset, int len)
+ {
+ if (this.mClosed)
+ throw new IOException("Cannot write application data on closed/failed TLS connection");
+
+ while (len > 0)
+ {
+ /*
+ * RFC 5246 6.2.1. Zero-length fragments of Application data MAY be sent as they are
+ * potentially useful as a traffic analysis countermeasure.
+ *
+ * NOTE: Actually, implementations appear to have settled on 1/n-1 record splitting.
+ */
+
+ if (this.mAppDataSplitEnabled)
+ {
+ /*
+ * Protect against known IV attack!
+ *
+ * DO NOT REMOVE THIS CODE, EXCEPT YOU KNOW EXACTLY WHAT YOU ARE DOING HERE.
+ */
+ switch (mAppDataSplitMode)
+ {
+ case ADS_MODE_0_N:
+ SafeWriteRecord(ContentType.application_data, TlsUtilities.EmptyBytes, 0, 0);
+ break;
+ case ADS_MODE_0_N_FIRSTONLY:
+ this.mAppDataSplitEnabled = false;
+ SafeWriteRecord(ContentType.application_data, TlsUtilities.EmptyBytes, 0, 0);
+ break;
+ case ADS_MODE_1_Nsub1:
+ default:
+ SafeWriteRecord(ContentType.application_data, buf, offset, 1);
+ ++offset;
+ --len;
+ break;
+ }
+ }
+
+ if (len > 0)
+ {
+ // Fragment data according to the current fragment limit.
+ int toWrite = System.Math.Min(len, mRecordStream.GetPlaintextLimit());
+ SafeWriteRecord(ContentType.application_data, buf, offset, toWrite);
+ offset += toWrite;
+ len -= toWrite;
+ }
+ }
+ }
+
+ protected virtual void SetAppDataSplitMode(int appDataSplitMode)
+ {
+ if (appDataSplitMode < ADS_MODE_1_Nsub1 || appDataSplitMode > ADS_MODE_0_N_FIRSTONLY)
+ throw new ArgumentException("Illegal appDataSplitMode mode: " + appDataSplitMode, "appDataSplitMode");
+
+ this.mAppDataSplitMode = appDataSplitMode;
+ }
+
+ protected virtual void WriteHandshakeMessage(byte[] buf, int off, int len)
+ {
+ if (len < 4)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ byte type = TlsUtilities.ReadUint8(buf, off);
+ if (type != HandshakeType.hello_request)
+ {
+ mRecordStream.HandshakeHashUpdater.Write(buf, off, len);
+ }
+
+ int total = 0;
+ do
+ {
+ // Fragment data according to the current fragment limit.
+ int toWrite = System.Math.Min(len - total, mRecordStream.GetPlaintextLimit());
+ SafeWriteRecord(ContentType.handshake, buf, off + total, toWrite);
+ total += toWrite;
+ }
+ while (total < len);
+ }
+
+ /// The secure bidirectional stream for this connection
+ /// Only allowed in blocking mode.
+ public virtual Stream Stream
+ {
+ get
+ {
+ if (!mBlocking)
+ throw new InvalidOperationException("Cannot use Stream in non-blocking mode! Use OfferInput()/OfferOutput() instead.");
+ return this.mTlsStream;
+ }
+ }
+
+ /**
+ * Should be called in non-blocking mode when the input data reaches EOF.
+ */
+ public virtual void CloseInput()
+ {
+ if (mBlocking)
+ throw new InvalidOperationException("Cannot use CloseInput() in blocking mode!");
+
+ if (mClosed)
+ return;
+
+ if (mInputBuffers.Available > 0)
+ throw new EndOfStreamException();
+
+ if (!mAppDataReady)
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+
+ throw new TlsNoCloseNotifyException();
+ }
+
+ /**
+ * Offer input from an arbitrary source. Only allowed in non-blocking mode.
+ *
+ * After this method returns, the input buffer is "owned" by this object. Other code
+ * must not attempt to do anything with it.
+ *
+ * This method will decrypt and process all records that are fully available.
+ * If only part of a record is available, the buffer will be retained until the
+ * remainder of the record is offered.
+ *
+ * If any records containing application data were processed, the decrypted data
+ * can be obtained using {@link #readInput(byte[], int, int)}. If any records
+ * containing protocol data were processed, a response may have been generated.
+ * You should always check to see if there is any available output after calling
+ * this method by calling {@link #getAvailableOutputBytes()}.
+ * @param input The input buffer to offer
+ * @throws IOException If an error occurs while decrypting or processing a record
+ */
+ public virtual void OfferInput(byte[] input)
+ {
+ if (mBlocking)
+ throw new InvalidOperationException("Cannot use OfferInput() in blocking mode! Use Stream instead.");
+ if (mClosed)
+ throw new IOException("Connection is closed, cannot accept any more input");
+
+ mInputBuffers.Write(input);
+
+ // loop while there are enough bytes to read the length of the next record
+ while (mInputBuffers.Available >= RecordStream.TLS_HEADER_SIZE)
+ {
+ byte[] recordHeader = new byte[RecordStream.TLS_HEADER_SIZE];
+ mInputBuffers.Peek(recordHeader);
+
+ int totalLength = TlsUtilities.ReadUint16(recordHeader, RecordStream.TLS_HEADER_LENGTH_OFFSET) + RecordStream.TLS_HEADER_SIZE;
+ if (mInputBuffers.Available < totalLength)
+ {
+ // not enough bytes to read a whole record
+ SafeCheckRecordHeader(recordHeader);
+ break;
+ }
+
+ SafeReadRecord();
+
+ if (mClosed)
+ {
+ if (mConnectionState != CS_END)
+ {
+ // NOTE: Any close during the handshake should have raised an exception.
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Gets the amount of received application data. A call to {@link #readInput(byte[], int, int)}
+ * is guaranteed to be able to return at least this much data.
+ *
+ * Only allowed in non-blocking mode.
+ * @return The number of bytes of available application data
+ */
+ public virtual int GetAvailableInputBytes()
+ {
+ if (mBlocking)
+ throw new InvalidOperationException("Cannot use GetAvailableInputBytes() in blocking mode! Use ApplicationDataAvailable() instead.");
+
+ return ApplicationDataAvailable();
+ }
+
+ /**
+ * Retrieves received application data. Use {@link #getAvailableInputBytes()} to check
+ * how much application data is currently available. This method functions similarly to
+ * {@link InputStream#read(byte[], int, int)}, except that it never blocks. If no data
+ * is available, nothing will be copied and zero will be returned.
+ *
+ * Only allowed in non-blocking mode.
+ * @param buffer The buffer to hold the application data
+ * @param offset The start offset in the buffer at which the data is written
+ * @param length The maximum number of bytes to read
+ * @return The total number of bytes copied to the buffer. May be less than the
+ * length specified if the length was greater than the amount of available data.
+ */
+ public virtual int ReadInput(byte[] buffer, int offset, int length)
+ {
+ if (mBlocking)
+ throw new InvalidOperationException("Cannot use ReadInput() in blocking mode! Use Stream instead.");
+
+ return ReadApplicationData(buffer, offset, System.Math.Min(length, ApplicationDataAvailable()));
+ }
+
+ /**
+ * Offer output from an arbitrary source. Only allowed in non-blocking mode.
+ *
+ * After this method returns, the specified section of the buffer will have been
+ * processed. Use {@link #readOutput(byte[], int, int)} to get the bytes to
+ * transmit to the other peer.
+ *
+ * This method must not be called until after the handshake is complete! Attempting
+ * to call it before the handshake is complete will result in an exception.
+ * @param buffer The buffer containing application data to encrypt
+ * @param offset The offset at which to begin reading data
+ * @param length The number of bytes of data to read
+ * @throws IOException If an error occurs encrypting the data, or the handshake is not complete
+ */
+ public virtual void OfferOutput(byte[] buffer, int offset, int length)
+ {
+ if (mBlocking)
+ throw new InvalidOperationException("Cannot use OfferOutput() in blocking mode! Use Stream instead.");
+ if (!mAppDataReady)
+ throw new IOException("Application data cannot be sent until the handshake is complete!");
+
+ WriteData(buffer, offset, length);
+ }
+
+ /**
+ * Gets the amount of encrypted data available to be sent. A call to
+ * {@link #readOutput(byte[], int, int)} is guaranteed to be able to return at
+ * least this much data.
+ *
+ * Only allowed in non-blocking mode.
+ * @return The number of bytes of available encrypted data
+ */
+ public virtual int GetAvailableOutputBytes()
+ {
+ if (mBlocking)
+ throw new InvalidOperationException("Cannot use GetAvailableOutputBytes() in blocking mode! Use Stream instead.");
+
+ return mOutputBuffer.Available;
+ }
+
+ /**
+ * Retrieves encrypted data to be sent. Use {@link #getAvailableOutputBytes()} to check
+ * how much encrypted data is currently available. This method functions similarly to
+ * {@link InputStream#read(byte[], int, int)}, except that it never blocks. If no data
+ * is available, nothing will be copied and zero will be returned.
+ *
+ * Only allowed in non-blocking mode.
+ * @param buffer The buffer to hold the encrypted data
+ * @param offset The start offset in the buffer at which the data is written
+ * @param length The maximum number of bytes to read
+ * @return The total number of bytes copied to the buffer. May be less than the
+ * length specified if the length was greater than the amount of available data.
+ */
+ public virtual int ReadOutput(byte[] buffer, int offset, int length)
+ {
+ if (mBlocking)
+ throw new InvalidOperationException("Cannot use ReadOutput() in blocking mode! Use Stream instead.");
+
+ return mOutputBuffer.Read(buffer, offset, length);
+ }
+
+ protected virtual void InvalidateSession()
+ {
+ if (this.mSessionParameters != null)
+ {
+ this.mSessionParameters.Clear();
+ this.mSessionParameters = null;
+ }
+
+ if (this.mTlsSession != null)
+ {
+ this.mTlsSession.Invalidate();
+ this.mTlsSession = null;
+ }
+ }
+
+ protected virtual void ProcessFinishedMessage(MemoryStream buf)
+ {
+ if (mExpectedVerifyData == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ byte[] verify_data = TlsUtilities.ReadFully(mExpectedVerifyData.Length, buf);
+
+ AssertEmpty(buf);
+
+ /*
+ * Compare both checksums.
+ */
+ if (!Arrays.ConstantTimeAreEqual(mExpectedVerifyData, verify_data))
+ {
+ /*
+ * Wrong checksum in the finished message.
+ */
+ throw new TlsFatalAlert(AlertDescription.decrypt_error);
+ }
+ }
+
+ protected virtual void RaiseAlertFatal(byte alertDescription, string message, Exception cause)
+ {
+ Peer.NotifyAlertRaised(AlertLevel.fatal, alertDescription, message, cause);
+
+ byte[] alert = new byte[]{ AlertLevel.fatal, alertDescription };
+
+ try
+ {
+ mRecordStream.WriteRecord(ContentType.alert, alert, 0, 2);
+ }
+ catch (Exception)
+ {
+ // We are already processing an exception, so just ignore this
+ }
+ }
+
+ protected virtual void RaiseAlertWarning(byte alertDescription, string message)
+ {
+ Peer.NotifyAlertRaised(AlertLevel.warning, alertDescription, message, null);
+
+ byte[] alert = new byte[]{ AlertLevel.warning, alertDescription };
+
+ SafeWriteRecord(ContentType.alert, alert, 0, 2);
+ }
+
+ protected virtual void SendCertificateMessage(Certificate certificate)
+ {
+ if (certificate == null)
+ {
+ certificate = Certificate.EmptyChain;
+ }
+
+ if (certificate.IsEmpty)
+ {
+ TlsContext context = Context;
+ if (!context.IsServer)
+ {
+ ProtocolVersion serverVersion = Context.ServerVersion;
+ if (serverVersion.IsSsl)
+ {
+ string errorMessage = serverVersion.ToString() + " client didn't provide credentials";
+ RaiseAlertWarning(AlertDescription.no_certificate, errorMessage);
+ return;
+ }
+ }
+ }
+
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate);
+
+ certificate.Encode(message);
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual void SendChangeCipherSpecMessage()
+ {
+ byte[] message = new byte[]{ 1 };
+ SafeWriteRecord(ContentType.change_cipher_spec, message, 0, message.Length);
+ mRecordStream.SentWriteCipherSpec();
+ }
+
+ protected virtual void SendFinishedMessage()
+ {
+ byte[] verify_data = CreateVerifyData(Context.IsServer);
+
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.finished, verify_data.Length);
+
+ message.Write(verify_data, 0, verify_data.Length);
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual void SendSupplementalDataMessage(IList supplementalData)
+ {
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.supplemental_data);
+
+ WriteSupplementalData(message, supplementalData);
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual byte[] CreateVerifyData(bool isServer)
+ {
+ TlsContext context = Context;
+ string asciiLabel = isServer ? ExporterLabel.server_finished : ExporterLabel.client_finished;
+ byte[] sslSender = isServer ? TlsUtilities.SSL_SERVER : TlsUtilities.SSL_CLIENT;
+ byte[] hash = GetCurrentPrfHash(context, mRecordStream.HandshakeHash, sslSender);
+ return TlsUtilities.CalculateVerifyData(context, asciiLabel, hash);
+ }
+
+ /**
+ * Closes this connection.
+ *
+ * @throws IOException If something goes wrong during closing.
+ */
+ public virtual void Close()
+ {
+ HandleClose(true);
+ }
+
+ protected internal virtual void Flush()
+ {
+ mRecordStream.Flush();
+ }
+
+ public virtual bool IsClosed
+ {
+ get { return mClosed; }
+ }
+
+ protected virtual short ProcessMaxFragmentLengthExtension(IDictionary clientExtensions, IDictionary serverExtensions,
+ byte alertDescription)
+ {
+ short maxFragmentLength = TlsExtensionsUtilities.GetMaxFragmentLengthExtension(serverExtensions);
+ if (maxFragmentLength >= 0)
+ {
+ if (!MaxFragmentLength.IsValid((byte)maxFragmentLength)
+ || (!this.mResumedSession && maxFragmentLength != TlsExtensionsUtilities
+ .GetMaxFragmentLengthExtension(clientExtensions)))
+ {
+ throw new TlsFatalAlert(alertDescription);
+ }
+ }
+ return maxFragmentLength;
+ }
+
+ protected virtual void RefuseRenegotiation()
+ {
+ /*
+ * RFC 5746 4.5 SSLv3 clients that refuse renegotiation SHOULD use a fatal
+ * handshake_failure alert.
+ */
+ if (TlsUtilities.IsSsl(Context))
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+
+ RaiseAlertWarning(AlertDescription.no_renegotiation, "Renegotiation not supported");
+ }
+
+ /**
+ * Make sure the InputStream 'buf' now empty. Fail otherwise.
+ *
+ * @param buf The InputStream to check.
+ * @throws IOException If 'buf' is not empty.
+ */
+ protected internal static void AssertEmpty(MemoryStream buf)
+ {
+ if (buf.Position < buf.Length)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ }
+
+ protected internal static byte[] CreateRandomBlock(bool useGmtUnixTime, IRandomGenerator randomGenerator)
+ {
+ byte[] result = new byte[32];
+ randomGenerator.NextBytes(result);
+
+ if (useGmtUnixTime)
+ {
+ TlsUtilities.WriteGmtUnixTime(result, 0);
+ }
+
+ return result;
+ }
+
+ protected internal static byte[] CreateRenegotiationInfo(byte[] renegotiated_connection)
+ {
+ return TlsUtilities.EncodeOpaque8(renegotiated_connection);
+ }
+
+ protected internal static void EstablishMasterSecret(TlsContext context, TlsKeyExchange keyExchange)
+ {
+ byte[] pre_master_secret = keyExchange.GeneratePremasterSecret();
+
+ try
+ {
+ context.SecurityParameters.masterSecret = TlsUtilities.CalculateMasterSecret(context, pre_master_secret);
+ }
+ finally
+ {
+ // TODO Is there a way to ensure the data is really overwritten?
+ /*
+ * RFC 2246 8.1. The pre_master_secret should be deleted from memory once the
+ * master_secret has been computed.
+ */
+ if (pre_master_secret != null)
+ {
+ Arrays.Fill(pre_master_secret, (byte)0);
+ }
+ }
+ }
+
+ /**
+ * 'sender' only relevant to SSLv3
+ */
+ protected internal static byte[] GetCurrentPrfHash(TlsContext context, TlsHandshakeHash handshakeHash, byte[] sslSender)
+ {
+ IDigest d = handshakeHash.ForkPrfHash();
+
+ if (sslSender != null && TlsUtilities.IsSsl(context))
+ {
+ d.BlockUpdate(sslSender, 0, sslSender.Length);
+ }
+
+ return DigestUtilities.DoFinal(d);
+ }
+
+ protected internal static IDictionary ReadExtensions(MemoryStream input)
+ {
+ if (input.Position >= input.Length)
+ return null;
+
+ byte[] extBytes = TlsUtilities.ReadOpaque16(input);
+
+ AssertEmpty(input);
+
+ MemoryStream buf = new MemoryStream(extBytes, false);
+
+ // Integer -> byte[]
+ IDictionary extensions = Platform.CreateHashtable();
+
+ while (buf.Position < buf.Length)
+ {
+ int extension_type = TlsUtilities.ReadUint16(buf);
+ byte[] extension_data = TlsUtilities.ReadOpaque16(buf);
+
+ /*
+ * RFC 3546 2.3 There MUST NOT be more than one extension of the same type.
+ */
+ if (extensions.Contains(extension_type))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ extensions.Add(extension_type, extension_data);
+ }
+
+ return extensions;
+ }
+
+ protected internal static IList ReadSupplementalDataMessage(MemoryStream input)
+ {
+ byte[] supp_data = TlsUtilities.ReadOpaque24(input);
+
+ AssertEmpty(input);
+
+ MemoryStream buf = new MemoryStream(supp_data, false);
+
+ IList supplementalData = Platform.CreateArrayList();
+
+ while (buf.Position < buf.Length)
+ {
+ int supp_data_type = TlsUtilities.ReadUint16(buf);
+ byte[] data = TlsUtilities.ReadOpaque16(buf);
+
+ supplementalData.Add(new SupplementalDataEntry(supp_data_type, data));
+ }
+
+ return supplementalData;
+ }
+
+ protected internal static void WriteExtensions(Stream output, IDictionary extensions)
+ {
+ MemoryStream buf = new MemoryStream();
+
+ /*
+ * NOTE: There are reports of servers that don't accept a zero-length extension as the last
+ * one, so we write out any zero-length ones first as a best-effort workaround.
+ */
+ WriteSelectedExtensions(buf, extensions, true);
+ WriteSelectedExtensions(buf, extensions, false);
+
+ byte[] extBytes = buf.ToArray();
+
+ TlsUtilities.WriteOpaque16(extBytes, output);
+ }
+
+ protected internal static void WriteSelectedExtensions(Stream output, IDictionary extensions, bool selectEmpty)
+ {
+ foreach (int extension_type in extensions.Keys)
+ {
+ byte[] extension_data = (byte[])extensions[extension_type];
+ if (selectEmpty == (extension_data.Length == 0))
+ {
+ TlsUtilities.CheckUint16(extension_type);
+ TlsUtilities.WriteUint16(extension_type, output);
+ TlsUtilities.WriteOpaque16(extension_data, output);
+ }
+ }
+ }
+
+ protected internal static void WriteSupplementalData(Stream output, IList supplementalData)
+ {
+ MemoryStream buf = new MemoryStream();
+
+ foreach (SupplementalDataEntry entry in supplementalData)
+ {
+ int supp_data_type = entry.DataType;
+ TlsUtilities.CheckUint16(supp_data_type);
+ TlsUtilities.WriteUint16(supp_data_type, buf);
+ TlsUtilities.WriteOpaque16(entry.Data, buf);
+ }
+
+ byte[] supp_data = buf.ToArray();
+
+ TlsUtilities.WriteOpaque24(supp_data, output);
+ }
+
+ protected internal static int GetPrfAlgorithm(TlsContext context, int ciphersuite)
+ {
+ bool isTLSv12 = TlsUtilities.IsTlsV12(context);
+
+ switch (ciphersuite)
+ {
+ case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_128_OCB:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_256_OCB:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+ {
+ if (isTLSv12)
+ {
+ return PrfAlgorithm.tls_prf_sha256;
+ }
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ {
+ if (isTLSv12)
+ {
+ return PrfAlgorithm.tls_prf_sha384;
+ }
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384:
+ {
+ if (isTLSv12)
+ {
+ return PrfAlgorithm.tls_prf_sha384;
+ }
+ return PrfAlgorithm.tls_prf_legacy;
+ }
+
+ default:
+ {
+ if (isTLSv12)
+ {
+ return PrfAlgorithm.tls_prf_sha256;
+ }
+ return PrfAlgorithm.tls_prf_legacy;
+ }
+ }
+ }
+
+ internal class HandshakeMessage
+ : MemoryStream
+ {
+ internal HandshakeMessage(byte handshakeType)
+ : this(handshakeType, 60)
+ {
+ }
+
+ internal HandshakeMessage(byte handshakeType, int length)
+ : base(length + 4)
+ {
+ TlsUtilities.WriteUint8(handshakeType, this);
+ // Reserve space for length
+ TlsUtilities.WriteUint24(0, this);
+ }
+
+ internal void Write(byte[] data)
+ {
+ Write(data, 0, data.Length);
+ }
+
+ internal void WriteToRecordStream(TlsProtocol protocol)
+ {
+ // Patch actual length back in
+ long length = Length - 4;
+ TlsUtilities.CheckUint24(length);
+ this.Position = 1;
+ TlsUtilities.WriteUint24((int)length, this);
+
+#if PORTABLE
+ byte[] buf = ToArray();
+ int bufLen = buf.Length;
+#else
+ byte[] buf = GetBuffer();
+ int bufLen = (int)Length;
+#endif
+
+ protocol.WriteHandshakeMessage(buf, 0, bufLen);
+ Platform.Dispose(this);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsProtocolHandler.cs b/bc-sharp-crypto/src/crypto/tls/TlsProtocolHandler.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6f223467f0a9ef9092c73a6f4d83987de72ba81f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsProtocolHandler.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Agreement.Srp;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Prng;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ [Obsolete("Use 'TlsClientProtocol' instead")]
+ public class TlsProtocolHandler
+ : TlsClientProtocol
+ {
+ public TlsProtocolHandler(Stream stream, SecureRandom secureRandom)
+ : base(stream, stream, secureRandom)
+ {
+ }
+
+ /// Both streams can be the same object
+ public TlsProtocolHandler(Stream input, Stream output, SecureRandom secureRandom)
+ : base(input, output, secureRandom)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsPskIdentity.cs b/bc-sharp-crypto/src/crypto/tls/TlsPskIdentity.cs
new file mode 100644
index 0000000000000000000000000000000000000000..119064ee7060654dfaab9e51734e80bf096e8058
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsPskIdentity.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsPskIdentity
+ {
+ void SkipIdentityHint();
+
+ void NotifyIdentityHint(byte[] psk_identity_hint);
+
+ byte[] GetPskIdentity();
+
+ byte[] GetPsk();
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsPskIdentityManager.cs b/bc-sharp-crypto/src/crypto/tls/TlsPskIdentityManager.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a72c2299c3200eafee8f63efbe1ae4a086998648
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsPskIdentityManager.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsPskIdentityManager
+ {
+ byte[] GetHint();
+
+ byte[] GetPsk(byte[] identity);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsPskKeyExchange.cs b/bc-sharp-crypto/src/crypto/tls/TlsPskKeyExchange.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0af7f7a690a3d72ee21e2eb02cb280e733f2cbbb
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsPskKeyExchange.cs
@@ -0,0 +1,328 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// (D)TLS PSK key exchange (RFC 4279).
+ public class TlsPskKeyExchange
+ : AbstractTlsKeyExchange
+ {
+ protected TlsPskIdentity mPskIdentity;
+ protected TlsPskIdentityManager mPskIdentityManager;
+
+ protected DHParameters mDHParameters;
+ protected int[] mNamedCurves;
+ protected byte[] mClientECPointFormats, mServerECPointFormats;
+
+ protected byte[] mPskIdentityHint = null;
+ protected byte[] mPsk = null;
+
+ protected DHPrivateKeyParameters mDHAgreePrivateKey = null;
+ protected DHPublicKeyParameters mDHAgreePublicKey = null;
+
+ protected ECPrivateKeyParameters mECAgreePrivateKey = null;
+ protected ECPublicKeyParameters mECAgreePublicKey = null;
+
+ protected AsymmetricKeyParameter mServerPublicKey = null;
+ protected RsaKeyParameters mRsaServerPublicKey = null;
+ protected TlsEncryptionCredentials mServerCredentials = null;
+ protected byte[] mPremasterSecret;
+
+ public TlsPskKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, TlsPskIdentity pskIdentity,
+ TlsPskIdentityManager pskIdentityManager, DHParameters dhParameters, int[] namedCurves,
+ byte[] clientECPointFormats, byte[] serverECPointFormats)
+ : base(keyExchange, supportedSignatureAlgorithms)
+ {
+ switch (keyExchange)
+ {
+ case KeyExchangeAlgorithm.DHE_PSK:
+ case KeyExchangeAlgorithm.ECDHE_PSK:
+ case KeyExchangeAlgorithm.PSK:
+ case KeyExchangeAlgorithm.RSA_PSK:
+ break;
+ default:
+ throw new InvalidOperationException("unsupported key exchange algorithm");
+ }
+
+ this.mPskIdentity = pskIdentity;
+ this.mPskIdentityManager = pskIdentityManager;
+ this.mDHParameters = dhParameters;
+ this.mNamedCurves = namedCurves;
+ this.mClientECPointFormats = clientECPointFormats;
+ this.mServerECPointFormats = serverECPointFormats;
+ }
+
+ public override void SkipServerCredentials()
+ {
+ if (mKeyExchange == KeyExchangeAlgorithm.RSA_PSK)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public override void ProcessServerCredentials(TlsCredentials serverCredentials)
+ {
+ if (!(serverCredentials is TlsEncryptionCredentials))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ ProcessServerCertificate(serverCredentials.Certificate);
+
+ this.mServerCredentials = (TlsEncryptionCredentials)serverCredentials;
+ }
+
+ public override byte[] GenerateServerKeyExchange()
+ {
+ this.mPskIdentityHint = mPskIdentityManager.GetHint();
+
+ if (this.mPskIdentityHint == null && !RequiresServerKeyExchange)
+ return null;
+
+ MemoryStream buf = new MemoryStream();
+
+ if (this.mPskIdentityHint == null)
+ {
+ TlsUtilities.WriteOpaque16(TlsUtilities.EmptyBytes, buf);
+ }
+ else
+ {
+ TlsUtilities.WriteOpaque16(this.mPskIdentityHint, buf);
+ }
+
+ if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
+ {
+ if (this.mDHParameters == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom,
+ this.mDHParameters, buf);
+ }
+ else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
+ {
+ this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom,
+ mNamedCurves, mClientECPointFormats, buf);
+ }
+
+ return buf.ToArray();
+ }
+
+ public override void ProcessServerCertificate(Certificate serverCertificate)
+ {
+ if (mKeyExchange != KeyExchangeAlgorithm.RSA_PSK)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ if (serverCertificate.IsEmpty)
+ throw new TlsFatalAlert(AlertDescription.bad_certificate);
+
+ X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
+
+ SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+ try
+ {
+ this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo);
+ }
+ catch (Exception e)
+ {
+ throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
+ }
+
+ // Sanity check the PublicKeyFactory
+ if (this.mServerPublicKey.IsPrivate)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ this.mRsaServerPublicKey = ValidateRsaPublicKey((RsaKeyParameters)this.mServerPublicKey);
+
+ TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyEncipherment);
+
+ base.ProcessServerCertificate(serverCertificate);
+ }
+
+ public override bool RequiresServerKeyExchange
+ {
+ get
+ {
+ switch (mKeyExchange)
+ {
+ case KeyExchangeAlgorithm.DHE_PSK:
+ case KeyExchangeAlgorithm.ECDHE_PSK:
+ return true;
+ default:
+ return false;
+ }
+ }
+ }
+
+ public override void ProcessServerKeyExchange(Stream input)
+ {
+ this.mPskIdentityHint = TlsUtilities.ReadOpaque16(input);
+
+ if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
+ {
+ ServerDHParams serverDHParams = ServerDHParams.Parse(input);
+
+ this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(serverDHParams.PublicKey);
+ this.mDHParameters = mDHAgreePublicKey.Parameters;
+ }
+ else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
+ {
+ ECDomainParameters ecParams = TlsEccUtilities.ReadECParameters(mNamedCurves, mClientECPointFormats, input);
+
+ byte[] point = TlsUtilities.ReadOpaque8(input);
+
+ this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
+ mClientECPointFormats, ecParams, point));
+ }
+ }
+
+ public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public override void ProcessClientCredentials(TlsCredentials clientCredentials)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public override void GenerateClientKeyExchange(Stream output)
+ {
+ if (mPskIdentityHint == null)
+ {
+ mPskIdentity.SkipIdentityHint();
+ }
+ else
+ {
+ mPskIdentity.NotifyIdentityHint(mPskIdentityHint);
+ }
+
+ byte[] psk_identity = mPskIdentity.GetPskIdentity();
+ if (psk_identity == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ this.mPsk = mPskIdentity.GetPsk();
+ if (mPsk == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ TlsUtilities.WriteOpaque16(psk_identity, output);
+
+ mContext.SecurityParameters.pskIdentity = psk_identity;
+
+ if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
+ {
+ this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom,
+ mDHParameters, output);
+ }
+ else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
+ {
+ this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom,
+ mServerECPointFormats, mECAgreePublicKey.Parameters, output);
+ }
+ else if (this.mKeyExchange == KeyExchangeAlgorithm.RSA_PSK)
+ {
+ this.mPremasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(mContext,
+ this.mRsaServerPublicKey, output);
+ }
+ }
+
+ public override void ProcessClientKeyExchange(Stream input)
+ {
+ byte[] psk_identity = TlsUtilities.ReadOpaque16(input);
+
+ this.mPsk = mPskIdentityManager.GetPsk(psk_identity);
+ if (mPsk == null)
+ throw new TlsFatalAlert(AlertDescription.unknown_psk_identity);
+
+ mContext.SecurityParameters.pskIdentity = psk_identity;
+
+ if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
+ {
+ BigInteger Yc = TlsDHUtilities.ReadDHParameter(input);
+
+ this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(new DHPublicKeyParameters(Yc, mDHParameters));
+ }
+ else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
+ {
+ byte[] point = TlsUtilities.ReadOpaque8(input);
+
+ ECDomainParameters curve_params = this.mECAgreePrivateKey.Parameters;
+
+ this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
+ mServerECPointFormats, curve_params, point));
+ }
+ else if (this.mKeyExchange == KeyExchangeAlgorithm.RSA_PSK)
+ {
+ byte[] encryptedPreMasterSecret;
+ if (TlsUtilities.IsSsl(mContext))
+ {
+ // TODO Do any SSLv3 clients actually include the length?
+ encryptedPreMasterSecret = Streams.ReadAll(input);
+ }
+ else
+ {
+ encryptedPreMasterSecret = TlsUtilities.ReadOpaque16(input);
+ }
+
+ this.mPremasterSecret = mServerCredentials.DecryptPreMasterSecret(encryptedPreMasterSecret);
+ }
+ }
+
+ public override byte[] GeneratePremasterSecret()
+ {
+ byte[] other_secret = GenerateOtherSecret(mPsk.Length);
+
+ MemoryStream buf = new MemoryStream(4 + other_secret.Length + mPsk.Length);
+ TlsUtilities.WriteOpaque16(other_secret, buf);
+ TlsUtilities.WriteOpaque16(mPsk, buf);
+
+ Arrays.Fill(mPsk, (byte)0);
+ this.mPsk = null;
+
+ return buf.ToArray();
+ }
+
+ protected virtual byte[] GenerateOtherSecret(int pskLength)
+ {
+ if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
+ {
+ if (mDHAgreePrivateKey != null)
+ {
+ return TlsDHUtilities.CalculateDHBasicAgreement(mDHAgreePublicKey, mDHAgreePrivateKey);
+ }
+
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
+ {
+ if (mECAgreePrivateKey != null)
+ {
+ return TlsEccUtilities.CalculateECDHBasicAgreement(mECAgreePublicKey, mECAgreePrivateKey);
+ }
+
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ if (this.mKeyExchange == KeyExchangeAlgorithm.RSA_PSK)
+ {
+ return this.mPremasterSecret;
+ }
+
+ return new byte[pskLength];
+ }
+
+ protected virtual RsaKeyParameters ValidateRsaPublicKey(RsaKeyParameters key)
+ {
+ // TODO What is the minimum bit length required?
+ // key.Modulus.BitLength;
+
+ if (!key.Exponent.IsProbablePrime(2))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ return key;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsRsaKeyExchange.cs b/bc-sharp-crypto/src/crypto/tls/TlsRsaKeyExchange.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b02d56486cc09f61813ded16342325aec3adce12
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsRsaKeyExchange.cs
@@ -0,0 +1,140 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// (D)TLS and SSLv3 RSA key exchange.
+ public class TlsRsaKeyExchange
+ : AbstractTlsKeyExchange
+ {
+ protected AsymmetricKeyParameter mServerPublicKey = null;
+
+ protected RsaKeyParameters mRsaServerPublicKey = null;
+
+ protected TlsEncryptionCredentials mServerCredentials = null;
+
+ protected byte[] mPremasterSecret;
+
+ public TlsRsaKeyExchange(IList supportedSignatureAlgorithms)
+ : base(KeyExchangeAlgorithm.RSA, supportedSignatureAlgorithms)
+ {
+ }
+
+ public override void SkipServerCredentials()
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public override void ProcessServerCredentials(TlsCredentials serverCredentials)
+ {
+ if (!(serverCredentials is TlsEncryptionCredentials))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ ProcessServerCertificate(serverCredentials.Certificate);
+
+ this.mServerCredentials = (TlsEncryptionCredentials)serverCredentials;
+ }
+
+ public override void ProcessServerCertificate(Certificate serverCertificate)
+ {
+ if (serverCertificate.IsEmpty)
+ throw new TlsFatalAlert(AlertDescription.bad_certificate);
+
+ X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
+
+ SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+ try
+ {
+ this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo);
+ }
+ catch (Exception e)
+ {
+ throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
+ }
+
+ // Sanity check the PublicKeyFactory
+ if (this.mServerPublicKey.IsPrivate)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ this.mRsaServerPublicKey = ValidateRsaPublicKey((RsaKeyParameters)this.mServerPublicKey);
+
+ TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyEncipherment);
+
+ base.ProcessServerCertificate(serverCertificate);
+ }
+
+ public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
+ {
+ byte[] types = certificateRequest.CertificateTypes;
+ for (int i = 0; i < types.Length; ++i)
+ {
+ switch (types[i])
+ {
+ case ClientCertificateType.rsa_sign:
+ case ClientCertificateType.dss_sign:
+ case ClientCertificateType.ecdsa_sign:
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+ }
+
+ public override void ProcessClientCredentials(TlsCredentials clientCredentials)
+ {
+ if (!(clientCredentials is TlsSignerCredentials))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public override void GenerateClientKeyExchange(Stream output)
+ {
+ this.mPremasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(mContext, mRsaServerPublicKey, output);
+ }
+
+ public override void ProcessClientKeyExchange(Stream input)
+ {
+ byte[] encryptedPreMasterSecret;
+ if (TlsUtilities.IsSsl(mContext))
+ {
+ // TODO Do any SSLv3 clients actually include the length?
+ encryptedPreMasterSecret = Streams.ReadAll(input);
+ }
+ else
+ {
+ encryptedPreMasterSecret = TlsUtilities.ReadOpaque16(input);
+ }
+
+ this.mPremasterSecret = mServerCredentials.DecryptPreMasterSecret(encryptedPreMasterSecret);
+ }
+
+ public override byte[] GeneratePremasterSecret()
+ {
+ if (this.mPremasterSecret == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ byte[] tmp = this.mPremasterSecret;
+ this.mPremasterSecret = null;
+ return tmp;
+ }
+
+ protected virtual RsaKeyParameters ValidateRsaPublicKey(RsaKeyParameters key)
+ {
+ // TODO What is the minimum bit length required?
+ // key.Modulus.BitLength;
+
+ if (!key.Exponent.IsProbablePrime(2))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ return key;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsRsaSigner.cs b/bc-sharp-crypto/src/crypto/tls/TlsRsaSigner.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1614f503b80ac896d83426fc86be3763119ac219
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsRsaSigner.cs
@@ -0,0 +1,102 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsRsaSigner
+ : AbstractTlsSigner
+ {
+ public override byte[] GenerateRawSignature(SignatureAndHashAlgorithm algorithm,
+ AsymmetricKeyParameter privateKey, byte[] hash)
+ {
+ ISigner signer = MakeSigner(algorithm, true, true,
+ new ParametersWithRandom(privateKey, this.mContext.SecureRandom));
+ signer.BlockUpdate(hash, 0, hash.Length);
+ return signer.GenerateSignature();
+ }
+
+ public override bool VerifyRawSignature(SignatureAndHashAlgorithm algorithm, byte[] sigBytes,
+ AsymmetricKeyParameter publicKey, byte[] hash)
+ {
+ ISigner signer = MakeSigner(algorithm, true, false, publicKey);
+ signer.BlockUpdate(hash, 0, hash.Length);
+ return signer.VerifySignature(sigBytes);
+ }
+
+ public override ISigner CreateSigner(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter privateKey)
+ {
+ return MakeSigner(algorithm, false, true, new ParametersWithRandom(privateKey, this.mContext.SecureRandom));
+ }
+
+ public override ISigner CreateVerifyer(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter publicKey)
+ {
+ return MakeSigner(algorithm, false, false, publicKey);
+ }
+
+ public override bool IsValidPublicKey(AsymmetricKeyParameter publicKey)
+ {
+ return publicKey is RsaKeyParameters && !publicKey.IsPrivate;
+ }
+
+ protected virtual ISigner MakeSigner(SignatureAndHashAlgorithm algorithm, bool raw, bool forSigning,
+ ICipherParameters cp)
+ {
+ if ((algorithm != null) != TlsUtilities.IsTlsV12(mContext))
+ throw new InvalidOperationException();
+ if (algorithm != null && algorithm.Signature != SignatureAlgorithm.rsa)
+ throw new InvalidOperationException();
+
+ IDigest d;
+ if (raw)
+ {
+ d = new NullDigest();
+ }
+ else if (algorithm == null)
+ {
+ d = new CombinedHash();
+ }
+ else
+ {
+ d = TlsUtilities.CreateHash(algorithm.Hash);
+ }
+
+ ISigner s;
+ if (algorithm != null)
+ {
+ /*
+ * RFC 5246 4.7. In RSA signing, the opaque vector contains the signature generated
+ * using the RSASSA-PKCS1-v1_5 signature scheme defined in [PKCS1].
+ */
+ s = new RsaDigestSigner(d, TlsUtilities.GetOidForHashAlgorithm(algorithm.Hash));
+ }
+ else
+ {
+ /*
+ * RFC 5246 4.7. Note that earlier versions of TLS used a different RSA signature scheme
+ * that did not include a DigestInfo encoding.
+ */
+ s = new GenericSigner(CreateRsaImpl(), d);
+ }
+ s.Init(forSigning, cp);
+ return s;
+ }
+
+ protected virtual IAsymmetricBlockCipher CreateRsaImpl()
+ {
+ /*
+ * RFC 5246 7.4.7.1. Implementation note: It is now known that remote timing-based attacks
+ * on TLS are possible, at least when the client and server are on the same LAN.
+ * Accordingly, implementations that use static RSA keys MUST use RSA blinding or some other
+ * anti-timing technique, as described in [TIMING].
+ */
+ return new Pkcs1Encoding(new RsaBlindedEngine());
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsRsaUtilities.cs b/bc-sharp-crypto/src/crypto/tls/TlsRsaUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0e42c1733b52399af2b7502ccc9f45eae45495a9
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsRsaUtilities.cs
@@ -0,0 +1,132 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class TlsRsaUtilities
+ {
+ ///
+ public static byte[] GenerateEncryptedPreMasterSecret(TlsContext context, RsaKeyParameters rsaServerPublicKey,
+ Stream output)
+ {
+ /*
+ * Choose a PremasterSecret and send it encrypted to the server
+ */
+ byte[] premasterSecret = new byte[48];
+ context.SecureRandom.NextBytes(premasterSecret);
+ TlsUtilities.WriteVersion(context.ClientVersion, premasterSecret, 0);
+
+ Pkcs1Encoding encoding = new Pkcs1Encoding(new RsaBlindedEngine());
+ encoding.Init(true, new ParametersWithRandom(rsaServerPublicKey, context.SecureRandom));
+
+ try
+ {
+ byte[] encryptedPreMasterSecret = encoding.ProcessBlock(premasterSecret, 0, premasterSecret.Length);
+
+ if (TlsUtilities.IsSsl(context))
+ {
+ // TODO Do any SSLv3 servers actually expect the length?
+ output.Write(encryptedPreMasterSecret, 0, encryptedPreMasterSecret.Length);
+ }
+ else
+ {
+ TlsUtilities.WriteOpaque16(encryptedPreMasterSecret, output);
+ }
+ }
+ catch (InvalidCipherTextException e)
+ {
+ /*
+ * This should never happen, only during decryption.
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error, e);
+ }
+
+ return premasterSecret;
+ }
+
+ public static byte[] SafeDecryptPreMasterSecret(TlsContext context, RsaKeyParameters rsaServerPrivateKey,
+ byte[] encryptedPreMasterSecret)
+ {
+ /*
+ * RFC 5246 7.4.7.1.
+ */
+ ProtocolVersion clientVersion = context.ClientVersion;
+
+ // TODO Provide as configuration option?
+ bool versionNumberCheckDisabled = false;
+
+ /*
+ * Generate 48 random bytes we can use as a Pre-Master-Secret, if the
+ * PKCS1 padding check should fail.
+ */
+ byte[] fallback = new byte[48];
+ context.SecureRandom.NextBytes(fallback);
+
+ byte[] M = Arrays.Clone(fallback);
+ try
+ {
+ Pkcs1Encoding encoding = new Pkcs1Encoding(new RsaBlindedEngine(), fallback);
+ encoding.Init(false,
+ new ParametersWithRandom(rsaServerPrivateKey, context.SecureRandom));
+
+ M = encoding.ProcessBlock(encryptedPreMasterSecret, 0, encryptedPreMasterSecret.Length);
+ }
+ catch (Exception)
+ {
+ /*
+ * This should never happen since the decryption should never throw an exception
+ * and return a random value instead.
+ *
+ * In any case, a TLS server MUST NOT generate an alert if processing an
+ * RSA-encrypted premaster secret message fails, or the version number is not as
+ * expected. Instead, it MUST continue the handshake with a randomly generated
+ * premaster secret.
+ */
+ }
+
+ /*
+ * If ClientHello.client_version is TLS 1.1 or higher, server implementations MUST
+ * check the version number [..].
+ */
+ if (versionNumberCheckDisabled && clientVersion.IsEqualOrEarlierVersionOf(ProtocolVersion.TLSv10))
+ {
+ /*
+ * If the version number is TLS 1.0 or earlier, server
+ * implementations SHOULD check the version number, but MAY have a
+ * configuration option to disable the check.
+ *
+ * So there is nothing to do here.
+ */
+ }
+ else
+ {
+ /*
+ * OK, we need to compare the version number in the decrypted Pre-Master-Secret with the
+ * clientVersion received during the handshake. If they don't match, we replace the
+ * decrypted Pre-Master-Secret with a random one.
+ */
+ int correct = (clientVersion.MajorVersion ^ (M[0] & 0xff))
+ | (clientVersion.MinorVersion ^ (M[1] & 0xff));
+ correct |= correct >> 1;
+ correct |= correct >> 2;
+ correct |= correct >> 4;
+ int mask = ~((correct & 1) - 1);
+
+ /*
+ * mask will be all bits set to 0xff if the version number differed.
+ */
+ for (int i = 0; i < 48; i++)
+ {
+ M[i] = (byte)((M[i] & (~mask)) | (fallback[i] & mask));
+ }
+ }
+ return M;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsServer.cs b/bc-sharp-crypto/src/crypto/tls/TlsServer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e791f93a96d1d051c193d1de4be11bafa82f9cec
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsServer.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsServer
+ : TlsPeer
+ {
+ void Init(TlsServerContext context);
+
+ ///
+ void NotifyClientVersion(ProtocolVersion clientVersion);
+
+ ///
+ void NotifyFallback(bool isFallback);
+
+ ///
+ void NotifyOfferedCipherSuites(int[] offeredCipherSuites);
+
+ ///
+ void NotifyOfferedCompressionMethods(byte[] offeredCompressionMethods);
+
+ /// A (Int32 -> byte[]). Will never be null.
+ ///
+ void ProcessClientExtensions(IDictionary clientExtensions);
+
+ ///
+ ProtocolVersion GetServerVersion();
+
+ ///
+ int GetSelectedCipherSuite();
+
+ ///
+ byte GetSelectedCompressionMethod();
+
+ ///
+ /// Get the (optional) table of server extensions to be included in (extended) server hello.
+ ///
+ ///
+ /// A (Int32 -> byte[]). May be null.
+ ///
+ ///
+ IDictionary GetServerExtensions();
+
+ ///
+ /// A ( ). May be null.
+ ///
+ ///
+ IList GetServerSupplementalData();
+
+ ///
+ TlsCredentials GetCredentials();
+
+ ///
+ /// This method will be called (only) if the server included an extension of type
+ /// "status_request" with empty "extension_data" in the extended server hello. See RFC 3546
+ /// 3.6. Certificate Status Request . If a non-null is returned, it
+ /// is sent to the client as a handshake message of type "certificate_status".
+ ///
+ /// A to be sent to the client (or null for none).
+ ///
+ CertificateStatus GetCertificateStatus();
+
+ ///
+ TlsKeyExchange GetKeyExchange();
+
+ ///
+ CertificateRequest GetCertificateRequest();
+
+ /// ( )
+ ///
+ void ProcessClientSupplementalData(IList clientSupplementalData);
+
+ ///
+ /// Called by the protocol handler to report the client certificate, only if GetCertificateRequest
+ /// returned non-null.
+ ///
+ /// Note: this method is responsible for certificate verification and validation.
+ /// the effective client certificate (may be an empty chain).
+ ///
+ void NotifyClientCertificate(Certificate clientCertificate);
+
+ /// RFC 5077 3.3. NewSessionTicket Handshake Message.
+ ///
+ /// This method will be called (only) if a NewSessionTicket extension was sent by the server. See
+ /// RFC 5077 4. Recommended Ticket Construction for recommended format and protection.
+ ///
+ /// The ticket )
+ ///
+ NewSessionTicket GetNewSessionTicket();
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsServerContext.cs b/bc-sharp-crypto/src/crypto/tls/TlsServerContext.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4021571aa53dac3797251db880aa01488e8ed1aa
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsServerContext.cs
@@ -0,0 +1,11 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsServerContext
+ : TlsContext
+ {
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsServerContextImpl.cs b/bc-sharp-crypto/src/crypto/tls/TlsServerContextImpl.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d56566ffcc237e9df0e5e4dd6b05d4b4c8eebd7c
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsServerContextImpl.cs
@@ -0,0 +1,20 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ internal class TlsServerContextImpl
+ : AbstractTlsContext, TlsServerContext
+ {
+ internal TlsServerContextImpl(SecureRandom secureRandom, SecurityParameters securityParameters)
+ : base(secureRandom, securityParameters)
+ {
+ }
+
+ public override bool IsServer
+ {
+ get { return true; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsServerProtocol.cs b/bc-sharp-crypto/src/crypto/tls/TlsServerProtocol.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c2bfbcb742049a9d67b1af436a9d92c007ed1783
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsServerProtocol.cs
@@ -0,0 +1,833 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsServerProtocol
+ : TlsProtocol
+ {
+ protected TlsServer mTlsServer = null;
+ internal TlsServerContextImpl mTlsServerContext = null;
+
+ protected TlsKeyExchange mKeyExchange = null;
+ protected TlsCredentials mServerCredentials = null;
+ protected CertificateRequest mCertificateRequest = null;
+
+ protected short mClientCertificateType = -1;
+ protected TlsHandshakeHash mPrepareFinishHash = null;
+
+ /**
+ * Constructor for blocking mode.
+ * @param stream The bi-directional stream of data to/from the client
+ * @param output The stream of data to the client
+ * @param secureRandom Random number generator for various cryptographic functions
+ */
+ public TlsServerProtocol(Stream stream, SecureRandom secureRandom)
+ : base(stream, secureRandom)
+ {
+ }
+
+ /**
+ * Constructor for blocking mode.
+ * @param input The stream of data from the client
+ * @param output The stream of data to the client
+ * @param secureRandom Random number generator for various cryptographic functions
+ */
+ public TlsServerProtocol(Stream input, Stream output, SecureRandom secureRandom)
+ : base(input, output, secureRandom)
+ {
+ }
+
+ /**
+ * Constructor for non-blocking mode.
+ *
+ * When data is received, use {@link #offerInput(java.nio.ByteBuffer)} to
+ * provide the received ciphertext, then use
+ * {@link #readInput(byte[], int, int)} to read the corresponding cleartext.
+ *
+ * Similarly, when data needs to be sent, use
+ * {@link #offerOutput(byte[], int, int)} to provide the cleartext, then use
+ * {@link #readOutput(byte[], int, int)} to get the corresponding
+ * ciphertext.
+ *
+ * @param secureRandom
+ * Random number generator for various cryptographic functions
+ */
+ public TlsServerProtocol(SecureRandom secureRandom)
+ : base(secureRandom)
+ {
+ }
+
+ /**
+ * Receives a TLS handshake in the role of server.
+ *
+ * In blocking mode, this will not return until the handshake is complete.
+ * In non-blocking mode, use {@link TlsPeer#notifyHandshakeComplete()} to
+ * receive a callback when the handshake is complete.
+ *
+ * @param tlsServer
+ * @throws IOException If in blocking mode and handshake was not successful.
+ */
+ public virtual void Accept(TlsServer tlsServer)
+ {
+ if (tlsServer == null)
+ throw new ArgumentNullException("tlsServer");
+ if (this.mTlsServer != null)
+ throw new InvalidOperationException("'Accept' can only be called once");
+
+ this.mTlsServer = tlsServer;
+
+ this.mSecurityParameters = new SecurityParameters();
+ this.mSecurityParameters.entity = ConnectionEnd.server;
+
+ this.mTlsServerContext = new TlsServerContextImpl(mSecureRandom, mSecurityParameters);
+
+ this.mSecurityParameters.serverRandom = CreateRandomBlock(tlsServer.ShouldUseGmtUnixTime(),
+ mTlsServerContext.NonceRandomGenerator);
+
+ this.mTlsServer.Init(mTlsServerContext);
+ this.mRecordStream.Init(mTlsServerContext);
+
+ this.mRecordStream.SetRestrictReadVersion(false);
+
+ BlockForHandshake();
+ }
+
+ protected override void CleanupHandshake()
+ {
+ base.CleanupHandshake();
+
+ this.mKeyExchange = null;
+ this.mServerCredentials = null;
+ this.mCertificateRequest = null;
+ this.mPrepareFinishHash = null;
+ }
+
+ protected override TlsContext Context
+ {
+ get { return mTlsServerContext; }
+ }
+
+ internal override AbstractTlsContext ContextAdmin
+ {
+ get { return mTlsServerContext; }
+ }
+
+ protected override TlsPeer Peer
+ {
+ get { return mTlsServer; }
+ }
+
+ protected override void HandleHandshakeMessage(byte type, MemoryStream buf)
+ {
+ switch (type)
+ {
+ case HandshakeType.client_hello:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_START:
+ {
+ ReceiveClientHelloMessage(buf);
+ this.mConnectionState = CS_CLIENT_HELLO;
+
+ SendServerHelloMessage();
+ this.mConnectionState = CS_SERVER_HELLO;
+
+ mRecordStream.NotifyHelloComplete();
+
+ IList serverSupplementalData = mTlsServer.GetServerSupplementalData();
+ if (serverSupplementalData != null)
+ {
+ SendSupplementalDataMessage(serverSupplementalData);
+ }
+ this.mConnectionState = CS_SERVER_SUPPLEMENTAL_DATA;
+
+ this.mKeyExchange = mTlsServer.GetKeyExchange();
+ this.mKeyExchange.Init(Context);
+
+ this.mServerCredentials = mTlsServer.GetCredentials();
+
+ Certificate serverCertificate = null;
+
+ if (this.mServerCredentials == null)
+ {
+ this.mKeyExchange.SkipServerCredentials();
+ }
+ else
+ {
+ this.mKeyExchange.ProcessServerCredentials(this.mServerCredentials);
+
+ serverCertificate = this.mServerCredentials.Certificate;
+ SendCertificateMessage(serverCertificate);
+ }
+ this.mConnectionState = CS_SERVER_CERTIFICATE;
+
+ // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
+ if (serverCertificate == null || serverCertificate.IsEmpty)
+ {
+ this.mAllowCertificateStatus = false;
+ }
+
+ if (this.mAllowCertificateStatus)
+ {
+ CertificateStatus certificateStatus = mTlsServer.GetCertificateStatus();
+ if (certificateStatus != null)
+ {
+ SendCertificateStatusMessage(certificateStatus);
+ }
+ }
+
+ this.mConnectionState = CS_CERTIFICATE_STATUS;
+
+ byte[] serverKeyExchange = this.mKeyExchange.GenerateServerKeyExchange();
+ if (serverKeyExchange != null)
+ {
+ SendServerKeyExchangeMessage(serverKeyExchange);
+ }
+ this.mConnectionState = CS_SERVER_KEY_EXCHANGE;
+
+ if (this.mServerCredentials != null)
+ {
+ this.mCertificateRequest = mTlsServer.GetCertificateRequest();
+ if (this.mCertificateRequest != null)
+ {
+ if (TlsUtilities.IsTlsV12(Context) != (mCertificateRequest.SupportedSignatureAlgorithms != null))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ this.mKeyExchange.ValidateCertificateRequest(mCertificateRequest);
+
+ SendCertificateRequestMessage(mCertificateRequest);
+
+ TlsUtilities.TrackHashAlgorithms(this.mRecordStream.HandshakeHash,
+ this.mCertificateRequest.SupportedSignatureAlgorithms);
+ }
+ }
+ this.mConnectionState = CS_CERTIFICATE_REQUEST;
+
+ SendServerHelloDoneMessage();
+ this.mConnectionState = CS_SERVER_HELLO_DONE;
+
+ this.mRecordStream.HandshakeHash.SealHashAlgorithms();
+
+ break;
+ }
+ case CS_END:
+ {
+ RefuseRenegotiation();
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.supplemental_data:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_SERVER_HELLO_DONE:
+ {
+ mTlsServer.ProcessClientSupplementalData(ReadSupplementalDataMessage(buf));
+ this.mConnectionState = CS_CLIENT_SUPPLEMENTAL_DATA;
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.certificate:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_SERVER_HELLO_DONE:
+ case CS_CLIENT_SUPPLEMENTAL_DATA:
+ {
+ if (mConnectionState < CS_CLIENT_SUPPLEMENTAL_DATA)
+ {
+ mTlsServer.ProcessClientSupplementalData(null);
+ }
+
+ if (this.mCertificateRequest == null)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ ReceiveCertificateMessage(buf);
+ this.mConnectionState = CS_CLIENT_CERTIFICATE;
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.client_key_exchange:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_SERVER_HELLO_DONE:
+ case CS_CLIENT_SUPPLEMENTAL_DATA:
+ case CS_CLIENT_CERTIFICATE:
+ {
+ if (mConnectionState < CS_CLIENT_SUPPLEMENTAL_DATA)
+ {
+ mTlsServer.ProcessClientSupplementalData(null);
+ }
+
+ if (mConnectionState < CS_CLIENT_CERTIFICATE)
+ {
+ if (this.mCertificateRequest == null)
+ {
+ this.mKeyExchange.SkipClientCredentials();
+ }
+ else
+ {
+ if (TlsUtilities.IsTlsV12(Context))
+ {
+ /*
+ * RFC 5246 If no suitable certificate is available, the client MUST Send a
+ * certificate message containing no certificates.
+ *
+ * NOTE: In previous RFCs, this was SHOULD instead of MUST.
+ */
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ else if (TlsUtilities.IsSsl(Context))
+ {
+ if (this.mPeerCertificate == null)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ else
+ {
+ NotifyClientCertificate(Certificate.EmptyChain);
+ }
+ }
+ }
+
+ ReceiveClientKeyExchangeMessage(buf);
+ this.mConnectionState = CS_CLIENT_KEY_EXCHANGE;
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.certificate_verify:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_CLIENT_KEY_EXCHANGE:
+ {
+ /*
+ * RFC 5246 7.4.8 This message is only sent following a client certificate that has
+ * signing capability (i.e., all certificates except those containing fixed
+ * Diffie-Hellman parameters).
+ */
+ if (!ExpectCertificateVerifyMessage())
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ ReceiveCertificateVerifyMessage(buf);
+ this.mConnectionState = CS_CERTIFICATE_VERIFY;
+
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.finished:
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_CLIENT_KEY_EXCHANGE:
+ case CS_CERTIFICATE_VERIFY:
+ {
+ if (mConnectionState < CS_CERTIFICATE_VERIFY && ExpectCertificateVerifyMessage())
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ ProcessFinishedMessage(buf);
+ this.mConnectionState = CS_CLIENT_FINISHED;
+
+ if (this.mExpectSessionTicket)
+ {
+ SendNewSessionTicketMessage(mTlsServer.GetNewSessionTicket());
+ SendChangeCipherSpecMessage();
+ }
+ this.mConnectionState = CS_SERVER_SESSION_TICKET;
+
+ SendFinishedMessage();
+ this.mConnectionState = CS_SERVER_FINISHED;
+
+ CompleteHandshake();
+ break;
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ break;
+ }
+ case HandshakeType.hello_request:
+ case HandshakeType.hello_verify_request:
+ case HandshakeType.server_hello:
+ case HandshakeType.server_key_exchange:
+ case HandshakeType.certificate_request:
+ case HandshakeType.server_hello_done:
+ case HandshakeType.session_ticket:
+ default:
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ }
+
+ protected override void HandleAlertWarningMessage(byte alertDescription)
+ {
+ base.HandleAlertWarningMessage(alertDescription);
+
+ switch (alertDescription)
+ {
+ case AlertDescription.no_certificate:
+ {
+ /*
+ * SSL 3.0 If the server has sent a certificate request Message, the client must send
+ * either the certificate message or a no_certificate alert.
+ */
+ if (TlsUtilities.IsSsl(Context) && this.mCertificateRequest != null)
+ {
+ switch (this.mConnectionState)
+ {
+ case CS_SERVER_HELLO_DONE:
+ case CS_CLIENT_SUPPLEMENTAL_DATA:
+ {
+ if (mConnectionState < CS_CLIENT_SUPPLEMENTAL_DATA)
+ {
+ mTlsServer.ProcessClientSupplementalData(null);
+ }
+
+ NotifyClientCertificate(Certificate.EmptyChain);
+ this.mConnectionState = CS_CLIENT_CERTIFICATE;
+ return;
+ }
+ }
+ }
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+ }
+ }
+
+ protected virtual void NotifyClientCertificate(Certificate clientCertificate)
+ {
+ if (mCertificateRequest == null)
+ throw new InvalidOperationException();
+ if (mPeerCertificate != null)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+ this.mPeerCertificate = clientCertificate;
+
+ if (clientCertificate.IsEmpty)
+ {
+ this.mKeyExchange.SkipClientCredentials();
+ }
+ else
+ {
+
+ /*
+ * TODO RFC 5246 7.4.6. If the certificate_authorities list in the certificate request
+ * message was non-empty, one of the certificates in the certificate chain SHOULD be
+ * issued by one of the listed CAs.
+ */
+
+ this.mClientCertificateType = TlsUtilities.GetClientCertificateType(clientCertificate,
+ this.mServerCredentials.Certificate);
+
+ this.mKeyExchange.ProcessClientCertificate(clientCertificate);
+ }
+
+ /*
+ * RFC 5246 7.4.6. If the client does not Send any certificates, the server MAY at its
+ * discretion either continue the handshake without client authentication, or respond with a
+ * fatal handshake_failure alert. Also, if some aspect of the certificate chain was
+ * unacceptable (e.g., it was not signed by a known, trusted CA), the server MAY at its
+ * discretion either continue the handshake (considering the client unauthenticated) or Send
+ * a fatal alert.
+ */
+ this.mTlsServer.NotifyClientCertificate(clientCertificate);
+ }
+
+ protected virtual void ReceiveCertificateMessage(MemoryStream buf)
+ {
+ Certificate clientCertificate = Certificate.Parse(buf);
+
+ AssertEmpty(buf);
+
+ NotifyClientCertificate(clientCertificate);
+ }
+
+ protected virtual void ReceiveCertificateVerifyMessage(MemoryStream buf)
+ {
+ if (mCertificateRequest == null)
+ throw new InvalidOperationException();
+
+ DigitallySigned clientCertificateVerify = DigitallySigned.Parse(Context, buf);
+
+ AssertEmpty(buf);
+
+ // Verify the CertificateVerify message contains a correct signature.
+ try
+ {
+ SignatureAndHashAlgorithm signatureAlgorithm = clientCertificateVerify.Algorithm;
+
+ byte[] hash;
+ if (TlsUtilities.IsTlsV12(Context))
+ {
+ TlsUtilities.VerifySupportedSignatureAlgorithm(mCertificateRequest.SupportedSignatureAlgorithms, signatureAlgorithm);
+ hash = mPrepareFinishHash.GetFinalHash(signatureAlgorithm.Hash);
+ }
+ else
+ {
+ hash = mSecurityParameters.SessionHash;
+ }
+
+ X509CertificateStructure x509Cert = mPeerCertificate.GetCertificateAt(0);
+ SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+ AsymmetricKeyParameter publicKey = PublicKeyFactory.CreateKey(keyInfo);
+
+ TlsSigner tlsSigner = TlsUtilities.CreateTlsSigner((byte)mClientCertificateType);
+ tlsSigner.Init(Context);
+ if (!tlsSigner.VerifyRawSignature(signatureAlgorithm, clientCertificateVerify.Signature, publicKey, hash))
+ throw new TlsFatalAlert(AlertDescription.decrypt_error);
+ }
+ catch (TlsFatalAlert e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new TlsFatalAlert(AlertDescription.decrypt_error, e);
+ }
+ }
+
+ protected virtual void ReceiveClientHelloMessage(MemoryStream buf)
+ {
+ ProtocolVersion client_version = TlsUtilities.ReadVersion(buf);
+ mRecordStream.SetWriteVersion(client_version);
+
+ if (client_version.IsDtls)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ byte[] client_random = TlsUtilities.ReadFully(32, buf);
+
+ /*
+ * TODO RFC 5077 3.4. If a ticket is presented by the client, the server MUST NOT attempt to
+ * use the Session ID in the ClientHello for stateful session resumption.
+ */
+ byte[] sessionID = TlsUtilities.ReadOpaque8(buf);
+ if (sessionID.Length > 32)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ /*
+ * TODO RFC 5246 7.4.1.2. If the session_id field is not empty (implying a session
+ * resumption request), this vector MUST include at least the cipher_suite from that
+ * session.
+ */
+ int cipher_suites_length = TlsUtilities.ReadUint16(buf);
+ if (cipher_suites_length < 2 || (cipher_suites_length & 1) != 0)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ this.mOfferedCipherSuites = TlsUtilities.ReadUint16Array(cipher_suites_length / 2, buf);
+
+ /*
+ * TODO RFC 5246 7.4.1.2. If the session_id field is not empty (implying a session
+ * resumption request), it MUST include the compression_method from that session.
+ */
+ int compression_methods_length = TlsUtilities.ReadUint8(buf);
+ if (compression_methods_length < 1)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ this.mOfferedCompressionMethods = TlsUtilities.ReadUint8Array(compression_methods_length, buf);
+
+ /*
+ * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
+ * extensions appearing in the client hello, and Send a server hello containing no
+ * extensions.
+ */
+ this.mClientExtensions = ReadExtensions(buf);
+
+ /*
+ * TODO[session-hash]
+ *
+ * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes
+ * that do not use the extended master secret [..]. (and see 5.2, 5.3)
+ */
+ this.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(mClientExtensions);
+
+ ContextAdmin.SetClientVersion(client_version);
+
+ mTlsServer.NotifyClientVersion(client_version);
+ mTlsServer.NotifyFallback(Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV));
+
+ mSecurityParameters.clientRandom = client_random;
+
+ mTlsServer.NotifyOfferedCipherSuites(mOfferedCipherSuites);
+ mTlsServer.NotifyOfferedCompressionMethods(mOfferedCompressionMethods);
+
+ /*
+ * RFC 5746 3.6. Server Behavior: Initial Handshake
+ */
+ {
+ /*
+ * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
+ * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
+ * ClientHello. Including both is NOT RECOMMENDED.
+ */
+
+ /*
+ * When a ClientHello is received, the server MUST check if it includes the
+ * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. If it does, set the secure_renegotiation flag
+ * to TRUE.
+ */
+ if (Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV))
+ {
+ this.mSecureRenegotiation = true;
+ }
+
+ /*
+ * The server MUST check if the "renegotiation_info" extension is included in the
+ * ClientHello.
+ */
+ byte[] renegExtData = TlsUtilities.GetExtensionData(mClientExtensions, ExtensionType.renegotiation_info);
+ if (renegExtData != null)
+ {
+ /*
+ * If the extension is present, set secure_renegotiation flag to TRUE. The
+ * server MUST then verify that the length of the "renegotiated_connection"
+ * field is zero, and if it is not, MUST abort the handshake.
+ */
+ this.mSecureRenegotiation = true;
+
+ if (!Arrays.ConstantTimeAreEqual(renegExtData, CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
+ throw new TlsFatalAlert(AlertDescription.handshake_failure);
+ }
+ }
+
+ mTlsServer.NotifySecureRenegotiation(this.mSecureRenegotiation);
+
+ if (mClientExtensions != null)
+ {
+ // NOTE: Validates the padding extension data, if present
+ TlsExtensionsUtilities.GetPaddingExtension(mClientExtensions);
+
+ mTlsServer.ProcessClientExtensions(mClientExtensions);
+ }
+ }
+
+ protected virtual void ReceiveClientKeyExchangeMessage(MemoryStream buf)
+ {
+ mKeyExchange.ProcessClientKeyExchange(buf);
+
+ AssertEmpty(buf);
+
+ if (TlsUtilities.IsSsl(Context))
+ {
+ EstablishMasterSecret(Context, mKeyExchange);
+ }
+
+ this.mPrepareFinishHash = mRecordStream.PrepareToFinish();
+ this.mSecurityParameters.sessionHash = GetCurrentPrfHash(Context, mPrepareFinishHash, null);
+
+ if (!TlsUtilities.IsSsl(Context))
+ {
+ EstablishMasterSecret(Context, mKeyExchange);
+ }
+
+ mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
+
+ if (!mExpectSessionTicket)
+ {
+ SendChangeCipherSpecMessage();
+ }
+ }
+
+ protected virtual void SendCertificateRequestMessage(CertificateRequest certificateRequest)
+ {
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_request);
+
+ certificateRequest.Encode(message);
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual void SendCertificateStatusMessage(CertificateStatus certificateStatus)
+ {
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_status);
+
+ certificateStatus.Encode(message);
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual void SendNewSessionTicketMessage(NewSessionTicket newSessionTicket)
+ {
+ if (newSessionTicket == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.session_ticket);
+
+ newSessionTicket.Encode(message);
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual void SendServerHelloMessage()
+ {
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.server_hello);
+
+ {
+ ProtocolVersion server_version = mTlsServer.GetServerVersion();
+ if (!server_version.IsEqualOrEarlierVersionOf(Context.ClientVersion))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ mRecordStream.ReadVersion = server_version;
+ mRecordStream.SetWriteVersion(server_version);
+ mRecordStream.SetRestrictReadVersion(true);
+ ContextAdmin.SetServerVersion(server_version);
+
+ TlsUtilities.WriteVersion(server_version, message);
+ }
+
+ message.Write(this.mSecurityParameters.serverRandom);
+
+ /*
+ * The server may return an empty session_id to indicate that the session will not be cached
+ * and therefore cannot be resumed.
+ */
+ TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, message);
+
+ int selectedCipherSuite = mTlsServer.GetSelectedCipherSuite();
+ if (!Arrays.Contains(mOfferedCipherSuites, selectedCipherSuite)
+ || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
+ || CipherSuite.IsScsv(selectedCipherSuite)
+ || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion))
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ mSecurityParameters.cipherSuite = selectedCipherSuite;
+
+ byte selectedCompressionMethod = mTlsServer.GetSelectedCompressionMethod();
+ if (!Arrays.Contains(mOfferedCompressionMethods, selectedCompressionMethod))
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ mSecurityParameters.compressionAlgorithm = selectedCompressionMethod;
+
+ TlsUtilities.WriteUint16(selectedCipherSuite, message);
+ TlsUtilities.WriteUint8(selectedCompressionMethod, message);
+
+ this.mServerExtensions = mTlsServer.GetServerExtensions();
+
+ /*
+ * RFC 5746 3.6. Server Behavior: Initial Handshake
+ */
+ if (this.mSecureRenegotiation)
+ {
+ byte[] renegExtData = TlsUtilities.GetExtensionData(this.mServerExtensions, ExtensionType.renegotiation_info);
+ bool noRenegExt = (null == renegExtData);
+
+ if (noRenegExt)
+ {
+ /*
+ * Note that Sending a "renegotiation_info" extension in response to a ClientHello
+ * containing only the SCSV is an explicit exception to the prohibition in RFC 5246,
+ * Section 7.4.1.4, on the server Sending unsolicited extensions and is only allowed
+ * because the client is signaling its willingness to receive the extension via the
+ * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
+ */
+
+ /*
+ * If the secure_renegotiation flag is set to TRUE, the server MUST include an empty
+ * "renegotiation_info" extension in the ServerHello message.
+ */
+ this.mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mServerExtensions);
+ this.mServerExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
+ }
+ }
+
+ if (mSecurityParameters.extendedMasterSecret)
+ {
+ this.mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mServerExtensions);
+ TlsExtensionsUtilities.AddExtendedMasterSecretExtension(mServerExtensions);
+ }
+
+ /*
+ * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
+ * extensions appearing in the client hello, and Send a server hello containing no
+ * extensions.
+ */
+
+ if (this.mServerExtensions != null)
+ {
+ this.mSecurityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(mServerExtensions);
+
+ this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(mClientExtensions,
+ mServerExtensions, AlertDescription.internal_error);
+
+ this.mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(mServerExtensions);
+
+ /*
+ * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
+ * a session resumption handshake.
+ */
+ this.mAllowCertificateStatus = !mResumedSession
+ && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, ExtensionType.status_request,
+ AlertDescription.internal_error);
+
+ this.mExpectSessionTicket = !mResumedSession
+ && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, ExtensionType.session_ticket,
+ AlertDescription.internal_error);
+
+ WriteExtensions(message, this.mServerExtensions);
+ }
+
+ mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, mSecurityParameters.CipherSuite);
+
+ /*
+ * RFC 5246 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has
+ * a verify_data_length equal to 12. This includes all existing cipher suites.
+ */
+ mSecurityParameters.verifyDataLength = 12;
+
+ ApplyMaxFragmentLengthExtension();
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual void SendServerHelloDoneMessage()
+ {
+ byte[] message = new byte[4];
+ TlsUtilities.WriteUint8(HandshakeType.server_hello_done, message, 0);
+ TlsUtilities.WriteUint24(0, message, 1);
+
+ WriteHandshakeMessage(message, 0, message.Length);
+ }
+
+ protected virtual void SendServerKeyExchangeMessage(byte[] serverKeyExchange)
+ {
+ HandshakeMessage message = new HandshakeMessage(HandshakeType.server_key_exchange, serverKeyExchange.Length);
+
+ message.Write(serverKeyExchange);
+
+ message.WriteToRecordStream(this);
+ }
+
+ protected virtual bool ExpectCertificateVerifyMessage()
+ {
+ return mClientCertificateType >= 0 && TlsUtilities.HasSigningCapability((byte)mClientCertificateType);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsSession.cs b/bc-sharp-crypto/src/crypto/tls/TlsSession.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6c229913bdb07ad5af0521018dc151fc4d5986bd
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsSession.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsSession
+ {
+ SessionParameters ExportSessionParameters();
+
+ byte[] SessionID { get; }
+
+ void Invalidate();
+
+ bool IsResumable { get; }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsSessionImpl.cs b/bc-sharp-crypto/src/crypto/tls/TlsSessionImpl.cs
new file mode 100644
index 0000000000000000000000000000000000000000..866392623fbb7b049f11b47b04393c76ef87c9fa
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsSessionImpl.cs
@@ -0,0 +1,54 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ internal class TlsSessionImpl
+ : TlsSession
+ {
+ internal readonly byte[] mSessionID;
+ internal SessionParameters mSessionParameters;
+
+ internal TlsSessionImpl(byte[] sessionID, SessionParameters sessionParameters)
+ {
+ if (sessionID == null)
+ throw new ArgumentNullException("sessionID");
+ if (sessionID.Length < 1 || sessionID.Length > 32)
+ throw new ArgumentException("must have length between 1 and 32 bytes, inclusive", "sessionID");
+
+ this.mSessionID = Arrays.Clone(sessionID);
+ this.mSessionParameters = sessionParameters;
+ }
+
+ public virtual SessionParameters ExportSessionParameters()
+ {
+ lock (this)
+ {
+ return this.mSessionParameters == null ? null : this.mSessionParameters.Copy();
+ }
+ }
+
+ public virtual byte[] SessionID
+ {
+ get { lock (this) return mSessionID; }
+ }
+
+ public virtual void Invalidate()
+ {
+ lock (this)
+ {
+ if (this.mSessionParameters != null)
+ {
+ this.mSessionParameters.Clear();
+ this.mSessionParameters = null;
+ }
+ }
+ }
+
+ public virtual bool IsResumable
+ {
+ get { lock (this) return this.mSessionParameters != null; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsSigner.cs b/bc-sharp-crypto/src/crypto/tls/TlsSigner.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ffdd4c9a16335ec0dceefdbac44073c606a22fd9
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsSigner.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsSigner
+ {
+ void Init(TlsContext context);
+
+ byte[] GenerateRawSignature(AsymmetricKeyParameter privateKey, byte[] md5AndSha1);
+
+ byte[] GenerateRawSignature(SignatureAndHashAlgorithm algorithm,
+ AsymmetricKeyParameter privateKey, byte[] hash);
+
+ bool VerifyRawSignature(byte[] sigBytes, AsymmetricKeyParameter publicKey, byte[] md5AndSha1);
+
+ bool VerifyRawSignature(SignatureAndHashAlgorithm algorithm, byte[] sigBytes,
+ AsymmetricKeyParameter publicKey, byte[] hash);
+
+ ISigner CreateSigner(AsymmetricKeyParameter privateKey);
+
+ ISigner CreateSigner(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter privateKey);
+
+ ISigner CreateVerifyer(AsymmetricKeyParameter publicKey);
+
+ ISigner CreateVerifyer(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter publicKey);
+
+ bool IsValidPublicKey(AsymmetricKeyParameter publicKey);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsSignerCredentials.cs b/bc-sharp-crypto/src/crypto/tls/TlsSignerCredentials.cs
new file mode 100644
index 0000000000000000000000000000000000000000..92ed7cc19dbaa26ee90e0a5e2728fea68c877a4a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsSignerCredentials.cs
@@ -0,0 +1,14 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsSignerCredentials
+ : TlsCredentials
+ {
+ ///
+ byte[] GenerateCertificateSignature(byte[] hash);
+
+ SignatureAndHashAlgorithm SignatureAndHashAlgorithm { get; }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsSrpGroupVerifier.cs b/bc-sharp-crypto/src/crypto/tls/TlsSrpGroupVerifier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..185f2f50a3250cb4dc3effc3a0852648a1bf7c92
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsSrpGroupVerifier.cs
@@ -0,0 +1,17 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsSrpGroupVerifier
+ {
+ /**
+ * Check whether the given SRP group parameters are acceptable for use.
+ *
+ * @param group the {@link SRP6GroupParameters} to check
+ * @return true if (and only if) the specified group parameters are acceptable
+ */
+ bool Accept(Srp6GroupParameters group);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsSrpIdentityManager.cs b/bc-sharp-crypto/src/crypto/tls/TlsSrpIdentityManager.cs
new file mode 100644
index 0000000000000000000000000000000000000000..080a0dc16df75a15c6401ddcf4d9b6e8898b2d3b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsSrpIdentityManager.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public interface TlsSrpIdentityManager
+ {
+ /**
+ * Lookup the {@link TlsSRPLoginParameters} corresponding to the specified identity.
+ *
+ * NOTE: To avoid "identity probing", unknown identities SHOULD be handled as recommended in RFC
+ * 5054 2.5.1.3. {@link SimulatedTlsSRPIdentityManager} is provided for this purpose.
+ *
+ * @param identity
+ * the SRP identity sent by the connecting client
+ * @return the {@link TlsSRPLoginParameters} for the specified identity, or else 'simulated'
+ * parameters if the identity is not recognized. A null value is also allowed, but not
+ * recommended.
+ */
+ TlsSrpLoginParameters GetLoginParameters(byte[] identity);
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsSrpKeyExchange.cs b/bc-sharp-crypto/src/crypto/tls/TlsSrpKeyExchange.cs
new file mode 100644
index 0000000000000000000000000000000000000000..09fa72348ecc3789da7f5710bc20a137dc3133d9
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsSrpKeyExchange.cs
@@ -0,0 +1,285 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Agreement.Srp;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// (D)TLS SRP key exchange (RFC 5054).
+ public class TlsSrpKeyExchange
+ : AbstractTlsKeyExchange
+ {
+ protected static TlsSigner CreateSigner(int keyExchange)
+ {
+ switch (keyExchange)
+ {
+ case KeyExchangeAlgorithm.SRP:
+ return null;
+ case KeyExchangeAlgorithm.SRP_RSA:
+ return new TlsRsaSigner();
+ case KeyExchangeAlgorithm.SRP_DSS:
+ return new TlsDssSigner();
+ default:
+ throw new ArgumentException("unsupported key exchange algorithm");
+ }
+ }
+
+ protected TlsSigner mTlsSigner;
+ protected TlsSrpGroupVerifier mGroupVerifier;
+ protected byte[] mIdentity;
+ protected byte[] mPassword;
+
+ protected AsymmetricKeyParameter mServerPublicKey = null;
+
+ protected Srp6GroupParameters mSrpGroup = null;
+ protected Srp6Client mSrpClient = null;
+ protected Srp6Server mSrpServer = null;
+ protected BigInteger mSrpPeerCredentials = null;
+ protected BigInteger mSrpVerifier = null;
+ protected byte[] mSrpSalt = null;
+
+ protected TlsSignerCredentials mServerCredentials = null;
+
+ [Obsolete("Use constructor taking an explicit 'groupVerifier' argument")]
+ public TlsSrpKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, byte[] identity, byte[] password)
+ : this(keyExchange, supportedSignatureAlgorithms, new DefaultTlsSrpGroupVerifier(), identity, password)
+ {
+ }
+
+ public TlsSrpKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, TlsSrpGroupVerifier groupVerifier,
+ byte[] identity, byte[] password)
+ : base(keyExchange, supportedSignatureAlgorithms)
+ {
+ this.mTlsSigner = CreateSigner(keyExchange);
+ this.mGroupVerifier = groupVerifier;
+ this.mIdentity = identity;
+ this.mPassword = password;
+ this.mSrpClient = new Srp6Client();
+ }
+
+ public TlsSrpKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, byte[] identity,
+ TlsSrpLoginParameters loginParameters)
+ : base(keyExchange, supportedSignatureAlgorithms)
+ {
+ this.mTlsSigner = CreateSigner(keyExchange);
+ this.mIdentity = identity;
+ this.mSrpServer = new Srp6Server();
+ this.mSrpGroup = loginParameters.Group;
+ this.mSrpVerifier = loginParameters.Verifier;
+ this.mSrpSalt = loginParameters.Salt;
+ }
+
+ public override void Init(TlsContext context)
+ {
+ base.Init(context);
+
+ if (this.mTlsSigner != null)
+ {
+ this.mTlsSigner.Init(context);
+ }
+ }
+
+ public override void SkipServerCredentials()
+ {
+ if (mTlsSigner != null)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public override void ProcessServerCertificate(Certificate serverCertificate)
+ {
+ if (mTlsSigner == null)
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ if (serverCertificate.IsEmpty)
+ throw new TlsFatalAlert(AlertDescription.bad_certificate);
+
+ X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
+
+ SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+ try
+ {
+ this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo);
+ }
+ catch (Exception e)
+ {
+ throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
+ }
+
+ if (!mTlsSigner.IsValidPublicKey(this.mServerPublicKey))
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+
+ TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
+
+ base.ProcessServerCertificate(serverCertificate);
+ }
+
+ public override void ProcessServerCredentials(TlsCredentials serverCredentials)
+ {
+ if ((mKeyExchange == KeyExchangeAlgorithm.SRP) || !(serverCredentials is TlsSignerCredentials))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ ProcessServerCertificate(serverCredentials.Certificate);
+
+ this.mServerCredentials = (TlsSignerCredentials)serverCredentials;
+ }
+
+ public override bool RequiresServerKeyExchange
+ {
+ get { return true; }
+ }
+
+ public override byte[] GenerateServerKeyExchange()
+ {
+ mSrpServer.Init(mSrpGroup, mSrpVerifier, TlsUtilities.CreateHash(HashAlgorithm.sha1), mContext.SecureRandom);
+ BigInteger B = mSrpServer.GenerateServerCredentials();
+
+ ServerSrpParams srpParams = new ServerSrpParams(mSrpGroup.N, mSrpGroup.G, mSrpSalt, B);
+
+ DigestInputBuffer buf = new DigestInputBuffer();
+
+ srpParams.Encode(buf);
+
+ if (mServerCredentials != null)
+ {
+ /*
+ * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
+ */
+ SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
+ mContext, mServerCredentials);
+
+ IDigest d = TlsUtilities.CreateHash(signatureAndHashAlgorithm);
+
+ SecurityParameters securityParameters = mContext.SecurityParameters;
+ d.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
+ d.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
+ buf.UpdateDigest(d);
+
+ byte[] hash = new byte[d.GetDigestSize()];
+ d.DoFinal(hash, 0);
+
+ byte[] signature = mServerCredentials.GenerateCertificateSignature(hash);
+
+ DigitallySigned signed_params = new DigitallySigned(signatureAndHashAlgorithm, signature);
+ signed_params.Encode(buf);
+ }
+
+ return buf.ToArray();
+ }
+
+ public override void ProcessServerKeyExchange(Stream input)
+ {
+ SecurityParameters securityParameters = mContext.SecurityParameters;
+
+ SignerInputBuffer buf = null;
+ Stream teeIn = input;
+
+ if (mTlsSigner != null)
+ {
+ buf = new SignerInputBuffer();
+ teeIn = new TeeInputStream(input, buf);
+ }
+
+ ServerSrpParams srpParams = ServerSrpParams.Parse(teeIn);
+
+ if (buf != null)
+ {
+ DigitallySigned signed_params = ParseSignature(input);
+
+ ISigner signer = InitVerifyer(mTlsSigner, signed_params.Algorithm, securityParameters);
+ buf.UpdateSigner(signer);
+ if (!signer.VerifySignature(signed_params.Signature))
+ throw new TlsFatalAlert(AlertDescription.decrypt_error);
+ }
+
+ this.mSrpGroup = new Srp6GroupParameters(srpParams.N, srpParams.G);
+
+ if (!mGroupVerifier.Accept(mSrpGroup))
+ throw new TlsFatalAlert(AlertDescription.insufficient_security);
+
+ this.mSrpSalt = srpParams.S;
+
+ /*
+ * RFC 5054 2.5.3: The client MUST abort the handshake with an "illegal_parameter" alert if
+ * B % N = 0.
+ */
+ try
+ {
+ this.mSrpPeerCredentials = Srp6Utilities.ValidatePublicValue(mSrpGroup.N, srpParams.B);
+ }
+ catch (CryptoException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
+ }
+
+ this.mSrpClient.Init(mSrpGroup, TlsUtilities.CreateHash(HashAlgorithm.sha1), mContext.SecureRandom);
+ }
+
+ public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public override void ProcessClientCredentials(TlsCredentials clientCredentials)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public override void GenerateClientKeyExchange(Stream output)
+ {
+ BigInteger A = mSrpClient.GenerateClientCredentials(mSrpSalt, mIdentity, mPassword);
+ TlsSrpUtilities.WriteSrpParameter(A, output);
+
+ mContext.SecurityParameters.srpIdentity = Arrays.Clone(mIdentity);
+ }
+
+ public override void ProcessClientKeyExchange(Stream input)
+ {
+ /*
+ * RFC 5054 2.5.4: The server MUST abort the handshake with an "illegal_parameter" alert if
+ * A % N = 0.
+ */
+ try
+ {
+ this.mSrpPeerCredentials = Srp6Utilities.ValidatePublicValue(mSrpGroup.N, TlsSrpUtilities.ReadSrpParameter(input));
+ }
+ catch (CryptoException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
+ }
+
+ mContext.SecurityParameters.srpIdentity = Arrays.Clone(mIdentity);
+ }
+
+ public override byte[] GeneratePremasterSecret()
+ {
+ try
+ {
+ BigInteger S = mSrpServer != null
+ ? mSrpServer.CalculateSecret(mSrpPeerCredentials)
+ : mSrpClient.CalculateSecret(mSrpPeerCredentials);
+
+ // TODO Check if this needs to be a fixed size
+ return BigIntegers.AsUnsignedByteArray(S);
+ }
+ catch (CryptoException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
+ }
+ }
+
+ protected virtual ISigner InitVerifyer(TlsSigner tlsSigner, SignatureAndHashAlgorithm algorithm,
+ SecurityParameters securityParameters)
+ {
+ ISigner signer = tlsSigner.CreateVerifyer(algorithm, this.mServerPublicKey);
+ signer.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
+ signer.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
+ return signer;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsSrpLoginParameters.cs b/bc-sharp-crypto/src/crypto/tls/TlsSrpLoginParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5ae4641f6506116dce0f873b8db9588e312dbe5f
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsSrpLoginParameters.cs
@@ -0,0 +1,36 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsSrpLoginParameters
+ {
+ protected readonly Srp6GroupParameters mGroup;
+ protected readonly BigInteger mVerifier;
+ protected readonly byte[] mSalt;
+
+ public TlsSrpLoginParameters(Srp6GroupParameters group, BigInteger verifier, byte[] salt)
+ {
+ this.mGroup = group;
+ this.mVerifier = verifier;
+ this.mSalt = salt;
+ }
+
+ public virtual Srp6GroupParameters Group
+ {
+ get { return mGroup; }
+ }
+
+ public virtual byte[] Salt
+ {
+ get { return mSalt; }
+ }
+
+ public virtual BigInteger Verifier
+ {
+ get { return mVerifier; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsSrpUtilities.cs b/bc-sharp-crypto/src/crypto/tls/TlsSrpUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..873189dc60afe7661623d4a82e17a7561a64650e
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsSrpUtilities.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public abstract class TlsSrpUtilities
+ {
+ public static void AddSrpExtension(IDictionary extensions, byte[] identity)
+ {
+ extensions[ExtensionType.srp] = CreateSrpExtension(identity);
+ }
+
+ public static byte[] GetSrpExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.srp);
+ return extensionData == null ? null : ReadSrpExtension(extensionData);
+ }
+
+ public static byte[] CreateSrpExtension(byte[] identity)
+ {
+ if (identity == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ return TlsUtilities.EncodeOpaque8(identity);
+ }
+
+ public static byte[] ReadSrpExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ MemoryStream buf = new MemoryStream(extensionData, false);
+ byte[] identity = TlsUtilities.ReadOpaque8(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ return identity;
+ }
+
+ public static BigInteger ReadSrpParameter(Stream input)
+ {
+ return new BigInteger(1, TlsUtilities.ReadOpaque16(input));
+ }
+
+ public static void WriteSrpParameter(BigInteger x, Stream output)
+ {
+ TlsUtilities.WriteOpaque16(BigIntegers.AsUnsignedByteArray(x), output);
+ }
+
+ public static bool IsSrpCipherSuite(int cipherSuite)
+ {
+ switch (cipherSuite)
+ {
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsSrtpUtilities.cs b/bc-sharp-crypto/src/crypto/tls/TlsSrtpUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..626c0e3a484dfcc4b2028fac59b718ff6098c0dc
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsSrtpUtilities.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * RFC 5764 DTLS Extension to Establish Keys for SRTP.
+ */
+ public abstract class TlsSRTPUtils
+ {
+ public static void AddUseSrtpExtension(IDictionary extensions, UseSrtpData useSRTPData)
+ {
+ extensions[ExtensionType.use_srtp] = CreateUseSrtpExtension(useSRTPData);
+ }
+
+ public static UseSrtpData GetUseSrtpExtension(IDictionary extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.use_srtp);
+ return extensionData == null ? null : ReadUseSrtpExtension(extensionData);
+ }
+
+ public static byte[] CreateUseSrtpExtension(UseSrtpData useSrtpData)
+ {
+ if (useSrtpData == null)
+ throw new ArgumentNullException("useSrtpData");
+
+ MemoryStream buf = new MemoryStream();
+
+ // SRTPProtectionProfiles
+ TlsUtilities.WriteUint16ArrayWithUint16Length(useSrtpData.ProtectionProfiles, buf);
+
+ // srtp_mki
+ TlsUtilities.WriteOpaque8(useSrtpData.Mki, buf);
+
+ return buf.ToArray();
+ }
+
+ public static UseSrtpData ReadUseSrtpExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ MemoryStream buf = new MemoryStream(extensionData, true);
+
+ // SRTPProtectionProfiles
+ int length = TlsUtilities.ReadUint16(buf);
+ if (length < 2 || (length & 1) != 0)
+ {
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ }
+ int[] protectionProfiles = TlsUtilities.ReadUint16Array(length / 2, buf);
+
+ // srtp_mki
+ byte[] mki = TlsUtilities.ReadOpaque8(buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ return new UseSrtpData(protectionProfiles, mki);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsStream.cs b/bc-sharp-crypto/src/crypto/tls/TlsStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bfd80edf2981dd89cd589551c6f15d1658d27960
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsStream.cs
@@ -0,0 +1,97 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ internal class TlsStream
+ : Stream
+ {
+ private readonly TlsProtocol handler;
+
+ internal TlsStream(TlsProtocol handler)
+ {
+ this.handler = handler;
+ }
+
+ public override bool CanRead
+ {
+ get { return !handler.IsClosed; }
+ }
+
+ public override bool CanSeek
+ {
+ get { return false; }
+ }
+
+ public override bool CanWrite
+ {
+ get { return !handler.IsClosed; }
+ }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ handler.Close();
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ handler.Close();
+ base.Close();
+ }
+#endif
+
+ public override void Flush()
+ {
+ handler.Flush();
+ }
+
+ public override long Length
+ {
+ get { throw new NotSupportedException(); }
+ }
+
+ public override long Position
+ {
+ get { throw new NotSupportedException(); }
+ set { throw new NotSupportedException(); }
+ }
+
+ public override int Read(byte[] buf, int off, int len)
+ {
+ return this.handler.ReadApplicationData(buf, off, len);
+ }
+
+ public override int ReadByte()
+ {
+ byte[] buf = new byte[1];
+ if (this.Read(buf, 0, 1) <= 0)
+ return -1;
+ return buf[0];
+ }
+
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void SetLength(long value)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override void Write(byte[] buf, int off, int len)
+ {
+ this.handler.WriteData(buf, off, len);
+ }
+
+ public override void WriteByte(byte b)
+ {
+ this.handler.WriteData(new byte[] { b }, 0, 1);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsStreamCipher.cs b/bc-sharp-crypto/src/crypto/tls/TlsStreamCipher.cs
new file mode 100644
index 0000000000000000000000000000000000000000..555442e9a2e393e05f3aa651bac43ba8865ae87b
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsStreamCipher.cs
@@ -0,0 +1,152 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Tls;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsStreamCipher
+ : TlsCipher
+ {
+ protected readonly TlsContext context;
+
+ protected readonly IStreamCipher encryptCipher;
+ protected readonly IStreamCipher decryptCipher;
+
+ protected readonly TlsMac writeMac;
+ protected readonly TlsMac readMac;
+
+ protected readonly bool usesNonce;
+
+ ///
+ public TlsStreamCipher(TlsContext context, IStreamCipher clientWriteCipher,
+ IStreamCipher serverWriteCipher, IDigest clientWriteDigest, IDigest serverWriteDigest,
+ int cipherKeySize, bool usesNonce)
+ {
+ bool isServer = context.IsServer;
+
+ this.context = context;
+ this.usesNonce = usesNonce;
+
+ this.encryptCipher = clientWriteCipher;
+ this.decryptCipher = serverWriteCipher;
+
+ int key_block_size = (2 * cipherKeySize) + clientWriteDigest.GetDigestSize()
+ + serverWriteDigest.GetDigestSize();
+
+ byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size);
+
+ int offset = 0;
+
+ // Init MACs
+ TlsMac clientWriteMac = new TlsMac(context, clientWriteDigest, key_block, offset,
+ clientWriteDigest.GetDigestSize());
+ offset += clientWriteDigest.GetDigestSize();
+ TlsMac serverWriteMac = new TlsMac(context, serverWriteDigest, key_block, offset,
+ serverWriteDigest.GetDigestSize());
+ offset += serverWriteDigest.GetDigestSize();
+
+ // Build keys
+ KeyParameter clientWriteKey = new KeyParameter(key_block, offset, cipherKeySize);
+ offset += cipherKeySize;
+ KeyParameter serverWriteKey = new KeyParameter(key_block, offset, cipherKeySize);
+ offset += cipherKeySize;
+
+ if (offset != key_block_size)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ ICipherParameters encryptParams, decryptParams;
+ if (isServer)
+ {
+ this.writeMac = serverWriteMac;
+ this.readMac = clientWriteMac;
+ this.encryptCipher = serverWriteCipher;
+ this.decryptCipher = clientWriteCipher;
+ encryptParams = serverWriteKey;
+ decryptParams = clientWriteKey;
+ }
+ else
+ {
+ this.writeMac = clientWriteMac;
+ this.readMac = serverWriteMac;
+ this.encryptCipher = clientWriteCipher;
+ this.decryptCipher = serverWriteCipher;
+ encryptParams = clientWriteKey;
+ decryptParams = serverWriteKey;
+ }
+
+ if (usesNonce)
+ {
+ byte[] dummyNonce = new byte[8];
+ encryptParams = new ParametersWithIV(encryptParams, dummyNonce);
+ decryptParams = new ParametersWithIV(decryptParams, dummyNonce);
+ }
+
+ this.encryptCipher.Init(true, encryptParams);
+ this.decryptCipher.Init(false, decryptParams);
+ }
+
+ public virtual int GetPlaintextLimit(int ciphertextLimit)
+ {
+ return ciphertextLimit - writeMac.Size;
+ }
+
+ public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
+ {
+ if (usesNonce)
+ {
+ UpdateIV(encryptCipher, true, seqNo);
+ }
+
+ byte[] outBuf = new byte[len + writeMac.Size];
+
+ encryptCipher.ProcessBytes(plaintext, offset, len, outBuf, 0);
+
+ byte[] mac = writeMac.CalculateMac(seqNo, type, plaintext, offset, len);
+ encryptCipher.ProcessBytes(mac, 0, mac.Length, outBuf, len);
+
+ return outBuf;
+ }
+
+ ///
+ public virtual byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len)
+ {
+ if (usesNonce)
+ {
+ UpdateIV(decryptCipher, false, seqNo);
+ }
+
+ int macSize = readMac.Size;
+ if (len < macSize)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ int plaintextLength = len - macSize;
+
+ byte[] deciphered = new byte[len];
+ decryptCipher.ProcessBytes(ciphertext, offset, len, deciphered, 0);
+ CheckMac(seqNo, type, deciphered, plaintextLength, len, deciphered, 0, plaintextLength);
+ return Arrays.CopyOfRange(deciphered, 0, plaintextLength);
+ }
+
+ ///
+ protected virtual void CheckMac(long seqNo, byte type, byte[] recBuf, int recStart, int recEnd, byte[] calcBuf, int calcOff, int calcLen)
+ {
+ byte[] receivedMac = Arrays.CopyOfRange(recBuf, recStart, recEnd);
+ byte[] computedMac = readMac.CalculateMac(seqNo, type, calcBuf, calcOff, calcLen);
+
+ if (!Arrays.ConstantTimeAreEqual(receivedMac, computedMac))
+ throw new TlsFatalAlert(AlertDescription.bad_record_mac);
+ }
+
+ protected virtual void UpdateIV(IStreamCipher cipher, bool forEncryption, long seqNo)
+ {
+ byte[] nonce = new byte[8];
+ TlsUtilities.WriteUint64(seqNo, nonce, 0);
+ cipher.Init(forEncryption, new ParametersWithIV(null, nonce));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/TlsUtilities.cs b/bc-sharp-crypto/src/crypto/tls/TlsUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..48eb9d3757172e15ef2673069f3aa09378b54f37
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/TlsUtilities.cs
@@ -0,0 +1,2398 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// Some helper functions for MicroTLS.
+ public abstract class TlsUtilities
+ {
+ public static readonly byte[] EmptyBytes = new byte[0];
+ public static readonly short[] EmptyShorts = new short[0];
+ public static readonly int[] EmptyInts = new int[0];
+ public static readonly long[] EmptyLongs = new long[0];
+
+ public static void CheckUint8(int i)
+ {
+ if (!IsValidUint8(i))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public static void CheckUint8(long i)
+ {
+ if (!IsValidUint8(i))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public static void CheckUint16(int i)
+ {
+ if (!IsValidUint16(i))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public static void CheckUint16(long i)
+ {
+ if (!IsValidUint16(i))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public static void CheckUint24(int i)
+ {
+ if (!IsValidUint24(i))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public static void CheckUint24(long i)
+ {
+ if (!IsValidUint24(i))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public static void CheckUint32(long i)
+ {
+ if (!IsValidUint32(i))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public static void CheckUint48(long i)
+ {
+ if (!IsValidUint48(i))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public static void CheckUint64(long i)
+ {
+ if (!IsValidUint64(i))
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ public static bool IsValidUint8(int i)
+ {
+ return (i & 0xFF) == i;
+ }
+
+ public static bool IsValidUint8(long i)
+ {
+ return (i & 0xFFL) == i;
+ }
+
+ public static bool IsValidUint16(int i)
+ {
+ return (i & 0xFFFF) == i;
+ }
+
+ public static bool IsValidUint16(long i)
+ {
+ return (i & 0xFFFFL) == i;
+ }
+
+ public static bool IsValidUint24(int i)
+ {
+ return (i & 0xFFFFFF) == i;
+ }
+
+ public static bool IsValidUint24(long i)
+ {
+ return (i & 0xFFFFFFL) == i;
+ }
+
+ public static bool IsValidUint32(long i)
+ {
+ return (i & 0xFFFFFFFFL) == i;
+ }
+
+ public static bool IsValidUint48(long i)
+ {
+ return (i & 0xFFFFFFFFFFFFL) == i;
+ }
+
+ public static bool IsValidUint64(long i)
+ {
+ return true;
+ }
+
+ public static bool IsSsl(TlsContext context)
+ {
+ return context.ServerVersion.IsSsl;
+ }
+
+ public static bool IsTlsV11(ProtocolVersion version)
+ {
+ return ProtocolVersion.TLSv11.IsEqualOrEarlierVersionOf(version.GetEquivalentTLSVersion());
+ }
+
+ public static bool IsTlsV11(TlsContext context)
+ {
+ return IsTlsV11(context.ServerVersion);
+ }
+
+ public static bool IsTlsV12(ProtocolVersion version)
+ {
+ return ProtocolVersion.TLSv12.IsEqualOrEarlierVersionOf(version.GetEquivalentTLSVersion());
+ }
+
+ public static bool IsTlsV12(TlsContext context)
+ {
+ return IsTlsV12(context.ServerVersion);
+ }
+
+ public static void WriteUint8(byte i, Stream output)
+ {
+ output.WriteByte(i);
+ }
+
+ public static void WriteUint8(byte i, byte[] buf, int offset)
+ {
+ buf[offset] = i;
+ }
+
+ public static void WriteUint16(int i, Stream output)
+ {
+ output.WriteByte((byte)(i >> 8));
+ output.WriteByte((byte)i);
+ }
+
+ public static void WriteUint16(int i, byte[] buf, int offset)
+ {
+ buf[offset] = (byte)(i >> 8);
+ buf[offset + 1] = (byte)i;
+ }
+
+ public static void WriteUint24(int i, Stream output)
+ {
+ output.WriteByte((byte)(i >> 16));
+ output.WriteByte((byte)(i >> 8));
+ output.WriteByte((byte)i);
+ }
+
+ public static void WriteUint24(int i, byte[] buf, int offset)
+ {
+ buf[offset] = (byte)(i >> 16);
+ buf[offset + 1] = (byte)(i >> 8);
+ buf[offset + 2] = (byte)i;
+ }
+
+ public static void WriteUint32(long i, Stream output)
+ {
+ output.WriteByte((byte)(i >> 24));
+ output.WriteByte((byte)(i >> 16));
+ output.WriteByte((byte)(i >> 8));
+ output.WriteByte((byte)i);
+ }
+
+ public static void WriteUint32(long i, byte[] buf, int offset)
+ {
+ buf[offset] = (byte)(i >> 24);
+ buf[offset + 1] = (byte)(i >> 16);
+ buf[offset + 2] = (byte)(i >> 8);
+ buf[offset + 3] = (byte)i;
+ }
+
+ public static void WriteUint48(long i, Stream output)
+ {
+ output.WriteByte((byte)(i >> 40));
+ output.WriteByte((byte)(i >> 32));
+ output.WriteByte((byte)(i >> 24));
+ output.WriteByte((byte)(i >> 16));
+ output.WriteByte((byte)(i >> 8));
+ output.WriteByte((byte)i);
+ }
+
+ public static void WriteUint48(long i, byte[] buf, int offset)
+ {
+ buf[offset] = (byte)(i >> 40);
+ buf[offset + 1] = (byte)(i >> 32);
+ buf[offset + 2] = (byte)(i >> 24);
+ buf[offset + 3] = (byte)(i >> 16);
+ buf[offset + 4] = (byte)(i >> 8);
+ buf[offset + 5] = (byte)i;
+ }
+
+ public static void WriteUint64(long i, Stream output)
+ {
+ output.WriteByte((byte)(i >> 56));
+ output.WriteByte((byte)(i >> 48));
+ output.WriteByte((byte)(i >> 40));
+ output.WriteByte((byte)(i >> 32));
+ output.WriteByte((byte)(i >> 24));
+ output.WriteByte((byte)(i >> 16));
+ output.WriteByte((byte)(i >> 8));
+ output.WriteByte((byte)i);
+ }
+
+ public static void WriteUint64(long i, byte[] buf, int offset)
+ {
+ buf[offset] = (byte)(i >> 56);
+ buf[offset + 1] = (byte)(i >> 48);
+ buf[offset + 2] = (byte)(i >> 40);
+ buf[offset + 3] = (byte)(i >> 32);
+ buf[offset + 4] = (byte)(i >> 24);
+ buf[offset + 5] = (byte)(i >> 16);
+ buf[offset + 6] = (byte)(i >> 8);
+ buf[offset + 7] = (byte)i;
+ }
+
+ public static void WriteOpaque8(byte[] buf, Stream output)
+ {
+ WriteUint8((byte)buf.Length, output);
+ output.Write(buf, 0, buf.Length);
+ }
+
+ public static void WriteOpaque16(byte[] buf, Stream output)
+ {
+ WriteUint16(buf.Length, output);
+ output.Write(buf, 0, buf.Length);
+ }
+
+ public static void WriteOpaque24(byte[] buf, Stream output)
+ {
+ WriteUint24(buf.Length, output);
+ output.Write(buf, 0, buf.Length);
+ }
+
+ public static void WriteUint8Array(byte[] uints, Stream output)
+ {
+ output.Write(uints, 0, uints.Length);
+ }
+
+ public static void WriteUint8Array(byte[] uints, byte[] buf, int offset)
+ {
+ for (int i = 0; i < uints.Length; ++i)
+ {
+ WriteUint8(uints[i], buf, offset);
+ ++offset;
+ }
+ }
+
+ public static void WriteUint8ArrayWithUint8Length(byte[] uints, Stream output)
+ {
+ CheckUint8(uints.Length);
+ WriteUint8((byte)uints.Length, output);
+ WriteUint8Array(uints, output);
+ }
+
+ public static void WriteUint8ArrayWithUint8Length(byte[] uints, byte[] buf, int offset)
+ {
+ CheckUint8(uints.Length);
+ WriteUint8((byte)uints.Length, buf, offset);
+ WriteUint8Array(uints, buf, offset + 1);
+ }
+
+ public static void WriteUint16Array(int[] uints, Stream output)
+ {
+ for (int i = 0; i < uints.Length; ++i)
+ {
+ WriteUint16(uints[i], output);
+ }
+ }
+
+ public static void WriteUint16Array(int[] uints, byte[] buf, int offset)
+ {
+ for (int i = 0; i < uints.Length; ++i)
+ {
+ WriteUint16(uints[i], buf, offset);
+ offset += 2;
+ }
+ }
+
+ public static void WriteUint16ArrayWithUint16Length(int[] uints, Stream output)
+ {
+ int length = 2 * uints.Length;
+ CheckUint16(length);
+ WriteUint16(length, output);
+ WriteUint16Array(uints, output);
+ }
+
+ public static void WriteUint16ArrayWithUint16Length(int[] uints, byte[] buf, int offset)
+ {
+ int length = 2 * uints.Length;
+ CheckUint16(length);
+ WriteUint16(length, buf, offset);
+ WriteUint16Array(uints, buf, offset + 2);
+ }
+
+ public static byte DecodeUint8(byte[] buf)
+ {
+ if (buf == null)
+ throw new ArgumentNullException("buf");
+ if (buf.Length != 1)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ return ReadUint8(buf, 0);
+ }
+
+ public static byte[] DecodeUint8ArrayWithUint8Length(byte[] buf)
+ {
+ if (buf == null)
+ throw new ArgumentNullException("buf");
+
+ int count = ReadUint8(buf, 0);
+ if (buf.Length != (count + 1))
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ byte[] uints = new byte[count];
+ for (int i = 0; i < count; ++i)
+ {
+ uints[i] = ReadUint8(buf, i + 1);
+ }
+ return uints;
+ }
+
+ public static byte[] EncodeOpaque8(byte[] buf)
+ {
+ CheckUint8(buf.Length);
+ return Arrays.Prepend(buf, (byte)buf.Length);
+ }
+
+ public static byte[] EncodeUint8(byte val)
+ {
+ CheckUint8(val);
+
+ byte[] extensionData = new byte[1];
+ WriteUint8(val, extensionData, 0);
+ return extensionData;
+ }
+
+ public static byte[] EncodeUint8ArrayWithUint8Length(byte[] uints)
+ {
+ byte[] result = new byte[1 + uints.Length];
+ WriteUint8ArrayWithUint8Length(uints, result, 0);
+ return result;
+ }
+
+ public static byte[] EncodeUint16ArrayWithUint16Length(int[] uints)
+ {
+ int length = 2 * uints.Length;
+ byte[] result = new byte[2 + length];
+ WriteUint16ArrayWithUint16Length(uints, result, 0);
+ return result;
+ }
+
+ public static byte ReadUint8(Stream input)
+ {
+ int i = input.ReadByte();
+ if (i < 0)
+ throw new EndOfStreamException();
+ return (byte)i;
+ }
+
+ public static byte ReadUint8(byte[] buf, int offset)
+ {
+ return buf[offset];
+ }
+
+ public static int ReadUint16(Stream input)
+ {
+ int i1 = input.ReadByte();
+ int i2 = input.ReadByte();
+ if (i2 < 0)
+ throw new EndOfStreamException();
+ return (i1 << 8) | i2;
+ }
+
+ public static int ReadUint16(byte[] buf, int offset)
+ {
+ uint n = (uint)buf[offset] << 8;
+ n |= (uint)buf[++offset];
+ return (int)n;
+ }
+
+ public static int ReadUint24(Stream input)
+ {
+ int i1 = input.ReadByte();
+ int i2 = input.ReadByte();
+ int i3 = input.ReadByte();
+ if (i3 < 0)
+ throw new EndOfStreamException();
+ return (i1 << 16) | (i2 << 8) | i3;
+ }
+
+ public static int ReadUint24(byte[] buf, int offset)
+ {
+ uint n = (uint)buf[offset] << 16;
+ n |= (uint)buf[++offset] << 8;
+ n |= (uint)buf[++offset];
+ return (int)n;
+ }
+
+ public static long ReadUint32(Stream input)
+ {
+ int i1 = input.ReadByte();
+ int i2 = input.ReadByte();
+ int i3 = input.ReadByte();
+ int i4 = input.ReadByte();
+ if (i4 < 0)
+ throw new EndOfStreamException();
+ return (long)(uint)((i1 << 24) | (i2 << 16) | (i3 << 8) | i4);
+ }
+
+ public static long ReadUint32(byte[] buf, int offset)
+ {
+ uint n = (uint)buf[offset] << 24;
+ n |= (uint)buf[++offset] << 16;
+ n |= (uint)buf[++offset] << 8;
+ n |= (uint)buf[++offset];
+ return (long)n;
+ }
+
+ public static long ReadUint48(Stream input)
+ {
+ int hi = ReadUint24(input);
+ int lo = ReadUint24(input);
+ return ((long)(hi & 0xffffffffL) << 24) | (long)(lo & 0xffffffffL);
+ }
+
+ public static long ReadUint48(byte[] buf, int offset)
+ {
+ int hi = ReadUint24(buf, offset);
+ int lo = ReadUint24(buf, offset + 3);
+ return ((long)(hi & 0xffffffffL) << 24) | (long)(lo & 0xffffffffL);
+ }
+
+ public static byte[] ReadAllOrNothing(int length, Stream input)
+ {
+ if (length < 1)
+ return EmptyBytes;
+ byte[] buf = new byte[length];
+ int read = Streams.ReadFully(input, buf);
+ if (read == 0)
+ return null;
+ if (read != length)
+ throw new EndOfStreamException();
+ return buf;
+ }
+
+ public static byte[] ReadFully(int length, Stream input)
+ {
+ if (length < 1)
+ return EmptyBytes;
+ byte[] buf = new byte[length];
+ if (length != Streams.ReadFully(input, buf))
+ throw new EndOfStreamException();
+ return buf;
+ }
+
+ public static void ReadFully(byte[] buf, Stream input)
+ {
+ if (Streams.ReadFully(input, buf, 0, buf.Length) < buf.Length)
+ throw new EndOfStreamException();
+ }
+
+ public static byte[] ReadOpaque8(Stream input)
+ {
+ byte length = ReadUint8(input);
+ byte[] bytes = new byte[length];
+ ReadFully(bytes, input);
+ return bytes;
+ }
+
+ public static byte[] ReadOpaque16(Stream input)
+ {
+ int length = ReadUint16(input);
+ byte[] bytes = new byte[length];
+ ReadFully(bytes, input);
+ return bytes;
+ }
+
+ public static byte[] ReadOpaque24(Stream input)
+ {
+ int length = ReadUint24(input);
+ return ReadFully(length, input);
+ }
+
+ public static byte[] ReadUint8Array(int count, Stream input)
+ {
+ byte[] uints = new byte[count];
+ for (int i = 0; i < count; ++i)
+ {
+ uints[i] = ReadUint8(input);
+ }
+ return uints;
+ }
+
+ public static int[] ReadUint16Array(int count, Stream input)
+ {
+ int[] uints = new int[count];
+ for (int i = 0; i < count; ++i)
+ {
+ uints[i] = ReadUint16(input);
+ }
+ return uints;
+ }
+
+ public static ProtocolVersion ReadVersion(byte[] buf, int offset)
+ {
+ return ProtocolVersion.Get(buf[offset], buf[offset + 1]);
+ }
+
+ public static ProtocolVersion ReadVersion(Stream input)
+ {
+ int i1 = input.ReadByte();
+ int i2 = input.ReadByte();
+ if (i2 < 0)
+ throw new EndOfStreamException();
+ return ProtocolVersion.Get(i1, i2);
+ }
+
+ public static int ReadVersionRaw(byte[] buf, int offset)
+ {
+ return (buf[offset] << 8) | buf[offset + 1];
+ }
+
+ public static int ReadVersionRaw(Stream input)
+ {
+ int i1 = input.ReadByte();
+ int i2 = input.ReadByte();
+ if (i2 < 0)
+ throw new EndOfStreamException();
+ return (i1 << 8) | i2;
+ }
+
+ public static Asn1Object ReadAsn1Object(byte[] encoding)
+ {
+ MemoryStream input = new MemoryStream(encoding, false);
+ Asn1InputStream asn1 = new Asn1InputStream(input, encoding.Length);
+ Asn1Object result = asn1.ReadObject();
+ if (null == result)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ if (input.Position != input.Length)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ return result;
+ }
+
+ public static Asn1Object ReadDerObject(byte[] encoding)
+ {
+ /*
+ * NOTE: The current ASN.1 parsing code can't enforce DER-only parsing, but since DER is
+ * canonical, we can check it by re-encoding the result and comparing to the original.
+ */
+ Asn1Object result = ReadAsn1Object(encoding);
+ byte[] check = result.GetEncoded(Asn1Encodable.Der);
+ if (!Arrays.AreEqual(check, encoding))
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ return result;
+ }
+
+ public static void WriteGmtUnixTime(byte[] buf, int offset)
+ {
+ int t = (int)(DateTimeUtilities.CurrentUnixMs() / 1000L);
+ buf[offset] = (byte)(t >> 24);
+ buf[offset + 1] = (byte)(t >> 16);
+ buf[offset + 2] = (byte)(t >> 8);
+ buf[offset + 3] = (byte)t;
+ }
+
+ public static void WriteVersion(ProtocolVersion version, Stream output)
+ {
+ output.WriteByte((byte)version.MajorVersion);
+ output.WriteByte((byte)version.MinorVersion);
+ }
+
+ public static void WriteVersion(ProtocolVersion version, byte[] buf, int offset)
+ {
+ buf[offset] = (byte)version.MajorVersion;
+ buf[offset + 1] = (byte)version.MinorVersion;
+ }
+
+ public static IList GetAllSignatureAlgorithms()
+ {
+ IList v = Platform.CreateArrayList(4);
+ v.Add(SignatureAlgorithm.anonymous);
+ v.Add(SignatureAlgorithm.rsa);
+ v.Add(SignatureAlgorithm.dsa);
+ v.Add(SignatureAlgorithm.ecdsa);
+ return v;
+ }
+
+ public static IList GetDefaultDssSignatureAlgorithms()
+ {
+ return VectorOfOne(new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.dsa));
+ }
+
+ public static IList GetDefaultECDsaSignatureAlgorithms()
+ {
+ return VectorOfOne(new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.ecdsa));
+ }
+
+ public static IList GetDefaultRsaSignatureAlgorithms()
+ {
+ return VectorOfOne(new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.rsa));
+ }
+
+ public static byte[] GetExtensionData(IDictionary extensions, int extensionType)
+ {
+ return extensions == null ? null : (byte[])extensions[extensionType];
+ }
+
+ public static IList GetDefaultSupportedSignatureAlgorithms()
+ {
+ byte[] hashAlgorithms = new byte[]{ HashAlgorithm.sha1, HashAlgorithm.sha224, HashAlgorithm.sha256,
+ HashAlgorithm.sha384, HashAlgorithm.sha512 };
+ byte[] signatureAlgorithms = new byte[]{ SignatureAlgorithm.rsa, SignatureAlgorithm.dsa,
+ SignatureAlgorithm.ecdsa };
+
+ IList result = Platform.CreateArrayList();
+ for (int i = 0; i < signatureAlgorithms.Length; ++i)
+ {
+ for (int j = 0; j < hashAlgorithms.Length; ++j)
+ {
+ result.Add(new SignatureAndHashAlgorithm(hashAlgorithms[j], signatureAlgorithms[i]));
+ }
+ }
+ return result;
+ }
+
+ public static SignatureAndHashAlgorithm GetSignatureAndHashAlgorithm(TlsContext context,
+ TlsSignerCredentials signerCredentials)
+ {
+ SignatureAndHashAlgorithm signatureAndHashAlgorithm = null;
+ if (IsTlsV12(context))
+ {
+ signatureAndHashAlgorithm = signerCredentials.SignatureAndHashAlgorithm;
+ if (signatureAndHashAlgorithm == null)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ return signatureAndHashAlgorithm;
+ }
+
+ public static bool HasExpectedEmptyExtensionData(IDictionary extensions, int extensionType,
+ byte alertDescription)
+ {
+ byte[] extension_data = GetExtensionData(extensions, extensionType);
+ if (extension_data == null)
+ return false;
+ if (extension_data.Length != 0)
+ throw new TlsFatalAlert(alertDescription);
+ return true;
+ }
+
+ public static TlsSession ImportSession(byte[] sessionID, SessionParameters sessionParameters)
+ {
+ return new TlsSessionImpl(sessionID, sessionParameters);
+ }
+
+ public static bool IsSignatureAlgorithmsExtensionAllowed(ProtocolVersion clientVersion)
+ {
+ return ProtocolVersion.TLSv12.IsEqualOrEarlierVersionOf(clientVersion.GetEquivalentTLSVersion());
+ }
+
+ /**
+ * Add a 'signature_algorithms' extension to existing extensions.
+ *
+ * @param extensions A {@link Hashtable} to add the extension to.
+ * @param supportedSignatureAlgorithms {@link Vector} containing at least 1 {@link SignatureAndHashAlgorithm}.
+ * @throws IOException
+ */
+ public static void AddSignatureAlgorithmsExtension(IDictionary extensions, IList supportedSignatureAlgorithms)
+ {
+ extensions[ExtensionType.signature_algorithms] = CreateSignatureAlgorithmsExtension(supportedSignatureAlgorithms);
+ }
+
+ /**
+ * Get a 'signature_algorithms' extension from extensions.
+ *
+ * @param extensions A {@link Hashtable} to get the extension from, if it is present.
+ * @return A {@link Vector} containing at least 1 {@link SignatureAndHashAlgorithm}, or null.
+ * @throws IOException
+ */
+ public static IList GetSignatureAlgorithmsExtension(IDictionary extensions)
+ {
+ byte[] extensionData = GetExtensionData(extensions, ExtensionType.signature_algorithms);
+ return extensionData == null ? null : ReadSignatureAlgorithmsExtension(extensionData);
+ }
+
+ /**
+ * Create a 'signature_algorithms' extension value.
+ *
+ * @param supportedSignatureAlgorithms A {@link Vector} containing at least 1 {@link SignatureAndHashAlgorithm}.
+ * @return A byte array suitable for use as an extension value.
+ * @throws IOException
+ */
+ public static byte[] CreateSignatureAlgorithmsExtension(IList supportedSignatureAlgorithms)
+ {
+ MemoryStream buf = new MemoryStream();
+
+ // supported_signature_algorithms
+ EncodeSupportedSignatureAlgorithms(supportedSignatureAlgorithms, false, buf);
+
+ return buf.ToArray();
+ }
+
+ /**
+ * Read 'signature_algorithms' extension data.
+ *
+ * @param extensionData The extension data.
+ * @return A {@link Vector} containing at least 1 {@link SignatureAndHashAlgorithm}.
+ * @throws IOException
+ */
+ public static IList ReadSignatureAlgorithmsExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ MemoryStream buf = new MemoryStream(extensionData, false);
+
+ // supported_signature_algorithms
+ IList supported_signature_algorithms = ParseSupportedSignatureAlgorithms(false, buf);
+
+ TlsProtocol.AssertEmpty(buf);
+
+ return supported_signature_algorithms;
+ }
+
+ public static void EncodeSupportedSignatureAlgorithms(IList supportedSignatureAlgorithms, bool allowAnonymous,
+ Stream output)
+ {
+ if (supportedSignatureAlgorithms == null)
+ throw new ArgumentNullException("supportedSignatureAlgorithms");
+ if (supportedSignatureAlgorithms.Count < 1 || supportedSignatureAlgorithms.Count >= (1 << 15))
+ throw new ArgumentException("must have length from 1 to (2^15 - 1)", "supportedSignatureAlgorithms");
+
+ // supported_signature_algorithms
+ int length = 2 * supportedSignatureAlgorithms.Count;
+ CheckUint16(length);
+ WriteUint16(length, output);
+
+ foreach (SignatureAndHashAlgorithm entry in supportedSignatureAlgorithms)
+ {
+ if (!allowAnonymous && entry.Signature == SignatureAlgorithm.anonymous)
+ {
+ /*
+ * RFC 5246 7.4.1.4.1 The "anonymous" value is meaningless in this context but used
+ * in Section 7.4.3. It MUST NOT appear in this extension.
+ */
+ throw new ArgumentException(
+ "SignatureAlgorithm.anonymous MUST NOT appear in the signature_algorithms extension");
+ }
+ entry.Encode(output);
+ }
+ }
+
+ public static IList ParseSupportedSignatureAlgorithms(bool allowAnonymous, Stream input)
+ {
+ // supported_signature_algorithms
+ int length = ReadUint16(input);
+ if (length < 2 || (length & 1) != 0)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ int count = length / 2;
+ IList supportedSignatureAlgorithms = Platform.CreateArrayList(count);
+ for (int i = 0; i < count; ++i)
+ {
+ SignatureAndHashAlgorithm entry = SignatureAndHashAlgorithm.Parse(input);
+ if (!allowAnonymous && entry.Signature == SignatureAlgorithm.anonymous)
+ {
+ /*
+ * RFC 5246 7.4.1.4.1 The "anonymous" value is meaningless in this context but used
+ * in Section 7.4.3. It MUST NOT appear in this extension.
+ */
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ supportedSignatureAlgorithms.Add(entry);
+ }
+ return supportedSignatureAlgorithms;
+ }
+
+ public static void VerifySupportedSignatureAlgorithm(IList supportedSignatureAlgorithms, SignatureAndHashAlgorithm signatureAlgorithm)
+ {
+ if (supportedSignatureAlgorithms == null)
+ throw new ArgumentNullException("supportedSignatureAlgorithms");
+ if (supportedSignatureAlgorithms.Count < 1 || supportedSignatureAlgorithms.Count >= (1 << 15))
+ throw new ArgumentException("must have length from 1 to (2^15 - 1)", "supportedSignatureAlgorithms");
+ if (signatureAlgorithm == null)
+ throw new ArgumentNullException("signatureAlgorithm");
+
+ if (signatureAlgorithm.Signature != SignatureAlgorithm.anonymous)
+ {
+ foreach (SignatureAndHashAlgorithm entry in supportedSignatureAlgorithms)
+ {
+ if (entry.Hash == signatureAlgorithm.Hash && entry.Signature == signatureAlgorithm.Signature)
+ return;
+ }
+ }
+
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ public static byte[] PRF(TlsContext context, byte[] secret, string asciiLabel, byte[] seed, int size)
+ {
+ ProtocolVersion version = context.ServerVersion;
+
+ if (version.IsSsl)
+ throw new InvalidOperationException("No PRF available for SSLv3 session");
+
+ byte[] label = Strings.ToByteArray(asciiLabel);
+ byte[] labelSeed = Concat(label, seed);
+
+ int prfAlgorithm = context.SecurityParameters.PrfAlgorithm;
+
+ if (prfAlgorithm == PrfAlgorithm.tls_prf_legacy)
+ return PRF_legacy(secret, label, labelSeed, size);
+
+ IDigest prfDigest = CreatePrfHash(prfAlgorithm);
+ byte[] buf = new byte[size];
+ HMacHash(prfDigest, secret, labelSeed, buf);
+ return buf;
+ }
+
+ public static byte[] PRF_legacy(byte[] secret, string asciiLabel, byte[] seed, int size)
+ {
+ byte[] label = Strings.ToByteArray(asciiLabel);
+ byte[] labelSeed = Concat(label, seed);
+
+ return PRF_legacy(secret, label, labelSeed, size);
+ }
+
+ internal static byte[] PRF_legacy(byte[] secret, byte[] label, byte[] labelSeed, int size)
+ {
+ int s_half = (secret.Length + 1) / 2;
+ byte[] s1 = new byte[s_half];
+ byte[] s2 = new byte[s_half];
+ Array.Copy(secret, 0, s1, 0, s_half);
+ Array.Copy(secret, secret.Length - s_half, s2, 0, s_half);
+
+ byte[] b1 = new byte[size];
+ byte[] b2 = new byte[size];
+ HMacHash(CreateHash(HashAlgorithm.md5), s1, labelSeed, b1);
+ HMacHash(CreateHash(HashAlgorithm.sha1), s2, labelSeed, b2);
+ for (int i = 0; i < size; i++)
+ {
+ b1[i] ^= b2[i];
+ }
+ return b1;
+ }
+
+ internal static byte[] Concat(byte[] a, byte[] b)
+ {
+ byte[] c = new byte[a.Length + b.Length];
+ Array.Copy(a, 0, c, 0, a.Length);
+ Array.Copy(b, 0, c, a.Length, b.Length);
+ return c;
+ }
+
+ internal static void HMacHash(IDigest digest, byte[] secret, byte[] seed, byte[] output)
+ {
+ HMac mac = new HMac(digest);
+ mac.Init(new KeyParameter(secret));
+ byte[] a = seed;
+ int size = digest.GetDigestSize();
+ int iterations = (output.Length + size - 1) / size;
+ byte[] buf = new byte[mac.GetMacSize()];
+ byte[] buf2 = new byte[mac.GetMacSize()];
+ for (int i = 0; i < iterations; i++)
+ {
+ mac.BlockUpdate(a, 0, a.Length);
+ mac.DoFinal(buf, 0);
+ a = buf;
+ mac.BlockUpdate(a, 0, a.Length);
+ mac.BlockUpdate(seed, 0, seed.Length);
+ mac.DoFinal(buf2, 0);
+ Array.Copy(buf2, 0, output, (size * i), System.Math.Min(size, output.Length - (size * i)));
+ }
+ }
+
+ internal static void ValidateKeyUsage(X509CertificateStructure c, int keyUsageBits)
+ {
+ X509Extensions exts = c.TbsCertificate.Extensions;
+ if (exts != null)
+ {
+ X509Extension ext = exts.GetExtension(X509Extensions.KeyUsage);
+ if (ext != null)
+ {
+ DerBitString ku = KeyUsage.GetInstance(ext);
+ int bits = ku.GetBytes()[0];
+ if ((bits & keyUsageBits) != keyUsageBits)
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+ }
+ }
+ }
+
+ internal static byte[] CalculateKeyBlock(TlsContext context, int size)
+ {
+ SecurityParameters securityParameters = context.SecurityParameters;
+ byte[] master_secret = securityParameters.MasterSecret;
+ byte[] seed = Concat(securityParameters.ServerRandom, securityParameters.ClientRandom);
+
+ if (IsSsl(context))
+ return CalculateKeyBlock_Ssl(master_secret, seed, size);
+
+ return PRF(context, master_secret, ExporterLabel.key_expansion, seed, size);
+ }
+
+ internal static byte[] CalculateKeyBlock_Ssl(byte[] master_secret, byte[] random, int size)
+ {
+ IDigest md5 = CreateHash(HashAlgorithm.md5);
+ IDigest sha1 = CreateHash(HashAlgorithm.sha1);
+ int md5Size = md5.GetDigestSize();
+ byte[] shatmp = new byte[sha1.GetDigestSize()];
+ byte[] tmp = new byte[size + md5Size];
+
+ int i = 0, pos = 0;
+ while (pos < size)
+ {
+ byte[] ssl3Const = SSL3_CONST[i];
+
+ sha1.BlockUpdate(ssl3Const, 0, ssl3Const.Length);
+ sha1.BlockUpdate(master_secret, 0, master_secret.Length);
+ sha1.BlockUpdate(random, 0, random.Length);
+ sha1.DoFinal(shatmp, 0);
+
+ md5.BlockUpdate(master_secret, 0, master_secret.Length);
+ md5.BlockUpdate(shatmp, 0, shatmp.Length);
+ md5.DoFinal(tmp, pos);
+
+ pos += md5Size;
+ ++i;
+ }
+
+ return Arrays.CopyOfRange(tmp, 0, size);
+ }
+
+ internal static byte[] CalculateMasterSecret(TlsContext context, byte[] pre_master_secret)
+ {
+ SecurityParameters securityParameters = context.SecurityParameters;
+
+ byte[] seed = securityParameters.extendedMasterSecret
+ ? securityParameters.SessionHash
+ : Concat(securityParameters.ClientRandom, securityParameters.ServerRandom);
+
+ if (IsSsl(context))
+ return CalculateMasterSecret_Ssl(pre_master_secret, seed);
+
+ string asciiLabel = securityParameters.extendedMasterSecret
+ ? ExporterLabel.extended_master_secret
+ : ExporterLabel.master_secret;
+
+ return PRF(context, pre_master_secret, asciiLabel, seed, 48);
+ }
+
+ internal static byte[] CalculateMasterSecret_Ssl(byte[] pre_master_secret, byte[] random)
+ {
+ IDigest md5 = CreateHash(HashAlgorithm.md5);
+ IDigest sha1 = CreateHash(HashAlgorithm.sha1);
+ int md5Size = md5.GetDigestSize();
+ byte[] shatmp = new byte[sha1.GetDigestSize()];
+
+ byte[] rval = new byte[md5Size * 3];
+ int pos = 0;
+
+ for (int i = 0; i < 3; ++i)
+ {
+ byte[] ssl3Const = SSL3_CONST[i];
+
+ sha1.BlockUpdate(ssl3Const, 0, ssl3Const.Length);
+ sha1.BlockUpdate(pre_master_secret, 0, pre_master_secret.Length);
+ sha1.BlockUpdate(random, 0, random.Length);
+ sha1.DoFinal(shatmp, 0);
+
+ md5.BlockUpdate(pre_master_secret, 0, pre_master_secret.Length);
+ md5.BlockUpdate(shatmp, 0, shatmp.Length);
+ md5.DoFinal(rval, pos);
+
+ pos += md5Size;
+ }
+
+ return rval;
+ }
+
+ internal static byte[] CalculateVerifyData(TlsContext context, string asciiLabel, byte[] handshakeHash)
+ {
+ if (IsSsl(context))
+ return handshakeHash;
+
+ SecurityParameters securityParameters = context.SecurityParameters;
+ byte[] master_secret = securityParameters.MasterSecret;
+ int verify_data_length = securityParameters.VerifyDataLength;
+
+ return PRF(context, master_secret, asciiLabel, handshakeHash, verify_data_length);
+ }
+
+ public static IDigest CreateHash(byte hashAlgorithm)
+ {
+ switch (hashAlgorithm)
+ {
+ case HashAlgorithm.md5:
+ return new MD5Digest();
+ case HashAlgorithm.sha1:
+ return new Sha1Digest();
+ case HashAlgorithm.sha224:
+ return new Sha224Digest();
+ case HashAlgorithm.sha256:
+ return new Sha256Digest();
+ case HashAlgorithm.sha384:
+ return new Sha384Digest();
+ case HashAlgorithm.sha512:
+ return new Sha512Digest();
+ default:
+ throw new ArgumentException("unknown HashAlgorithm", "hashAlgorithm");
+ }
+ }
+
+ public static IDigest CreateHash(SignatureAndHashAlgorithm signatureAndHashAlgorithm)
+ {
+ return signatureAndHashAlgorithm == null
+ ? new CombinedHash()
+ : CreateHash(signatureAndHashAlgorithm.Hash);
+ }
+
+ public static IDigest CloneHash(byte hashAlgorithm, IDigest hash)
+ {
+ switch (hashAlgorithm)
+ {
+ case HashAlgorithm.md5:
+ return new MD5Digest((MD5Digest)hash);
+ case HashAlgorithm.sha1:
+ return new Sha1Digest((Sha1Digest)hash);
+ case HashAlgorithm.sha224:
+ return new Sha224Digest((Sha224Digest)hash);
+ case HashAlgorithm.sha256:
+ return new Sha256Digest((Sha256Digest)hash);
+ case HashAlgorithm.sha384:
+ return new Sha384Digest((Sha384Digest)hash);
+ case HashAlgorithm.sha512:
+ return new Sha512Digest((Sha512Digest)hash);
+ default:
+ throw new ArgumentException("unknown HashAlgorithm", "hashAlgorithm");
+ }
+ }
+
+ public static IDigest CreatePrfHash(int prfAlgorithm)
+ {
+ switch (prfAlgorithm)
+ {
+ case PrfAlgorithm.tls_prf_legacy:
+ return new CombinedHash();
+ default:
+ return CreateHash(GetHashAlgorithmForPrfAlgorithm(prfAlgorithm));
+ }
+ }
+
+ public static IDigest ClonePrfHash(int prfAlgorithm, IDigest hash)
+ {
+ switch (prfAlgorithm)
+ {
+ case PrfAlgorithm.tls_prf_legacy:
+ return new CombinedHash((CombinedHash)hash);
+ default:
+ return CloneHash(GetHashAlgorithmForPrfAlgorithm(prfAlgorithm), hash);
+ }
+ }
+
+ public static byte GetHashAlgorithmForPrfAlgorithm(int prfAlgorithm)
+ {
+ switch (prfAlgorithm)
+ {
+ case PrfAlgorithm.tls_prf_legacy:
+ throw new ArgumentException("legacy PRF not a valid algorithm", "prfAlgorithm");
+ case PrfAlgorithm.tls_prf_sha256:
+ return HashAlgorithm.sha256;
+ case PrfAlgorithm.tls_prf_sha384:
+ return HashAlgorithm.sha384;
+ default:
+ throw new ArgumentException("unknown PrfAlgorithm", "prfAlgorithm");
+ }
+ }
+
+ public static DerObjectIdentifier GetOidForHashAlgorithm(byte hashAlgorithm)
+ {
+ switch (hashAlgorithm)
+ {
+ case HashAlgorithm.md5:
+ return PkcsObjectIdentifiers.MD5;
+ case HashAlgorithm.sha1:
+ return X509ObjectIdentifiers.IdSha1;
+ case HashAlgorithm.sha224:
+ return NistObjectIdentifiers.IdSha224;
+ case HashAlgorithm.sha256:
+ return NistObjectIdentifiers.IdSha256;
+ case HashAlgorithm.sha384:
+ return NistObjectIdentifiers.IdSha384;
+ case HashAlgorithm.sha512:
+ return NistObjectIdentifiers.IdSha512;
+ default:
+ throw new ArgumentException("unknown HashAlgorithm", "hashAlgorithm");
+ }
+ }
+
+ internal static short GetClientCertificateType(Certificate clientCertificate, Certificate serverCertificate)
+ {
+ if (clientCertificate.IsEmpty)
+ return -1;
+
+ X509CertificateStructure x509Cert = clientCertificate.GetCertificateAt(0);
+ SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+ try
+ {
+ AsymmetricKeyParameter publicKey = PublicKeyFactory.CreateKey(keyInfo);
+ if (publicKey.IsPrivate)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ /*
+ * TODO RFC 5246 7.4.6. The certificates MUST be signed using an acceptable hash/
+ * signature algorithm pair, as described in Section 7.4.4. Note that this relaxes the
+ * constraints on certificate-signing algorithms found in prior versions of TLS.
+ */
+
+ /*
+ * RFC 5246 7.4.6. Client Certificate
+ */
+
+ /*
+ * RSA public key; the certificate MUST allow the key to be used for signing with the
+ * signature scheme and hash algorithm that will be employed in the certificate verify
+ * message.
+ */
+ if (publicKey is RsaKeyParameters)
+ {
+ ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
+ return ClientCertificateType.rsa_sign;
+ }
+
+ /*
+ * DSA public key; the certificate MUST allow the key to be used for signing with the
+ * hash algorithm that will be employed in the certificate verify message.
+ */
+ if (publicKey is DsaPublicKeyParameters)
+ {
+ ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
+ return ClientCertificateType.dss_sign;
+ }
+
+ /*
+ * ECDSA-capable public key; the certificate MUST allow the key to be used for signing
+ * with the hash algorithm that will be employed in the certificate verify message; the
+ * public key MUST use a curve and point format supported by the server.
+ */
+ if (publicKey is ECPublicKeyParameters)
+ {
+ ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
+ // TODO Check the curve and point format
+ return ClientCertificateType.ecdsa_sign;
+ }
+
+ // TODO Add support for ClientCertificateType.*_fixed_*
+
+ throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
+ }
+ catch (Exception e)
+ {
+ throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
+ }
+ }
+
+ internal static void TrackHashAlgorithms(TlsHandshakeHash handshakeHash, IList supportedSignatureAlgorithms)
+ {
+ if (supportedSignatureAlgorithms != null)
+ {
+ foreach (SignatureAndHashAlgorithm signatureAndHashAlgorithm in supportedSignatureAlgorithms)
+ {
+ byte hashAlgorithm = signatureAndHashAlgorithm.Hash;
+
+ // TODO Support values in the "Reserved for Private Use" range
+ if (!HashAlgorithm.IsPrivate(hashAlgorithm))
+ {
+ handshakeHash.TrackHashAlgorithm(hashAlgorithm);
+ }
+ }
+ }
+ }
+
+ public static bool HasSigningCapability(byte clientCertificateType)
+ {
+ switch (clientCertificateType)
+ {
+ case ClientCertificateType.dss_sign:
+ case ClientCertificateType.ecdsa_sign:
+ case ClientCertificateType.rsa_sign:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public static TlsSigner CreateTlsSigner(byte clientCertificateType)
+ {
+ switch (clientCertificateType)
+ {
+ case ClientCertificateType.dss_sign:
+ return new TlsDssSigner();
+ case ClientCertificateType.ecdsa_sign:
+ return new TlsECDsaSigner();
+ case ClientCertificateType.rsa_sign:
+ return new TlsRsaSigner();
+ default:
+ throw new ArgumentException("not a type with signing capability", "clientCertificateType");
+ }
+ }
+
+ internal static readonly byte[] SSL_CLIENT = {0x43, 0x4C, 0x4E, 0x54};
+ internal static readonly byte[] SSL_SERVER = {0x53, 0x52, 0x56, 0x52};
+
+ // SSL3 magic mix constants ("A", "BB", "CCC", ...)
+ internal static readonly byte[][] SSL3_CONST = GenSsl3Const();
+
+ private static byte[][] GenSsl3Const()
+ {
+ int n = 10;
+ byte[][] arr = new byte[n][];
+ for (int i = 0; i < n; i++)
+ {
+ byte[] b = new byte[i + 1];
+ Arrays.Fill(b, (byte)('A' + i));
+ arr[i] = b;
+ }
+ return arr;
+ }
+
+ private static IList VectorOfOne(object obj)
+ {
+ IList v = Platform.CreateArrayList(1);
+ v.Add(obj);
+ return v;
+ }
+
+ public static int GetCipherType(int ciphersuite)
+ {
+ switch (GetEncryptionAlgorithm(ciphersuite))
+ {
+ case EncryptionAlgorithm.AES_128_CCM:
+ case EncryptionAlgorithm.AES_128_CCM_8:
+ case EncryptionAlgorithm.AES_128_GCM:
+ case EncryptionAlgorithm.AES_128_OCB_TAGLEN96:
+ case EncryptionAlgorithm.AES_256_CCM:
+ case EncryptionAlgorithm.AES_256_CCM_8:
+ case EncryptionAlgorithm.AES_256_GCM:
+ case EncryptionAlgorithm.AES_256_OCB_TAGLEN96:
+ case EncryptionAlgorithm.CAMELLIA_128_GCM:
+ case EncryptionAlgorithm.CAMELLIA_256_GCM:
+ case EncryptionAlgorithm.CHACHA20_POLY1305:
+ return CipherType.aead;
+
+ case EncryptionAlgorithm.RC2_CBC_40:
+ case EncryptionAlgorithm.IDEA_CBC:
+ case EncryptionAlgorithm.DES40_CBC:
+ case EncryptionAlgorithm.DES_CBC:
+ case EncryptionAlgorithm.cls_3DES_EDE_CBC:
+ case EncryptionAlgorithm.AES_128_CBC:
+ case EncryptionAlgorithm.AES_256_CBC:
+ case EncryptionAlgorithm.CAMELLIA_128_CBC:
+ case EncryptionAlgorithm.CAMELLIA_256_CBC:
+ case EncryptionAlgorithm.SEED_CBC:
+ return CipherType.block;
+
+ case EncryptionAlgorithm.NULL:
+ case EncryptionAlgorithm.RC4_40:
+ case EncryptionAlgorithm.RC4_128:
+ return CipherType.stream;
+
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public static int GetEncryptionAlgorithm(int ciphersuite)
+ {
+ switch (ciphersuite)
+ {
+ case CipherSuite.TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
+ return EncryptionAlgorithm.cls_3DES_EDE_CBC;
+
+ case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
+ return EncryptionAlgorithm.AES_128_CBC;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+ return EncryptionAlgorithm.AES_128_CCM;
+
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+ return EncryptionAlgorithm.AES_128_CCM_8;
+
+ case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+ return EncryptionAlgorithm.AES_128_GCM;
+
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_128_OCB:
+ return EncryptionAlgorithm.AES_128_OCB_TAGLEN96;
+
+ case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
+ return EncryptionAlgorithm.AES_256_CBC;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+ return EncryptionAlgorithm.AES_256_CCM;
+
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+ return EncryptionAlgorithm.AES_256_CCM_8;
+
+ case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+ return EncryptionAlgorithm.AES_256_GCM;
+
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_256_OCB:
+ return EncryptionAlgorithm.AES_256_OCB_TAGLEN96;
+
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ return EncryptionAlgorithm.CAMELLIA_128_CBC;
+
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ return EncryptionAlgorithm.CAMELLIA_128_GCM;
+
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ return EncryptionAlgorithm.CAMELLIA_256_CBC;
+
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ return EncryptionAlgorithm.CAMELLIA_256_GCM;
+
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ return EncryptionAlgorithm.CHACHA20_POLY1305;
+
+ case CipherSuite.TLS_RSA_WITH_NULL_MD5:
+ return EncryptionAlgorithm.NULL;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_RSA_WITH_NULL_SHA:
+ return EncryptionAlgorithm.NULL;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+ return EncryptionAlgorithm.NULL;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384:
+ return EncryptionAlgorithm.NULL;
+
+ case CipherSuite.TLS_DH_anon_WITH_RC4_128_MD5:
+ case CipherSuite.TLS_RSA_WITH_RC4_128_MD5:
+ return EncryptionAlgorithm.RC4_128;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
+ return EncryptionAlgorithm.RC4_128;
+
+ case CipherSuite.TLS_DH_anon_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_SEED_CBC_SHA:
+ return EncryptionAlgorithm.SEED_CBC;
+
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public static int GetKeyExchangeAlgorithm(int ciphersuite)
+ {
+ switch (ciphersuite)
+ {
+ case CipherSuite.TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_anon_WITH_RC4_128_MD5:
+ case CipherSuite.TLS_DH_anon_WITH_SEED_CBC_SHA:
+ return KeyExchangeAlgorithm.DH_anon;
+
+ case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA:
+ return KeyExchangeAlgorithm.DH_DSS;
+
+ case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA:
+ return KeyExchangeAlgorithm.DH_RSA;
+
+ case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA:
+ return KeyExchangeAlgorithm.DHE_DSS;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
+ return KeyExchangeAlgorithm.DHE_PSK;
+
+ case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA:
+ return KeyExchangeAlgorithm.DHE_RSA;
+
+ case CipherSuite.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_RC4_128_SHA:
+ return KeyExchangeAlgorithm.ECDH_anon;
+
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+ return KeyExchangeAlgorithm.ECDH_ECDSA;
+
+ case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
+ return KeyExchangeAlgorithm.ECDH_RSA;
+
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+ return KeyExchangeAlgorithm.ECDHE_ECDSA;
+
+ case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA:
+ return KeyExchangeAlgorithm.ECDHE_PSK;
+
+ case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+ return KeyExchangeAlgorithm.ECDHE_RSA;
+
+ case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_128_OCB:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_256_OCB:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_PSK_WITH_RC4_128_SHA:
+ return KeyExchangeAlgorithm.PSK;
+
+ case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_RSA_WITH_NULL_MD5:
+ case CipherSuite.TLS_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+ case CipherSuite.TLS_RSA_WITH_RC4_128_MD5:
+ case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_RSA_WITH_SEED_CBC_SHA:
+ return KeyExchangeAlgorithm.RSA;
+
+ case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
+ return KeyExchangeAlgorithm.RSA_PSK;
+
+ case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
+ return KeyExchangeAlgorithm.SRP;
+
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
+ return KeyExchangeAlgorithm.SRP_DSS;
+
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
+ return KeyExchangeAlgorithm.SRP_RSA;
+
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public static int GetMacAlgorithm(int ciphersuite)
+ {
+ switch (ciphersuite)
+ {
+ case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_128_OCB:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_256_OCB:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ return MacAlgorithm.cls_null;
+
+ case CipherSuite.TLS_DH_anon_WITH_RC4_128_MD5:
+ case CipherSuite.TLS_RSA_WITH_NULL_MD5:
+ case CipherSuite.TLS_RSA_WITH_RC4_128_MD5:
+ return MacAlgorithm.hmac_md5;
+
+ case CipherSuite.TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DH_anon_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
+ case CipherSuite.TLS_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_RSA_WITH_SEED_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
+ return MacAlgorithm.hmac_sha1;
+
+ case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+ return MacAlgorithm.hmac_sha256;
+
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384:
+ return MacAlgorithm.hmac_sha384;
+
+ default:
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public static ProtocolVersion GetMinimumVersion(int ciphersuite)
+ {
+ switch (ciphersuite)
+ {
+ case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_128_OCB:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_AES_256_OCB:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_128_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_AES_256_OCB:
+ case CipherSuite.DRAFT_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_128_OCB:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
+ case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_AES_256_OCB:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.DRAFT_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+ case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+ case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+ case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+ return ProtocolVersion.TLSv12;
+
+ default:
+ return ProtocolVersion.SSLv3;
+ }
+ }
+
+ public static bool IsAeadCipherSuite(int ciphersuite)
+ {
+ return CipherType.aead == GetCipherType(ciphersuite);
+ }
+
+ public static bool IsBlockCipherSuite(int ciphersuite)
+ {
+ return CipherType.block == GetCipherType(ciphersuite);
+ }
+
+ public static bool IsStreamCipherSuite(int ciphersuite)
+ {
+ return CipherType.stream == GetCipherType(ciphersuite);
+ }
+
+ public static bool IsValidCipherSuiteForSignatureAlgorithms(int cipherSuite, IList sigAlgs)
+ {
+ int keyExchangeAlgorithm;
+ try
+ {
+ keyExchangeAlgorithm = GetKeyExchangeAlgorithm(cipherSuite);
+ }
+ catch (IOException e)
+ {
+ return true;
+ }
+
+ switch (keyExchangeAlgorithm)
+ {
+ case KeyExchangeAlgorithm.DH_anon:
+ case KeyExchangeAlgorithm.DH_anon_EXPORT:
+ case KeyExchangeAlgorithm.ECDH_anon:
+ return sigAlgs.Contains(SignatureAlgorithm.anonymous);
+
+ case KeyExchangeAlgorithm.DHE_RSA:
+ case KeyExchangeAlgorithm.DHE_RSA_EXPORT:
+ case KeyExchangeAlgorithm.ECDHE_RSA:
+ case KeyExchangeAlgorithm.SRP_RSA:
+ return sigAlgs.Contains(SignatureAlgorithm.rsa);
+
+ case KeyExchangeAlgorithm.DHE_DSS:
+ case KeyExchangeAlgorithm.DHE_DSS_EXPORT:
+ case KeyExchangeAlgorithm.SRP_DSS:
+ return sigAlgs.Contains(SignatureAlgorithm.dsa);
+
+ case KeyExchangeAlgorithm.ECDHE_ECDSA:
+ return sigAlgs.Contains(SignatureAlgorithm.ecdsa);
+
+ default:
+ return true;
+ }
+ }
+
+ public static bool IsValidCipherSuiteForVersion(int cipherSuite, ProtocolVersion serverVersion)
+ {
+ return GetMinimumVersion(cipherSuite).IsEqualOrEarlierVersionOf(serverVersion.GetEquivalentTLSVersion());
+ }
+
+ public static IList GetUsableSignatureAlgorithms(IList sigHashAlgs)
+ {
+ if (sigHashAlgs == null)
+ return GetAllSignatureAlgorithms();
+
+ IList v = Platform.CreateArrayList(4);
+ v.Add(SignatureAlgorithm.anonymous);
+ foreach (SignatureAndHashAlgorithm sigHashAlg in sigHashAlgs)
+ {
+ //if (sigHashAlg.Hash >= MINIMUM_HASH_STRICT)
+ {
+ byte sigAlg = sigHashAlg.Signature;
+ if (!v.Contains(sigAlg))
+ {
+ v.Add(sigAlg);
+ }
+ }
+ }
+ return v;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/UrlAndHash.cs b/bc-sharp-crypto/src/crypto/tls/UrlAndHash.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9ffd2cbf8f2d71293564bdb821884c0240c8797c
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/UrlAndHash.cs
@@ -0,0 +1,94 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * RFC 6066 5.
+ */
+ public class UrlAndHash
+ {
+ protected readonly string mUrl;
+ protected readonly byte[] mSha1Hash;
+
+ public UrlAndHash(string url, byte[] sha1Hash)
+ {
+ if (url == null || url.Length < 1 || url.Length >= (1 << 16))
+ throw new ArgumentException("must have length from 1 to (2^16 - 1)", "url");
+ if (sha1Hash != null && sha1Hash.Length != 20)
+ throw new ArgumentException("must have length == 20, if present", "sha1Hash");
+
+ this.mUrl = url;
+ this.mSha1Hash = sha1Hash;
+ }
+
+ public virtual string Url
+ {
+ get { return mUrl; }
+ }
+
+ public virtual byte[] Sha1Hash
+ {
+ get { return mSha1Hash; }
+ }
+
+ /**
+ * Encode this {@link UrlAndHash} to a {@link Stream}.
+ *
+ * @param output the {@link Stream} to encode to.
+ * @throws IOException
+ */
+ public virtual void Encode(Stream output)
+ {
+ byte[] urlEncoding = Strings.ToByteArray(this.mUrl);
+ TlsUtilities.WriteOpaque16(urlEncoding, output);
+
+ if (this.mSha1Hash == null)
+ {
+ TlsUtilities.WriteUint8(0, output);
+ }
+ else
+ {
+ TlsUtilities.WriteUint8(1, output);
+ output.Write(this.mSha1Hash, 0, this.mSha1Hash.Length);
+ }
+ }
+
+ /**
+ * Parse a {@link UrlAndHash} from a {@link Stream}.
+ *
+ * @param context
+ * the {@link TlsContext} of the current connection.
+ * @param input
+ * the {@link Stream} to parse from.
+ * @return a {@link UrlAndHash} object.
+ * @throws IOException
+ */
+ public static UrlAndHash Parse(TlsContext context, Stream input)
+ {
+ byte[] urlEncoding = TlsUtilities.ReadOpaque16(input);
+ if (urlEncoding.Length < 1)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ string url = Strings.FromByteArray(urlEncoding);
+
+ byte[] sha1Hash = null;
+ byte padding = TlsUtilities.ReadUint8(input);
+ switch (padding)
+ {
+ case 0:
+ if (TlsUtilities.IsTlsV12(context))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ break;
+ case 1:
+ sha1Hash = TlsUtilities.ReadFully(20, input);
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ return new UrlAndHash(url, sha1Hash);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/UseSrtpData.cs b/bc-sharp-crypto/src/crypto/tls/UseSrtpData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fe8f8accbad524141aec58987e906ffb448e68a1
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/UseSrtpData.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /**
+ * RFC 5764 4.1.1
+ */
+ public class UseSrtpData
+ {
+ protected readonly int[] mProtectionProfiles;
+ protected readonly byte[] mMki;
+
+ /**
+ * @param protectionProfiles see {@link SrtpProtectionProfile} for valid constants.
+ * @param mki valid lengths from 0 to 255.
+ */
+ public UseSrtpData(int[] protectionProfiles, byte[] mki)
+ {
+ if (protectionProfiles == null || protectionProfiles.Length < 1
+ || protectionProfiles.Length >= (1 << 15))
+ {
+ throw new ArgumentException("must have length from 1 to (2^15 - 1)", "protectionProfiles");
+ }
+
+ if (mki == null)
+ {
+ mki = TlsUtilities.EmptyBytes;
+ }
+ else if (mki.Length > 255)
+ {
+ throw new ArgumentException("cannot be longer than 255 bytes", "mki");
+ }
+
+ this.mProtectionProfiles = protectionProfiles;
+ this.mMki = mki;
+ }
+
+ /**
+ * @return see {@link SrtpProtectionProfile} for valid constants.
+ */
+ public virtual int[] ProtectionProfiles
+ {
+ get { return mProtectionProfiles; }
+ }
+
+ /**
+ * @return valid lengths from 0 to 255.
+ */
+ public virtual byte[] Mki
+ {
+ get { return mMki; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/tls/UserMappingType.cs b/bc-sharp-crypto/src/crypto/tls/UserMappingType.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6cff51736568170183b1c02e34b9ee22c94c48f7
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/tls/UserMappingType.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ /// RFC 4681
+ public abstract class UserMappingType
+ {
+ /*
+ * RFC 4681
+ */
+ public const byte upn_domain_hint = 64;
+ }
+}
diff --git a/bc-sharp-crypto/src/crypto/util/Pack.cs b/bc-sharp-crypto/src/crypto/util/Pack.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1b94fee0e332f509a7ac3a8b4706bb2481e34e7a
--- /dev/null
+++ b/bc-sharp-crypto/src/crypto/util/Pack.cs
@@ -0,0 +1,345 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Utilities
+{
+ internal sealed class Pack
+ {
+ private Pack()
+ {
+ }
+
+ internal static void UInt16_To_BE(ushort n, byte[] bs)
+ {
+ bs[0] = (byte)(n >> 8);
+ bs[1] = (byte)(n);
+ }
+
+ internal static void UInt16_To_BE(ushort n, byte[] bs, int off)
+ {
+ bs[off] = (byte)(n >> 8);
+ bs[off + 1] = (byte)(n);
+ }
+
+ internal static ushort BE_To_UInt16(byte[] bs)
+ {
+ uint n = (uint)bs[0] << 8
+ | (uint)bs[1];
+ return (ushort)n;
+ }
+
+ internal static ushort BE_To_UInt16(byte[] bs, int off)
+ {
+ uint n = (uint)bs[off] << 8
+ | (uint)bs[off + 1];
+ return (ushort)n;
+ }
+
+ internal static byte[] UInt32_To_BE(uint n)
+ {
+ byte[] bs = new byte[4];
+ UInt32_To_BE(n, bs, 0);
+ return bs;
+ }
+
+ internal static void UInt32_To_BE(uint n, byte[] bs)
+ {
+ bs[0] = (byte)(n >> 24);
+ bs[1] = (byte)(n >> 16);
+ bs[2] = (byte)(n >> 8);
+ bs[3] = (byte)(n);
+ }
+
+ internal static void UInt32_To_BE(uint n, byte[] bs, int off)
+ {
+ bs[off] = (byte)(n >> 24);
+ bs[off + 1] = (byte)(n >> 16);
+ bs[off + 2] = (byte)(n >> 8);
+ bs[off + 3] = (byte)(n);
+ }
+
+ internal static byte[] UInt32_To_BE(uint[] ns)
+ {
+ byte[] bs = new byte[4 * ns.Length];
+ UInt32_To_BE(ns, bs, 0);
+ return bs;
+ }
+
+ internal static void UInt32_To_BE(uint[] ns, byte[] bs, int off)
+ {
+ for (int i = 0; i < ns.Length; ++i)
+ {
+ UInt32_To_BE(ns[i], bs, off);
+ off += 4;
+ }
+ }
+
+ internal static uint BE_To_UInt32(byte[] bs)
+ {
+ return (uint)bs[0] << 24
+ | (uint)bs[1] << 16
+ | (uint)bs[2] << 8
+ | (uint)bs[3];
+ }
+
+ internal static uint BE_To_UInt32(byte[] bs, int off)
+ {
+ return (uint)bs[off] << 24
+ | (uint)bs[off + 1] << 16
+ | (uint)bs[off + 2] << 8
+ | (uint)bs[off + 3];
+ }
+
+ internal static void BE_To_UInt32(byte[] bs, int off, uint[] ns)
+ {
+ for (int i = 0; i < ns.Length; ++i)
+ {
+ ns[i] = BE_To_UInt32(bs, off);
+ off += 4;
+ }
+ }
+
+ internal static byte[] UInt64_To_BE(ulong n)
+ {
+ byte[] bs = new byte[8];
+ UInt64_To_BE(n, bs, 0);
+ return bs;
+ }
+
+ internal static void UInt64_To_BE(ulong n, byte[] bs)
+ {
+ UInt32_To_BE((uint)(n >> 32), bs);
+ UInt32_To_BE((uint)(n), bs, 4);
+ }
+
+ internal static void UInt64_To_BE(ulong n, byte[] bs, int off)
+ {
+ UInt32_To_BE((uint)(n >> 32), bs, off);
+ UInt32_To_BE((uint)(n), bs, off + 4);
+ }
+
+ internal static byte[] UInt64_To_BE(ulong[] ns)
+ {
+ byte[] bs = new byte[8 * ns.Length];
+ UInt64_To_BE(ns, bs, 0);
+ return bs;
+ }
+
+ internal static void UInt64_To_BE(ulong[] ns, byte[] bs, int off)
+ {
+ for (int i = 0; i < ns.Length; ++i)
+ {
+ UInt64_To_BE(ns[i], bs, off);
+ off += 8;
+ }
+ }
+
+ internal static ulong BE_To_UInt64(byte[] bs)
+ {
+ uint hi = BE_To_UInt32(bs);
+ uint lo = BE_To_UInt32(bs, 4);
+ return ((ulong)hi << 32) | (ulong)lo;
+ }
+
+ internal static ulong BE_To_UInt64(byte[] bs, int off)
+ {
+ uint hi = BE_To_UInt32(bs, off);
+ uint lo = BE_To_UInt32(bs, off + 4);
+ return ((ulong)hi << 32) | (ulong)lo;
+ }
+
+ internal static void BE_To_UInt64(byte[] bs, int off, ulong[] ns)
+ {
+ for (int i = 0; i < ns.Length; ++i)
+ {
+ ns[i] = BE_To_UInt64(bs, off);
+ off += 8;
+ }
+ }
+
+ internal static void UInt16_To_LE(ushort n, byte[] bs)
+ {
+ bs[0] = (byte)(n);
+ bs[1] = (byte)(n >> 8);
+ }
+
+ internal static void UInt16_To_LE(ushort n, byte[] bs, int off)
+ {
+ bs[off] = (byte)(n);
+ bs[off + 1] = (byte)(n >> 8);
+ }
+
+ internal static ushort LE_To_UInt16(byte[] bs)
+ {
+ uint n = (uint)bs[0]
+ | (uint)bs[1] << 8;
+ return (ushort)n;
+ }
+
+ internal static ushort LE_To_UInt16(byte[] bs, int off)
+ {
+ uint n = (uint)bs[off]
+ | (uint)bs[off + 1] << 8;
+ return (ushort)n;
+ }
+
+ internal static byte[] UInt32_To_LE(uint n)
+ {
+ byte[] bs = new byte[4];
+ UInt32_To_LE(n, bs, 0);
+ return bs;
+ }
+
+ internal static void UInt32_To_LE(uint n, byte[] bs)
+ {
+ bs[0] = (byte)(n);
+ bs[1] = (byte)(n >> 8);
+ bs[2] = (byte)(n >> 16);
+ bs[3] = (byte)(n >> 24);
+ }
+
+ internal static void UInt32_To_LE(uint n, byte[] bs, int off)
+ {
+ bs[off] = (byte)(n);
+ bs[off + 1] = (byte)(n >> 8);
+ bs[off + 2] = (byte)(n >> 16);
+ bs[off + 3] = (byte)(n >> 24);
+ }
+
+ internal static byte[] UInt32_To_LE(uint[] ns)
+ {
+ byte[] bs = new byte[4 * ns.Length];
+ UInt32_To_LE(ns, bs, 0);
+ return bs;
+ }
+
+ internal static void UInt32_To_LE(uint[] ns, byte[] bs, int off)
+ {
+ for (int i = 0; i < ns.Length; ++i)
+ {
+ UInt32_To_LE(ns[i], bs, off);
+ off += 4;
+ }
+ }
+
+ internal static uint LE_To_UInt32(byte[] bs)
+ {
+ return (uint)bs[0]
+ | (uint)bs[1] << 8
+ | (uint)bs[2] << 16
+ | (uint)bs[3] << 24;
+ }
+
+ internal static uint LE_To_UInt32(byte[] bs, int off)
+ {
+ return (uint)bs[off]
+ | (uint)bs[off + 1] << 8
+ | (uint)bs[off + 2] << 16
+ | (uint)bs[off + 3] << 24;
+ }
+
+ internal static void LE_To_UInt32(byte[] bs, int off, uint[] ns)
+ {
+ for (int i = 0; i < ns.Length; ++i)
+ {
+ ns[i] = LE_To_UInt32(bs, off);
+ off += 4;
+ }
+ }
+
+ internal static void LE_To_UInt32(byte[] bs, int bOff, uint[] ns, int nOff, int count)
+ {
+ for (int i = 0; i < count; ++i)
+ {
+ ns[nOff + i] = LE_To_UInt32(bs, bOff);
+ bOff += 4;
+ }
+ }
+
+ internal static uint[] LE_To_UInt32(byte[] bs, int off, int count)
+ {
+ uint[] ns = new uint[count];
+ for (int i = 0; i < ns.Length; ++i)
+ {
+ ns[i] = LE_To_UInt32(bs, off);
+ off += 4;
+ }
+ return ns;
+ }
+
+ internal static byte[] UInt64_To_LE(ulong n)
+ {
+ byte[] bs = new byte[8];
+ UInt64_To_LE(n, bs, 0);
+ return bs;
+ }
+
+ internal static void UInt64_To_LE(ulong n, byte[] bs)
+ {
+ UInt32_To_LE((uint)(n), bs);
+ UInt32_To_LE((uint)(n >> 32), bs, 4);
+ }
+
+ internal static void UInt64_To_LE(ulong n, byte[] bs, int off)
+ {
+ UInt32_To_LE((uint)(n), bs, off);
+ UInt32_To_LE((uint)(n >> 32), bs, off + 4);
+ }
+
+ internal static byte[] UInt64_To_LE(ulong[] ns)
+ {
+ byte[] bs = new byte[8 * ns.Length];
+ UInt64_To_LE(ns, bs, 0);
+ return bs;
+ }
+
+ internal static void UInt64_To_LE(ulong[] ns, byte[] bs, int off)
+ {
+ for (int i = 0; i < ns.Length; ++i)
+ {
+ UInt64_To_LE(ns[i], bs, off);
+ off += 8;
+ }
+ }
+
+ internal static void UInt64_To_LE(ulong[] ns, int nsOff, int nsLen, byte[] bs, int bsOff)
+ {
+ for (int i = 0; i < nsLen; ++i)
+ {
+ UInt64_To_LE(ns[nsOff + i], bs, bsOff);
+ bsOff += 8;
+ }
+ }
+
+ internal static ulong LE_To_UInt64(byte[] bs)
+ {
+ uint lo = LE_To_UInt32(bs);
+ uint hi = LE_To_UInt32(bs, 4);
+ return ((ulong)hi << 32) | (ulong)lo;
+ }
+
+ internal static ulong LE_To_UInt64(byte[] bs, int off)
+ {
+ uint lo = LE_To_UInt32(bs, off);
+ uint hi = LE_To_UInt32(bs, off + 4);
+ return ((ulong)hi << 32) | (ulong)lo;
+ }
+
+ internal static void LE_To_UInt64(byte[] bs, int off, ulong[] ns)
+ {
+ for (int i = 0; i < ns.Length; ++i)
+ {
+ ns[i] = LE_To_UInt64(bs, off);
+ off += 8;
+ }
+ }
+
+ internal static void LE_To_UInt64(byte[] bs, int bsOff, ulong[] ns, int nsOff, int nsLen)
+ {
+ for (int i = 0; i < nsLen; ++i)
+ {
+ ns[nsOff + i] = LE_To_UInt64(bs, bsOff);
+ bsOff += 8;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/BigInteger.cs b/bc-sharp-crypto/src/math/BigInteger.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b35701fb37138d8ab34a51e00192c9f24264c2ec
--- /dev/null
+++ b/bc-sharp-crypto/src/math/BigInteger.cs
@@ -0,0 +1,3592 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.Globalization;
+using System.Text;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class BigInteger
+ {
+ // The first few odd primes
+ /*
+ 3 5 7 11 13 17 19 23 29
+ 31 37 41 43 47 53 59 61 67 71
+ 73 79 83 89 97 101 103 107 109 113
+ 127 131 137 139 149 151 157 163 167 173
+ 179 181 191 193 197 199 211 223 227 229
+ 233 239 241 251 257 263 269 271 277 281
+ 283 293 307 311 313 317 331 337 347 349
+ 353 359 367 373 379 383 389 397 401 409
+ 419 421 431 433 439 443 449 457 461 463
+ 467 479 487 491 499 503 509 521 523 541
+ 547 557 563 569 571 577 587 593 599 601
+ 607 613 617 619 631 641 643 647 653 659
+ 661 673 677 683 691 701 709 719 727 733
+ 739 743 751 757 761 769 773 787 797 809
+ 811 821 823 827 829 839 853 857 859 863
+ 877 881 883 887 907 911 919 929 937 941
+ 947 953 967 971 977 983 991 997 1009
+ 1013 1019 1021 1031 1033 1039 1049 1051
+ 1061 1063 1069 1087 1091 1093 1097 1103
+ 1109 1117 1123 1129 1151 1153 1163 1171
+ 1181 1187 1193 1201 1213 1217 1223 1229
+ 1231 1237 1249 1259 1277 1279 1283 1289
+ */
+
+ // Each list has a product < 2^31
+ internal static readonly int[][] primeLists = new int[][]
+ {
+ new int[]{ 3, 5, 7, 11, 13, 17, 19, 23 },
+ new int[]{ 29, 31, 37, 41, 43 },
+ new int[]{ 47, 53, 59, 61, 67 },
+ new int[]{ 71, 73, 79, 83 },
+ new int[]{ 89, 97, 101, 103 },
+
+ new int[]{ 107, 109, 113, 127 },
+ new int[]{ 131, 137, 139, 149 },
+ new int[]{ 151, 157, 163, 167 },
+ new int[]{ 173, 179, 181, 191 },
+ new int[]{ 193, 197, 199, 211 },
+
+ new int[]{ 223, 227, 229 },
+ new int[]{ 233, 239, 241 },
+ new int[]{ 251, 257, 263 },
+ new int[]{ 269, 271, 277 },
+ new int[]{ 281, 283, 293 },
+
+ new int[]{ 307, 311, 313 },
+ new int[]{ 317, 331, 337 },
+ new int[]{ 347, 349, 353 },
+ new int[]{ 359, 367, 373 },
+ new int[]{ 379, 383, 389 },
+
+ new int[]{ 397, 401, 409 },
+ new int[]{ 419, 421, 431 },
+ new int[]{ 433, 439, 443 },
+ new int[]{ 449, 457, 461 },
+ new int[]{ 463, 467, 479 },
+
+ new int[]{ 487, 491, 499 },
+ new int[]{ 503, 509, 521 },
+ new int[]{ 523, 541, 547 },
+ new int[]{ 557, 563, 569 },
+ new int[]{ 571, 577, 587 },
+
+ new int[]{ 593, 599, 601 },
+ new int[]{ 607, 613, 617 },
+ new int[]{ 619, 631, 641 },
+ new int[]{ 643, 647, 653 },
+ new int[]{ 659, 661, 673 },
+
+ new int[]{ 677, 683, 691 },
+ new int[]{ 701, 709, 719 },
+ new int[]{ 727, 733, 739 },
+ new int[]{ 743, 751, 757 },
+ new int[]{ 761, 769, 773 },
+
+ new int[]{ 787, 797, 809 },
+ new int[]{ 811, 821, 823 },
+ new int[]{ 827, 829, 839 },
+ new int[]{ 853, 857, 859 },
+ new int[]{ 863, 877, 881 },
+
+ new int[]{ 883, 887, 907 },
+ new int[]{ 911, 919, 929 },
+ new int[]{ 937, 941, 947 },
+ new int[]{ 953, 967, 971 },
+ new int[]{ 977, 983, 991 },
+
+ new int[]{ 997, 1009, 1013 },
+ new int[]{ 1019, 1021, 1031 },
+ new int[]{ 1033, 1039, 1049 },
+ new int[]{ 1051, 1061, 1063 },
+ new int[]{ 1069, 1087, 1091 },
+
+ new int[]{ 1093, 1097, 1103 },
+ new int[]{ 1109, 1117, 1123 },
+ new int[]{ 1129, 1151, 1153 },
+ new int[]{ 1163, 1171, 1181 },
+ new int[]{ 1187, 1193, 1201 },
+
+ new int[]{ 1213, 1217, 1223 },
+ new int[]{ 1229, 1231, 1237 },
+ new int[]{ 1249, 1259, 1277 },
+ new int[]{ 1279, 1283, 1289 },
+ };
+
+ internal static readonly int[] primeProducts;
+
+ private const long IMASK = 0xFFFFFFFFL;
+ private const ulong UIMASK = 0xFFFFFFFFUL;
+
+ private static readonly int[] ZeroMagnitude = new int[0];
+ private static readonly byte[] ZeroEncoding = new byte[0];
+
+ private static readonly BigInteger[] SMALL_CONSTANTS = new BigInteger[17];
+ public static readonly BigInteger Zero;
+ public static readonly BigInteger One;
+ public static readonly BigInteger Two;
+ public static readonly BigInteger Three;
+ public static readonly BigInteger Ten;
+
+ //private readonly static byte[] BitCountTable =
+ //{
+ // 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+ // 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ // 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ // 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ // 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ // 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ // 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ // 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ // 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+ // 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ // 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ // 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ // 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+ // 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ // 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+ // 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+ //};
+
+ private readonly static byte[] BitLengthTable =
+ {
+ 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
+ };
+
+ // TODO Parse radix-2 64 bits at a time and radix-8 63 bits at a time
+ private const int chunk2 = 1, chunk8 = 1, chunk10 = 19, chunk16 = 16;
+ private static readonly BigInteger radix2, radix2E, radix8, radix8E, radix10, radix10E, radix16, radix16E;
+
+ private static readonly SecureRandom RandomSource = new SecureRandom();
+
+ /*
+ * These are the threshold bit-lengths (of an exponent) where we increase the window size.
+ * They are calculated according to the expected savings in multiplications.
+ * Some squares will also be saved on average, but we offset these against the extra storage costs.
+ */
+ private static readonly int[] ExpWindowThresholds = { 7, 25, 81, 241, 673, 1793, 4609, Int32.MaxValue };
+
+ private const int BitsPerByte = 8;
+ private const int BitsPerInt = 32;
+ private const int BytesPerInt = 4;
+
+ static BigInteger()
+ {
+ Zero = new BigInteger(0, ZeroMagnitude, false);
+ Zero.nBits = 0; Zero.nBitLength = 0;
+
+ SMALL_CONSTANTS[0] = Zero;
+ for (uint i = 1; i < SMALL_CONSTANTS.Length; ++i)
+ {
+ SMALL_CONSTANTS[i] = CreateUValueOf(i);
+ }
+
+ One = SMALL_CONSTANTS[1];
+ Two = SMALL_CONSTANTS[2];
+ Three = SMALL_CONSTANTS[3];
+ Ten = SMALL_CONSTANTS[10];
+
+ radix2 = ValueOf(2);
+ radix2E = radix2.Pow(chunk2);
+
+ radix8 = ValueOf(8);
+ radix8E = radix8.Pow(chunk8);
+
+ radix10 = ValueOf(10);
+ radix10E = radix10.Pow(chunk10);
+
+ radix16 = ValueOf(16);
+ radix16E = radix16.Pow(chunk16);
+
+ primeProducts = new int[primeLists.Length];
+
+ for (int i = 0; i < primeLists.Length; ++i)
+ {
+ int[] primeList = primeLists[i];
+ int product = primeList[0];
+ for (int j = 1; j < primeList.Length; ++j)
+ {
+ product *= primeList[j];
+ }
+ primeProducts[i] = product;
+ }
+ }
+
+ private int[] magnitude; // array of ints with [0] being the most significant
+ private int sign; // -1 means -ve; +1 means +ve; 0 means 0;
+ private int nBits = -1; // cache BitCount() value
+ private int nBitLength = -1; // cache BitLength() value
+ private int mQuote = 0; // -m^(-1) mod b, b = 2^32 (see Montgomery mult.), 0 when uninitialised
+
+ private static int GetByteLength(
+ int nBits)
+ {
+ return (nBits + BitsPerByte - 1) / BitsPerByte;
+ }
+
+ internal static BigInteger Arbitrary(int sizeInBits)
+ {
+ return new BigInteger(sizeInBits, RandomSource);
+ }
+
+ private BigInteger(
+ int signum,
+ int[] mag,
+ bool checkMag)
+ {
+ if (checkMag)
+ {
+ int i = 0;
+ while (i < mag.Length && mag[i] == 0)
+ {
+ ++i;
+ }
+
+ if (i == mag.Length)
+ {
+ this.sign = 0;
+ this.magnitude = ZeroMagnitude;
+ }
+ else
+ {
+ this.sign = signum;
+
+ if (i == 0)
+ {
+ this.magnitude = mag;
+ }
+ else
+ {
+ // strip leading 0 words
+ this.magnitude = new int[mag.Length - i];
+ Array.Copy(mag, i, this.magnitude, 0, this.magnitude.Length);
+ }
+ }
+ }
+ else
+ {
+ this.sign = signum;
+ this.magnitude = mag;
+ }
+ }
+
+ public BigInteger(
+ string value)
+ : this(value, 10)
+ {
+ }
+
+ public BigInteger(
+ string str,
+ int radix)
+ {
+ if (str.Length == 0)
+ throw new FormatException("Zero length BigInteger");
+
+ NumberStyles style;
+ int chunk;
+ BigInteger r;
+ BigInteger rE;
+
+ switch (radix)
+ {
+ case 2:
+ // Is there anyway to restrict to binary digits?
+ style = NumberStyles.Integer;
+ chunk = chunk2;
+ r = radix2;
+ rE = radix2E;
+ break;
+ case 8:
+ // Is there anyway to restrict to octal digits?
+ style = NumberStyles.Integer;
+ chunk = chunk8;
+ r = radix8;
+ rE = radix8E;
+ break;
+ case 10:
+ // This style seems to handle spaces and minus sign already (our processing redundant?)
+ style = NumberStyles.Integer;
+ chunk = chunk10;
+ r = radix10;
+ rE = radix10E;
+ break;
+ case 16:
+ // TODO Should this be HexNumber?
+ style = NumberStyles.AllowHexSpecifier;
+ chunk = chunk16;
+ r = radix16;
+ rE = radix16E;
+ break;
+ default:
+ throw new FormatException("Only bases 2, 8, 10, or 16 allowed");
+ }
+
+
+ int index = 0;
+ sign = 1;
+
+ if (str[0] == '-')
+ {
+ if (str.Length == 1)
+ throw new FormatException("Zero length BigInteger");
+
+ sign = -1;
+ index = 1;
+ }
+
+ // strip leading zeros from the string str
+ while (index < str.Length && Int32.Parse(str[index].ToString(), style) == 0)
+ {
+ index++;
+ }
+
+ if (index >= str.Length)
+ {
+ // zero value - we're done
+ sign = 0;
+ magnitude = ZeroMagnitude;
+ return;
+ }
+
+ //////
+ // could we work out the max number of ints required to store
+ // str.Length digits in the given base, then allocate that
+ // storage in one hit?, then Generate the magnitude in one hit too?
+ //////
+
+ BigInteger b = Zero;
+
+
+ int next = index + chunk;
+
+ if (next <= str.Length)
+ {
+ do
+ {
+ string s = str.Substring(index, chunk);
+ ulong i = ulong.Parse(s, style);
+ BigInteger bi = CreateUValueOf(i);
+
+ switch (radix)
+ {
+ case 2:
+ // TODO Need this because we are parsing in radix 10 above
+ if (i >= 2)
+ throw new FormatException("Bad character in radix 2 string: " + s);
+
+ // TODO Parse 64 bits at a time
+ b = b.ShiftLeft(1);
+ break;
+ case 8:
+ // TODO Need this because we are parsing in radix 10 above
+ if (i >= 8)
+ throw new FormatException("Bad character in radix 8 string: " + s);
+
+ // TODO Parse 63 bits at a time
+ b = b.ShiftLeft(3);
+ break;
+ case 16:
+ b = b.ShiftLeft(64);
+ break;
+ default:
+ b = b.Multiply(rE);
+ break;
+ }
+
+ b = b.Add(bi);
+
+ index = next;
+ next += chunk;
+ }
+ while (next <= str.Length);
+ }
+
+ if (index < str.Length)
+ {
+ string s = str.Substring(index);
+ ulong i = ulong.Parse(s, style);
+ BigInteger bi = CreateUValueOf(i);
+
+ if (b.sign > 0)
+ {
+ if (radix == 2)
+ {
+ // NB: Can't reach here since we are parsing one char at a time
+ Debug.Assert(false);
+
+ // TODO Parse all bits at once
+// b = b.ShiftLeft(s.Length);
+ }
+ else if (radix == 8)
+ {
+ // NB: Can't reach here since we are parsing one char at a time
+ Debug.Assert(false);
+
+ // TODO Parse all bits at once
+// b = b.ShiftLeft(s.Length * 3);
+ }
+ else if (radix == 16)
+ {
+ b = b.ShiftLeft(s.Length << 2);
+ }
+ else
+ {
+ b = b.Multiply(r.Pow(s.Length));
+ }
+
+ b = b.Add(bi);
+ }
+ else
+ {
+ b = bi;
+ }
+ }
+
+ // Note: This is the previous (slower) algorithm
+// while (index < value.Length)
+// {
+// char c = value[index];
+// string s = c.ToString();
+// int i = Int32.Parse(s, style);
+//
+// b = b.Multiply(r).Add(ValueOf(i));
+// index++;
+// }
+
+ magnitude = b.magnitude;
+ }
+
+ public BigInteger(
+ byte[] bytes)
+ : this(bytes, 0, bytes.Length)
+ {
+ }
+
+ public BigInteger(
+ byte[] bytes,
+ int offset,
+ int length)
+ {
+ if (length == 0)
+ throw new FormatException("Zero length BigInteger");
+
+ // TODO Move this processing into MakeMagnitude (provide sign argument)
+ if ((sbyte)bytes[offset] < 0)
+ {
+ this.sign = -1;
+
+ int end = offset + length;
+
+ int iBval;
+ // strip leading sign bytes
+ for (iBval = offset; iBval < end && ((sbyte)bytes[iBval] == -1); iBval++)
+ {
+ }
+
+ if (iBval >= end)
+ {
+ this.magnitude = One.magnitude;
+ }
+ else
+ {
+ int numBytes = end - iBval;
+ byte[] inverse = new byte[numBytes];
+
+ int index = 0;
+ while (index < numBytes)
+ {
+ inverse[index++] = (byte)~bytes[iBval++];
+ }
+
+ Debug.Assert(iBval == end);
+
+ while (inverse[--index] == byte.MaxValue)
+ {
+ inverse[index] = byte.MinValue;
+ }
+
+ inverse[index]++;
+
+ this.magnitude = MakeMagnitude(inverse, 0, inverse.Length);
+ }
+ }
+ else
+ {
+ // strip leading zero bytes and return magnitude bytes
+ this.magnitude = MakeMagnitude(bytes, offset, length);
+ this.sign = this.magnitude.Length > 0 ? 1 : 0;
+ }
+ }
+
+ private static int[] MakeMagnitude(
+ byte[] bytes,
+ int offset,
+ int length)
+ {
+ int end = offset + length;
+
+ // strip leading zeros
+ int firstSignificant;
+ for (firstSignificant = offset; firstSignificant < end
+ && bytes[firstSignificant] == 0; firstSignificant++)
+ {
+ }
+
+ if (firstSignificant >= end)
+ {
+ return ZeroMagnitude;
+ }
+
+ int nInts = (end - firstSignificant + 3) / BytesPerInt;
+ int bCount = (end - firstSignificant) % BytesPerInt;
+ if (bCount == 0)
+ {
+ bCount = BytesPerInt;
+ }
+
+ if (nInts < 1)
+ {
+ return ZeroMagnitude;
+ }
+
+ int[] mag = new int[nInts];
+
+ int v = 0;
+ int magnitudeIndex = 0;
+ for (int i = firstSignificant; i < end; ++i)
+ {
+ v <<= 8;
+ v |= bytes[i] & 0xff;
+ bCount--;
+ if (bCount <= 0)
+ {
+ mag[magnitudeIndex] = v;
+ magnitudeIndex++;
+ bCount = BytesPerInt;
+ v = 0;
+ }
+ }
+
+ if (magnitudeIndex < mag.Length)
+ {
+ mag[magnitudeIndex] = v;
+ }
+
+ return mag;
+ }
+
+ public BigInteger(
+ int sign,
+ byte[] bytes)
+ : this(sign, bytes, 0, bytes.Length)
+ {
+ }
+
+ public BigInteger(
+ int sign,
+ byte[] bytes,
+ int offset,
+ int length)
+ {
+ if (sign < -1 || sign > 1)
+ throw new FormatException("Invalid sign value");
+
+ if (sign == 0)
+ {
+ this.sign = 0;
+ this.magnitude = ZeroMagnitude;
+ }
+ else
+ {
+ // copy bytes
+ this.magnitude = MakeMagnitude(bytes, offset, length);
+ this.sign = this.magnitude.Length < 1 ? 0 : sign;
+ }
+ }
+
+ public BigInteger(
+ int sizeInBits,
+ Random random)
+ {
+ if (sizeInBits < 0)
+ throw new ArgumentException("sizeInBits must be non-negative");
+
+ this.nBits = -1;
+ this.nBitLength = -1;
+
+ if (sizeInBits == 0)
+ {
+ this.sign = 0;
+ this.magnitude = ZeroMagnitude;
+ return;
+ }
+
+ int nBytes = GetByteLength(sizeInBits);
+ byte[] b = new byte[nBytes];
+ random.NextBytes(b);
+
+ // strip off any excess bits in the MSB
+ int xBits = BitsPerByte * nBytes - sizeInBits;
+ b[0] &= (byte)(255U >> xBits);
+
+ this.magnitude = MakeMagnitude(b, 0, b.Length);
+ this.sign = this.magnitude.Length < 1 ? 0 : 1;
+ }
+
+ public BigInteger(
+ int bitLength,
+ int certainty,
+ Random random)
+ {
+ if (bitLength < 2)
+ throw new ArithmeticException("bitLength < 2");
+
+ this.sign = 1;
+ this.nBitLength = bitLength;
+
+ if (bitLength == 2)
+ {
+ this.magnitude = random.Next(2) == 0
+ ? Two.magnitude
+ : Three.magnitude;
+ return;
+ }
+
+ int nBytes = GetByteLength(bitLength);
+ byte[] b = new byte[nBytes];
+
+ int xBits = BitsPerByte * nBytes - bitLength;
+ byte mask = (byte)(255U >> xBits);
+ byte lead = (byte)(1 << (7 - xBits));
+
+ for (;;)
+ {
+ random.NextBytes(b);
+
+ // strip off any excess bits in the MSB
+ b[0] &= mask;
+
+ // ensure the leading bit is 1 (to meet the strength requirement)
+ b[0] |= lead;
+
+ // ensure the trailing bit is 1 (i.e. must be odd)
+ b[nBytes - 1] |= 1;
+
+ this.magnitude = MakeMagnitude(b, 0, b.Length);
+ this.nBits = -1;
+ this.mQuote = 0;
+
+ if (certainty < 1)
+ break;
+
+ if (CheckProbablePrime(certainty, random, true))
+ break;
+
+ for (int j = 1; j < (magnitude.Length - 1); ++j)
+ {
+ this.magnitude[j] ^= random.Next();
+
+ if (CheckProbablePrime(certainty, random, true))
+ return;
+ }
+ }
+ }
+
+ public BigInteger Abs()
+ {
+ return sign >= 0 ? this : Negate();
+ }
+
+ /**
+ * return a = a + b - b preserved.
+ */
+ private static int[] AddMagnitudes(
+ int[] a,
+ int[] b)
+ {
+ int tI = a.Length - 1;
+ int vI = b.Length - 1;
+ long m = 0;
+
+ while (vI >= 0)
+ {
+ m += ((long)(uint)a[tI] + (long)(uint)b[vI--]);
+ a[tI--] = (int)m;
+ m = (long)((ulong)m >> 32);
+ }
+
+ if (m != 0)
+ {
+ while (tI >= 0 && ++a[tI--] == 0)
+ {
+ }
+ }
+
+ return a;
+ }
+
+ public BigInteger Add(
+ BigInteger value)
+ {
+ if (this.sign == 0)
+ return value;
+
+ if (this.sign != value.sign)
+ {
+ if (value.sign == 0)
+ return this;
+
+ if (value.sign < 0)
+ return Subtract(value.Negate());
+
+ return value.Subtract(Negate());
+ }
+
+ return AddToMagnitude(value.magnitude);
+ }
+
+ private BigInteger AddToMagnitude(
+ int[] magToAdd)
+ {
+ int[] big, small;
+ if (this.magnitude.Length < magToAdd.Length)
+ {
+ big = magToAdd;
+ small = this.magnitude;
+ }
+ else
+ {
+ big = this.magnitude;
+ small = magToAdd;
+ }
+
+ // Conservatively avoid over-allocation when no overflow possible
+ uint limit = uint.MaxValue;
+ if (big.Length == small.Length)
+ limit -= (uint) small[0];
+
+ bool possibleOverflow = (uint) big[0] >= limit;
+
+ int[] bigCopy;
+ if (possibleOverflow)
+ {
+ bigCopy = new int[big.Length + 1];
+ big.CopyTo(bigCopy, 1);
+ }
+ else
+ {
+ bigCopy = (int[]) big.Clone();
+ }
+
+ bigCopy = AddMagnitudes(bigCopy, small);
+
+ return new BigInteger(this.sign, bigCopy, possibleOverflow);
+ }
+
+ public BigInteger And(
+ BigInteger value)
+ {
+ if (this.sign == 0 || value.sign == 0)
+ {
+ return Zero;
+ }
+
+ int[] aMag = this.sign > 0
+ ? this.magnitude
+ : Add(One).magnitude;
+
+ int[] bMag = value.sign > 0
+ ? value.magnitude
+ : value.Add(One).magnitude;
+
+ bool resultNeg = sign < 0 && value.sign < 0;
+ int resultLength = System.Math.Max(aMag.Length, bMag.Length);
+ int[] resultMag = new int[resultLength];
+
+ int aStart = resultMag.Length - aMag.Length;
+ int bStart = resultMag.Length - bMag.Length;
+
+ for (int i = 0; i < resultMag.Length; ++i)
+ {
+ int aWord = i >= aStart ? aMag[i - aStart] : 0;
+ int bWord = i >= bStart ? bMag[i - bStart] : 0;
+
+ if (this.sign < 0)
+ {
+ aWord = ~aWord;
+ }
+
+ if (value.sign < 0)
+ {
+ bWord = ~bWord;
+ }
+
+ resultMag[i] = aWord & bWord;
+
+ if (resultNeg)
+ {
+ resultMag[i] = ~resultMag[i];
+ }
+ }
+
+ BigInteger result = new BigInteger(1, resultMag, true);
+
+ // TODO Optimise this case
+ if (resultNeg)
+ {
+ result = result.Not();
+ }
+
+ return result;
+ }
+
+ public BigInteger AndNot(
+ BigInteger val)
+ {
+ return And(val.Not());
+ }
+
+ public int BitCount
+ {
+ get
+ {
+ if (nBits == -1)
+ {
+ if (sign < 0)
+ {
+ // TODO Optimise this case
+ nBits = Not().BitCount;
+ }
+ else
+ {
+ int sum = 0;
+ for (int i = 0; i < magnitude.Length; ++i)
+ {
+ sum += BitCnt(magnitude[i]);
+ }
+ nBits = sum;
+ }
+ }
+
+ return nBits;
+ }
+ }
+
+ public static int BitCnt(int i)
+ {
+ uint u = (uint)i;
+ u = u - ((u >> 1) & 0x55555555);
+ u = (u & 0x33333333) + ((u >> 2) & 0x33333333);
+ u = (u + (u >> 4)) & 0x0f0f0f0f;
+ u += (u >> 8);
+ u += (u >> 16);
+ u &= 0x3f;
+ return (int)u;
+ }
+
+ private static int CalcBitLength(int sign, int indx, int[] mag)
+ {
+ for (;;)
+ {
+ if (indx >= mag.Length)
+ return 0;
+
+ if (mag[indx] != 0)
+ break;
+
+ ++indx;
+ }
+
+ // bit length for everything after the first int
+ int bitLength = 32 * ((mag.Length - indx) - 1);
+
+ // and determine bitlength of first int
+ int firstMag = mag[indx];
+ bitLength += BitLen(firstMag);
+
+ // Check for negative powers of two
+ if (sign < 0 && ((firstMag & -firstMag) == firstMag))
+ {
+ do
+ {
+ if (++indx >= mag.Length)
+ {
+ --bitLength;
+ break;
+ }
+ }
+ while (mag[indx] == 0);
+ }
+
+ return bitLength;
+ }
+
+ public int BitLength
+ {
+ get
+ {
+ if (nBitLength == -1)
+ {
+ nBitLength = sign == 0
+ ? 0
+ : CalcBitLength(sign, 0, magnitude);
+ }
+
+ return nBitLength;
+ }
+ }
+
+ //
+ // BitLen(value) is the number of bits in value.
+ //
+ internal static int BitLen(int w)
+ {
+ uint v = (uint)w;
+ uint t = v >> 24;
+ if (t != 0)
+ return 24 + BitLengthTable[t];
+ t = v >> 16;
+ if (t != 0)
+ return 16 + BitLengthTable[t];
+ t = v >> 8;
+ if (t != 0)
+ return 8 + BitLengthTable[t];
+ return BitLengthTable[v];
+ }
+
+ private bool QuickPow2Check()
+ {
+ return sign > 0 && nBits == 1;
+ }
+
+ public int CompareTo(
+ object obj)
+ {
+ return CompareTo((BigInteger)obj);
+ }
+
+ /**
+ * unsigned comparison on two arrays - note the arrays may
+ * start with leading zeros.
+ */
+ private static int CompareTo(
+ int xIndx,
+ int[] x,
+ int yIndx,
+ int[] y)
+ {
+ while (xIndx != x.Length && x[xIndx] == 0)
+ {
+ xIndx++;
+ }
+
+ while (yIndx != y.Length && y[yIndx] == 0)
+ {
+ yIndx++;
+ }
+
+ return CompareNoLeadingZeroes(xIndx, x, yIndx, y);
+ }
+
+ private static int CompareNoLeadingZeroes(
+ int xIndx,
+ int[] x,
+ int yIndx,
+ int[] y)
+ {
+ int diff = (x.Length - y.Length) - (xIndx - yIndx);
+
+ if (diff != 0)
+ {
+ return diff < 0 ? -1 : 1;
+ }
+
+ // lengths of magnitudes the same, test the magnitude values
+
+ while (xIndx < x.Length)
+ {
+ uint v1 = (uint)x[xIndx++];
+ uint v2 = (uint)y[yIndx++];
+
+ if (v1 != v2)
+ return v1 < v2 ? -1 : 1;
+ }
+
+ return 0;
+ }
+
+ public int CompareTo(
+ BigInteger value)
+ {
+ return sign < value.sign ? -1
+ : sign > value.sign ? 1
+ : sign == 0 ? 0
+ : sign * CompareNoLeadingZeroes(0, magnitude, 0, value.magnitude);
+ }
+
+ /**
+ * return z = x / y - done in place (z value preserved, x contains the
+ * remainder)
+ */
+ private int[] Divide(
+ int[] x,
+ int[] y)
+ {
+ int xStart = 0;
+ while (xStart < x.Length && x[xStart] == 0)
+ {
+ ++xStart;
+ }
+
+ int yStart = 0;
+ while (yStart < y.Length && y[yStart] == 0)
+ {
+ ++yStart;
+ }
+
+ Debug.Assert(yStart < y.Length);
+
+ int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
+ int[] count;
+
+ if (xyCmp > 0)
+ {
+ int yBitLength = CalcBitLength(1, yStart, y);
+ int xBitLength = CalcBitLength(1, xStart, x);
+ int shift = xBitLength - yBitLength;
+
+ int[] iCount;
+ int iCountStart = 0;
+
+ int[] c;
+ int cStart = 0;
+ int cBitLength = yBitLength;
+ if (shift > 0)
+ {
+// iCount = ShiftLeft(One.magnitude, shift);
+ iCount = new int[(shift >> 5) + 1];
+ iCount[0] = 1 << (shift % 32);
+
+ c = ShiftLeft(y, shift);
+ cBitLength += shift;
+ }
+ else
+ {
+ iCount = new int[] { 1 };
+
+ int len = y.Length - yStart;
+ c = new int[len];
+ Array.Copy(y, yStart, c, 0, len);
+ }
+
+ count = new int[iCount.Length];
+
+ for (;;)
+ {
+ if (cBitLength < xBitLength
+ || CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0)
+ {
+ Subtract(xStart, x, cStart, c);
+ AddMagnitudes(count, iCount);
+
+ while (x[xStart] == 0)
+ {
+ if (++xStart == x.Length)
+ return count;
+ }
+
+ //xBitLength = CalcBitLength(xStart, x);
+ xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]);
+
+ if (xBitLength <= yBitLength)
+ {
+ if (xBitLength < yBitLength)
+ return count;
+
+ xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
+
+ if (xyCmp <= 0)
+ break;
+ }
+ }
+
+ shift = cBitLength - xBitLength;
+
+ // NB: The case where c[cStart] is 1-bit is harmless
+ if (shift == 1)
+ {
+ uint firstC = (uint) c[cStart] >> 1;
+ uint firstX = (uint) x[xStart];
+ if (firstC > firstX)
+ ++shift;
+ }
+
+ if (shift < 2)
+ {
+ ShiftRightOneInPlace(cStart, c);
+ --cBitLength;
+ ShiftRightOneInPlace(iCountStart, iCount);
+ }
+ else
+ {
+ ShiftRightInPlace(cStart, c, shift);
+ cBitLength -= shift;
+ ShiftRightInPlace(iCountStart, iCount, shift);
+ }
+
+ //cStart = c.Length - ((cBitLength + 31) / 32);
+ while (c[cStart] == 0)
+ {
+ ++cStart;
+ }
+
+ while (iCount[iCountStart] == 0)
+ {
+ ++iCountStart;
+ }
+ }
+ }
+ else
+ {
+ count = new int[1];
+ }
+
+ if (xyCmp == 0)
+ {
+ AddMagnitudes(count, One.magnitude);
+ Array.Clear(x, xStart, x.Length - xStart);
+ }
+
+ return count;
+ }
+
+ public BigInteger Divide(
+ BigInteger val)
+ {
+ if (val.sign == 0)
+ throw new ArithmeticException("Division by zero error");
+
+ if (sign == 0)
+ return Zero;
+
+ if (val.QuickPow2Check()) // val is power of two
+ {
+ BigInteger result = this.Abs().ShiftRight(val.Abs().BitLength - 1);
+ return val.sign == this.sign ? result : result.Negate();
+ }
+
+ int[] mag = (int[]) this.magnitude.Clone();
+
+ return new BigInteger(this.sign * val.sign, Divide(mag, val.magnitude), true);
+ }
+
+ public BigInteger[] DivideAndRemainder(
+ BigInteger val)
+ {
+ if (val.sign == 0)
+ throw new ArithmeticException("Division by zero error");
+
+ BigInteger[] biggies = new BigInteger[2];
+
+ if (sign == 0)
+ {
+ biggies[0] = Zero;
+ biggies[1] = Zero;
+ }
+ else if (val.QuickPow2Check()) // val is power of two
+ {
+ int e = val.Abs().BitLength - 1;
+ BigInteger quotient = this.Abs().ShiftRight(e);
+ int[] remainder = this.LastNBits(e);
+
+ biggies[0] = val.sign == this.sign ? quotient : quotient.Negate();
+ biggies[1] = new BigInteger(this.sign, remainder, true);
+ }
+ else
+ {
+ int[] remainder = (int[]) this.magnitude.Clone();
+ int[] quotient = Divide(remainder, val.magnitude);
+
+ biggies[0] = new BigInteger(this.sign * val.sign, quotient, true);
+ biggies[1] = new BigInteger(this.sign, remainder, true);
+ }
+
+ return biggies;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ BigInteger biggie = obj as BigInteger;
+ if (biggie == null)
+ return false;
+
+ return sign == biggie.sign && IsEqualMagnitude(biggie);
+ }
+
+ private bool IsEqualMagnitude(BigInteger x)
+ {
+ int[] xMag = x.magnitude;
+ if (magnitude.Length != x.magnitude.Length)
+ return false;
+ for (int i = 0; i < magnitude.Length; i++)
+ {
+ if (magnitude[i] != x.magnitude[i])
+ return false;
+ }
+ return true;
+ }
+
+ public BigInteger Gcd(
+ BigInteger value)
+ {
+ if (value.sign == 0)
+ return Abs();
+
+ if (sign == 0)
+ return value.Abs();
+
+ BigInteger r;
+ BigInteger u = this;
+ BigInteger v = value;
+
+ while (v.sign != 0)
+ {
+ r = u.Mod(v);
+ u = v;
+ v = r;
+ }
+
+ return u;
+ }
+
+ public override int GetHashCode()
+ {
+ int hc = magnitude.Length;
+ if (magnitude.Length > 0)
+ {
+ hc ^= magnitude[0];
+
+ if (magnitude.Length > 1)
+ {
+ hc ^= magnitude[magnitude.Length - 1];
+ }
+ }
+
+ return sign < 0 ? ~hc : hc;
+ }
+
+ // TODO Make public?
+ private BigInteger Inc()
+ {
+ if (this.sign == 0)
+ return One;
+
+ if (this.sign < 0)
+ return new BigInteger(-1, doSubBigLil(this.magnitude, One.magnitude), true);
+
+ return AddToMagnitude(One.magnitude);
+ }
+
+ public int IntValue
+ {
+ get
+ {
+ if (sign == 0)
+ return 0;
+
+ int n = magnitude.Length;
+
+ int v = magnitude[n - 1];
+
+ return sign < 0 ? -v : v;
+ }
+ }
+
+ /**
+ * return whether or not a BigInteger is probably prime with a
+ * probability of 1 - (1/2)**certainty.
+ * From Knuth Vol 2, pg 395.
+ */
+ public bool IsProbablePrime(int certainty)
+ {
+ return IsProbablePrime(certainty, false);
+ }
+
+ internal bool IsProbablePrime(int certainty, bool randomlySelected)
+ {
+ if (certainty <= 0)
+ return true;
+
+ BigInteger n = Abs();
+
+ if (!n.TestBit(0))
+ return n.Equals(Two);
+
+ if (n.Equals(One))
+ return false;
+
+ return n.CheckProbablePrime(certainty, RandomSource, randomlySelected);
+ }
+
+ private bool CheckProbablePrime(int certainty, Random random, bool randomlySelected)
+ {
+ Debug.Assert(certainty > 0);
+ Debug.Assert(CompareTo(Two) > 0);
+ Debug.Assert(TestBit(0));
+
+
+ // Try to reduce the penalty for really small numbers
+ int numLists = System.Math.Min(BitLength - 1, primeLists.Length);
+
+ for (int i = 0; i < numLists; ++i)
+ {
+ int test = Remainder(primeProducts[i]);
+
+ int[] primeList = primeLists[i];
+ for (int j = 0; j < primeList.Length; ++j)
+ {
+ int prime = primeList[j];
+ int qRem = test % prime;
+ if (qRem == 0)
+ {
+ // We may find small numbers in the list
+ return BitLength < 16 && IntValue == prime;
+ }
+ }
+ }
+
+
+ // TODO Special case for < 10^16 (RabinMiller fixed list)
+// if (BitLength < 30)
+// {
+// RabinMiller against 2, 3, 5, 7, 11, 13, 23 is sufficient
+// }
+
+
+ // TODO Is it worth trying to create a hybrid of these two?
+ return RabinMillerTest(certainty, random, randomlySelected);
+// return SolovayStrassenTest(certainty, random);
+
+// bool rbTest = RabinMillerTest(certainty, random);
+// bool ssTest = SolovayStrassenTest(certainty, random);
+//
+// Debug.Assert(rbTest == ssTest);
+//
+// return rbTest;
+ }
+
+ public bool RabinMillerTest(int certainty, Random random)
+ {
+ return RabinMillerTest(certainty, random, false);
+ }
+
+ internal bool RabinMillerTest(int certainty, Random random, bool randomlySelected)
+ {
+ int bits = BitLength;
+
+ Debug.Assert(certainty > 0);
+ Debug.Assert(bits > 2);
+ Debug.Assert(TestBit(0));
+
+ int iterations = ((certainty - 1) / 2) + 1;
+ if (randomlySelected)
+ {
+ int itersFor100Cert = bits >= 1024 ? 4
+ : bits >= 512 ? 8
+ : bits >= 256 ? 16
+ : 50;
+
+ if (certainty < 100)
+ {
+ iterations = System.Math.Min(itersFor100Cert, iterations);
+ }
+ else
+ {
+ iterations -= 50;
+ iterations += itersFor100Cert;
+ }
+ }
+
+ // let n = 1 + d . 2^s
+ BigInteger n = this;
+ int s = n.GetLowestSetBitMaskFirst(-1 << 1);
+ Debug.Assert(s >= 1);
+ BigInteger r = n.ShiftRight(s);
+
+ // NOTE: Avoid conversion to/from Montgomery form and check for R/-R as result instead
+
+ BigInteger montRadix = One.ShiftLeft(32 * n.magnitude.Length).Remainder(n);
+ BigInteger minusMontRadix = n.Subtract(montRadix);
+
+ do
+ {
+ BigInteger a;
+ do
+ {
+ a = new BigInteger(n.BitLength, random);
+ }
+ while (a.sign == 0 || a.CompareTo(n) >= 0
+ || a.IsEqualMagnitude(montRadix) || a.IsEqualMagnitude(minusMontRadix));
+
+ BigInteger y = ModPowMonty(a, r, n, false);
+
+ if (!y.Equals(montRadix))
+ {
+ int j = 0;
+ while (!y.Equals(minusMontRadix))
+ {
+ if (++j == s)
+ return false;
+
+ y = ModPowMonty(y, Two, n, false);
+
+ if (y.Equals(montRadix))
+ return false;
+ }
+ }
+ }
+ while (--iterations > 0);
+
+ return true;
+ }
+
+// private bool SolovayStrassenTest(
+// int certainty,
+// Random random)
+// {
+// Debug.Assert(certainty > 0);
+// Debug.Assert(CompareTo(Two) > 0);
+// Debug.Assert(TestBit(0));
+//
+// BigInteger n = this;
+// BigInteger nMinusOne = n.Subtract(One);
+// BigInteger e = nMinusOne.ShiftRight(1);
+//
+// do
+// {
+// BigInteger a;
+// do
+// {
+// a = new BigInteger(nBitLength, random);
+// }
+// // NB: Spec says 0 < x < n, but 1 is trivial
+// while (a.CompareTo(One) <= 0 || a.CompareTo(n) >= 0);
+//
+//
+// // TODO Check this is redundant given the way Jacobi() works?
+//// if (!a.Gcd(n).Equals(One))
+//// return false;
+//
+// int x = Jacobi(a, n);
+//
+// if (x == 0)
+// return false;
+//
+// BigInteger check = a.ModPow(e, n);
+//
+// if (x == 1 && !check.Equals(One))
+// return false;
+//
+// if (x == -1 && !check.Equals(nMinusOne))
+// return false;
+//
+// --certainty;
+// }
+// while (certainty > 0);
+//
+// return true;
+// }
+//
+// private static int Jacobi(
+// BigInteger a,
+// BigInteger b)
+// {
+// Debug.Assert(a.sign >= 0);
+// Debug.Assert(b.sign > 0);
+// Debug.Assert(b.TestBit(0));
+// Debug.Assert(a.CompareTo(b) < 0);
+//
+// int totalS = 1;
+// for (;;)
+// {
+// if (a.sign == 0)
+// return 0;
+//
+// if (a.Equals(One))
+// break;
+//
+// int e = a.GetLowestSetBit();
+//
+// int bLsw = b.magnitude[b.magnitude.Length - 1];
+// if ((e & 1) != 0 && ((bLsw & 7) == 3 || (bLsw & 7) == 5))
+// totalS = -totalS;
+//
+// // TODO Confirm this is faster than later a1.Equals(One) test
+// if (a.BitLength == e + 1)
+// break;
+// BigInteger a1 = a.ShiftRight(e);
+//// if (a1.Equals(One))
+//// break;
+//
+// int a1Lsw = a1.magnitude[a1.magnitude.Length - 1];
+// if ((bLsw & 3) == 3 && (a1Lsw & 3) == 3)
+// totalS = -totalS;
+//
+//// a = b.Mod(a1);
+// a = b.Remainder(a1);
+// b = a1;
+// }
+// return totalS;
+// }
+
+ public long LongValue
+ {
+ get
+ {
+ if (sign == 0)
+ return 0;
+
+ int n = magnitude.Length;
+
+ long v = magnitude[n - 1] & IMASK;
+ if (n > 1)
+ {
+ v |= (magnitude[n - 2] & IMASK) << 32;
+ }
+
+ return sign < 0 ? -v : v;
+ }
+ }
+
+ public BigInteger Max(
+ BigInteger value)
+ {
+ return CompareTo(value) > 0 ? this : value;
+ }
+
+ public BigInteger Min(
+ BigInteger value)
+ {
+ return CompareTo(value) < 0 ? this : value;
+ }
+
+ public BigInteger Mod(
+ BigInteger m)
+ {
+ if (m.sign < 1)
+ throw new ArithmeticException("Modulus must be positive");
+
+ BigInteger biggie = Remainder(m);
+
+ return (biggie.sign >= 0 ? biggie : biggie.Add(m));
+ }
+
+ public BigInteger ModInverse(
+ BigInteger m)
+ {
+ if (m.sign < 1)
+ throw new ArithmeticException("Modulus must be positive");
+
+ // TODO Too slow at the moment
+// // "Fast Key Exchange with Elliptic Curve Systems" R.Schoeppel
+// if (m.TestBit(0))
+// {
+// //The Almost Inverse Algorithm
+// int k = 0;
+// BigInteger B = One, C = Zero, F = this, G = m, tmp;
+//
+// for (;;)
+// {
+// // While F is even, do F=F/u, C=C*u, k=k+1.
+// int zeroes = F.GetLowestSetBit();
+// if (zeroes > 0)
+// {
+// F = F.ShiftRight(zeroes);
+// C = C.ShiftLeft(zeroes);
+// k += zeroes;
+// }
+//
+// // If F = 1, then return B,k.
+// if (F.Equals(One))
+// {
+// BigInteger half = m.Add(One).ShiftRight(1);
+// BigInteger halfK = half.ModPow(BigInteger.ValueOf(k), m);
+// return B.Multiply(halfK).Mod(m);
+// }
+//
+// if (F.CompareTo(G) < 0)
+// {
+// tmp = G; G = F; F = tmp;
+// tmp = B; B = C; C = tmp;
+// }
+//
+// F = F.Add(G);
+// B = B.Add(C);
+// }
+// }
+
+ if (m.QuickPow2Check())
+ {
+ return ModInversePow2(m);
+ }
+
+ BigInteger d = this.Remainder(m);
+ BigInteger x;
+ BigInteger gcd = ExtEuclid(d, m, out x);
+
+ if (!gcd.Equals(One))
+ throw new ArithmeticException("Numbers not relatively prime.");
+
+ if (x.sign < 0)
+ {
+ x = x.Add(m);
+ }
+
+ return x;
+ }
+
+ private BigInteger ModInversePow2(BigInteger m)
+ {
+ Debug.Assert(m.SignValue > 0);
+ Debug.Assert(m.BitCount == 1);
+
+ if (!TestBit(0))
+ {
+ throw new ArithmeticException("Numbers not relatively prime.");
+ }
+
+ int pow = m.BitLength - 1;
+
+ long inv64 = ModInverse64(LongValue);
+ if (pow < 64)
+ {
+ inv64 &= ((1L << pow) - 1);
+ }
+
+ BigInteger x = BigInteger.ValueOf(inv64);
+
+ if (pow > 64)
+ {
+ BigInteger d = this.Remainder(m);
+ int bitsCorrect = 64;
+
+ do
+ {
+ BigInteger t = x.Multiply(d).Remainder(m);
+ x = x.Multiply(Two.Subtract(t)).Remainder(m);
+ bitsCorrect <<= 1;
+ }
+ while (bitsCorrect < pow);
+ }
+
+ if (x.sign < 0)
+ {
+ x = x.Add(m);
+ }
+
+ return x;
+ }
+
+ private static int ModInverse32(int d)
+ {
+ // Newton's method with initial estimate "correct to 4 bits"
+ Debug.Assert((d & 1) != 0);
+ int x = d + (((d + 1) & 4) << 1); // d.x == 1 mod 2**4
+ Debug.Assert(((d * x) & 15) == 1);
+ x *= 2 - d * x; // d.x == 1 mod 2**8
+ x *= 2 - d * x; // d.x == 1 mod 2**16
+ x *= 2 - d * x; // d.x == 1 mod 2**32
+ Debug.Assert(d * x == 1);
+ return x;
+ }
+
+ private static long ModInverse64(long d)
+ {
+ // Newton's method with initial estimate "correct to 4 bits"
+ Debug.Assert((d & 1L) != 0);
+ long x = d + (((d + 1L) & 4L) << 1); // d.x == 1 mod 2**4
+ Debug.Assert(((d * x) & 15L) == 1L);
+ x *= 2 - d * x; // d.x == 1 mod 2**8
+ x *= 2 - d * x; // d.x == 1 mod 2**16
+ x *= 2 - d * x; // d.x == 1 mod 2**32
+ x *= 2 - d * x; // d.x == 1 mod 2**64
+ Debug.Assert(d * x == 1L);
+ return x;
+ }
+
+ /**
+ * Calculate the numbers u1, u2, and u3 such that:
+ *
+ * u1 * a + u2 * b = u3
+ *
+ * where u3 is the greatest common divider of a and b.
+ * a and b using the extended Euclid algorithm (refer p. 323
+ * of The Art of Computer Programming vol 2, 2nd ed).
+ * This also seems to have the side effect of calculating
+ * some form of multiplicative inverse.
+ *
+ * @param a First number to calculate gcd for
+ * @param b Second number to calculate gcd for
+ * @param u1Out the return object for the u1 value
+ * @return The greatest common divisor of a and b
+ */
+ private static BigInteger ExtEuclid(BigInteger a, BigInteger b, out BigInteger u1Out)
+ {
+ BigInteger u1 = One, v1 = Zero;
+ BigInteger u3 = a, v3 = b;
+
+ if (v3.sign > 0)
+ {
+ for (;;)
+ {
+ BigInteger[] q = u3.DivideAndRemainder(v3);
+ u3 = v3;
+ v3 = q[1];
+
+ BigInteger oldU1 = u1;
+ u1 = v1;
+
+ if (v3.sign <= 0)
+ break;
+
+ v1 = oldU1.Subtract(v1.Multiply(q[0]));
+ }
+ }
+
+ u1Out = u1;
+
+ return u3;
+ }
+
+ private static void ZeroOut(
+ int[] x)
+ {
+ Array.Clear(x, 0, x.Length);
+ }
+
+ public BigInteger ModPow(BigInteger e, BigInteger m)
+ {
+ if (m.sign < 1)
+ throw new ArithmeticException("Modulus must be positive");
+
+ if (m.Equals(One))
+ return Zero;
+
+ if (e.sign == 0)
+ return One;
+
+ if (sign == 0)
+ return Zero;
+
+ bool negExp = e.sign < 0;
+ if (negExp)
+ e = e.Negate();
+
+ BigInteger result = this.Mod(m);
+ if (!e.Equals(One))
+ {
+ if ((m.magnitude[m.magnitude.Length - 1] & 1) == 0)
+ {
+ result = ModPowBarrett(result, e, m);
+ }
+ else
+ {
+ result = ModPowMonty(result, e, m, true);
+ }
+ }
+
+ if (negExp)
+ result = result.ModInverse(m);
+
+ return result;
+ }
+
+ private static BigInteger ModPowBarrett(BigInteger b, BigInteger e, BigInteger m)
+ {
+ int k = m.magnitude.Length;
+ BigInteger mr = One.ShiftLeft((k + 1) << 5);
+ BigInteger yu = One.ShiftLeft(k << 6).Divide(m);
+
+ // Sliding window from MSW to LSW
+ int extraBits = 0, expLength = e.BitLength;
+ while (expLength > ExpWindowThresholds[extraBits])
+ {
+ ++extraBits;
+ }
+
+ int numPowers = 1 << extraBits;
+ BigInteger[] oddPowers = new BigInteger[numPowers];
+ oddPowers[0] = b;
+
+ BigInteger b2 = ReduceBarrett(b.Square(), m, mr, yu);
+
+ for (int i = 1; i < numPowers; ++i)
+ {
+ oddPowers[i] = ReduceBarrett(oddPowers[i - 1].Multiply(b2), m, mr, yu);
+ }
+
+ int[] windowList = GetWindowList(e.magnitude, extraBits);
+ Debug.Assert(windowList.Length > 0);
+
+ int window = windowList[0];
+ int mult = window & 0xFF, lastZeroes = window >> 8;
+
+ BigInteger y;
+ if (mult == 1)
+ {
+ y = b2;
+ --lastZeroes;
+ }
+ else
+ {
+ y = oddPowers[mult >> 1];
+ }
+
+ int windowPos = 1;
+ while ((window = windowList[windowPos++]) != -1)
+ {
+ mult = window & 0xFF;
+
+ int bits = lastZeroes + BitLengthTable[mult];
+ for (int j = 0; j < bits; ++j)
+ {
+ y = ReduceBarrett(y.Square(), m, mr, yu);
+ }
+
+ y = ReduceBarrett(y.Multiply(oddPowers[mult >> 1]), m, mr, yu);
+
+ lastZeroes = window >> 8;
+ }
+
+ for (int i = 0; i < lastZeroes; ++i)
+ {
+ y = ReduceBarrett(y.Square(), m, mr, yu);
+ }
+
+ return y;
+ }
+
+ private static BigInteger ReduceBarrett(BigInteger x, BigInteger m, BigInteger mr, BigInteger yu)
+ {
+ int xLen = x.BitLength, mLen = m.BitLength;
+ if (xLen < mLen)
+ return x;
+
+ if (xLen - mLen > 1)
+ {
+ int k = m.magnitude.Length;
+
+ BigInteger q1 = x.DivideWords(k - 1);
+ BigInteger q2 = q1.Multiply(yu); // TODO Only need partial multiplication here
+ BigInteger q3 = q2.DivideWords(k + 1);
+
+ BigInteger r1 = x.RemainderWords(k + 1);
+ BigInteger r2 = q3.Multiply(m); // TODO Only need partial multiplication here
+ BigInteger r3 = r2.RemainderWords(k + 1);
+
+ x = r1.Subtract(r3);
+ if (x.sign < 0)
+ {
+ x = x.Add(mr);
+ }
+ }
+
+ while (x.CompareTo(m) >= 0)
+ {
+ x = x.Subtract(m);
+ }
+
+ return x;
+ }
+
+ private static BigInteger ModPowMonty(BigInteger b, BigInteger e, BigInteger m, bool convert)
+ {
+ int n = m.magnitude.Length;
+ int powR = 32 * n;
+ bool smallMontyModulus = m.BitLength + 2 <= powR;
+ uint mDash = (uint)m.GetMQuote();
+
+ // tmp = this * R mod m
+ if (convert)
+ {
+ b = b.ShiftLeft(powR).Remainder(m);
+ }
+
+ int[] yAccum = new int[n + 1];
+
+ int[] zVal = b.magnitude;
+ Debug.Assert(zVal.Length <= n);
+ if (zVal.Length < n)
+ {
+ int[] tmp = new int[n];
+ zVal.CopyTo(tmp, n - zVal.Length);
+ zVal = tmp;
+ }
+
+ // Sliding window from MSW to LSW
+
+ int extraBits = 0;
+
+ // Filter the common case of small RSA exponents with few bits set
+ if (e.magnitude.Length > 1 || e.BitCount > 2)
+ {
+ int expLength = e.BitLength;
+ while (expLength > ExpWindowThresholds[extraBits])
+ {
+ ++extraBits;
+ }
+ }
+
+ int numPowers = 1 << extraBits;
+ int[][] oddPowers = new int[numPowers][];
+ oddPowers[0] = zVal;
+
+ int[] zSquared = Arrays.Clone(zVal);
+ SquareMonty(yAccum, zSquared, m.magnitude, mDash, smallMontyModulus);
+
+ for (int i = 1; i < numPowers; ++i)
+ {
+ oddPowers[i] = Arrays.Clone(oddPowers[i - 1]);
+ MultiplyMonty(yAccum, oddPowers[i], zSquared, m.magnitude, mDash, smallMontyModulus);
+ }
+
+ int[] windowList = GetWindowList(e.magnitude, extraBits);
+ Debug.Assert(windowList.Length > 1);
+
+ int window = windowList[0];
+ int mult = window & 0xFF, lastZeroes = window >> 8;
+
+ int[] yVal;
+ if (mult == 1)
+ {
+ yVal = zSquared;
+ --lastZeroes;
+ }
+ else
+ {
+ yVal = Arrays.Clone(oddPowers[mult >> 1]);
+ }
+
+ int windowPos = 1;
+ while ((window = windowList[windowPos++]) != -1)
+ {
+ mult = window & 0xFF;
+
+ int bits = lastZeroes + BitLengthTable[mult];
+ for (int j = 0; j < bits; ++j)
+ {
+ SquareMonty(yAccum, yVal, m.magnitude, mDash, smallMontyModulus);
+ }
+
+ MultiplyMonty(yAccum, yVal, oddPowers[mult >> 1], m.magnitude, mDash, smallMontyModulus);
+
+ lastZeroes = window >> 8;
+ }
+
+ for (int i = 0; i < lastZeroes; ++i)
+ {
+ SquareMonty(yAccum, yVal, m.magnitude, mDash, smallMontyModulus);
+ }
+
+ if (convert)
+ {
+ // Return y * R^(-1) mod m
+ MontgomeryReduce(yVal, m.magnitude, mDash);
+ }
+ else if (smallMontyModulus && CompareTo(0, yVal, 0, m.magnitude) >= 0)
+ {
+ Subtract(0, yVal, 0, m.magnitude);
+ }
+
+ return new BigInteger(1, yVal, true);
+ }
+
+ private static int[] GetWindowList(int[] mag, int extraBits)
+ {
+ int v = mag[0];
+ Debug.Assert(v != 0);
+
+ int leadingBits = BitLen(v);
+
+ int resultSize = (((mag.Length - 1) << 5) + leadingBits) / (1 + extraBits) + 2;
+ int[] result = new int[resultSize];
+ int resultPos = 0;
+
+ int bitPos = 33 - leadingBits;
+ v <<= bitPos;
+
+ int mult = 1, multLimit = 1 << extraBits;
+ int zeroes = 0;
+
+ int i = 0;
+ for (; ; )
+ {
+ for (; bitPos < 32; ++bitPos)
+ {
+ if (mult < multLimit)
+ {
+ mult = (mult << 1) | (int)((uint)v >> 31);
+ }
+ else if (v < 0)
+ {
+ result[resultPos++] = CreateWindowEntry(mult, zeroes);
+ mult = 1;
+ zeroes = 0;
+ }
+ else
+ {
+ ++zeroes;
+ }
+
+ v <<= 1;
+ }
+
+ if (++i == mag.Length)
+ {
+ result[resultPos++] = CreateWindowEntry(mult, zeroes);
+ break;
+ }
+
+ v = mag[i];
+ bitPos = 0;
+ }
+
+ result[resultPos] = -1;
+ return result;
+ }
+
+ private static int CreateWindowEntry(int mult, int zeroes)
+ {
+ while ((mult & 1) == 0)
+ {
+ mult >>= 1;
+ ++zeroes;
+ }
+
+ return mult | (zeroes << 8);
+ }
+
+ /**
+ * return w with w = x * x - w is assumed to have enough space.
+ */
+ private static int[] Square(
+ int[] w,
+ int[] x)
+ {
+ // Note: this method allows w to be only (2 * x.Length - 1) words if result will fit
+// if (w.Length != 2 * x.Length)
+// throw new ArgumentException("no I don't think so...");
+
+ ulong c;
+
+ int wBase = w.Length - 1;
+
+ for (int i = x.Length - 1; i > 0; --i)
+ {
+ ulong v = (uint)x[i];
+
+ c = v * v + (uint)w[wBase];
+ w[wBase] = (int)c;
+ c >>= 32;
+
+ for (int j = i - 1; j >= 0; --j)
+ {
+ ulong prod = v * (uint)x[j];
+
+ c += ((uint)w[--wBase] & UIMASK) + ((uint)prod << 1);
+ w[wBase] = (int)c;
+ c = (c >> 32) + (prod >> 31);
+ }
+
+ c += (uint)w[--wBase];
+ w[wBase] = (int)c;
+
+ if (--wBase >= 0)
+ {
+ w[wBase] = (int)(c >> 32);
+ }
+ else
+ {
+ Debug.Assert((c >> 32) == 0);
+ }
+
+ wBase += i;
+ }
+
+ c = (uint)x[0];
+
+ c = c * c + (uint)w[wBase];
+ w[wBase] = (int)c;
+
+ if (--wBase >= 0)
+ {
+ w[wBase] += (int)(c >> 32);
+ }
+ else
+ {
+ Debug.Assert((c >> 32) == 0);
+ }
+
+ return w;
+ }
+
+ /**
+ * return x with x = y * z - x is assumed to have enough space.
+ */
+ private static int[] Multiply(int[] x, int[] y, int[] z)
+ {
+ int i = z.Length;
+
+ if (i < 1)
+ return x;
+
+ int xBase = x.Length - y.Length;
+
+ do
+ {
+ long a = z[--i] & IMASK;
+ long val = 0;
+
+ if (a != 0)
+ {
+ for (int j = y.Length - 1; j >= 0; j--)
+ {
+ val += a * (y[j] & IMASK) + (x[xBase + j] & IMASK);
+
+ x[xBase + j] = (int)val;
+
+ val = (long)((ulong)val >> 32);
+ }
+ }
+
+ --xBase;
+
+ if (xBase >= 0)
+ {
+ x[xBase] = (int)val;
+ }
+ else
+ {
+ Debug.Assert(val == 0);
+ }
+ }
+ while (i > 0);
+
+ return x;
+ }
+
+ /**
+ * Calculate mQuote = -m^(-1) mod b with b = 2^32 (32 = word size)
+ */
+ private int GetMQuote()
+ {
+ if (mQuote != 0)
+ {
+ return mQuote; // already calculated
+ }
+
+ Debug.Assert(this.sign > 0);
+
+ int d = -magnitude[magnitude.Length - 1];
+
+ Debug.Assert((d & 1) != 0);
+
+ return mQuote = ModInverse32(d);
+ }
+
+ private static void MontgomeryReduce(int[] x, int[] m, uint mDash) // mDash = -m^(-1) mod b
+ {
+ // NOTE: Not a general purpose reduction (which would allow x up to twice the bitlength of m)
+ Debug.Assert(x.Length == m.Length);
+
+ int n = m.Length;
+
+ for (int i = n - 1; i >= 0; --i)
+ {
+ uint x0 = (uint)x[n - 1];
+ ulong t = x0 * mDash;
+
+ ulong carry = t * (uint)m[n - 1] + x0;
+ Debug.Assert((uint)carry == 0);
+ carry >>= 32;
+
+ for (int j = n - 2; j >= 0; --j)
+ {
+ carry += t * (uint)m[j] + (uint)x[j];
+ x[j + 1] = (int)carry;
+ carry >>= 32;
+ }
+
+ x[0] = (int)carry;
+ Debug.Assert(carry >> 32 == 0);
+ }
+
+ if (CompareTo(0, x, 0, m) >= 0)
+ {
+ Subtract(0, x, 0, m);
+ }
+ }
+
+ /**
+ * Montgomery multiplication: a = x * y * R^(-1) mod m
+ *
+ * Based algorithm 14.36 of Handbook of Applied Cryptography.
+ *
+ * m, x, y should have length n
+ * a should have length (n + 1)
+ * b = 2^32, R = b^n
+ *
+ * The result is put in x
+ *
+ * NOTE: the indices of x, y, m, a different in HAC and in Java
+ */
+ private static void MultiplyMonty(int[] a, int[] x, int[] y, int[] m, uint mDash, bool smallMontyModulus)
+ // mDash = -m^(-1) mod b
+ {
+ int n = m.Length;
+
+ if (n == 1)
+ {
+ x[0] = (int)MultiplyMontyNIsOne((uint)x[0], (uint)y[0], (uint)m[0], mDash);
+ return;
+ }
+
+ uint y0 = (uint)y[n - 1];
+ int aMax;
+
+ {
+ ulong xi = (uint)x[n - 1];
+
+ ulong carry = xi * y0;
+ ulong t = (uint)carry * mDash;
+
+ ulong prod2 = t * (uint)m[n - 1];
+ carry += (uint)prod2;
+ Debug.Assert((uint)carry == 0);
+ carry = (carry >> 32) + (prod2 >> 32);
+
+ for (int j = n - 2; j >= 0; --j)
+ {
+ ulong prod1 = xi * (uint)y[j];
+ prod2 = t * (uint)m[j];
+
+ carry += (prod1 & UIMASK) + (uint)prod2;
+ a[j + 2] = (int)carry;
+ carry = (carry >> 32) + (prod1 >> 32) + (prod2 >> 32);
+ }
+
+ a[1] = (int)carry;
+ aMax = (int)(carry >> 32);
+ }
+
+ for (int i = n - 2; i >= 0; --i)
+ {
+ uint a0 = (uint)a[n];
+ ulong xi = (uint)x[i];
+
+ ulong prod1 = xi * y0;
+ ulong carry = (prod1 & UIMASK) + a0;
+ ulong t = (uint)carry * mDash;
+
+ ulong prod2 = t * (uint)m[n - 1];
+ carry += (uint)prod2;
+ Debug.Assert((uint)carry == 0);
+ carry = (carry >> 32) + (prod1 >> 32) + (prod2 >> 32);
+
+ for (int j = n - 2; j >= 0; --j)
+ {
+ prod1 = xi * (uint)y[j];
+ prod2 = t * (uint)m[j];
+
+ carry += (prod1 & UIMASK) + (uint)prod2 + (uint)a[j + 1];
+ a[j + 2] = (int)carry;
+ carry = (carry >> 32) + (prod1 >> 32) + (prod2 >> 32);
+ }
+
+ carry += (uint)aMax;
+ a[1] = (int)carry;
+ aMax = (int)(carry >> 32);
+ }
+
+ a[0] = aMax;
+
+ if (!smallMontyModulus && CompareTo(0, a, 0, m) >= 0)
+ {
+ Subtract(0, a, 0, m);
+ }
+
+ Array.Copy(a, 1, x, 0, n);
+ }
+
+ private static void SquareMonty(int[] a, int[] x, int[] m, uint mDash, bool smallMontyModulus)
+ // mDash = -m^(-1) mod b
+ {
+ int n = m.Length;
+
+ if (n == 1)
+ {
+ uint xVal = (uint)x[0];
+ x[0] = (int)MultiplyMontyNIsOne(xVal, xVal, (uint)m[0], mDash);
+ return;
+ }
+
+ ulong x0 = (uint)x[n - 1];
+ int aMax;
+
+ {
+ ulong carry = x0 * x0;
+ ulong t = (uint)carry * mDash;
+
+ ulong prod2 = t * (uint)m[n - 1];
+ carry += (uint)prod2;
+ Debug.Assert((uint)carry == 0);
+ carry = (carry >> 32) + (prod2 >> 32);
+
+ for (int j = n - 2; j >= 0; --j)
+ {
+ ulong prod1 = x0 * (uint)x[j];
+ prod2 = t * (uint)m[j];
+
+ carry += (prod2 & UIMASK) + ((uint)prod1 << 1);
+ a[j + 2] = (int)carry;
+ carry = (carry >> 32) + (prod1 >> 31) + (prod2 >> 32);
+ }
+
+ a[1] = (int)carry;
+ aMax = (int)(carry >> 32);
+ }
+
+ for (int i = n - 2; i >= 0; --i)
+ {
+ uint a0 = (uint)a[n];
+ ulong t = a0 * mDash;
+
+ ulong carry = t * (uint)m[n - 1] + a0;
+ Debug.Assert((uint)carry == 0);
+ carry >>= 32;
+
+ for (int j = n - 2; j > i; --j)
+ {
+ carry += t * (uint)m[j] + (uint)a[j + 1];
+ a[j + 2] = (int)carry;
+ carry >>= 32;
+ }
+
+ ulong xi = (uint)x[i];
+
+ {
+ ulong prod1 = xi * xi;
+ ulong prod2 = t * (uint)m[i];
+
+ carry += (prod1 & UIMASK) + (uint)prod2 + (uint)a[i + 1];
+ a[i + 2] = (int)carry;
+ carry = (carry >> 32) + (prod1 >> 32) + (prod2 >> 32);
+ }
+
+ for (int j = i - 1; j >= 0; --j)
+ {
+ ulong prod1 = xi * (uint)x[j];
+ ulong prod2 = t * (uint)m[j];
+
+ carry += (prod2 & UIMASK) + ((uint)prod1 << 1) + (uint)a[j + 1];
+ a[j + 2] = (int)carry;
+ carry = (carry >> 32) + (prod1 >> 31) + (prod2 >> 32);
+ }
+
+ carry += (uint)aMax;
+ a[1] = (int)carry;
+ aMax = (int)(carry >> 32);
+ }
+
+ a[0] = aMax;
+
+ if (!smallMontyModulus && CompareTo(0, a, 0, m) >= 0)
+ {
+ Subtract(0, a, 0, m);
+ }
+
+ Array.Copy(a, 1, x, 0, n);
+ }
+
+ private static uint MultiplyMontyNIsOne(uint x, uint y, uint m, uint mDash)
+ {
+ ulong carry = (ulong)x * y;
+ uint t = (uint)carry * mDash;
+ ulong um = m;
+ ulong prod2 = um * t;
+ carry += (uint)prod2;
+ Debug.Assert((uint)carry == 0);
+ carry = (carry >> 32) + (prod2 >> 32);
+ if (carry > um)
+ {
+ carry -= um;
+ }
+ Debug.Assert(carry < um);
+ return (uint)carry;
+ }
+
+ public BigInteger Multiply(
+ BigInteger val)
+ {
+ if (val == this)
+ return Square();
+
+ if ((sign & val.sign) == 0)
+ return Zero;
+
+ if (val.QuickPow2Check()) // val is power of two
+ {
+ BigInteger result = this.ShiftLeft(val.Abs().BitLength - 1);
+ return val.sign > 0 ? result : result.Negate();
+ }
+
+ if (this.QuickPow2Check()) // this is power of two
+ {
+ BigInteger result = val.ShiftLeft(this.Abs().BitLength - 1);
+ return this.sign > 0 ? result : result.Negate();
+ }
+
+ int resLength = magnitude.Length + val.magnitude.Length;
+ int[] res = new int[resLength];
+
+ Multiply(res, this.magnitude, val.magnitude);
+
+ int resSign = sign ^ val.sign ^ 1;
+ return new BigInteger(resSign, res, true);
+ }
+
+ public BigInteger Square()
+ {
+ if (sign == 0)
+ return Zero;
+ if (this.QuickPow2Check())
+ return ShiftLeft(Abs().BitLength - 1);
+ int resLength = magnitude.Length << 1;
+ if ((uint)magnitude[0] >> 16 == 0)
+ --resLength;
+ int[] res = new int[resLength];
+ Square(res, magnitude);
+ return new BigInteger(1, res, false);
+ }
+
+ public BigInteger Negate()
+ {
+ if (sign == 0)
+ return this;
+
+ return new BigInteger(-sign, magnitude, false);
+ }
+
+ public BigInteger NextProbablePrime()
+ {
+ if (sign < 0)
+ throw new ArithmeticException("Cannot be called on value < 0");
+
+ if (CompareTo(Two) < 0)
+ return Two;
+
+ BigInteger n = Inc().SetBit(0);
+
+ while (!n.CheckProbablePrime(100, RandomSource, false))
+ {
+ n = n.Add(Two);
+ }
+
+ return n;
+ }
+
+ public BigInteger Not()
+ {
+ return Inc().Negate();
+ }
+
+ public BigInteger Pow(int exp)
+ {
+ if (exp <= 0)
+ {
+ if (exp < 0)
+ throw new ArithmeticException("Negative exponent");
+
+ return One;
+ }
+
+ if (sign == 0)
+ {
+ return this;
+ }
+
+ if (QuickPow2Check())
+ {
+ long powOf2 = (long)exp * (BitLength - 1);
+ if (powOf2 > Int32.MaxValue)
+ {
+ throw new ArithmeticException("Result too large");
+ }
+ return One.ShiftLeft((int)powOf2);
+ }
+
+ BigInteger y = One;
+ BigInteger z = this;
+
+ for (;;)
+ {
+ if ((exp & 0x1) == 1)
+ {
+ y = y.Multiply(z);
+ }
+ exp >>= 1;
+ if (exp == 0) break;
+ z = z.Multiply(z);
+ }
+
+ return y;
+ }
+
+ public static BigInteger ProbablePrime(
+ int bitLength,
+ Random random)
+ {
+ return new BigInteger(bitLength, 100, random);
+ }
+
+ private int Remainder(
+ int m)
+ {
+ Debug.Assert(m > 0);
+
+ long acc = 0;
+ for (int pos = 0; pos < magnitude.Length; ++pos)
+ {
+ long posVal = (uint) magnitude[pos];
+ acc = (acc << 32 | posVal) % m;
+ }
+
+ return (int) acc;
+ }
+
+ /**
+ * return x = x % y - done in place (y value preserved)
+ */
+ private static int[] Remainder(
+ int[] x,
+ int[] y)
+ {
+ int xStart = 0;
+ while (xStart < x.Length && x[xStart] == 0)
+ {
+ ++xStart;
+ }
+
+ int yStart = 0;
+ while (yStart < y.Length && y[yStart] == 0)
+ {
+ ++yStart;
+ }
+
+ Debug.Assert(yStart < y.Length);
+
+ int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
+
+ if (xyCmp > 0)
+ {
+ int yBitLength = CalcBitLength(1, yStart, y);
+ int xBitLength = CalcBitLength(1, xStart, x);
+ int shift = xBitLength - yBitLength;
+
+ int[] c;
+ int cStart = 0;
+ int cBitLength = yBitLength;
+ if (shift > 0)
+ {
+ c = ShiftLeft(y, shift);
+ cBitLength += shift;
+ Debug.Assert(c[0] != 0);
+ }
+ else
+ {
+ int len = y.Length - yStart;
+ c = new int[len];
+ Array.Copy(y, yStart, c, 0, len);
+ }
+
+ for (;;)
+ {
+ if (cBitLength < xBitLength
+ || CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0)
+ {
+ Subtract(xStart, x, cStart, c);
+
+ while (x[xStart] == 0)
+ {
+ if (++xStart == x.Length)
+ return x;
+ }
+
+ //xBitLength = CalcBitLength(xStart, x);
+ xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]);
+
+ if (xBitLength <= yBitLength)
+ {
+ if (xBitLength < yBitLength)
+ return x;
+
+ xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
+
+ if (xyCmp <= 0)
+ break;
+ }
+ }
+
+ shift = cBitLength - xBitLength;
+
+ // NB: The case where c[cStart] is 1-bit is harmless
+ if (shift == 1)
+ {
+ uint firstC = (uint) c[cStart] >> 1;
+ uint firstX = (uint) x[xStart];
+ if (firstC > firstX)
+ ++shift;
+ }
+
+ if (shift < 2)
+ {
+ ShiftRightOneInPlace(cStart, c);
+ --cBitLength;
+ }
+ else
+ {
+ ShiftRightInPlace(cStart, c, shift);
+ cBitLength -= shift;
+ }
+
+ //cStart = c.Length - ((cBitLength + 31) / 32);
+ while (c[cStart] == 0)
+ {
+ ++cStart;
+ }
+ }
+ }
+
+ if (xyCmp == 0)
+ {
+ Array.Clear(x, xStart, x.Length - xStart);
+ }
+
+ return x;
+ }
+
+ public BigInteger Remainder(
+ BigInteger n)
+ {
+ if (n.sign == 0)
+ throw new ArithmeticException("Division by zero error");
+
+ if (this.sign == 0)
+ return Zero;
+
+ // For small values, use fast remainder method
+ if (n.magnitude.Length == 1)
+ {
+ int val = n.magnitude[0];
+
+ if (val > 0)
+ {
+ if (val == 1)
+ return Zero;
+
+ // TODO Make this func work on uint, and handle val == 1?
+ int rem = Remainder(val);
+
+ return rem == 0
+ ? Zero
+ : new BigInteger(sign, new int[]{ rem }, false);
+ }
+ }
+
+ if (CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude) < 0)
+ return this;
+
+ int[] result;
+ if (n.QuickPow2Check()) // n is power of two
+ {
+ // TODO Move before small values branch above?
+ result = LastNBits(n.Abs().BitLength - 1);
+ }
+ else
+ {
+ result = (int[]) this.magnitude.Clone();
+ result = Remainder(result, n.magnitude);
+ }
+
+ return new BigInteger(sign, result, true);
+ }
+
+ private int[] LastNBits(
+ int n)
+ {
+ if (n < 1)
+ return ZeroMagnitude;
+
+ int numWords = (n + BitsPerInt - 1) / BitsPerInt;
+ numWords = System.Math.Min(numWords, this.magnitude.Length);
+ int[] result = new int[numWords];
+
+ Array.Copy(this.magnitude, this.magnitude.Length - numWords, result, 0, numWords);
+
+ int excessBits = (numWords << 5) - n;
+ if (excessBits > 0)
+ {
+ result[0] &= (int)(UInt32.MaxValue >> excessBits);
+ }
+
+ return result;
+ }
+
+ private BigInteger DivideWords(int w)
+ {
+ Debug.Assert(w >= 0);
+ int n = magnitude.Length;
+ if (w >= n)
+ return Zero;
+ int[] mag = new int[n - w];
+ Array.Copy(magnitude, 0, mag, 0, n - w);
+ return new BigInteger(sign, mag, false);
+ }
+
+ private BigInteger RemainderWords(int w)
+ {
+ Debug.Assert(w >= 0);
+ int n = magnitude.Length;
+ if (w >= n)
+ return this;
+ int[] mag = new int[w];
+ Array.Copy(magnitude, n - w, mag, 0, w);
+ return new BigInteger(sign, mag, false);
+ }
+
+ /**
+ * do a left shift - this returns a new array.
+ */
+ private static int[] ShiftLeft(
+ int[] mag,
+ int n)
+ {
+ int nInts = (int)((uint)n >> 5);
+ int nBits = n & 0x1f;
+ int magLen = mag.Length;
+ int[] newMag;
+
+ if (nBits == 0)
+ {
+ newMag = new int[magLen + nInts];
+ mag.CopyTo(newMag, 0);
+ }
+ else
+ {
+ int i = 0;
+ int nBits2 = 32 - nBits;
+ int highBits = (int)((uint)mag[0] >> nBits2);
+
+ if (highBits != 0)
+ {
+ newMag = new int[magLen + nInts + 1];
+ newMag[i++] = highBits;
+ }
+ else
+ {
+ newMag = new int[magLen + nInts];
+ }
+
+ int m = mag[0];
+ for (int j = 0; j < magLen - 1; j++)
+ {
+ int next = mag[j + 1];
+
+ newMag[i++] = (m << nBits) | (int)((uint)next >> nBits2);
+ m = next;
+ }
+
+ newMag[i] = mag[magLen - 1] << nBits;
+ }
+
+ return newMag;
+ }
+
+ private static int ShiftLeftOneInPlace(int[] x, int carry)
+ {
+ Debug.Assert(carry == 0 || carry == 1);
+ int pos = x.Length;
+ while (--pos >= 0)
+ {
+ uint val = (uint)x[pos];
+ x[pos] = (int)(val << 1) | carry;
+ carry = (int)(val >> 31);
+ }
+ return carry;
+ }
+
+ public BigInteger ShiftLeft(
+ int n)
+ {
+ if (sign == 0 || magnitude.Length == 0)
+ return Zero;
+
+ if (n == 0)
+ return this;
+
+ if (n < 0)
+ return ShiftRight(-n);
+
+ BigInteger result = new BigInteger(sign, ShiftLeft(magnitude, n), true);
+
+ if (this.nBits != -1)
+ {
+ result.nBits = sign > 0
+ ? this.nBits
+ : this.nBits + n;
+ }
+
+ if (this.nBitLength != -1)
+ {
+ result.nBitLength = this.nBitLength + n;
+ }
+
+ return result;
+ }
+
+ /**
+ * do a right shift - this does it in place.
+ */
+ private static void ShiftRightInPlace(
+ int start,
+ int[] mag,
+ int n)
+ {
+ int nInts = (int)((uint)n >> 5) + start;
+ int nBits = n & 0x1f;
+ int magEnd = mag.Length - 1;
+
+ if (nInts != start)
+ {
+ int delta = (nInts - start);
+
+ for (int i = magEnd; i >= nInts; i--)
+ {
+ mag[i] = mag[i - delta];
+ }
+ for (int i = nInts - 1; i >= start; i--)
+ {
+ mag[i] = 0;
+ }
+ }
+
+ if (nBits != 0)
+ {
+ int nBits2 = 32 - nBits;
+ int m = mag[magEnd];
+
+ for (int i = magEnd; i > nInts; --i)
+ {
+ int next = mag[i - 1];
+
+ mag[i] = (int)((uint)m >> nBits) | (next << nBits2);
+ m = next;
+ }
+
+ mag[nInts] = (int)((uint)mag[nInts] >> nBits);
+ }
+ }
+
+ /**
+ * do a right shift by one - this does it in place.
+ */
+ private static void ShiftRightOneInPlace(
+ int start,
+ int[] mag)
+ {
+ int i = mag.Length;
+ int m = mag[i - 1];
+
+ while (--i > start)
+ {
+ int next = mag[i - 1];
+ mag[i] = ((int)((uint)m >> 1)) | (next << 31);
+ m = next;
+ }
+
+ mag[start] = (int)((uint)mag[start] >> 1);
+ }
+
+ public BigInteger ShiftRight(
+ int n)
+ {
+ if (n == 0)
+ return this;
+
+ if (n < 0)
+ return ShiftLeft(-n);
+
+ if (n >= BitLength)
+ return (this.sign < 0 ? One.Negate() : Zero);
+
+// int[] res = (int[]) this.magnitude.Clone();
+//
+// ShiftRightInPlace(0, res, n);
+//
+// return new BigInteger(this.sign, res, true);
+
+ int resultLength = (BitLength - n + 31) >> 5;
+ int[] res = new int[resultLength];
+
+ int numInts = n >> 5;
+ int numBits = n & 31;
+
+ if (numBits == 0)
+ {
+ Array.Copy(this.magnitude, 0, res, 0, res.Length);
+ }
+ else
+ {
+ int numBits2 = 32 - numBits;
+
+ int magPos = this.magnitude.Length - 1 - numInts;
+ for (int i = resultLength - 1; i >= 0; --i)
+ {
+ res[i] = (int)((uint) this.magnitude[magPos--] >> numBits);
+
+ if (magPos >= 0)
+ {
+ res[i] |= this.magnitude[magPos] << numBits2;
+ }
+ }
+ }
+
+ Debug.Assert(res[0] != 0);
+
+ return new BigInteger(this.sign, res, false);
+ }
+
+ public int SignValue
+ {
+ get { return sign; }
+ }
+
+ /**
+ * returns x = x - y - we assume x is >= y
+ */
+ private static int[] Subtract(
+ int xStart,
+ int[] x,
+ int yStart,
+ int[] y)
+ {
+ Debug.Assert(yStart < y.Length);
+ Debug.Assert(x.Length - xStart >= y.Length - yStart);
+
+ int iT = x.Length;
+ int iV = y.Length;
+ long m;
+ int borrow = 0;
+
+ do
+ {
+ m = (x[--iT] & IMASK) - (y[--iV] & IMASK) + borrow;
+ x[iT] = (int) m;
+
+// borrow = (m < 0) ? -1 : 0;
+ borrow = (int)(m >> 63);
+ }
+ while (iV > yStart);
+
+ if (borrow != 0)
+ {
+ while (--x[--iT] == -1)
+ {
+ }
+ }
+
+ return x;
+ }
+
+ public BigInteger Subtract(
+ BigInteger n)
+ {
+ if (n.sign == 0)
+ return this;
+
+ if (this.sign == 0)
+ return n.Negate();
+
+ if (this.sign != n.sign)
+ return Add(n.Negate());
+
+ int compare = CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude);
+ if (compare == 0)
+ return Zero;
+
+ BigInteger bigun, lilun;
+ if (compare < 0)
+ {
+ bigun = n;
+ lilun = this;
+ }
+ else
+ {
+ bigun = this;
+ lilun = n;
+ }
+
+ return new BigInteger(this.sign * compare, doSubBigLil(bigun.magnitude, lilun.magnitude), true);
+ }
+
+ private static int[] doSubBigLil(
+ int[] bigMag,
+ int[] lilMag)
+ {
+ int[] res = (int[]) bigMag.Clone();
+
+ return Subtract(0, res, 0, lilMag);
+ }
+
+ public byte[] ToByteArray()
+ {
+ return ToByteArray(false);
+ }
+
+ public byte[] ToByteArrayUnsigned()
+ {
+ return ToByteArray(true);
+ }
+
+ private byte[] ToByteArray(
+ bool unsigned)
+ {
+ if (sign == 0)
+ return unsigned ? ZeroEncoding : new byte[1];
+
+ int nBits = (unsigned && sign > 0)
+ ? BitLength
+ : BitLength + 1;
+
+ int nBytes = GetByteLength(nBits);
+ byte[] bytes = new byte[nBytes];
+
+ int magIndex = magnitude.Length;
+ int bytesIndex = bytes.Length;
+
+ if (sign > 0)
+ {
+ while (magIndex > 1)
+ {
+ uint mag = (uint) magnitude[--magIndex];
+ bytes[--bytesIndex] = (byte) mag;
+ bytes[--bytesIndex] = (byte)(mag >> 8);
+ bytes[--bytesIndex] = (byte)(mag >> 16);
+ bytes[--bytesIndex] = (byte)(mag >> 24);
+ }
+
+ uint lastMag = (uint) magnitude[0];
+ while (lastMag > byte.MaxValue)
+ {
+ bytes[--bytesIndex] = (byte) lastMag;
+ lastMag >>= 8;
+ }
+
+ bytes[--bytesIndex] = (byte) lastMag;
+ }
+ else // sign < 0
+ {
+ bool carry = true;
+
+ while (magIndex > 1)
+ {
+ uint mag = ~((uint) magnitude[--magIndex]);
+
+ if (carry)
+ {
+ carry = (++mag == uint.MinValue);
+ }
+
+ bytes[--bytesIndex] = (byte) mag;
+ bytes[--bytesIndex] = (byte)(mag >> 8);
+ bytes[--bytesIndex] = (byte)(mag >> 16);
+ bytes[--bytesIndex] = (byte)(mag >> 24);
+ }
+
+ uint lastMag = (uint) magnitude[0];
+
+ if (carry)
+ {
+ // Never wraps because magnitude[0] != 0
+ --lastMag;
+ }
+
+ while (lastMag > byte.MaxValue)
+ {
+ bytes[--bytesIndex] = (byte) ~lastMag;
+ lastMag >>= 8;
+ }
+
+ bytes[--bytesIndex] = (byte) ~lastMag;
+
+ if (bytesIndex > 0)
+ {
+ bytes[--bytesIndex] = byte.MaxValue;
+ }
+ }
+
+ return bytes;
+ }
+
+ public override string ToString()
+ {
+ return ToString(10);
+ }
+
+ public string ToString(int radix)
+ {
+ // TODO Make this method work for other radices (ideally 2 <= radix <= 36 as in Java)
+
+ switch (radix)
+ {
+ case 2:
+ case 8:
+ case 10:
+ case 16:
+ break;
+ default:
+ throw new FormatException("Only bases 2, 8, 10, 16 are allowed");
+ }
+
+ // NB: Can only happen to internally managed instances
+ if (magnitude == null)
+ return "null";
+
+ if (sign == 0)
+ return "0";
+
+
+ // NOTE: This *should* be unnecessary, since the magnitude *should* never have leading zero digits
+ int firstNonZero = 0;
+ while (firstNonZero < magnitude.Length)
+ {
+ if (magnitude[firstNonZero] != 0)
+ {
+ break;
+ }
+ ++firstNonZero;
+ }
+
+ if (firstNonZero == magnitude.Length)
+ {
+ return "0";
+ }
+
+
+ StringBuilder sb = new StringBuilder();
+ if (sign == -1)
+ {
+ sb.Append('-');
+ }
+
+ switch (radix)
+ {
+ case 2:
+ {
+ int pos = firstNonZero;
+ sb.Append(Convert.ToString(magnitude[pos], 2));
+ while (++pos < magnitude.Length)
+ {
+ AppendZeroExtendedString(sb, Convert.ToString(magnitude[pos], 2), 32);
+ }
+ break;
+ }
+ case 8:
+ {
+ int mask = (1 << 30) - 1;
+ BigInteger u = this.Abs();
+ int bits = u.BitLength;
+ IList S = Platform.CreateArrayList();
+ while (bits > 30)
+ {
+ S.Add(Convert.ToString(u.IntValue & mask, 8));
+ u = u.ShiftRight(30);
+ bits -= 30;
+ }
+ sb.Append(Convert.ToString(u.IntValue, 8));
+ for (int i = S.Count - 1; i >= 0; --i)
+ {
+ AppendZeroExtendedString(sb, (string)S[i], 10);
+ }
+ break;
+ }
+ case 16:
+ {
+ int pos = firstNonZero;
+ sb.Append(Convert.ToString(magnitude[pos], 16));
+ while (++pos < magnitude.Length)
+ {
+ AppendZeroExtendedString(sb, Convert.ToString(magnitude[pos], 16), 8);
+ }
+ break;
+ }
+ // TODO This could work for other radices if there is an alternative to Convert.ToString method
+ //default:
+ case 10:
+ {
+ BigInteger q = this.Abs();
+ if (q.BitLength < 64)
+ {
+ sb.Append(Convert.ToString(q.LongValue, radix));
+ break;
+ }
+
+ // Based on algorithm 1a from chapter 4.4 in Seminumerical Algorithms (Knuth)
+
+ // Work out the largest power of 'rdx' that is a positive 64-bit integer
+ // TODO possibly cache power/exponent against radix?
+ long limit = Int64.MaxValue / radix;
+ long power = radix;
+ int exponent = 1;
+ while (power <= limit)
+ {
+ power *= radix;
+ ++exponent;
+ }
+
+ BigInteger bigPower = BigInteger.ValueOf(power);
+
+ IList S = Platform.CreateArrayList();
+ while (q.CompareTo(bigPower) >= 0)
+ {
+ BigInteger[] qr = q.DivideAndRemainder(bigPower);
+ S.Add(Convert.ToString(qr[1].LongValue, radix));
+ q = qr[0];
+ }
+
+ sb.Append(Convert.ToString(q.LongValue, radix));
+ for (int i = S.Count - 1; i >= 0; --i)
+ {
+ AppendZeroExtendedString(sb, (string)S[i], exponent);
+ }
+ break;
+ }
+ }
+
+ return sb.ToString();
+ }
+
+ private static void AppendZeroExtendedString(StringBuilder sb, string s, int minLength)
+ {
+ for (int len = s.Length; len < minLength; ++len)
+ {
+ sb.Append('0');
+ }
+ sb.Append(s);
+ }
+
+ private static BigInteger CreateUValueOf(
+ ulong value)
+ {
+ int msw = (int)(value >> 32);
+ int lsw = (int)value;
+
+ if (msw != 0)
+ return new BigInteger(1, new int[] { msw, lsw }, false);
+
+ if (lsw != 0)
+ {
+ BigInteger n = new BigInteger(1, new int[] { lsw }, false);
+ // Check for a power of two
+ if ((lsw & -lsw) == lsw)
+ {
+ n.nBits = 1;
+ }
+ return n;
+ }
+
+ return Zero;
+ }
+
+ private static BigInteger CreateValueOf(
+ long value)
+ {
+ if (value < 0)
+ {
+ if (value == long.MinValue)
+ return CreateValueOf(~value).Not();
+
+ return CreateValueOf(-value).Negate();
+ }
+
+ return CreateUValueOf((ulong)value);
+ }
+
+ public static BigInteger ValueOf(
+ long value)
+ {
+ if (value >= 0 && value < SMALL_CONSTANTS.Length)
+ {
+ return SMALL_CONSTANTS[value];
+ }
+
+ return CreateValueOf(value);
+ }
+
+ public int GetLowestSetBit()
+ {
+ if (this.sign == 0)
+ return -1;
+
+ return GetLowestSetBitMaskFirst(-1);
+ }
+
+ private int GetLowestSetBitMaskFirst(int firstWordMask)
+ {
+ int w = magnitude.Length, offset = 0;
+
+ uint word = (uint)(magnitude[--w] & firstWordMask);
+ Debug.Assert(magnitude[0] != 0);
+
+ while (word == 0)
+ {
+ word = (uint)magnitude[--w];
+ offset += 32;
+ }
+
+ while ((word & 0xFF) == 0)
+ {
+ word >>= 8;
+ offset += 8;
+ }
+
+ while ((word & 1) == 0)
+ {
+ word >>= 1;
+ ++offset;
+ }
+
+ return offset;
+ }
+
+ public bool TestBit(
+ int n)
+ {
+ if (n < 0)
+ throw new ArithmeticException("Bit position must not be negative");
+
+ if (sign < 0)
+ return !Not().TestBit(n);
+
+ int wordNum = n / 32;
+ if (wordNum >= magnitude.Length)
+ return false;
+
+ int word = magnitude[magnitude.Length - 1 - wordNum];
+ return ((word >> (n % 32)) & 1) > 0;
+ }
+
+ public BigInteger Or(
+ BigInteger value)
+ {
+ if (this.sign == 0)
+ return value;
+
+ if (value.sign == 0)
+ return this;
+
+ int[] aMag = this.sign > 0
+ ? this.magnitude
+ : Add(One).magnitude;
+
+ int[] bMag = value.sign > 0
+ ? value.magnitude
+ : value.Add(One).magnitude;
+
+ bool resultNeg = sign < 0 || value.sign < 0;
+ int resultLength = System.Math.Max(aMag.Length, bMag.Length);
+ int[] resultMag = new int[resultLength];
+
+ int aStart = resultMag.Length - aMag.Length;
+ int bStart = resultMag.Length - bMag.Length;
+
+ for (int i = 0; i < resultMag.Length; ++i)
+ {
+ int aWord = i >= aStart ? aMag[i - aStart] : 0;
+ int bWord = i >= bStart ? bMag[i - bStart] : 0;
+
+ if (this.sign < 0)
+ {
+ aWord = ~aWord;
+ }
+
+ if (value.sign < 0)
+ {
+ bWord = ~bWord;
+ }
+
+ resultMag[i] = aWord | bWord;
+
+ if (resultNeg)
+ {
+ resultMag[i] = ~resultMag[i];
+ }
+ }
+
+ BigInteger result = new BigInteger(1, resultMag, true);
+
+ // TODO Optimise this case
+ if (resultNeg)
+ {
+ result = result.Not();
+ }
+
+ return result;
+ }
+
+ public BigInteger Xor(
+ BigInteger value)
+ {
+ if (this.sign == 0)
+ return value;
+
+ if (value.sign == 0)
+ return this;
+
+ int[] aMag = this.sign > 0
+ ? this.magnitude
+ : Add(One).magnitude;
+
+ int[] bMag = value.sign > 0
+ ? value.magnitude
+ : value.Add(One).magnitude;
+
+ // TODO Can just replace with sign != value.sign?
+ bool resultNeg = (sign < 0 && value.sign >= 0) || (sign >= 0 && value.sign < 0);
+ int resultLength = System.Math.Max(aMag.Length, bMag.Length);
+ int[] resultMag = new int[resultLength];
+
+ int aStart = resultMag.Length - aMag.Length;
+ int bStart = resultMag.Length - bMag.Length;
+
+ for (int i = 0; i < resultMag.Length; ++i)
+ {
+ int aWord = i >= aStart ? aMag[i - aStart] : 0;
+ int bWord = i >= bStart ? bMag[i - bStart] : 0;
+
+ if (this.sign < 0)
+ {
+ aWord = ~aWord;
+ }
+
+ if (value.sign < 0)
+ {
+ bWord = ~bWord;
+ }
+
+ resultMag[i] = aWord ^ bWord;
+
+ if (resultNeg)
+ {
+ resultMag[i] = ~resultMag[i];
+ }
+ }
+
+ BigInteger result = new BigInteger(1, resultMag, true);
+
+ // TODO Optimise this case
+ if (resultNeg)
+ {
+ result = result.Not();
+ }
+
+ return result;
+ }
+
+ public BigInteger SetBit(
+ int n)
+ {
+ if (n < 0)
+ throw new ArithmeticException("Bit address less than zero");
+
+ if (TestBit(n))
+ return this;
+
+ // TODO Handle negative values and zero
+ if (sign > 0 && n < (BitLength - 1))
+ return FlipExistingBit(n);
+
+ return Or(One.ShiftLeft(n));
+ }
+
+ public BigInteger ClearBit(
+ int n)
+ {
+ if (n < 0)
+ throw new ArithmeticException("Bit address less than zero");
+
+ if (!TestBit(n))
+ return this;
+
+ // TODO Handle negative values
+ if (sign > 0 && n < (BitLength - 1))
+ return FlipExistingBit(n);
+
+ return AndNot(One.ShiftLeft(n));
+ }
+
+ public BigInteger FlipBit(
+ int n)
+ {
+ if (n < 0)
+ throw new ArithmeticException("Bit address less than zero");
+
+ // TODO Handle negative values and zero
+ if (sign > 0 && n < (BitLength - 1))
+ return FlipExistingBit(n);
+
+ return Xor(One.ShiftLeft(n));
+ }
+
+ private BigInteger FlipExistingBit(
+ int n)
+ {
+ Debug.Assert(sign > 0);
+ Debug.Assert(n >= 0);
+ Debug.Assert(n < BitLength - 1);
+
+ int[] mag = (int[]) this.magnitude.Clone();
+ mag[mag.Length - 1 - (n >> 5)] ^= (1 << (n & 31)); // Flip bit
+ //mag[mag.Length - 1 - (n / 32)] ^= (1 << (n % 32));
+ return new BigInteger(this.sign, mag, false);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/Primes.cs b/bc-sharp-crypto/src/math/Primes.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fb279f103273b51cd024f30433372ea2bde3be31
--- /dev/null
+++ b/bc-sharp-crypto/src/math/Primes.cs
@@ -0,0 +1,629 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math
+{
+ /**
+ * Utility methods for generating primes and testing for primality.
+ */
+ public abstract class Primes
+ {
+ public static readonly int SmallFactorLimit = 211;
+
+ private static readonly BigInteger One = BigInteger.One;
+ private static readonly BigInteger Two = BigInteger.Two;
+ private static readonly BigInteger Three = BigInteger.Three;
+
+ /**
+ * Used to return the output from the
+ * {@linkplain Primes#enhancedMRProbablePrimeTest(BigInteger, SecureRandom, int) Enhanced
+ * Miller-Rabin Probabilistic Primality Test}
+ */
+ public class MROutput
+ {
+ internal static MROutput ProbablyPrime()
+ {
+ return new MROutput(false, null);
+ }
+
+ internal static MROutput ProvablyCompositeWithFactor(BigInteger factor)
+ {
+ return new MROutput(true, factor);
+ }
+
+ internal static MROutput ProvablyCompositeNotPrimePower()
+ {
+ return new MROutput(true, null);
+ }
+
+ private readonly bool mProvablyComposite;
+ private readonly BigInteger mFactor;
+
+ private MROutput(bool provablyComposite, BigInteger factor)
+ {
+ this.mProvablyComposite = provablyComposite;
+ this.mFactor = factor;
+ }
+
+ public BigInteger Factor
+ {
+ get { return mFactor; }
+ }
+
+ public bool IsProvablyComposite
+ {
+ get { return mProvablyComposite; }
+ }
+
+ public bool IsNotPrimePower
+ {
+ get { return mProvablyComposite && mFactor == null; }
+ }
+ }
+
+ /**
+ * Used to return the output from the {@linkplain Primes#generateSTRandomPrime(Digest, int, byte[]) Shawe-Taylor Random_Prime Routine}
+ */
+ public class STOutput
+ {
+ private readonly BigInteger mPrime;
+ private readonly byte[] mPrimeSeed;
+ private readonly int mPrimeGenCounter;
+
+ internal STOutput(BigInteger prime, byte[] primeSeed, int primeGenCounter)
+ {
+ this.mPrime = prime;
+ this.mPrimeSeed = primeSeed;
+ this.mPrimeGenCounter = primeGenCounter;
+ }
+
+ public BigInteger Prime
+ {
+ get { return mPrime; }
+ }
+
+ public byte[] PrimeSeed
+ {
+ get { return mPrimeSeed; }
+ }
+
+ public int PrimeGenCounter
+ {
+ get { return mPrimeGenCounter; }
+ }
+ }
+
+ /**
+ * FIPS 186-4 C.6 Shawe-Taylor Random_Prime Routine
+ *
+ * Construct a provable prime number using a hash function.
+ *
+ * @param hash
+ * the {@link Digest} instance to use (as "Hash()"). Cannot be null.
+ * @param length
+ * the length (in bits) of the prime to be generated. Must be at least 2.
+ * @param inputSeed
+ * the seed to be used for the generation of the requested prime. Cannot be null or
+ * empty.
+ * @return an {@link STOutput} instance containing the requested prime.
+ */
+ public static STOutput GenerateSTRandomPrime(IDigest hash, int length, byte[] inputSeed)
+ {
+ if (hash == null)
+ throw new ArgumentNullException("hash");
+ if (length < 2)
+ throw new ArgumentException("must be >= 2", "length");
+ if (inputSeed == null)
+ throw new ArgumentNullException("inputSeed");
+ if (inputSeed.Length == 0)
+ throw new ArgumentException("cannot be empty", "inputSeed");
+
+ return ImplSTRandomPrime(hash, length, Arrays.Clone(inputSeed));
+ }
+
+ /**
+ * FIPS 186-4 C.3.2 Enhanced Miller-Rabin Probabilistic Primality Test
+ *
+ * Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases. This is an
+ * alternative to {@link #isMRProbablePrime(BigInteger, SecureRandom, int)} that provides more
+ * information about a composite candidate, which may be useful when generating or validating
+ * RSA moduli.
+ *
+ * @param candidate
+ * the {@link BigInteger} instance to test for primality.
+ * @param random
+ * the source of randomness to use to choose bases.
+ * @param iterations
+ * the number of randomly-chosen bases to perform the test for.
+ * @return an {@link MROutput} instance that can be further queried for details.
+ */
+ public static MROutput EnhancedMRProbablePrimeTest(BigInteger candidate, SecureRandom random, int iterations)
+ {
+ CheckCandidate(candidate, "candidate");
+
+ if (random == null)
+ throw new ArgumentNullException("random");
+ if (iterations < 1)
+ throw new ArgumentException("must be > 0", "iterations");
+
+ if (candidate.BitLength == 2)
+ return MROutput.ProbablyPrime();
+
+ if (!candidate.TestBit(0))
+ return MROutput.ProvablyCompositeWithFactor(Two);
+
+ BigInteger w = candidate;
+ BigInteger wSubOne = candidate.Subtract(One);
+ BigInteger wSubTwo = candidate.Subtract(Two);
+
+ int a = wSubOne.GetLowestSetBit();
+ BigInteger m = wSubOne.ShiftRight(a);
+
+ for (int i = 0; i < iterations; ++i)
+ {
+ BigInteger b = BigIntegers.CreateRandomInRange(Two, wSubTwo, random);
+ BigInteger g = b.Gcd(w);
+
+ if (g.CompareTo(One) > 0)
+ return MROutput.ProvablyCompositeWithFactor(g);
+
+ BigInteger z = b.ModPow(m, w);
+
+ if (z.Equals(One) || z.Equals(wSubOne))
+ continue;
+
+ bool primeToBase = false;
+
+ BigInteger x = z;
+ for (int j = 1; j < a; ++j)
+ {
+ z = z.ModPow(Two, w);
+
+ if (z.Equals(wSubOne))
+ {
+ primeToBase = true;
+ break;
+ }
+
+ if (z.Equals(One))
+ break;
+
+ x = z;
+ }
+
+ if (!primeToBase)
+ {
+ if (!z.Equals(One))
+ {
+ x = z;
+ z = z.ModPow(Two, w);
+
+ if (!z.Equals(One))
+ {
+ x = z;
+ }
+ }
+
+ g = x.Subtract(One).Gcd(w);
+
+ if (g.CompareTo(One) > 0)
+ return MROutput.ProvablyCompositeWithFactor(g);
+
+ return MROutput.ProvablyCompositeNotPrimePower();
+ }
+ }
+
+ return MROutput.ProbablyPrime();
+ }
+
+ /**
+ * A fast check for small divisors, up to some implementation-specific limit.
+ *
+ * @param candidate
+ * the {@link BigInteger} instance to test for division by small factors.
+ *
+ * @return true
if the candidate is found to have any small factors,
+ * false
otherwise.
+ */
+ public static bool HasAnySmallFactors(BigInteger candidate)
+ {
+ CheckCandidate(candidate, "candidate");
+
+ return ImplHasAnySmallFactors(candidate);
+ }
+
+ /**
+ * FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test
+ *
+ * Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases.
+ *
+ * @param candidate
+ * the {@link BigInteger} instance to test for primality.
+ * @param random
+ * the source of randomness to use to choose bases.
+ * @param iterations
+ * the number of randomly-chosen bases to perform the test for.
+ * @return false
if any witness to compositeness is found amongst the chosen bases
+ * (so candidate
is definitely NOT prime), or else true
+ * (indicating primality with some probability dependent on the number of iterations
+ * that were performed).
+ */
+ public static bool IsMRProbablePrime(BigInteger candidate, SecureRandom random, int iterations)
+ {
+ CheckCandidate(candidate, "candidate");
+
+ if (random == null)
+ throw new ArgumentException("cannot be null", "random");
+ if (iterations < 1)
+ throw new ArgumentException("must be > 0", "iterations");
+
+ if (candidate.BitLength == 2)
+ return true;
+ if (!candidate.TestBit(0))
+ return false;
+
+ BigInteger w = candidate;
+ BigInteger wSubOne = candidate.Subtract(One);
+ BigInteger wSubTwo = candidate.Subtract(Two);
+
+ int a = wSubOne.GetLowestSetBit();
+ BigInteger m = wSubOne.ShiftRight(a);
+
+ for (int i = 0; i < iterations; ++i)
+ {
+ BigInteger b = BigIntegers.CreateRandomInRange(Two, wSubTwo, random);
+
+ if (!ImplMRProbablePrimeToBase(w, wSubOne, m, a, b))
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test (to a fixed base).
+ *
+ * Run a single iteration of the Miller-Rabin algorithm against the specified base.
+ *
+ * @param candidate
+ * the {@link BigInteger} instance to test for primality.
+ * @param baseValue
+ * the base value to use for this iteration.
+ * @return false
if the specified base is a witness to compositeness (so
+ * candidate
is definitely NOT prime), or else true
.
+ */
+ public static bool IsMRProbablePrimeToBase(BigInteger candidate, BigInteger baseValue)
+ {
+ CheckCandidate(candidate, "candidate");
+ CheckCandidate(baseValue, "baseValue");
+
+ if (baseValue.CompareTo(candidate.Subtract(One)) >= 0)
+ throw new ArgumentException("must be < ('candidate' - 1)", "baseValue");
+
+ if (candidate.BitLength == 2)
+ return true;
+
+ BigInteger w = candidate;
+ BigInteger wSubOne = candidate.Subtract(One);
+
+ int a = wSubOne.GetLowestSetBit();
+ BigInteger m = wSubOne.ShiftRight(a);
+
+ return ImplMRProbablePrimeToBase(w, wSubOne, m, a, baseValue);
+ }
+
+ private static void CheckCandidate(BigInteger n, string name)
+ {
+ if (n == null || n.SignValue < 1 || n.BitLength < 2)
+ throw new ArgumentException("must be non-null and >= 2", name);
+ }
+
+ private static bool ImplHasAnySmallFactors(BigInteger x)
+ {
+ /*
+ * Bundle trial divisors into ~32-bit moduli then use fast tests on the ~32-bit remainders.
+ */
+ int m = 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23;
+ int r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+ if ((r % 2) == 0 || (r % 3) == 0 || (r % 5) == 0 || (r % 7) == 0 || (r % 11) == 0 || (r % 13) == 0
+ || (r % 17) == 0 || (r % 19) == 0 || (r % 23) == 0)
+ {
+ return true;
+ }
+
+ m = 29 * 31 * 37 * 41 * 43;
+ r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+ if ((r % 29) == 0 || (r % 31) == 0 || (r % 37) == 0 || (r % 41) == 0 || (r % 43) == 0)
+ {
+ return true;
+ }
+
+ m = 47 * 53 * 59 * 61 * 67;
+ r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+ if ((r % 47) == 0 || (r % 53) == 0 || (r % 59) == 0 || (r % 61) == 0 || (r % 67) == 0)
+ {
+ return true;
+ }
+
+ m = 71 * 73 * 79 * 83;
+ r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+ if ((r % 71) == 0 || (r % 73) == 0 || (r % 79) == 0 || (r % 83) == 0)
+ {
+ return true;
+ }
+
+ m = 89 * 97 * 101 * 103;
+ r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+ if ((r % 89) == 0 || (r % 97) == 0 || (r % 101) == 0 || (r % 103) == 0)
+ {
+ return true;
+ }
+
+ m = 107 * 109 * 113 * 127;
+ r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+ if ((r % 107) == 0 || (r % 109) == 0 || (r % 113) == 0 || (r % 127) == 0)
+ {
+ return true;
+ }
+
+ m = 131 * 137 * 139 * 149;
+ r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+ if ((r % 131) == 0 || (r % 137) == 0 || (r % 139) == 0 || (r % 149) == 0)
+ {
+ return true;
+ }
+
+ m = 151 * 157 * 163 * 167;
+ r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+ if ((r % 151) == 0 || (r % 157) == 0 || (r % 163) == 0 || (r % 167) == 0)
+ {
+ return true;
+ }
+
+ m = 173 * 179 * 181 * 191;
+ r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+ if ((r % 173) == 0 || (r % 179) == 0 || (r % 181) == 0 || (r % 191) == 0)
+ {
+ return true;
+ }
+
+ m = 193 * 197 * 199 * 211;
+ r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+ if ((r % 193) == 0 || (r % 197) == 0 || (r % 199) == 0 || (r % 211) == 0)
+ {
+ return true;
+ }
+
+ /*
+ * NOTE: Unit tests depend on SMALL_FACTOR_LIMIT matching the
+ * highest small factor tested here.
+ */
+ return false;
+ }
+
+ private static bool ImplMRProbablePrimeToBase(BigInteger w, BigInteger wSubOne, BigInteger m, int a, BigInteger b)
+ {
+ BigInteger z = b.ModPow(m, w);
+
+ if (z.Equals(One) || z.Equals(wSubOne))
+ return true;
+
+ bool result = false;
+
+ for (int j = 1; j < a; ++j)
+ {
+ z = z.ModPow(Two, w);
+
+ if (z.Equals(wSubOne))
+ {
+ result = true;
+ break;
+ }
+
+ if (z.Equals(One))
+ return false;
+ }
+
+ return result;
+ }
+
+ private static STOutput ImplSTRandomPrime(IDigest d, int length, byte[] primeSeed)
+ {
+ int dLen = d.GetDigestSize();
+
+ if (length < 33)
+ {
+ int primeGenCounter = 0;
+
+ byte[] c0 = new byte[dLen];
+ byte[] c1 = new byte[dLen];
+
+ for (;;)
+ {
+ Hash(d, primeSeed, c0, 0);
+ Inc(primeSeed, 1);
+
+ Hash(d, primeSeed, c1, 0);
+ Inc(primeSeed, 1);
+
+ uint c = Extract32(c0) ^ Extract32(c1);
+ c &= (uint.MaxValue >> (32 - length));
+ c |= (1U << (length - 1)) | 1U;
+
+ ++primeGenCounter;
+
+ if (IsPrime32(c))
+ {
+ return new STOutput(BigInteger.ValueOf((long)c), primeSeed, primeGenCounter);
+ }
+
+ if (primeGenCounter > (4 * length))
+ {
+ throw new InvalidOperationException("Too many iterations in Shawe-Taylor Random_Prime Routine");
+ }
+ }
+ }
+
+ STOutput rec = ImplSTRandomPrime(d, (length + 3)/2, primeSeed);
+
+ {
+ BigInteger c0 = rec.Prime;
+ primeSeed = rec.PrimeSeed;
+ int primeGenCounter = rec.PrimeGenCounter;
+
+ int outlen = 8 * dLen;
+ int iterations = (length - 1)/outlen;
+
+ int oldCounter = primeGenCounter;
+
+ BigInteger x = HashGen(d, primeSeed, iterations + 1);
+ x = x.Mod(One.ShiftLeft(length - 1)).SetBit(length - 1);
+
+ BigInteger c0x2 = c0.ShiftLeft(1);
+ BigInteger tx2 = x.Subtract(One).Divide(c0x2).Add(One).ShiftLeft(1);
+ int dt = 0;
+
+ BigInteger c = tx2.Multiply(c0).Add(One);
+
+ /*
+ * TODO Since the candidate primes are generated by constant steps ('c0x2'),
+ * sieving could be used here in place of the 'HasAnySmallFactors' approach.
+ */
+ for (;;)
+ {
+ if (c.BitLength > length)
+ {
+ tx2 = One.ShiftLeft(length - 1).Subtract(One).Divide(c0x2).Add(One).ShiftLeft(1);
+ c = tx2.Multiply(c0).Add(One);
+ }
+
+ ++primeGenCounter;
+
+ /*
+ * This is an optimization of the original algorithm, using trial division to screen out
+ * many non-primes quickly.
+ *
+ * NOTE: 'primeSeed' is still incremented as if we performed the full check!
+ */
+ if (!ImplHasAnySmallFactors(c))
+ {
+ BigInteger a = HashGen(d, primeSeed, iterations + 1);
+ a = a.Mod(c.Subtract(Three)).Add(Two);
+
+ tx2 = tx2.Add(BigInteger.ValueOf(dt));
+ dt = 0;
+
+ BigInteger z = a.ModPow(tx2, c);
+
+ if (c.Gcd(z.Subtract(One)).Equals(One) && z.ModPow(c0, c).Equals(One))
+ {
+ return new STOutput(c, primeSeed, primeGenCounter);
+ }
+ }
+ else
+ {
+ Inc(primeSeed, iterations + 1);
+ }
+
+ if (primeGenCounter >= ((4 * length) + oldCounter))
+ {
+ throw new InvalidOperationException("Too many iterations in Shawe-Taylor Random_Prime Routine");
+ }
+
+ dt += 2;
+ c = c.Add(c0x2);
+ }
+ }
+ }
+
+ private static uint Extract32(byte[] bs)
+ {
+ uint result = 0;
+
+ int count = System.Math.Min(4, bs.Length);
+ for (int i = 0; i < count; ++i)
+ {
+ uint b = bs[bs.Length - (i + 1)];
+ result |= (b << (8 * i));
+ }
+
+ return result;
+ }
+
+ private static void Hash(IDigest d, byte[] input, byte[] output, int outPos)
+ {
+ d.BlockUpdate(input, 0, input.Length);
+ d.DoFinal(output, outPos);
+ }
+
+ private static BigInteger HashGen(IDigest d, byte[] seed, int count)
+ {
+ int dLen = d.GetDigestSize();
+ int pos = count * dLen;
+ byte[] buf = new byte[pos];
+ for (int i = 0; i < count; ++i)
+ {
+ pos -= dLen;
+ Hash(d, seed, buf, pos);
+ Inc(seed, 1);
+ }
+ return new BigInteger(1, buf);
+ }
+
+ private static void Inc(byte[] seed, int c)
+ {
+ int pos = seed.Length;
+ while (c > 0 && --pos >= 0)
+ {
+ c += seed[pos];
+ seed[pos] = (byte)c;
+ c >>= 8;
+ }
+ }
+
+ private static bool IsPrime32(uint x)
+ {
+ /*
+ * Use wheel factorization with 2, 3, 5 to select trial divisors.
+ */
+
+ if (x <= 5)
+ {
+ return x == 2 || x == 3 || x == 5;
+ }
+
+ if ((x & 1) == 0 || (x % 3) == 0 || (x % 5) == 0)
+ {
+ return false;
+ }
+
+ uint[] ds = new uint[]{ 1, 7, 11, 13, 17, 19, 23, 29 };
+ uint b = 0;
+ for (int pos = 1; ; pos = 0)
+ {
+ /*
+ * Trial division by wheel-selected divisors
+ */
+ while (pos < ds.Length)
+ {
+ uint d = b + ds[pos];
+ if (x % d == 0)
+ {
+ return x < 30;
+ }
+ ++pos;
+ }
+
+ b += 30;
+
+ if ((b >> 16 != 0) || (b * b >= x))
+ {
+ return true;
+ }
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/ECAlgorithms.cs b/bc-sharp-crypto/src/math/ec/ECAlgorithms.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5d60de40fe5f95280db85083ebddc6ad53b8737e
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/ECAlgorithms.cs
@@ -0,0 +1,479 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Endo;
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Math.Field;
+
+namespace Org.BouncyCastle.Math.EC
+{
+ public class ECAlgorithms
+ {
+ public static bool IsF2mCurve(ECCurve c)
+ {
+ return IsF2mField(c.Field);
+ }
+
+ public static bool IsF2mField(IFiniteField field)
+ {
+ return field.Dimension > 1 && field.Characteristic.Equals(BigInteger.Two)
+ && field is IPolynomialExtensionField;
+ }
+
+ public static bool IsFpCurve(ECCurve c)
+ {
+ return IsFpField(c.Field);
+ }
+
+ public static bool IsFpField(IFiniteField field)
+ {
+ return field.Dimension == 1;
+ }
+
+ public static ECPoint SumOfMultiplies(ECPoint[] ps, BigInteger[] ks)
+ {
+ if (ps == null || ks == null || ps.Length != ks.Length || ps.Length < 1)
+ throw new ArgumentException("point and scalar arrays should be non-null, and of equal, non-zero, length");
+
+ int count = ps.Length;
+ switch (count)
+ {
+ case 1:
+ return ps[0].Multiply(ks[0]);
+ case 2:
+ return SumOfTwoMultiplies(ps[0], ks[0], ps[1], ks[1]);
+ default:
+ break;
+ }
+
+ ECPoint p = ps[0];
+ ECCurve c = p.Curve;
+
+ ECPoint[] imported = new ECPoint[count];
+ imported[0] = p;
+ for (int i = 1; i < count; ++i)
+ {
+ imported[i] = ImportPoint(c, ps[i]);
+ }
+
+ GlvEndomorphism glvEndomorphism = c.GetEndomorphism() as GlvEndomorphism;
+ if (glvEndomorphism != null)
+ {
+ return ValidatePoint(ImplSumOfMultipliesGlv(imported, ks, glvEndomorphism));
+ }
+
+ return ValidatePoint(ImplSumOfMultiplies(imported, ks));
+ }
+
+ public static ECPoint SumOfTwoMultiplies(ECPoint P, BigInteger a, ECPoint Q, BigInteger b)
+ {
+ ECCurve cp = P.Curve;
+ Q = ImportPoint(cp, Q);
+
+ // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
+ {
+ AbstractF2mCurve f2mCurve = cp as AbstractF2mCurve;
+ if (f2mCurve != null && f2mCurve.IsKoblitz)
+ {
+ return ValidatePoint(P.Multiply(a).Add(Q.Multiply(b)));
+ }
+ }
+
+ GlvEndomorphism glvEndomorphism = cp.GetEndomorphism() as GlvEndomorphism;
+ if (glvEndomorphism != null)
+ {
+ return ValidatePoint(
+ ImplSumOfMultipliesGlv(new ECPoint[] { P, Q }, new BigInteger[] { a, b }, glvEndomorphism));
+ }
+
+ return ValidatePoint(ImplShamirsTrickWNaf(P, a, Q, b));
+ }
+
+ /*
+ * "Shamir's Trick", originally due to E. G. Straus
+ * (Addition chains of vectors. American Mathematical Monthly,
+ * 71(7):806-808, Aug./Sept. 1964)
+ *
+ * Input: The points P, Q, scalar k = (km?, ... , k1, k0)
+ * and scalar l = (lm?, ... , l1, l0).
+ * Output: R = k * P + l * Q.
+ * 1: Z <- P + Q
+ * 2: R <- O
+ * 3: for i from m-1 down to 0 do
+ * 4: R <- R + R {point doubling}
+ * 5: if (ki = 1) and (li = 0) then R <- R + P end if
+ * 6: if (ki = 0) and (li = 1) then R <- R + Q end if
+ * 7: if (ki = 1) and (li = 1) then R <- R + Z end if
+ * 8: end for
+ * 9: return R
+ */
+ public static ECPoint ShamirsTrick(ECPoint P, BigInteger k, ECPoint Q, BigInteger l)
+ {
+ ECCurve cp = P.Curve;
+ Q = ImportPoint(cp, Q);
+
+ return ValidatePoint(ImplShamirsTrickJsf(P, k, Q, l));
+ }
+
+ public static ECPoint ImportPoint(ECCurve c, ECPoint p)
+ {
+ ECCurve cp = p.Curve;
+ if (!c.Equals(cp))
+ throw new ArgumentException("Point must be on the same curve");
+
+ return c.ImportPoint(p);
+ }
+
+ public static void MontgomeryTrick(ECFieldElement[] zs, int off, int len)
+ {
+ MontgomeryTrick(zs, off, len, null);
+ }
+
+ public static void MontgomeryTrick(ECFieldElement[] zs, int off, int len, ECFieldElement scale)
+ {
+ /*
+ * Uses the "Montgomery Trick" to invert many field elements, with only a single actual
+ * field inversion. See e.g. the paper:
+ * "Fast Multi-scalar Multiplication Methods on Elliptic Curves with Precomputation Strategy Using Montgomery Trick"
+ * by Katsuyuki Okeya, Kouichi Sakurai.
+ */
+
+ ECFieldElement[] c = new ECFieldElement[len];
+ c[0] = zs[off];
+
+ int i = 0;
+ while (++i < len)
+ {
+ c[i] = c[i - 1].Multiply(zs[off + i]);
+ }
+
+ --i;
+
+ if (scale != null)
+ {
+ c[i] = c[i].Multiply(scale);
+ }
+
+ ECFieldElement u = c[i].Invert();
+
+ while (i > 0)
+ {
+ int j = off + i--;
+ ECFieldElement tmp = zs[j];
+ zs[j] = c[i].Multiply(u);
+ u = u.Multiply(tmp);
+ }
+
+ zs[off] = u;
+ }
+
+ /**
+ * Simple shift-and-add multiplication. Serves as reference implementation
+ * to verify (possibly faster) implementations, and for very small scalars.
+ *
+ * @param p
+ * The point to multiply.
+ * @param k
+ * The multiplier.
+ * @return The result of the point multiplication kP
.
+ */
+ public static ECPoint ReferenceMultiply(ECPoint p, BigInteger k)
+ {
+ BigInteger x = k.Abs();
+ ECPoint q = p.Curve.Infinity;
+ int t = x.BitLength;
+ if (t > 0)
+ {
+ if (x.TestBit(0))
+ {
+ q = p;
+ }
+ for (int i = 1; i < t; i++)
+ {
+ p = p.Twice();
+ if (x.TestBit(i))
+ {
+ q = q.Add(p);
+ }
+ }
+ }
+ return k.SignValue < 0 ? q.Negate() : q;
+ }
+
+ public static ECPoint ValidatePoint(ECPoint p)
+ {
+ if (!p.IsValid())
+ throw new ArgumentException("Invalid point", "p");
+
+ return p;
+ }
+
+ internal static ECPoint ImplShamirsTrickJsf(ECPoint P, BigInteger k, ECPoint Q, BigInteger l)
+ {
+ ECCurve curve = P.Curve;
+ ECPoint infinity = curve.Infinity;
+
+ // TODO conjugate co-Z addition (ZADDC) can return both of these
+ ECPoint PaddQ = P.Add(Q);
+ ECPoint PsubQ = P.Subtract(Q);
+
+ ECPoint[] points = new ECPoint[] { Q, PsubQ, P, PaddQ };
+ curve.NormalizeAll(points);
+
+ ECPoint[] table = new ECPoint[] {
+ points[3].Negate(), points[2].Negate(), points[1].Negate(),
+ points[0].Negate(), infinity, points[0],
+ points[1], points[2], points[3] };
+
+ byte[] jsf = WNafUtilities.GenerateJsf(k, l);
+
+ ECPoint R = infinity;
+
+ int i = jsf.Length;
+ while (--i >= 0)
+ {
+ int jsfi = jsf[i];
+
+ // NOTE: The shifting ensures the sign is extended correctly
+ int kDigit = ((jsfi << 24) >> 28), lDigit = ((jsfi << 28) >> 28);
+
+ int index = 4 + (kDigit * 3) + lDigit;
+ R = R.TwicePlus(table[index]);
+ }
+
+ return R;
+ }
+
+ internal static ECPoint ImplShamirsTrickWNaf(ECPoint P, BigInteger k,
+ ECPoint Q, BigInteger l)
+ {
+ bool negK = k.SignValue < 0, negL = l.SignValue < 0;
+
+ k = k.Abs();
+ l = l.Abs();
+
+ int widthP = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(k.BitLength)));
+ int widthQ = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(l.BitLength)));
+
+ WNafPreCompInfo infoP = WNafUtilities.Precompute(P, widthP, true);
+ WNafPreCompInfo infoQ = WNafUtilities.Precompute(Q, widthQ, true);
+
+ ECPoint[] preCompP = negK ? infoP.PreCompNeg : infoP.PreComp;
+ ECPoint[] preCompQ = negL ? infoQ.PreCompNeg : infoQ.PreComp;
+ ECPoint[] preCompNegP = negK ? infoP.PreComp : infoP.PreCompNeg;
+ ECPoint[] preCompNegQ = negL ? infoQ.PreComp : infoQ.PreCompNeg;
+
+ byte[] wnafP = WNafUtilities.GenerateWindowNaf(widthP, k);
+ byte[] wnafQ = WNafUtilities.GenerateWindowNaf(widthQ, l);
+
+ return ImplShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ);
+ }
+
+ internal static ECPoint ImplShamirsTrickWNaf(ECPoint P, BigInteger k, ECPointMap pointMapQ, BigInteger l)
+ {
+ bool negK = k.SignValue < 0, negL = l.SignValue < 0;
+
+ k = k.Abs();
+ l = l.Abs();
+
+ int width = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(System.Math.Max(k.BitLength, l.BitLength))));
+
+ ECPoint Q = WNafUtilities.MapPointWithPrecomp(P, width, true, pointMapQ);
+ WNafPreCompInfo infoP = WNafUtilities.GetWNafPreCompInfo(P);
+ WNafPreCompInfo infoQ = WNafUtilities.GetWNafPreCompInfo(Q);
+
+ ECPoint[] preCompP = negK ? infoP.PreCompNeg : infoP.PreComp;
+ ECPoint[] preCompQ = negL ? infoQ.PreCompNeg : infoQ.PreComp;
+ ECPoint[] preCompNegP = negK ? infoP.PreComp : infoP.PreCompNeg;
+ ECPoint[] preCompNegQ = negL ? infoQ.PreComp : infoQ.PreCompNeg;
+
+ byte[] wnafP = WNafUtilities.GenerateWindowNaf(width, k);
+ byte[] wnafQ = WNafUtilities.GenerateWindowNaf(width, l);
+
+ return ImplShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ);
+ }
+
+ private static ECPoint ImplShamirsTrickWNaf(ECPoint[] preCompP, ECPoint[] preCompNegP, byte[] wnafP,
+ ECPoint[] preCompQ, ECPoint[] preCompNegQ, byte[] wnafQ)
+ {
+ int len = System.Math.Max(wnafP.Length, wnafQ.Length);
+
+ ECCurve curve = preCompP[0].Curve;
+ ECPoint infinity = curve.Infinity;
+
+ ECPoint R = infinity;
+ int zeroes = 0;
+
+ for (int i = len - 1; i >= 0; --i)
+ {
+ int wiP = i < wnafP.Length ? (int)(sbyte)wnafP[i] : 0;
+ int wiQ = i < wnafQ.Length ? (int)(sbyte)wnafQ[i] : 0;
+
+ if ((wiP | wiQ) == 0)
+ {
+ ++zeroes;
+ continue;
+ }
+
+ ECPoint r = infinity;
+ if (wiP != 0)
+ {
+ int nP = System.Math.Abs(wiP);
+ ECPoint[] tableP = wiP < 0 ? preCompNegP : preCompP;
+ r = r.Add(tableP[nP >> 1]);
+ }
+ if (wiQ != 0)
+ {
+ int nQ = System.Math.Abs(wiQ);
+ ECPoint[] tableQ = wiQ < 0 ? preCompNegQ : preCompQ;
+ r = r.Add(tableQ[nQ >> 1]);
+ }
+
+ if (zeroes > 0)
+ {
+ R = R.TimesPow2(zeroes);
+ zeroes = 0;
+ }
+
+ R = R.TwicePlus(r);
+ }
+
+ if (zeroes > 0)
+ {
+ R = R.TimesPow2(zeroes);
+ }
+
+ return R;
+ }
+
+ internal static ECPoint ImplSumOfMultiplies(ECPoint[] ps, BigInteger[] ks)
+ {
+ int count = ps.Length;
+ bool[] negs = new bool[count];
+ WNafPreCompInfo[] infos = new WNafPreCompInfo[count];
+ byte[][] wnafs = new byte[count][];
+
+ for (int i = 0; i < count; ++i)
+ {
+ BigInteger ki = ks[i]; negs[i] = ki.SignValue < 0; ki = ki.Abs();
+
+ int width = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(ki.BitLength)));
+ infos[i] = WNafUtilities.Precompute(ps[i], width, true);
+ wnafs[i] = WNafUtilities.GenerateWindowNaf(width, ki);
+ }
+
+ return ImplSumOfMultiplies(negs, infos, wnafs);
+ }
+
+ internal static ECPoint ImplSumOfMultipliesGlv(ECPoint[] ps, BigInteger[] ks, GlvEndomorphism glvEndomorphism)
+ {
+ BigInteger n = ps[0].Curve.Order;
+
+ int len = ps.Length;
+
+ BigInteger[] abs = new BigInteger[len << 1];
+ for (int i = 0, j = 0; i < len; ++i)
+ {
+ BigInteger[] ab = glvEndomorphism.DecomposeScalar(ks[i].Mod(n));
+ abs[j++] = ab[0];
+ abs[j++] = ab[1];
+ }
+
+ ECPointMap pointMap = glvEndomorphism.PointMap;
+ if (glvEndomorphism.HasEfficientPointMap)
+ {
+ return ECAlgorithms.ImplSumOfMultiplies(ps, pointMap, abs);
+ }
+
+ ECPoint[] pqs = new ECPoint[len << 1];
+ for (int i = 0, j = 0; i < len; ++i)
+ {
+ ECPoint p = ps[i], q = pointMap.Map(p);
+ pqs[j++] = p;
+ pqs[j++] = q;
+ }
+
+ return ECAlgorithms.ImplSumOfMultiplies(pqs, abs);
+ }
+
+ internal static ECPoint ImplSumOfMultiplies(ECPoint[] ps, ECPointMap pointMap, BigInteger[] ks)
+ {
+ int halfCount = ps.Length, fullCount = halfCount << 1;
+
+ bool[] negs = new bool[fullCount];
+ WNafPreCompInfo[] infos = new WNafPreCompInfo[fullCount];
+ byte[][] wnafs = new byte[fullCount][];
+
+ for (int i = 0; i < halfCount; ++i)
+ {
+ int j0 = i << 1, j1 = j0 + 1;
+
+ BigInteger kj0 = ks[j0]; negs[j0] = kj0.SignValue < 0; kj0 = kj0.Abs();
+ BigInteger kj1 = ks[j1]; negs[j1] = kj1.SignValue < 0; kj1 = kj1.Abs();
+
+ int width = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(System.Math.Max(kj0.BitLength, kj1.BitLength))));
+
+ ECPoint P = ps[i], Q = WNafUtilities.MapPointWithPrecomp(P, width, true, pointMap);
+ infos[j0] = WNafUtilities.GetWNafPreCompInfo(P);
+ infos[j1] = WNafUtilities.GetWNafPreCompInfo(Q);
+ wnafs[j0] = WNafUtilities.GenerateWindowNaf(width, kj0);
+ wnafs[j1] = WNafUtilities.GenerateWindowNaf(width, kj1);
+ }
+
+ return ImplSumOfMultiplies(negs, infos, wnafs);
+ }
+
+ private static ECPoint ImplSumOfMultiplies(bool[] negs, WNafPreCompInfo[] infos, byte[][] wnafs)
+ {
+ int len = 0, count = wnafs.Length;
+ for (int i = 0; i < count; ++i)
+ {
+ len = System.Math.Max(len, wnafs[i].Length);
+ }
+
+ ECCurve curve = infos[0].PreComp[0].Curve;
+ ECPoint infinity = curve.Infinity;
+
+ ECPoint R = infinity;
+ int zeroes = 0;
+
+ for (int i = len - 1; i >= 0; --i)
+ {
+ ECPoint r = infinity;
+
+ for (int j = 0; j < count; ++j)
+ {
+ byte[] wnaf = wnafs[j];
+ int wi = i < wnaf.Length ? (int)(sbyte)wnaf[i] : 0;
+ if (wi != 0)
+ {
+ int n = System.Math.Abs(wi);
+ WNafPreCompInfo info = infos[j];
+ ECPoint[] table = (wi < 0 == negs[j]) ? info.PreComp : info.PreCompNeg;
+ r = r.Add(table[n >> 1]);
+ }
+ }
+
+ if (r == infinity)
+ {
+ ++zeroes;
+ continue;
+ }
+
+ if (zeroes > 0)
+ {
+ R = R.TimesPow2(zeroes);
+ zeroes = 0;
+ }
+
+ R = R.TwicePlus(r);
+ }
+
+ if (zeroes > 0)
+ {
+ R = R.TimesPow2(zeroes);
+ }
+
+ return R;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/ECCurve.cs b/bc-sharp-crypto/src/math/ec/ECCurve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6ccd97e7b300bbae924021d7bb838057eb4cc267
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/ECCurve.cs
@@ -0,0 +1,1131 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math.EC.Abc;
+using Org.BouncyCastle.Math.EC.Endo;
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Math.Field;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC
+{
+ /// Base class for an elliptic curve.
+ public abstract class ECCurve
+ {
+ public const int COORD_AFFINE = 0;
+ public const int COORD_HOMOGENEOUS = 1;
+ public const int COORD_JACOBIAN = 2;
+ public const int COORD_JACOBIAN_CHUDNOVSKY = 3;
+ public const int COORD_JACOBIAN_MODIFIED = 4;
+ public const int COORD_LAMBDA_AFFINE = 5;
+ public const int COORD_LAMBDA_PROJECTIVE = 6;
+ public const int COORD_SKEWED = 7;
+
+ public static int[] GetAllCoordinateSystems()
+ {
+ return new int[]{ COORD_AFFINE, COORD_HOMOGENEOUS, COORD_JACOBIAN, COORD_JACOBIAN_CHUDNOVSKY,
+ COORD_JACOBIAN_MODIFIED, COORD_LAMBDA_AFFINE, COORD_LAMBDA_PROJECTIVE, COORD_SKEWED };
+ }
+
+ public class Config
+ {
+ protected ECCurve outer;
+ protected int coord;
+ protected ECEndomorphism endomorphism;
+ protected ECMultiplier multiplier;
+
+ internal Config(ECCurve outer, int coord, ECEndomorphism endomorphism, ECMultiplier multiplier)
+ {
+ this.outer = outer;
+ this.coord = coord;
+ this.endomorphism = endomorphism;
+ this.multiplier = multiplier;
+ }
+
+ public Config SetCoordinateSystem(int coord)
+ {
+ this.coord = coord;
+ return this;
+ }
+
+ public Config SetEndomorphism(ECEndomorphism endomorphism)
+ {
+ this.endomorphism = endomorphism;
+ return this;
+ }
+
+ public Config SetMultiplier(ECMultiplier multiplier)
+ {
+ this.multiplier = multiplier;
+ return this;
+ }
+
+ public ECCurve Create()
+ {
+ if (!outer.SupportsCoordinateSystem(coord))
+ {
+ throw new InvalidOperationException("unsupported coordinate system");
+ }
+
+ ECCurve c = outer.CloneCurve();
+ if (c == outer)
+ {
+ throw new InvalidOperationException("implementation returned current curve");
+ }
+
+ c.m_coord = coord;
+ c.m_endomorphism = endomorphism;
+ c.m_multiplier = multiplier;
+
+ return c;
+ }
+ }
+
+ protected readonly IFiniteField m_field;
+ protected ECFieldElement m_a, m_b;
+ protected BigInteger m_order, m_cofactor;
+
+ protected int m_coord = COORD_AFFINE;
+ protected ECEndomorphism m_endomorphism = null;
+ protected ECMultiplier m_multiplier = null;
+
+ protected ECCurve(IFiniteField field)
+ {
+ this.m_field = field;
+ }
+
+ public abstract int FieldSize { get; }
+ public abstract ECFieldElement FromBigInteger(BigInteger x);
+ public abstract bool IsValidFieldElement(BigInteger x);
+
+ public virtual Config Configure()
+ {
+ return new Config(this, this.m_coord, this.m_endomorphism, this.m_multiplier);
+ }
+
+ public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y)
+ {
+ ECPoint p = CreatePoint(x, y);
+ if (!p.IsValid())
+ {
+ throw new ArgumentException("Invalid point coordinates");
+ }
+ return p;
+ }
+
+ [Obsolete("Per-point compression property will be removed")]
+ public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y, bool withCompression)
+ {
+ ECPoint p = CreatePoint(x, y, withCompression);
+ if (!p.IsValid())
+ {
+ throw new ArgumentException("Invalid point coordinates");
+ }
+ return p;
+ }
+
+ public virtual ECPoint CreatePoint(BigInteger x, BigInteger y)
+ {
+ return CreatePoint(x, y, false);
+ }
+
+ [Obsolete("Per-point compression property will be removed")]
+ public virtual ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression)
+ {
+ return CreateRawPoint(FromBigInteger(x), FromBigInteger(y), withCompression);
+ }
+
+ protected abstract ECCurve CloneCurve();
+
+ protected internal abstract ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression);
+
+ protected internal abstract ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression);
+
+ protected virtual ECMultiplier CreateDefaultMultiplier()
+ {
+ GlvEndomorphism glvEndomorphism = m_endomorphism as GlvEndomorphism;
+ if (glvEndomorphism != null)
+ {
+ return new GlvMultiplier(this, glvEndomorphism);
+ }
+
+ return new WNafL2RMultiplier();
+ }
+
+ public virtual bool SupportsCoordinateSystem(int coord)
+ {
+ return coord == COORD_AFFINE;
+ }
+
+ public virtual PreCompInfo GetPreCompInfo(ECPoint point, string name)
+ {
+ CheckPoint(point);
+ lock (point)
+ {
+ IDictionary table = point.m_preCompTable;
+ return table == null ? null : (PreCompInfo)table[name];
+ }
+ }
+
+ /**
+ * Adds PreCompInfo
for a point on this curve, under a given name. Used by
+ * ECMultiplier
s to save the precomputation for this ECPoint
for use
+ * by subsequent multiplication.
+ *
+ * @param point
+ * The ECPoint
to store precomputations for.
+ * @param name
+ * A String
used to index precomputations of different types.
+ * @param preCompInfo
+ * The values precomputed by the ECMultiplier
.
+ */
+ public virtual void SetPreCompInfo(ECPoint point, string name, PreCompInfo preCompInfo)
+ {
+ CheckPoint(point);
+ lock (point)
+ {
+ IDictionary table = point.m_preCompTable;
+ if (null == table)
+ {
+ point.m_preCompTable = table = Platform.CreateHashtable(4);
+ }
+ table[name] = preCompInfo;
+ }
+ }
+
+ public virtual ECPoint ImportPoint(ECPoint p)
+ {
+ if (this == p.Curve)
+ {
+ return p;
+ }
+ if (p.IsInfinity)
+ {
+ return Infinity;
+ }
+
+ // TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates.
+ p = p.Normalize();
+
+ return ValidatePoint(p.XCoord.ToBigInteger(), p.YCoord.ToBigInteger(), p.IsCompressed);
+ }
+
+ /**
+ * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
+ * coordinates reflect those of the equivalent point in an affine coordinate system. Where more
+ * than one point is to be normalized, this method will generally be more efficient than
+ * normalizing each point separately.
+ *
+ * @param points
+ * An array of points that will be updated in place with their normalized versions,
+ * where necessary
+ */
+ public virtual void NormalizeAll(ECPoint[] points)
+ {
+ NormalizeAll(points, 0, points.Length, null);
+ }
+
+ /**
+ * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
+ * coordinates reflect those of the equivalent point in an affine coordinate system. Where more
+ * than one point is to be normalized, this method will generally be more efficient than
+ * normalizing each point separately. An (optional) z-scaling factor can be applied; effectively
+ * each z coordinate is scaled by this value prior to normalization (but only one
+ * actual multiplication is needed).
+ *
+ * @param points
+ * An array of points that will be updated in place with their normalized versions,
+ * where necessary
+ * @param off
+ * The start of the range of points to normalize
+ * @param len
+ * The length of the range of points to normalize
+ * @param iso
+ * The (optional) z-scaling factor - can be null
+ */
+ public virtual void NormalizeAll(ECPoint[] points, int off, int len, ECFieldElement iso)
+ {
+ CheckPoints(points, off, len);
+
+ switch (this.CoordinateSystem)
+ {
+ case ECCurve.COORD_AFFINE:
+ case ECCurve.COORD_LAMBDA_AFFINE:
+ {
+ if (iso != null)
+ throw new ArgumentException("not valid for affine coordinates", "iso");
+
+ return;
+ }
+ }
+
+ /*
+ * Figure out which of the points actually need to be normalized
+ */
+ ECFieldElement[] zs = new ECFieldElement[len];
+ int[] indices = new int[len];
+ int count = 0;
+ for (int i = 0; i < len; ++i)
+ {
+ ECPoint p = points[off + i];
+ if (null != p && (iso != null || !p.IsNormalized()))
+ {
+ zs[count] = p.GetZCoord(0);
+ indices[count++] = off + i;
+ }
+ }
+
+ if (count == 0)
+ {
+ return;
+ }
+
+ ECAlgorithms.MontgomeryTrick(zs, 0, count, iso);
+
+ for (int j = 0; j < count; ++j)
+ {
+ int index = indices[j];
+ points[index] = points[index].Normalize(zs[j]);
+ }
+ }
+
+ public abstract ECPoint Infinity { get; }
+
+ public virtual IFiniteField Field
+ {
+ get { return m_field; }
+ }
+
+ public virtual ECFieldElement A
+ {
+ get { return m_a; }
+ }
+
+ public virtual ECFieldElement B
+ {
+ get { return m_b; }
+ }
+
+ public virtual BigInteger Order
+ {
+ get { return m_order; }
+ }
+
+ public virtual BigInteger Cofactor
+ {
+ get { return m_cofactor; }
+ }
+
+ public virtual int CoordinateSystem
+ {
+ get { return m_coord; }
+ }
+
+ protected virtual void CheckPoint(ECPoint point)
+ {
+ if (null == point || (this != point.Curve))
+ throw new ArgumentException("must be non-null and on this curve", "point");
+ }
+
+ protected virtual void CheckPoints(ECPoint[] points)
+ {
+ CheckPoints(points, 0, points.Length);
+ }
+
+ protected virtual void CheckPoints(ECPoint[] points, int off, int len)
+ {
+ if (points == null)
+ throw new ArgumentNullException("points");
+ if (off < 0 || len < 0 || (off > (points.Length - len)))
+ throw new ArgumentException("invalid range specified", "points");
+
+ for (int i = 0; i < len; ++i)
+ {
+ ECPoint point = points[off + i];
+ if (null != point && this != point.Curve)
+ throw new ArgumentException("entries must be null or on this curve", "points");
+ }
+ }
+
+ public virtual bool Equals(ECCurve other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Field.Equals(other.Field)
+ && A.ToBigInteger().Equals(other.A.ToBigInteger())
+ && B.ToBigInteger().Equals(other.B.ToBigInteger());
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as ECCurve);
+ }
+
+ public override int GetHashCode()
+ {
+ return Field.GetHashCode()
+ ^ Integers.RotateLeft(A.ToBigInteger().GetHashCode(), 8)
+ ^ Integers.RotateLeft(B.ToBigInteger().GetHashCode(), 16);
+ }
+
+ protected abstract ECPoint DecompressPoint(int yTilde, BigInteger X1);
+
+ public virtual ECEndomorphism GetEndomorphism()
+ {
+ return m_endomorphism;
+ }
+
+ /**
+ * Sets the default ECMultiplier
, unless already set.
+ */
+ public virtual ECMultiplier GetMultiplier()
+ {
+ lock (this)
+ {
+ if (this.m_multiplier == null)
+ {
+ this.m_multiplier = CreateDefaultMultiplier();
+ }
+ return this.m_multiplier;
+ }
+ }
+
+ /**
+ * Decode a point on this curve from its ASN.1 encoding. The different
+ * encodings are taken account of, including point compression for
+ * Fp
(X9.62 s 4.2.1 pg 17).
+ * @return The decoded point.
+ */
+ public virtual ECPoint DecodePoint(byte[] encoded)
+ {
+ ECPoint p = null;
+ int expectedLength = (FieldSize + 7) / 8;
+
+ byte type = encoded[0];
+ switch (type)
+ {
+ case 0x00: // infinity
+ {
+ if (encoded.Length != 1)
+ throw new ArgumentException("Incorrect length for infinity encoding", "encoded");
+
+ p = Infinity;
+ break;
+ }
+
+ case 0x02: // compressed
+ case 0x03: // compressed
+ {
+ if (encoded.Length != (expectedLength + 1))
+ throw new ArgumentException("Incorrect length for compressed encoding", "encoded");
+
+ int yTilde = type & 1;
+ BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
+
+ p = DecompressPoint(yTilde, X);
+ if (!p.SatisfiesCofactor())
+ throw new ArgumentException("Invalid point");
+
+ break;
+ }
+
+ case 0x04: // uncompressed
+ {
+ if (encoded.Length != (2 * expectedLength + 1))
+ throw new ArgumentException("Incorrect length for uncompressed encoding", "encoded");
+
+ BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
+ BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
+
+ p = ValidatePoint(X, Y);
+ break;
+ }
+
+ case 0x06: // hybrid
+ case 0x07: // hybrid
+ {
+ if (encoded.Length != (2 * expectedLength + 1))
+ throw new ArgumentException("Incorrect length for hybrid encoding", "encoded");
+
+ BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
+ BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
+
+ if (Y.TestBit(0) != (type == 0x07))
+ throw new ArgumentException("Inconsistent Y coordinate in hybrid encoding", "encoded");
+
+ p = ValidatePoint(X, Y);
+ break;
+ }
+
+ default:
+ throw new FormatException("Invalid point encoding " + type);
+ }
+
+ if (type != 0x00 && p.IsInfinity)
+ throw new ArgumentException("Invalid infinity encoding", "encoded");
+
+ return p;
+ }
+ }
+
+ public abstract class AbstractFpCurve
+ : ECCurve
+ {
+ protected AbstractFpCurve(BigInteger q)
+ : base(FiniteFields.GetPrimeField(q))
+ {
+ }
+
+ public override bool IsValidFieldElement(BigInteger x)
+ {
+ return x != null && x.SignValue >= 0 && x.CompareTo(Field.Characteristic) < 0;
+ }
+
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement x = FromBigInteger(X1);
+ ECFieldElement rhs = x.Square().Add(A).Multiply(x).Add(B);
+ ECFieldElement y = rhs.Sqrt();
+
+ /*
+ * If y is not a square, then we haven't got a point on the curve
+ */
+ if (y == null)
+ throw new ArgumentException("Invalid point compression");
+
+ if (y.TestBitZero() != (yTilde == 1))
+ {
+ // Use the other root
+ y = y.Negate();
+ }
+
+ return CreateRawPoint(x, y, true);
+ }
+ }
+
+ /**
+ * Elliptic curve over Fp
+ */
+ public class FpCurve
+ : AbstractFpCurve
+ {
+ private const int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
+
+ protected readonly BigInteger m_q, m_r;
+ protected readonly FpPoint m_infinity;
+
+ public FpCurve(BigInteger q, BigInteger a, BigInteger b)
+ : this(q, a, b, null, null)
+ {
+ }
+
+ public FpCurve(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor)
+ : base(q)
+ {
+ this.m_q = q;
+ this.m_r = FpFieldElement.CalculateResidue(q);
+ this.m_infinity = new FpPoint(this, null, null);
+
+ this.m_a = FromBigInteger(a);
+ this.m_b = FromBigInteger(b);
+ this.m_order = order;
+ this.m_cofactor = cofactor;
+ this.m_coord = FP_DEFAULT_COORDS;
+ }
+
+ protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b)
+ : this(q, r, a, b, null, null)
+ {
+ }
+
+ protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
+ : base(q)
+ {
+ this.m_q = q;
+ this.m_r = r;
+ this.m_infinity = new FpPoint(this, null, null);
+
+ this.m_a = a;
+ this.m_b = b;
+ this.m_order = order;
+ this.m_cofactor = cofactor;
+ this.m_coord = FP_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new FpCurve(m_q, m_r, m_a, m_b, m_order, m_cofactor);
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_AFFINE:
+ case COORD_HOMOGENEOUS:
+ case COORD_JACOBIAN:
+ case COORD_JACOBIAN_MODIFIED:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return m_q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return m_q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new FpFieldElement(this.m_q, this.m_r, x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new FpPoint(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new FpPoint(this, x, y, zs, withCompression);
+ }
+
+ public override ECPoint ImportPoint(ECPoint p)
+ {
+ if (this != p.Curve && this.CoordinateSystem == COORD_JACOBIAN && !p.IsInfinity)
+ {
+ switch (p.Curve.CoordinateSystem)
+ {
+ case COORD_JACOBIAN:
+ case COORD_JACOBIAN_CHUDNOVSKY:
+ case COORD_JACOBIAN_MODIFIED:
+ return new FpPoint(this,
+ FromBigInteger(p.RawXCoord.ToBigInteger()),
+ FromBigInteger(p.RawYCoord.ToBigInteger()),
+ new ECFieldElement[] { FromBigInteger(p.GetZCoord(0).ToBigInteger()) },
+ p.IsCompressed);
+ default:
+ break;
+ }
+ }
+
+ return base.ImportPoint(p);
+ }
+ }
+
+ public abstract class AbstractF2mCurve
+ : ECCurve
+ {
+ public static BigInteger Inverse(int m, int[] ks, BigInteger x)
+ {
+ return new LongArray(x).ModInverse(m, ks).ToBigInteger();
+ }
+
+ /**
+ * The auxiliary values s0
and
+ * s1
used for partial modular reduction for
+ * Koblitz curves.
+ */
+ private BigInteger[] si = null;
+
+ private static IFiniteField BuildField(int m, int k1, int k2, int k3)
+ {
+ if (k1 == 0)
+ {
+ throw new ArgumentException("k1 must be > 0");
+ }
+
+ if (k2 == 0)
+ {
+ if (k3 != 0)
+ {
+ throw new ArgumentException("k3 must be 0 if k2 == 0");
+ }
+
+ return FiniteFields.GetBinaryExtensionField(new int[]{ 0, k1, m });
+ }
+
+ if (k2 <= k1)
+ {
+ throw new ArgumentException("k2 must be > k1");
+ }
+
+ if (k3 <= k2)
+ {
+ throw new ArgumentException("k3 must be > k2");
+ }
+
+ return FiniteFields.GetBinaryExtensionField(new int[]{ 0, k1, k2, k3, m });
+ }
+
+ protected AbstractF2mCurve(int m, int k1, int k2, int k3)
+ : base(BuildField(m, k1, k2, k3))
+ {
+ }
+
+ public override bool IsValidFieldElement(BigInteger x)
+ {
+ return x != null && x.SignValue >= 0 && x.BitLength <= FieldSize;
+ }
+
+ [Obsolete("Per-point compression property will be removed")]
+ public override ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression)
+ {
+ ECFieldElement X = FromBigInteger(x), Y = FromBigInteger(y);
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ if (X.IsZero)
+ {
+ if (!Y.Square().Equals(B))
+ throw new ArgumentException();
+ }
+ else
+ {
+ // Y becomes Lambda (X + Y/X) here
+ Y = Y.Divide(X).Add(X);
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ return CreateRawPoint(X, Y, withCompression);
+ }
+
+ protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+ {
+ ECFieldElement xp = FromBigInteger(X1), yp = null;
+ if (xp.IsZero)
+ {
+ yp = B.Sqrt();
+ }
+ else
+ {
+ ECFieldElement beta = xp.Square().Invert().Multiply(B).Add(A).Add(xp);
+ ECFieldElement z = SolveQuadradicEquation(beta);
+
+ if (z != null)
+ {
+ if (z.TestBitZero() != (yTilde == 1))
+ {
+ z = z.AddOne();
+ }
+
+ switch (this.CoordinateSystem)
+ {
+ case COORD_LAMBDA_AFFINE:
+ case COORD_LAMBDA_PROJECTIVE:
+ {
+ yp = z.Add(xp);
+ break;
+ }
+ default:
+ {
+ yp = z.Multiply(xp);
+ break;
+ }
+ }
+ }
+ }
+
+ if (yp == null)
+ throw new ArgumentException("Invalid point compression");
+
+ return CreateRawPoint(xp, yp, true);
+ }
+
+ /**
+ * Solves a quadratic equation z2 + z = beta
(X9.62
+ * D.1.6) The other solution is z + 1
.
+ *
+ * @param beta
+ * The value to solve the qradratic equation for.
+ * @return the solution for z2 + z = beta
or
+ * null
if no solution exists.
+ */
+ private ECFieldElement SolveQuadradicEquation(ECFieldElement beta)
+ {
+ if (beta.IsZero)
+ return beta;
+
+ ECFieldElement gamma, z, zeroElement = FromBigInteger(BigInteger.Zero);
+
+ int m = FieldSize;
+ do
+ {
+ ECFieldElement t = FromBigInteger(BigInteger.Arbitrary(m));
+ z = zeroElement;
+ ECFieldElement w = beta;
+ for (int i = 1; i < m; i++)
+ {
+ ECFieldElement w2 = w.Square();
+ z = z.Square().Add(w2.Multiply(t));
+ w = w2.Add(beta);
+ }
+ if (!w.IsZero)
+ {
+ return null;
+ }
+ gamma = z.Square().Add(z);
+ }
+ while (gamma.IsZero);
+
+ return z;
+ }
+
+ /**
+ * @return the auxiliary values s0
and
+ * s1
used for partial modular reduction for
+ * Koblitz curves.
+ */
+ internal virtual BigInteger[] GetSi()
+ {
+ if (si == null)
+ {
+ lock (this)
+ {
+ if (si == null)
+ {
+ si = Tnaf.GetSi(this);
+ }
+ }
+ }
+ return si;
+ }
+
+ /**
+ * Returns true if this is a Koblitz curve (ABC curve).
+ * @return true if this is a Koblitz curve (ABC curve), false otherwise
+ */
+ public virtual bool IsKoblitz
+ {
+ get
+ {
+ return m_order != null && m_cofactor != null && m_b.IsOne && (m_a.IsZero || m_a.IsOne);
+ }
+ }
+ }
+
+ /**
+ * Elliptic curves over F2m. The Weierstrass equation is given by
+ * y2 + xy = x3 + ax2 + b
.
+ */
+ public class F2mCurve
+ : AbstractF2mCurve
+ {
+ private const int F2M_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ /**
+ * The exponent m
of F2m
.
+ */
+ private readonly int m;
+
+ /**
+ * TPB: The integer k
where xm +
+ * xk + 1
represents the reduction polynomial
+ * f(z)
.
+ * PPB: The integer k1
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ private readonly int k1;
+
+ /**
+ * TPB: Always set to 0
+ * PPB: The integer k2
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ private readonly int k2;
+
+ /**
+ * TPB: Always set to 0
+ * PPB: The integer k3
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ private readonly int k3;
+
+ /**
+ * The point at infinity on this curve.
+ */
+ protected readonly F2mPoint m_infinity;
+
+ /**
+ * Constructor for Trinomial Polynomial Basis (TPB).
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k The integer k
where xm +
+ * xk + 1
represents the reduction
+ * polynomial f(z)
.
+ * @param a The coefficient a
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ * @param b The coefficient b
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ */
+ public F2mCurve(
+ int m,
+ int k,
+ BigInteger a,
+ BigInteger b)
+ : this(m, k, 0, 0, a, b, null, null)
+ {
+ }
+
+ /**
+ * Constructor for Trinomial Polynomial Basis (TPB).
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k The integer k
where xm +
+ * xk + 1
represents the reduction
+ * polynomial f(z)
.
+ * @param a The coefficient a
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ * @param b The coefficient b
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ * @param order The order of the main subgroup of the elliptic curve.
+ * @param cofactor The cofactor of the elliptic curve, i.e.
+ * #Ea (F2m ) = h * n
.
+ */
+ public F2mCurve(
+ int m,
+ int k,
+ BigInteger a,
+ BigInteger b,
+ BigInteger order,
+ BigInteger cofactor)
+ : this(m, k, 0, 0, a, b, order, cofactor)
+ {
+ }
+
+ /**
+ * Constructor for Pentanomial Polynomial Basis (PPB).
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k1 The integer k1
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k2 The integer k2
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k3 The integer k3
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param a The coefficient a
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ * @param b The coefficient b
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ */
+ public F2mCurve(
+ int m,
+ int k1,
+ int k2,
+ int k3,
+ BigInteger a,
+ BigInteger b)
+ : this(m, k1, k2, k3, a, b, null, null)
+ {
+ }
+
+ /**
+ * Constructor for Pentanomial Polynomial Basis (PPB).
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k1 The integer k1
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k2 The integer k2
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k3 The integer k3
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param a The coefficient a
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ * @param b The coefficient b
in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * F2m
.
+ * @param order The order of the main subgroup of the elliptic curve.
+ * @param cofactor The cofactor of the elliptic curve, i.e.
+ * #Ea (F2m ) = h * n
.
+ */
+ public F2mCurve(
+ int m,
+ int k1,
+ int k2,
+ int k3,
+ BigInteger a,
+ BigInteger b,
+ BigInteger order,
+ BigInteger cofactor)
+ : base(m, k1, k2, k3)
+ {
+ this.m = m;
+ this.k1 = k1;
+ this.k2 = k2;
+ this.k3 = k3;
+ this.m_order = order;
+ this.m_cofactor = cofactor;
+ this.m_infinity = new F2mPoint(this, null, null);
+
+ if (k1 == 0)
+ throw new ArgumentException("k1 must be > 0");
+
+ if (k2 == 0)
+ {
+ if (k3 != 0)
+ throw new ArgumentException("k3 must be 0 if k2 == 0");
+ }
+ else
+ {
+ if (k2 <= k1)
+ throw new ArgumentException("k2 must be > k1");
+
+ if (k3 <= k2)
+ throw new ArgumentException("k3 must be > k2");
+ }
+
+ this.m_a = FromBigInteger(a);
+ this.m_b = FromBigInteger(b);
+ this.m_coord = F2M_DEFAULT_COORDS;
+ }
+
+ protected F2mCurve(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
+ : base(m, k1, k2, k3)
+ {
+ this.m = m;
+ this.k1 = k1;
+ this.k2 = k2;
+ this.k3 = k3;
+ this.m_order = order;
+ this.m_cofactor = cofactor;
+
+ this.m_infinity = new F2mPoint(this, null, null);
+ this.m_a = a;
+ this.m_b = b;
+ this.m_coord = F2M_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new F2mCurve(m, k1, k2, k3, m_a, m_b, m_order, m_cofactor);
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_AFFINE:
+ case COORD_HOMOGENEOUS:
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ protected override ECMultiplier CreateDefaultMultiplier()
+ {
+ if (IsKoblitz)
+ {
+ return new WTauNafMultiplier();
+ }
+
+ return base.CreateDefaultMultiplier();
+ }
+
+ public override int FieldSize
+ {
+ get { return m; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new F2mFieldElement(this.m, this.k1, this.k2, this.k3, x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new F2mPoint(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new F2mPoint(this, x, y, zs, withCompression);
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public int M
+ {
+ get { return m; }
+ }
+
+ /**
+ * Return true if curve uses a Trinomial basis.
+ *
+ * @return true if curve Trinomial, false otherwise.
+ */
+ public bool IsTrinomial()
+ {
+ return k2 == 0 && k3 == 0;
+ }
+
+ public int K1
+ {
+ get { return k1; }
+ }
+
+ public int K2
+ {
+ get { return k2; }
+ }
+
+ public int K3
+ {
+ get { return k3; }
+ }
+
+ [Obsolete("Use 'Order' property instead")]
+ public BigInteger N
+ {
+ get { return m_order; }
+ }
+
+ [Obsolete("Use 'Cofactor' property instead")]
+ public BigInteger H
+ {
+ get { return m_cofactor; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/ECFieldElement.cs b/bc-sharp-crypto/src/math/ec/ECFieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d0e008aab372c9c6375c47c057caf4603424ecaa
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/ECFieldElement.cs
@@ -0,0 +1,928 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC
+{
+ public abstract class ECFieldElement
+ {
+ public abstract BigInteger ToBigInteger();
+ public abstract string FieldName { get; }
+ public abstract int FieldSize { get; }
+ public abstract ECFieldElement Add(ECFieldElement b);
+ public abstract ECFieldElement AddOne();
+ public abstract ECFieldElement Subtract(ECFieldElement b);
+ public abstract ECFieldElement Multiply(ECFieldElement b);
+ public abstract ECFieldElement Divide(ECFieldElement b);
+ public abstract ECFieldElement Negate();
+ public abstract ECFieldElement Square();
+ public abstract ECFieldElement Invert();
+ public abstract ECFieldElement Sqrt();
+
+ public virtual int BitLength
+ {
+ get { return ToBigInteger().BitLength; }
+ }
+
+ public virtual bool IsOne
+ {
+ get { return BitLength == 1; }
+ }
+
+ public virtual bool IsZero
+ {
+ get { return 0 == ToBigInteger().SignValue; }
+ }
+
+ public virtual ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return Multiply(b).Subtract(x.Multiply(y));
+ }
+
+ public virtual ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return Multiply(b).Add(x.Multiply(y));
+ }
+
+ public virtual ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return Square().Subtract(x.Multiply(y));
+ }
+
+ public virtual ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return Square().Add(x.Multiply(y));
+ }
+
+ public virtual ECFieldElement SquarePow(int pow)
+ {
+ ECFieldElement r = this;
+ for (int i = 0; i < pow; ++i)
+ {
+ r = r.Square();
+ }
+ return r;
+ }
+
+ public virtual bool TestBitZero()
+ {
+ return ToBigInteger().TestBit(0);
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as ECFieldElement);
+ }
+
+ public virtual bool Equals(ECFieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return ToBigInteger().Equals(other.ToBigInteger());
+ }
+
+ public override int GetHashCode()
+ {
+ return ToBigInteger().GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return this.ToBigInteger().ToString(16);
+ }
+
+ public virtual byte[] GetEncoded()
+ {
+ return BigIntegers.AsUnsignedByteArray((FieldSize + 7) / 8, ToBigInteger());
+ }
+ }
+
+ public class FpFieldElement
+ : ECFieldElement
+ {
+ private readonly BigInteger q, r, x;
+
+ internal static BigInteger CalculateResidue(BigInteger p)
+ {
+ int bitLength = p.BitLength;
+ if (bitLength >= 96)
+ {
+ BigInteger firstWord = p.ShiftRight(bitLength - 64);
+ if (firstWord.LongValue == -1L)
+ {
+ return BigInteger.One.ShiftLeft(bitLength).Subtract(p);
+ }
+ if ((bitLength & 7) == 0)
+ {
+ return BigInteger.One.ShiftLeft(bitLength << 1).Divide(p).Negate();
+ }
+ }
+ return null;
+ }
+
+ [Obsolete("Use ECCurve.FromBigInteger to construct field elements")]
+ public FpFieldElement(BigInteger q, BigInteger x)
+ : this(q, CalculateResidue(q), x)
+ {
+ }
+
+ internal FpFieldElement(BigInteger q, BigInteger r, BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.CompareTo(q) >= 0)
+ throw new ArgumentException("value invalid in Fp field element", "x");
+
+ this.q = q;
+ this.r = r;
+ this.x = x;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return x;
+ }
+
+ /**
+ * return the field name for this field.
+ *
+ * @return the string "Fp".
+ */
+ public override string FieldName
+ {
+ get { return "Fp"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECFieldElement Add(
+ ECFieldElement b)
+ {
+ return new FpFieldElement(q, r, ModAdd(x, b.ToBigInteger()));
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ BigInteger x2 = x.Add(BigInteger.One);
+ if (x2.CompareTo(q) == 0)
+ {
+ x2 = BigInteger.Zero;
+ }
+ return new FpFieldElement(q, r, x2);
+ }
+
+ public override ECFieldElement Subtract(
+ ECFieldElement b)
+ {
+ return new FpFieldElement(q, r, ModSubtract(x, b.ToBigInteger()));
+ }
+
+ public override ECFieldElement Multiply(
+ ECFieldElement b)
+ {
+ return new FpFieldElement(q, r, ModMult(x, b.ToBigInteger()));
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ BigInteger ax = this.x, bx = b.ToBigInteger(), xx = x.ToBigInteger(), yx = y.ToBigInteger();
+ BigInteger ab = ax.Multiply(bx);
+ BigInteger xy = xx.Multiply(yx);
+ return new FpFieldElement(q, r, ModReduce(ab.Subtract(xy)));
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ BigInteger ax = this.x, bx = b.ToBigInteger(), xx = x.ToBigInteger(), yx = y.ToBigInteger();
+ BigInteger ab = ax.Multiply(bx);
+ BigInteger xy = xx.Multiply(yx);
+ BigInteger sum = ab.Add(xy);
+ if (r != null && r.SignValue < 0 && sum.BitLength > (q.BitLength << 1))
+ {
+ sum = sum.Subtract(q.ShiftLeft(q.BitLength));
+ }
+ return new FpFieldElement(q, r, ModReduce(sum));
+ }
+
+ public override ECFieldElement Divide(
+ ECFieldElement b)
+ {
+ return new FpFieldElement(q, r, ModMult(x, ModInverse(b.ToBigInteger())));
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return x.SignValue == 0 ? this : new FpFieldElement(q, r, q.Subtract(x));
+ }
+
+ public override ECFieldElement Square()
+ {
+ return new FpFieldElement(q, r, ModMult(x, x));
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ BigInteger ax = this.x, xx = x.ToBigInteger(), yx = y.ToBigInteger();
+ BigInteger aa = ax.Multiply(ax);
+ BigInteger xy = xx.Multiply(yx);
+ return new FpFieldElement(q, r, ModReduce(aa.Subtract(xy)));
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ BigInteger ax = this.x, xx = x.ToBigInteger(), yx = y.ToBigInteger();
+ BigInteger aa = ax.Multiply(ax);
+ BigInteger xy = xx.Multiply(yx);
+ BigInteger sum = aa.Add(xy);
+ if (r != null && r.SignValue < 0 && sum.BitLength > (q.BitLength << 1))
+ {
+ sum = sum.Subtract(q.ShiftLeft(q.BitLength));
+ }
+ return new FpFieldElement(q, r, ModReduce(sum));
+ }
+
+ public override ECFieldElement Invert()
+ {
+ // TODO Modular inversion can be faster for a (Generalized) Mersenne Prime.
+ return new FpFieldElement(q, r, ModInverse(x));
+ }
+
+ /**
+ * return a sqrt root - the routine verifies that the calculation
+ * returns the right value - if none exists it returns null.
+ */
+ public override ECFieldElement Sqrt()
+ {
+ if (IsZero || IsOne)
+ return this;
+
+ if (!q.TestBit(0))
+ throw Platform.CreateNotImplementedException("even value of q");
+
+ if (q.TestBit(1)) // q == 4m + 3
+ {
+ BigInteger e = q.ShiftRight(2).Add(BigInteger.One);
+ return CheckSqrt(new FpFieldElement(q, r, x.ModPow(e, q)));
+ }
+
+ if (q.TestBit(2)) // q == 8m + 5
+ {
+ BigInteger t1 = x.ModPow(q.ShiftRight(3), q);
+ BigInteger t2 = ModMult(t1, x);
+ BigInteger t3 = ModMult(t2, t1);
+
+ if (t3.Equals(BigInteger.One))
+ {
+ return CheckSqrt(new FpFieldElement(q, r, t2));
+ }
+
+ // TODO This is constant and could be precomputed
+ BigInteger t4 = BigInteger.Two.ModPow(q.ShiftRight(2), q);
+
+ BigInteger y = ModMult(t2, t4);
+
+ return CheckSqrt(new FpFieldElement(q, r, y));
+ }
+
+ // q == 8m + 1
+
+ BigInteger legendreExponent = q.ShiftRight(1);
+ if (!(x.ModPow(legendreExponent, q).Equals(BigInteger.One)))
+ return null;
+
+ BigInteger X = this.x;
+ BigInteger fourX = ModDouble(ModDouble(X)); ;
+
+ BigInteger k = legendreExponent.Add(BigInteger.One), qMinusOne = q.Subtract(BigInteger.One);
+
+ BigInteger U, V;
+ do
+ {
+ BigInteger P;
+ do
+ {
+ P = BigInteger.Arbitrary(q.BitLength);
+ }
+ while (P.CompareTo(q) >= 0
+ || !ModReduce(P.Multiply(P).Subtract(fourX)).ModPow(legendreExponent, q).Equals(qMinusOne));
+
+ BigInteger[] result = LucasSequence(P, X, k);
+ U = result[0];
+ V = result[1];
+
+ if (ModMult(V, V).Equals(fourX))
+ {
+ return new FpFieldElement(q, r, ModHalfAbs(V));
+ }
+ }
+ while (U.Equals(BigInteger.One) || U.Equals(qMinusOne));
+
+ return null;
+ }
+
+ private ECFieldElement CheckSqrt(ECFieldElement z)
+ {
+ return z.Square().Equals(this) ? z : null;
+ }
+
+ private BigInteger[] LucasSequence(
+ BigInteger P,
+ BigInteger Q,
+ BigInteger k)
+ {
+ // TODO Research and apply "common-multiplicand multiplication here"
+
+ int n = k.BitLength;
+ int s = k.GetLowestSetBit();
+
+ Debug.Assert(k.TestBit(s));
+
+ BigInteger Uh = BigInteger.One;
+ BigInteger Vl = BigInteger.Two;
+ BigInteger Vh = P;
+ BigInteger Ql = BigInteger.One;
+ BigInteger Qh = BigInteger.One;
+
+ for (int j = n - 1; j >= s + 1; --j)
+ {
+ Ql = ModMult(Ql, Qh);
+
+ if (k.TestBit(j))
+ {
+ Qh = ModMult(Ql, Q);
+ Uh = ModMult(Uh, Vh);
+ Vl = ModReduce(Vh.Multiply(Vl).Subtract(P.Multiply(Ql)));
+ Vh = ModReduce(Vh.Multiply(Vh).Subtract(Qh.ShiftLeft(1)));
+ }
+ else
+ {
+ Qh = Ql;
+ Uh = ModReduce(Uh.Multiply(Vl).Subtract(Ql));
+ Vh = ModReduce(Vh.Multiply(Vl).Subtract(P.Multiply(Ql)));
+ Vl = ModReduce(Vl.Multiply(Vl).Subtract(Ql.ShiftLeft(1)));
+ }
+ }
+
+ Ql = ModMult(Ql, Qh);
+ Qh = ModMult(Ql, Q);
+ Uh = ModReduce(Uh.Multiply(Vl).Subtract(Ql));
+ Vl = ModReduce(Vh.Multiply(Vl).Subtract(P.Multiply(Ql)));
+ Ql = ModMult(Ql, Qh);
+
+ for (int j = 1; j <= s; ++j)
+ {
+ Uh = ModMult(Uh, Vl);
+ Vl = ModReduce(Vl.Multiply(Vl).Subtract(Ql.ShiftLeft(1)));
+ Ql = ModMult(Ql, Ql);
+ }
+
+ return new BigInteger[] { Uh, Vl };
+ }
+
+ protected virtual BigInteger ModAdd(BigInteger x1, BigInteger x2)
+ {
+ BigInteger x3 = x1.Add(x2);
+ if (x3.CompareTo(q) >= 0)
+ {
+ x3 = x3.Subtract(q);
+ }
+ return x3;
+ }
+
+ protected virtual BigInteger ModDouble(BigInteger x)
+ {
+ BigInteger _2x = x.ShiftLeft(1);
+ if (_2x.CompareTo(q) >= 0)
+ {
+ _2x = _2x.Subtract(q);
+ }
+ return _2x;
+ }
+
+ protected virtual BigInteger ModHalf(BigInteger x)
+ {
+ if (x.TestBit(0))
+ {
+ x = q.Add(x);
+ }
+ return x.ShiftRight(1);
+ }
+
+ protected virtual BigInteger ModHalfAbs(BigInteger x)
+ {
+ if (x.TestBit(0))
+ {
+ x = q.Subtract(x);
+ }
+ return x.ShiftRight(1);
+ }
+
+ protected virtual BigInteger ModInverse(BigInteger x)
+ {
+ int bits = FieldSize;
+ int len = (bits + 31) >> 5;
+ uint[] p = Nat.FromBigInteger(bits, q);
+ uint[] n = Nat.FromBigInteger(bits, x);
+ uint[] z = Nat.Create(len);
+ Mod.Invert(p, n, z);
+ return Nat.ToBigInteger(len, z);
+ }
+
+ protected virtual BigInteger ModMult(BigInteger x1, BigInteger x2)
+ {
+ return ModReduce(x1.Multiply(x2));
+ }
+
+ protected virtual BigInteger ModReduce(BigInteger x)
+ {
+ if (r == null)
+ {
+ x = x.Mod(q);
+ }
+ else
+ {
+ bool negative = x.SignValue < 0;
+ if (negative)
+ {
+ x = x.Abs();
+ }
+ int qLen = q.BitLength;
+ if (r.SignValue > 0)
+ {
+ BigInteger qMod = BigInteger.One.ShiftLeft(qLen);
+ bool rIsOne = r.Equals(BigInteger.One);
+ while (x.BitLength > (qLen + 1))
+ {
+ BigInteger u = x.ShiftRight(qLen);
+ BigInteger v = x.Remainder(qMod);
+ if (!rIsOne)
+ {
+ u = u.Multiply(r);
+ }
+ x = u.Add(v);
+ }
+ }
+ else
+ {
+ int d = ((qLen - 1) & 31) + 1;
+ BigInteger mu = r.Negate();
+ BigInteger u = mu.Multiply(x.ShiftRight(qLen - d));
+ BigInteger quot = u.ShiftRight(qLen + d);
+ BigInteger v = quot.Multiply(q);
+ BigInteger bk1 = BigInteger.One.ShiftLeft(qLen + d);
+ v = v.Remainder(bk1);
+ x = x.Remainder(bk1);
+ x = x.Subtract(v);
+ if (x.SignValue < 0)
+ {
+ x = x.Add(bk1);
+ }
+ }
+ while (x.CompareTo(q) >= 0)
+ {
+ x = x.Subtract(q);
+ }
+ if (negative && x.SignValue != 0)
+ {
+ x = q.Subtract(x);
+ }
+ }
+ return x;
+ }
+
+ protected virtual BigInteger ModSubtract(BigInteger x1, BigInteger x2)
+ {
+ BigInteger x3 = x1.Subtract(x2);
+ if (x3.SignValue < 0)
+ {
+ x3 = x3.Add(q);
+ }
+ return x3;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ FpFieldElement other = obj as FpFieldElement;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ public virtual bool Equals(
+ FpFieldElement other)
+ {
+ return q.Equals(other.q) && base.Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return q.GetHashCode() ^ base.GetHashCode();
+ }
+ }
+
+ /**
+ * Class representing the Elements of the finite field
+ * F2m
in polynomial basis (PB)
+ * representation. Both trinomial (Tpb) and pentanomial (Ppb) polynomial
+ * basis representations are supported. Gaussian normal basis (GNB)
+ * representation is not supported.
+ */
+ public class F2mFieldElement
+ : ECFieldElement
+ {
+ /**
+ * Indicates gaussian normal basis representation (GNB). Number chosen
+ * according to X9.62. GNB is not implemented at present.
+ */
+ public const int Gnb = 1;
+
+ /**
+ * Indicates trinomial basis representation (Tpb). Number chosen
+ * according to X9.62.
+ */
+ public const int Tpb = 2;
+
+ /**
+ * Indicates pentanomial basis representation (Ppb). Number chosen
+ * according to X9.62.
+ */
+ public const int Ppb = 3;
+
+ /**
+ * Tpb or Ppb.
+ */
+ private int representation;
+
+ /**
+ * The exponent m
of F2m
.
+ */
+ private int m;
+
+ private int[] ks;
+
+ /**
+ * The LongArray
holding the bits.
+ */
+ private LongArray x;
+
+ /**
+ * Constructor for Ppb.
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k1 The integer k1
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k2 The integer k2
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param k3 The integer k3
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ * @param x The BigInteger representing the value of the field element.
+ */
+ public F2mFieldElement(
+ int m,
+ int k1,
+ int k2,
+ int k3,
+ BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.BitLength > m)
+ throw new ArgumentException("value invalid in F2m field element", "x");
+
+ if ((k2 == 0) && (k3 == 0))
+ {
+ this.representation = Tpb;
+ this.ks = new int[] { k1 };
+ }
+ else
+ {
+ if (k2 >= k3)
+ throw new ArgumentException("k2 must be smaller than k3");
+ if (k2 <= 0)
+ throw new ArgumentException("k2 must be larger than 0");
+
+ this.representation = Ppb;
+ this.ks = new int[] { k1, k2, k3 };
+ }
+
+ this.m = m;
+ this.x = new LongArray(x);
+ }
+
+ /**
+ * Constructor for Tpb.
+ * @param m The exponent m
of
+ * F2m
.
+ * @param k The integer k
where xm +
+ * xk + 1
represents the reduction
+ * polynomial f(z)
.
+ * @param x The BigInteger representing the value of the field element.
+ */
+ public F2mFieldElement(
+ int m,
+ int k,
+ BigInteger x)
+ : this(m, k, 0, 0, x)
+ {
+ // Set k1 to k, and set k2 and k3 to 0
+ }
+
+ private F2mFieldElement(int m, int[] ks, LongArray x)
+ {
+ this.m = m;
+ this.representation = (ks.Length == 1) ? Tpb : Ppb;
+ this.ks = ks;
+ this.x = x;
+ }
+
+ public override int BitLength
+ {
+ get { return x.Degree(); }
+ }
+
+ public override bool IsOne
+ {
+ get { return x.IsOne(); }
+ }
+
+ public override bool IsZero
+ {
+ get { return x.IsZero(); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return x.TestBitZero();
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return x.ToBigInteger();
+ }
+
+ public override string FieldName
+ {
+ get { return "F2m"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return m; }
+ }
+
+ /**
+ * Checks, if the ECFieldElements a
and b
+ * are elements of the same field F2m
+ * (having the same representation).
+ * @param a field element.
+ * @param b field element to be compared.
+ * @throws ArgumentException if a
and b
+ * are not elements of the same field
+ * F2m
(having the same
+ * representation).
+ */
+ public static void CheckFieldElements(
+ ECFieldElement a,
+ ECFieldElement b)
+ {
+ if (!(a is F2mFieldElement) || !(b is F2mFieldElement))
+ {
+ throw new ArgumentException("Field elements are not "
+ + "both instances of F2mFieldElement");
+ }
+
+ F2mFieldElement aF2m = (F2mFieldElement)a;
+ F2mFieldElement bF2m = (F2mFieldElement)b;
+
+ if (aF2m.representation != bF2m.representation)
+ {
+ // Should never occur
+ throw new ArgumentException("One of the F2m field elements has incorrect representation");
+ }
+
+ if ((aF2m.m != bF2m.m) || !Arrays.AreEqual(aF2m.ks, bF2m.ks))
+ {
+ throw new ArgumentException("Field elements are not elements of the same field F2m");
+ }
+ }
+
+ public override ECFieldElement Add(
+ ECFieldElement b)
+ {
+ // No check performed here for performance reasons. Instead the
+ // elements involved are checked in ECPoint.F2m
+ // checkFieldElements(this, b);
+ LongArray iarrClone = this.x.Copy();
+ F2mFieldElement bF2m = (F2mFieldElement)b;
+ iarrClone.AddShiftedByWords(bF2m.x, 0);
+ return new F2mFieldElement(m, ks, iarrClone);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ return new F2mFieldElement(m, ks, x.AddOne());
+ }
+
+ public override ECFieldElement Subtract(
+ ECFieldElement b)
+ {
+ // Addition and subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(
+ ECFieldElement b)
+ {
+ // Right-to-left comb multiplication in the LongArray
+ // Input: Binary polynomials a(z) and b(z) of degree at most m-1
+ // Output: c(z) = a(z) * b(z) mod f(z)
+
+ // No check performed here for performance reasons. Instead the
+ // elements involved are checked in ECPoint.F2m
+ // checkFieldElements(this, b);
+ return new F2mFieldElement(m, ks, x.ModMultiply(((F2mFieldElement)b).x, m, ks));
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return MultiplyPlusProduct(b, x, y);
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ LongArray ax = this.x, bx = ((F2mFieldElement)b).x, xx = ((F2mFieldElement)x).x, yx = ((F2mFieldElement)y).x;
+
+ LongArray ab = ax.Multiply(bx, m, ks);
+ LongArray xy = xx.Multiply(yx, m, ks);
+
+ if (ab == ax || ab == bx)
+ {
+ ab = (LongArray)ab.Copy();
+ }
+
+ ab.AddShiftedByWords(xy, 0);
+ ab.Reduce(m, ks);
+
+ return new F2mFieldElement(m, ks, ab);
+ }
+
+ public override ECFieldElement Divide(
+ ECFieldElement b)
+ {
+ // There may be more efficient implementations
+ ECFieldElement bInv = b.Invert();
+ return Multiply(bInv);
+ }
+
+ public override ECFieldElement Negate()
+ {
+ // -x == x holds for all x in F2m
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ return new F2mFieldElement(m, ks, x.ModSquare(m, ks));
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return SquarePlusProduct(x, y);
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ LongArray ax = this.x, xx = ((F2mFieldElement)x).x, yx = ((F2mFieldElement)y).x;
+
+ LongArray aa = ax.Square(m, ks);
+ LongArray xy = xx.Multiply(yx, m, ks);
+
+ if (aa == ax)
+ {
+ aa = (LongArray)aa.Copy();
+ }
+
+ aa.AddShiftedByWords(xy, 0);
+ aa.Reduce(m, ks);
+
+ return new F2mFieldElement(m, ks, aa);
+ }
+
+ public override ECFieldElement SquarePow(int pow)
+ {
+ return pow < 1 ? this : new F2mFieldElement(m, ks, x.ModSquareN(pow, m, ks));
+ }
+
+ public override ECFieldElement Invert()
+ {
+ return new F2mFieldElement(this.m, this.ks, this.x.ModInverse(m, ks));
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ return (x.IsZero() || x.IsOne()) ? this : SquarePow(m - 1);
+ }
+
+ /**
+ * @return the representation of the field
+ * F2m
, either of
+ * {@link F2mFieldElement.Tpb} (trinomial
+ * basis representation) or
+ * {@link F2mFieldElement.Ppb} (pentanomial
+ * basis representation).
+ */
+ public int Representation
+ {
+ get { return this.representation; }
+ }
+
+ /**
+ * @return the degree m
of the reduction polynomial
+ * f(z)
.
+ */
+ public int M
+ {
+ get { return this.m; }
+ }
+
+ /**
+ * @return Tpb: The integer k
where xm +
+ * xk + 1
represents the reduction polynomial
+ * f(z)
.
+ * Ppb: The integer k1
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ public int K1
+ {
+ get { return this.ks[0]; }
+ }
+
+ /**
+ * @return Tpb: Always returns 0
+ * Ppb: The integer k2
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ public int K2
+ {
+ get { return this.ks.Length >= 2 ? this.ks[1] : 0; }
+ }
+
+ /**
+ * @return Tpb: Always set to 0
+ * Ppb: The integer k3
where xm +
+ * xk3 + xk2 + xk1 + 1
+ * represents the reduction polynomial f(z)
.
+ */
+ public int K3
+ {
+ get { return this.ks.Length >= 3 ? this.ks[2] : 0; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ F2mFieldElement other = obj as F2mFieldElement;
+
+ if (other == null)
+ return false;
+
+ return Equals(other);
+ }
+
+ public virtual bool Equals(
+ F2mFieldElement other)
+ {
+ return ((this.m == other.m)
+ && (this.representation == other.representation)
+ && Arrays.AreEqual(this.ks, other.ks)
+ && (this.x.Equals(other.x)));
+ }
+
+ public override int GetHashCode()
+ {
+ return x.GetHashCode() ^ m ^ Arrays.GetHashCode(ks);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/ECPoint.cs b/bc-sharp-crypto/src/math/ec/ECPoint.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a5ba515c566e92c192b94bf0295495e5602711df
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/ECPoint.cs
@@ -0,0 +1,2064 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.Text;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+
+namespace Org.BouncyCastle.Math.EC
+{
+ /**
+ * base class for points on elliptic curves.
+ */
+ public abstract class ECPoint
+ {
+ protected static ECFieldElement[] EMPTY_ZS = new ECFieldElement[0];
+
+ protected static ECFieldElement[] GetInitialZCoords(ECCurve curve)
+ {
+ // Cope with null curve, most commonly used by implicitlyCa
+ int coord = null == curve ? ECCurve.COORD_AFFINE : curve.CoordinateSystem;
+
+ switch (coord)
+ {
+ case ECCurve.COORD_AFFINE:
+ case ECCurve.COORD_LAMBDA_AFFINE:
+ return EMPTY_ZS;
+ default:
+ break;
+ }
+
+ ECFieldElement one = curve.FromBigInteger(BigInteger.One);
+
+ switch (coord)
+ {
+ case ECCurve.COORD_HOMOGENEOUS:
+ case ECCurve.COORD_JACOBIAN:
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ return new ECFieldElement[] { one };
+ case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+ return new ECFieldElement[] { one, one, one };
+ case ECCurve.COORD_JACOBIAN_MODIFIED:
+ return new ECFieldElement[] { one, curve.A };
+ default:
+ throw new ArgumentException("unknown coordinate system");
+ }
+ }
+
+ protected internal readonly ECCurve m_curve;
+ protected internal readonly ECFieldElement m_x, m_y;
+ protected internal readonly ECFieldElement[] m_zs;
+ protected internal readonly bool m_withCompression;
+
+ // Dictionary is (string -> PreCompInfo)
+ protected internal IDictionary m_preCompTable = null;
+
+ protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : this(curve, x, y, GetInitialZCoords(curve), withCompression)
+ {
+ }
+
+ internal ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ this.m_curve = curve;
+ this.m_x = x;
+ this.m_y = y;
+ this.m_zs = zs;
+ this.m_withCompression = withCompression;
+ }
+
+ protected internal bool SatisfiesCofactor()
+ {
+ BigInteger h = Curve.Cofactor;
+ return h == null || h.Equals(BigInteger.One) || !ECAlgorithms.ReferenceMultiply(this, h).IsInfinity;
+ }
+
+ protected abstract bool SatisfiesCurveEquation();
+
+ public ECPoint GetDetachedPoint()
+ {
+ return Normalize().Detach();
+ }
+
+ public virtual ECCurve Curve
+ {
+ get { return m_curve; }
+ }
+
+ protected abstract ECPoint Detach();
+
+ protected virtual int CurveCoordinateSystem
+ {
+ get
+ {
+ // Cope with null curve, most commonly used by implicitlyCa
+ return null == m_curve ? ECCurve.COORD_AFFINE : m_curve.CoordinateSystem;
+ }
+ }
+
+ /**
+ * Normalizes this point, and then returns the affine x-coordinate.
+ *
+ * Note: normalization can be expensive, this method is deprecated in favour
+ * of caller-controlled normalization.
+ */
+ [Obsolete("Use AffineXCoord, or Normalize() and XCoord, instead")]
+ public virtual ECFieldElement X
+ {
+ get { return Normalize().XCoord; }
+ }
+
+ /**
+ * Normalizes this point, and then returns the affine y-coordinate.
+ *
+ * Note: normalization can be expensive, this method is deprecated in favour
+ * of caller-controlled normalization.
+ */
+ [Obsolete("Use AffineYCoord, or Normalize() and YCoord, instead")]
+ public virtual ECFieldElement Y
+ {
+ get { return Normalize().YCoord; }
+ }
+
+ /**
+ * Returns the affine x-coordinate after checking that this point is normalized.
+ *
+ * @return The affine x-coordinate of this point
+ * @throws IllegalStateException if the point is not normalized
+ */
+ public virtual ECFieldElement AffineXCoord
+ {
+ get
+ {
+ CheckNormalized();
+ return XCoord;
+ }
+ }
+
+ /**
+ * Returns the affine y-coordinate after checking that this point is normalized
+ *
+ * @return The affine y-coordinate of this point
+ * @throws IllegalStateException if the point is not normalized
+ */
+ public virtual ECFieldElement AffineYCoord
+ {
+ get
+ {
+ CheckNormalized();
+ return YCoord;
+ }
+ }
+
+ /**
+ * Returns the x-coordinate.
+ *
+ * Caution: depending on the curve's coordinate system, this may not be the same value as in an
+ * affine coordinate system; use Normalize() to get a point where the coordinates have their
+ * affine values, or use AffineXCoord if you expect the point to already have been normalized.
+ *
+ * @return the x-coordinate of this point
+ */
+ public virtual ECFieldElement XCoord
+ {
+ get { return m_x; }
+ }
+
+ /**
+ * Returns the y-coordinate.
+ *
+ * Caution: depending on the curve's coordinate system, this may not be the same value as in an
+ * affine coordinate system; use Normalize() to get a point where the coordinates have their
+ * affine values, or use AffineYCoord if you expect the point to already have been normalized.
+ *
+ * @return the y-coordinate of this point
+ */
+ public virtual ECFieldElement YCoord
+ {
+ get { return m_y; }
+ }
+
+ public virtual ECFieldElement GetZCoord(int index)
+ {
+ return (index < 0 || index >= m_zs.Length) ? null : m_zs[index];
+ }
+
+ public virtual ECFieldElement[] GetZCoords()
+ {
+ int zsLen = m_zs.Length;
+ if (zsLen == 0)
+ {
+ return m_zs;
+ }
+ ECFieldElement[] copy = new ECFieldElement[zsLen];
+ Array.Copy(m_zs, 0, copy, 0, zsLen);
+ return copy;
+ }
+
+ protected internal ECFieldElement RawXCoord
+ {
+ get { return m_x; }
+ }
+
+ protected internal ECFieldElement RawYCoord
+ {
+ get { return m_y; }
+ }
+
+ protected internal ECFieldElement[] RawZCoords
+ {
+ get { return m_zs; }
+ }
+
+ protected virtual void CheckNormalized()
+ {
+ if (!IsNormalized())
+ throw new InvalidOperationException("point not in normal form");
+ }
+
+ public virtual bool IsNormalized()
+ {
+ int coord = this.CurveCoordinateSystem;
+
+ return coord == ECCurve.COORD_AFFINE
+ || coord == ECCurve.COORD_LAMBDA_AFFINE
+ || IsInfinity
+ || RawZCoords[0].IsOne;
+ }
+
+ /**
+ * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
+ * coordinates reflect those of the equivalent point in an affine coordinate system.
+ *
+ * @return a new ECPoint instance representing the same point, but with normalized coordinates
+ */
+ public virtual ECPoint Normalize()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ switch (this.CurveCoordinateSystem)
+ {
+ case ECCurve.COORD_AFFINE:
+ case ECCurve.COORD_LAMBDA_AFFINE:
+ {
+ return this;
+ }
+ default:
+ {
+ ECFieldElement Z1 = RawZCoords[0];
+ if (Z1.IsOne)
+ {
+ return this;
+ }
+
+ return Normalize(Z1.Invert());
+ }
+ }
+ }
+
+ internal virtual ECPoint Normalize(ECFieldElement zInv)
+ {
+ switch (this.CurveCoordinateSystem)
+ {
+ case ECCurve.COORD_HOMOGENEOUS:
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ return CreateScaledPoint(zInv, zInv);
+ }
+ case ECCurve.COORD_JACOBIAN:
+ case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+ case ECCurve.COORD_JACOBIAN_MODIFIED:
+ {
+ ECFieldElement zInv2 = zInv.Square(), zInv3 = zInv2.Multiply(zInv);
+ return CreateScaledPoint(zInv2, zInv3);
+ }
+ default:
+ {
+ throw new InvalidOperationException("not a projective coordinate system");
+ }
+ }
+ }
+
+ protected virtual ECPoint CreateScaledPoint(ECFieldElement sx, ECFieldElement sy)
+ {
+ return Curve.CreateRawPoint(RawXCoord.Multiply(sx), RawYCoord.Multiply(sy), IsCompressed);
+ }
+
+ public bool IsInfinity
+ {
+ get { return m_x == null && m_y == null; }
+ }
+
+ public bool IsCompressed
+ {
+ get { return m_withCompression; }
+ }
+
+ public bool IsValid()
+ {
+ if (IsInfinity)
+ return true;
+
+ // TODO Sanity-check the field elements
+
+ ECCurve curve = Curve;
+ if (curve != null)
+ {
+ if (!SatisfiesCurveEquation())
+ return false;
+
+ if (!SatisfiesCofactor())
+ return false;
+ }
+
+ return true;
+ }
+
+ public virtual ECPoint ScaleX(ECFieldElement scale)
+ {
+ return IsInfinity
+ ? this
+ : Curve.CreateRawPoint(RawXCoord.Multiply(scale), RawYCoord, RawZCoords, IsCompressed);
+ }
+
+ public virtual ECPoint ScaleY(ECFieldElement scale)
+ {
+ return IsInfinity
+ ? this
+ : Curve.CreateRawPoint(RawXCoord, RawYCoord.Multiply(scale), RawZCoords, IsCompressed);
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as ECPoint);
+ }
+
+ public virtual bool Equals(ECPoint other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+
+ ECCurve c1 = this.Curve, c2 = other.Curve;
+ bool n1 = (null == c1), n2 = (null == c2);
+ bool i1 = IsInfinity, i2 = other.IsInfinity;
+
+ if (i1 || i2)
+ {
+ return (i1 && i2) && (n1 || n2 || c1.Equals(c2));
+ }
+
+ ECPoint p1 = this, p2 = other;
+ if (n1 && n2)
+ {
+ // Points with null curve are in affine form, so already normalized
+ }
+ else if (n1)
+ {
+ p2 = p2.Normalize();
+ }
+ else if (n2)
+ {
+ p1 = p1.Normalize();
+ }
+ else if (!c1.Equals(c2))
+ {
+ return false;
+ }
+ else
+ {
+ // TODO Consider just requiring already normalized, to avoid silent performance degradation
+
+ ECPoint[] points = new ECPoint[] { this, c1.ImportPoint(p2) };
+
+ // TODO This is a little strong, really only requires coZNormalizeAll to get Zs equal
+ c1.NormalizeAll(points);
+
+ p1 = points[0];
+ p2 = points[1];
+ }
+
+ return p1.XCoord.Equals(p2.XCoord) && p1.YCoord.Equals(p2.YCoord);
+ }
+
+ public override int GetHashCode()
+ {
+ ECCurve c = this.Curve;
+ int hc = (null == c) ? 0 : ~c.GetHashCode();
+
+ if (!this.IsInfinity)
+ {
+ // TODO Consider just requiring already normalized, to avoid silent performance degradation
+
+ ECPoint p = Normalize();
+
+ hc ^= p.XCoord.GetHashCode() * 17;
+ hc ^= p.YCoord.GetHashCode() * 257;
+ }
+
+ return hc;
+ }
+
+ public override string ToString()
+ {
+ if (this.IsInfinity)
+ {
+ return "INF";
+ }
+
+ StringBuilder sb = new StringBuilder();
+ sb.Append('(');
+ sb.Append(RawXCoord);
+ sb.Append(',');
+ sb.Append(RawYCoord);
+ for (int i = 0; i < m_zs.Length; ++i)
+ {
+ sb.Append(',');
+ sb.Append(m_zs[i]);
+ }
+ sb.Append(')');
+ return sb.ToString();
+ }
+
+ public virtual byte[] GetEncoded()
+ {
+ return GetEncoded(m_withCompression);
+ }
+
+ public abstract byte[] GetEncoded(bool compressed);
+
+ protected internal abstract bool CompressionYTilde { get; }
+
+ public abstract ECPoint Add(ECPoint b);
+ public abstract ECPoint Subtract(ECPoint b);
+ public abstract ECPoint Negate();
+
+ public virtual ECPoint TimesPow2(int e)
+ {
+ if (e < 0)
+ throw new ArgumentException("cannot be negative", "e");
+
+ ECPoint p = this;
+ while (--e >= 0)
+ {
+ p = p.Twice();
+ }
+ return p;
+ }
+
+ public abstract ECPoint Twice();
+ public abstract ECPoint Multiply(BigInteger b);
+
+ public virtual ECPoint TwicePlus(ECPoint b)
+ {
+ return Twice().Add(b);
+ }
+
+ public virtual ECPoint ThreeTimes()
+ {
+ return TwicePlus(this);
+ }
+ }
+
+ public abstract class ECPointBase
+ : ECPoint
+ {
+ protected internal ECPointBase(
+ ECCurve curve,
+ ECFieldElement x,
+ ECFieldElement y,
+ bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ }
+
+ protected internal ECPointBase(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ /**
+ * return the field element encoded with point compression. (S 4.3.6)
+ */
+ public override byte[] GetEncoded(bool compressed)
+ {
+ if (this.IsInfinity)
+ {
+ return new byte[1];
+ }
+
+ ECPoint normed = Normalize();
+
+ byte[] X = normed.XCoord.GetEncoded();
+
+ if (compressed)
+ {
+ byte[] PO = new byte[X.Length + 1];
+ PO[0] = (byte)(normed.CompressionYTilde ? 0x03 : 0x02);
+ Array.Copy(X, 0, PO, 1, X.Length);
+ return PO;
+ }
+
+ byte[] Y = normed.YCoord.GetEncoded();
+
+ {
+ byte[] PO = new byte[X.Length + Y.Length + 1];
+ PO[0] = 0x04;
+ Array.Copy(X, 0, PO, 1, X.Length);
+ Array.Copy(Y, 0, PO, X.Length + 1, Y.Length);
+ return PO;
+ }
+ }
+
+ /**
+ * Multiplies this ECPoint
by the given number.
+ * @param k The multiplicator.
+ * @return k * this
.
+ */
+ public override ECPoint Multiply(BigInteger k)
+ {
+ return this.Curve.GetMultiplier().Multiply(this, k);
+ }
+ }
+
+ public abstract class AbstractFpPoint
+ : ECPointBase
+ {
+ protected AbstractFpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ }
+
+ protected AbstractFpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get { return this.AffineYCoord.TestBitZero(); }
+ }
+
+ protected override bool SatisfiesCurveEquation()
+ {
+ ECFieldElement X = this.RawXCoord, Y = this.RawYCoord, A = Curve.A, B = Curve.B;
+ ECFieldElement lhs = Y.Square();
+
+ switch (CurveCoordinateSystem)
+ {
+ case ECCurve.COORD_AFFINE:
+ break;
+ case ECCurve.COORD_HOMOGENEOUS:
+ {
+ ECFieldElement Z = this.RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ ECFieldElement Z2 = Z.Square(), Z3 = Z.Multiply(Z2);
+ lhs = lhs.Multiply(Z);
+ A = A.Multiply(Z2);
+ B = B.Multiply(Z3);
+ }
+ break;
+ }
+ case ECCurve.COORD_JACOBIAN:
+ case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+ case ECCurve.COORD_JACOBIAN_MODIFIED:
+ {
+ ECFieldElement Z = this.RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ ECFieldElement Z2 = Z.Square(), Z4 = Z2.Square(), Z6 = Z2.Multiply(Z4);
+ A = A.Multiply(Z4);
+ B = B.Multiply(Z6);
+ }
+ break;
+ }
+ default:
+ throw new InvalidOperationException("unsupported coordinate system");
+ }
+
+ ECFieldElement rhs = X.Square().Add(A).Multiply(X).Add(B);
+ return lhs.Equals(rhs);
+ }
+
+ public override ECPoint Subtract(ECPoint b)
+ {
+ if (b.IsInfinity)
+ return this;
+
+ // Add -b
+ return Add(b.Negate());
+ }
+ }
+
+ /**
+ * Elliptic curve points over Fp
+ */
+ public class FpPoint
+ : AbstractFpPoint
+ {
+ /**
+ * Create a point which encodes without point compression.
+ *
+ * @param curve the curve to use
+ * @param x affine x co-ordinate
+ * @param y affine y co-ordinate
+ */
+ public FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compression.
+ *
+ * @param curve the curve to use
+ * @param x affine x co-ordinate
+ * @param y affine y co-ordinate
+ * @param withCompression if true encode with point compression
+ */
+ public FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new FpPoint(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement GetZCoord(int index)
+ {
+ if (index == 1 && ECCurve.COORD_JACOBIAN_MODIFIED == this.CurveCoordinateSystem)
+ {
+ return GetJacobianModifiedW();
+ }
+
+ return base.GetZCoord(index);
+ }
+
+ // B.3 pg 62
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+ if (this == b)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+ int coord = curve.CoordinateSystem;
+
+ ECFieldElement X1 = this.RawXCoord, Y1 = this.RawYCoord;
+ ECFieldElement X2 = b.RawXCoord, Y2 = b.RawYCoord;
+
+ switch (coord)
+ {
+ case ECCurve.COORD_AFFINE:
+ {
+ ECFieldElement dx = X2.Subtract(X1), dy = Y2.Subtract(Y1);
+
+ if (dx.IsZero)
+ {
+ if (dy.IsZero)
+ {
+ // this == b, i.e. this must be doubled
+ return Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return Curve.Infinity;
+ }
+
+ ECFieldElement gamma = dy.Divide(dx);
+ ECFieldElement X3 = gamma.Square().Subtract(X1).Subtract(X2);
+ ECFieldElement Y3 = gamma.Multiply(X1.Subtract(X3)).Subtract(Y1);
+
+ return new FpPoint(Curve, X3, Y3, IsCompressed);
+ }
+
+ case ECCurve.COORD_HOMOGENEOUS:
+ {
+ ECFieldElement Z1 = this.RawZCoords[0];
+ ECFieldElement Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ bool Z2IsOne = Z2.IsOne;
+
+ ECFieldElement u1 = Z1IsOne ? Y2 : Y2.Multiply(Z1);
+ ECFieldElement u2 = Z2IsOne ? Y1 : Y1.Multiply(Z2);
+ ECFieldElement u = u1.Subtract(u2);
+ ECFieldElement v1 = Z1IsOne ? X2 : X2.Multiply(Z1);
+ ECFieldElement v2 = Z2IsOne ? X1 : X1.Multiply(Z2);
+ ECFieldElement v = v1.Subtract(v2);
+
+ // Check if b == this or b == -this
+ if (v.IsZero)
+ {
+ if (u.IsZero)
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ // TODO Optimize for when w == 1
+ ECFieldElement w = Z1IsOne ? Z2 : Z2IsOne ? Z1 : Z1.Multiply(Z2);
+ ECFieldElement vSquared = v.Square();
+ ECFieldElement vCubed = vSquared.Multiply(v);
+ ECFieldElement vSquaredV2 = vSquared.Multiply(v2);
+ ECFieldElement A = u.Square().Multiply(w).Subtract(vCubed).Subtract(Two(vSquaredV2));
+
+ ECFieldElement X3 = v.Multiply(A);
+ ECFieldElement Y3 = vSquaredV2.Subtract(A).MultiplyMinusProduct(u, u2, vCubed);
+ ECFieldElement Z3 = vCubed.Multiply(w);
+
+ return new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ case ECCurve.COORD_JACOBIAN:
+ case ECCurve.COORD_JACOBIAN_MODIFIED:
+ {
+ ECFieldElement Z1 = this.RawZCoords[0];
+ ECFieldElement Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+
+ ECFieldElement X3, Y3, Z3, Z3Squared = null;
+
+ if (!Z1IsOne && Z1.Equals(Z2))
+ {
+ // TODO Make this available as public method coZAdd?
+
+ ECFieldElement dx = X1.Subtract(X2), dy = Y1.Subtract(Y2);
+ if (dx.IsZero)
+ {
+ if (dy.IsZero)
+ {
+ return Twice();
+ }
+ return curve.Infinity;
+ }
+
+ ECFieldElement C = dx.Square();
+ ECFieldElement W1 = X1.Multiply(C), W2 = X2.Multiply(C);
+ ECFieldElement A1 = W1.Subtract(W2).Multiply(Y1);
+
+ X3 = dy.Square().Subtract(W1).Subtract(W2);
+ Y3 = W1.Subtract(X3).Multiply(dy).Subtract(A1);
+ Z3 = dx;
+
+ if (Z1IsOne)
+ {
+ Z3Squared = C;
+ }
+ else
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+ else
+ {
+ ECFieldElement Z1Squared, U2, S2;
+ if (Z1IsOne)
+ {
+ Z1Squared = Z1; U2 = X2; S2 = Y2;
+ }
+ else
+ {
+ Z1Squared = Z1.Square();
+ U2 = Z1Squared.Multiply(X2);
+ ECFieldElement Z1Cubed = Z1Squared.Multiply(Z1);
+ S2 = Z1Cubed.Multiply(Y2);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement Z2Squared, U1, S1;
+ if (Z2IsOne)
+ {
+ Z2Squared = Z2; U1 = X1; S1 = Y1;
+ }
+ else
+ {
+ Z2Squared = Z2.Square();
+ U1 = Z2Squared.Multiply(X1);
+ ECFieldElement Z2Cubed = Z2Squared.Multiply(Z2);
+ S1 = Z2Cubed.Multiply(Y1);
+ }
+
+ ECFieldElement H = U1.Subtract(U2);
+ ECFieldElement R = S1.Subtract(S2);
+
+ // Check if b == this or b == -this
+ if (H.IsZero)
+ {
+ if (R.IsZero)
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ ECFieldElement HSquared = H.Square();
+ ECFieldElement G = HSquared.Multiply(H);
+ ECFieldElement V = HSquared.Multiply(U1);
+
+ X3 = R.Square().Add(G).Subtract(Two(V));
+ Y3 = V.Subtract(X3).MultiplyMinusProduct(R, G, S1);
+
+ Z3 = H;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ if (!Z2IsOne)
+ {
+ Z3 = Z3.Multiply(Z2);
+ }
+
+ // Alternative calculation of Z3 using fast square
+ //X3 = four(X3);
+ //Y3 = eight(Y3);
+ //Z3 = doubleProductFromSquares(Z1, Z2, Z1Squared, Z2Squared).Multiply(H);
+
+ if (Z3 == H)
+ {
+ Z3Squared = HSquared;
+ }
+ }
+
+ ECFieldElement[] zs;
+ if (coord == ECCurve.COORD_JACOBIAN_MODIFIED)
+ {
+ // TODO If the result will only be used in a subsequent addition, we don't need W3
+ ECFieldElement W3 = CalculateJacobianModifiedW(Z3, Z3Squared);
+
+ zs = new ECFieldElement[] { Z3, W3 };
+ }
+ else
+ {
+ zs = new ECFieldElement[] { Z3 };
+ }
+
+ return new FpPoint(curve, X3, Y3, zs, IsCompressed);
+ }
+
+ default:
+ {
+ throw new InvalidOperationException("unsupported coordinate system");
+ }
+ }
+ }
+
+ // B.3 pg 62
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ int coord = curve.CoordinateSystem;
+
+ ECFieldElement X1 = this.RawXCoord;
+
+ switch (coord)
+ {
+ case ECCurve.COORD_AFFINE:
+ {
+ ECFieldElement X1Squared = X1.Square();
+ ECFieldElement gamma = Three(X1Squared).Add(this.Curve.A).Divide(Two(Y1));
+ ECFieldElement X3 = gamma.Square().Subtract(Two(X1));
+ ECFieldElement Y3 = gamma.Multiply(X1.Subtract(X3)).Subtract(Y1);
+
+ return new FpPoint(Curve, X3, Y3, IsCompressed);
+ }
+
+ case ECCurve.COORD_HOMOGENEOUS:
+ {
+ ECFieldElement Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+
+ // TODO Optimize for small negative a4 and -3
+ ECFieldElement w = curve.A;
+ if (!w.IsZero && !Z1IsOne)
+ {
+ w = w.Multiply(Z1.Square());
+ }
+ w = w.Add(Three(X1.Square()));
+
+ ECFieldElement s = Z1IsOne ? Y1 : Y1.Multiply(Z1);
+ ECFieldElement t = Z1IsOne ? Y1.Square() : s.Multiply(Y1);
+ ECFieldElement B = X1.Multiply(t);
+ ECFieldElement _4B = Four(B);
+ ECFieldElement h = w.Square().Subtract(Two(_4B));
+
+ ECFieldElement _2s = Two(s);
+ ECFieldElement X3 = h.Multiply(_2s);
+ ECFieldElement _2t = Two(t);
+ ECFieldElement Y3 = _4B.Subtract(h).Multiply(w).Subtract(Two(_2t.Square()));
+ ECFieldElement _4sSquared = Z1IsOne ? Two(_2t) : _2s.Square();
+ ECFieldElement Z3 = Two(_4sSquared).Multiply(s);
+
+ return new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ case ECCurve.COORD_JACOBIAN:
+ {
+ ECFieldElement Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+
+ ECFieldElement Y1Squared = Y1.Square();
+ ECFieldElement T = Y1Squared.Square();
+
+ ECFieldElement a4 = curve.A;
+ ECFieldElement a4Neg = a4.Negate();
+
+ ECFieldElement M, S;
+ if (a4Neg.ToBigInteger().Equals(BigInteger.ValueOf(3)))
+ {
+ ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.Square();
+ M = Three(X1.Add(Z1Squared).Multiply(X1.Subtract(Z1Squared)));
+ S = Four(Y1Squared.Multiply(X1));
+ }
+ else
+ {
+ ECFieldElement X1Squared = X1.Square();
+ M = Three(X1Squared);
+ if (Z1IsOne)
+ {
+ M = M.Add(a4);
+ }
+ else if (!a4.IsZero)
+ {
+ ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement Z1Pow4 = Z1Squared.Square();
+ if (a4Neg.BitLength < a4.BitLength)
+ {
+ M = M.Subtract(Z1Pow4.Multiply(a4Neg));
+ }
+ else
+ {
+ M = M.Add(Z1Pow4.Multiply(a4));
+ }
+ }
+ //S = two(doubleProductFromSquares(X1, Y1Squared, X1Squared, T));
+ S = Four(X1.Multiply(Y1Squared));
+ }
+
+ ECFieldElement X3 = M.Square().Subtract(Two(S));
+ ECFieldElement Y3 = S.Subtract(X3).Multiply(M).Subtract(Eight(T));
+
+ ECFieldElement Z3 = Two(Y1);
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+
+ // Alternative calculation of Z3 using fast square
+ //ECFieldElement Z3 = doubleProductFromSquares(Y1, Z1, Y1Squared, Z1Squared);
+
+ return new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ case ECCurve.COORD_JACOBIAN_MODIFIED:
+ {
+ return TwiceJacobianModified(true);
+ }
+
+ default:
+ {
+ throw new InvalidOperationException("unsupported coordinate system");
+ }
+ }
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this == b)
+ return ThreeTimes();
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return b;
+
+ ECCurve curve = this.Curve;
+ int coord = curve.CoordinateSystem;
+
+ switch (coord)
+ {
+ case ECCurve.COORD_AFFINE:
+ {
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord, Y2 = b.RawYCoord;
+
+ ECFieldElement dx = X2.Subtract(X1), dy = Y2.Subtract(Y1);
+
+ if (dx.IsZero)
+ {
+ if (dy.IsZero)
+ {
+ // this == b i.e. the result is 3P
+ return ThreeTimes();
+ }
+
+ // this == -b, i.e. the result is P
+ return this;
+ }
+
+ /*
+ * Optimized calculation of 2P + Q, as described in "Trading Inversions for
+ * Multiplications in Elliptic Curve Cryptography", by Ciet, Joye, Lauter, Montgomery.
+ */
+
+ ECFieldElement X = dx.Square(), Y = dy.Square();
+ ECFieldElement d = X.Multiply(Two(X1).Add(X2)).Subtract(Y);
+ if (d.IsZero)
+ {
+ return Curve.Infinity;
+ }
+
+ ECFieldElement D = d.Multiply(dx);
+ ECFieldElement I = D.Invert();
+ ECFieldElement L1 = d.Multiply(I).Multiply(dy);
+ ECFieldElement L2 = Two(Y1).Multiply(X).Multiply(dx).Multiply(I).Subtract(L1);
+ ECFieldElement X4 = (L2.Subtract(L1)).Multiply(L1.Add(L2)).Add(X2);
+ ECFieldElement Y4 = (X1.Subtract(X4)).Multiply(L2).Subtract(Y1);
+
+ return new FpPoint(Curve, X4, Y4, IsCompressed);
+ }
+ case ECCurve.COORD_JACOBIAN_MODIFIED:
+ {
+ return TwiceJacobianModified(false).Add(b);
+ }
+ default:
+ {
+ return Twice().Add(b);
+ }
+ }
+ }
+
+ public override ECPoint ThreeTimes()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return this;
+
+ ECCurve curve = this.Curve;
+ int coord = curve.CoordinateSystem;
+
+ switch (coord)
+ {
+ case ECCurve.COORD_AFFINE:
+ {
+ ECFieldElement X1 = this.RawXCoord;
+
+ ECFieldElement _2Y1 = Two(Y1);
+ ECFieldElement X = _2Y1.Square();
+ ECFieldElement Z = Three(X1.Square()).Add(Curve.A);
+ ECFieldElement Y = Z.Square();
+
+ ECFieldElement d = Three(X1).Multiply(X).Subtract(Y);
+ if (d.IsZero)
+ {
+ return Curve.Infinity;
+ }
+
+ ECFieldElement D = d.Multiply(_2Y1);
+ ECFieldElement I = D.Invert();
+ ECFieldElement L1 = d.Multiply(I).Multiply(Z);
+ ECFieldElement L2 = X.Square().Multiply(I).Subtract(L1);
+
+ ECFieldElement X4 = (L2.Subtract(L1)).Multiply(L1.Add(L2)).Add(X1);
+ ECFieldElement Y4 = (X1.Subtract(X4)).Multiply(L2).Subtract(Y1);
+ return new FpPoint(Curve, X4, Y4, IsCompressed);
+ }
+ case ECCurve.COORD_JACOBIAN_MODIFIED:
+ {
+ return TwiceJacobianModified(false).Add(this);
+ }
+ default:
+ {
+ // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+ return Twice().Add(this);
+ }
+ }
+ }
+
+ public override ECPoint TimesPow2(int e)
+ {
+ if (e < 0)
+ throw new ArgumentException("cannot be negative", "e");
+ if (e == 0 || this.IsInfinity)
+ return this;
+ if (e == 1)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ int coord = curve.CoordinateSystem;
+
+ ECFieldElement W1 = curve.A;
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement Z1 = this.RawZCoords.Length < 1 ? curve.FromBigInteger(BigInteger.One) : this.RawZCoords[0];
+
+ if (!Z1.IsOne)
+ {
+ switch (coord)
+ {
+ case ECCurve.COORD_HOMOGENEOUS:
+ ECFieldElement Z1Sq = Z1.Square();
+ X1 = X1.Multiply(Z1);
+ Y1 = Y1.Multiply(Z1Sq);
+ W1 = CalculateJacobianModifiedW(Z1, Z1Sq);
+ break;
+ case ECCurve.COORD_JACOBIAN:
+ W1 = CalculateJacobianModifiedW(Z1, null);
+ break;
+ case ECCurve.COORD_JACOBIAN_MODIFIED:
+ W1 = GetJacobianModifiedW();
+ break;
+ }
+ }
+
+ for (int i = 0; i < e; ++i)
+ {
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ ECFieldElement X1Squared = X1.Square();
+ ECFieldElement M = Three(X1Squared);
+ ECFieldElement _2Y1 = Two(Y1);
+ ECFieldElement _2Y1Squared = _2Y1.Multiply(Y1);
+ ECFieldElement S = Two(X1.Multiply(_2Y1Squared));
+ ECFieldElement _4T = _2Y1Squared.Square();
+ ECFieldElement _8T = Two(_4T);
+
+ if (!W1.IsZero)
+ {
+ M = M.Add(W1);
+ W1 = Two(_8T.Multiply(W1));
+ }
+
+ X1 = M.Square().Subtract(Two(S));
+ Y1 = M.Multiply(S.Subtract(X1)).Subtract(_8T);
+ Z1 = Z1.IsOne ? _2Y1 : _2Y1.Multiply(Z1);
+ }
+
+ switch (coord)
+ {
+ case ECCurve.COORD_AFFINE:
+ ECFieldElement zInv = Z1.Invert(), zInv2 = zInv.Square(), zInv3 = zInv2.Multiply(zInv);
+ return new FpPoint(curve, X1.Multiply(zInv2), Y1.Multiply(zInv3), IsCompressed);
+ case ECCurve.COORD_HOMOGENEOUS:
+ X1 = X1.Multiply(Z1);
+ Z1 = Z1.Multiply(Z1.Square());
+ return new FpPoint(curve, X1, Y1, new ECFieldElement[] { Z1 }, IsCompressed);
+ case ECCurve.COORD_JACOBIAN:
+ return new FpPoint(curve, X1, Y1, new ECFieldElement[] { Z1 }, IsCompressed);
+ case ECCurve.COORD_JACOBIAN_MODIFIED:
+ return new FpPoint(curve, X1, Y1, new ECFieldElement[] { Z1, W1 }, IsCompressed);
+ default:
+ throw new InvalidOperationException("unsupported coordinate system");
+ }
+ }
+
+ protected virtual ECFieldElement Two(ECFieldElement x)
+ {
+ return x.Add(x);
+ }
+
+ protected virtual ECFieldElement Three(ECFieldElement x)
+ {
+ return Two(x).Add(x);
+ }
+
+ protected virtual ECFieldElement Four(ECFieldElement x)
+ {
+ return Two(Two(x));
+ }
+
+ protected virtual ECFieldElement Eight(ECFieldElement x)
+ {
+ return Four(Two(x));
+ }
+
+ protected virtual ECFieldElement DoubleProductFromSquares(ECFieldElement a, ECFieldElement b,
+ ECFieldElement aSquared, ECFieldElement bSquared)
+ {
+ /*
+ * NOTE: If squaring in the field is faster than multiplication, then this is a quicker
+ * way to calculate 2.A.B, if A^2 and B^2 are already known.
+ */
+ return a.Add(b).Square().Subtract(aSquared).Subtract(bSquared);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ ECCurve curve = Curve;
+ int coord = curve.CoordinateSystem;
+
+ if (ECCurve.COORD_AFFINE != coord)
+ {
+ return new FpPoint(curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+ }
+
+ return new FpPoint(curve, RawXCoord, RawYCoord.Negate(), IsCompressed);
+ }
+
+ protected virtual ECFieldElement CalculateJacobianModifiedW(ECFieldElement Z, ECFieldElement ZSquared)
+ {
+ ECFieldElement a4 = this.Curve.A;
+ if (a4.IsZero || Z.IsOne)
+ return a4;
+
+ if (ZSquared == null)
+ {
+ ZSquared = Z.Square();
+ }
+
+ ECFieldElement W = ZSquared.Square();
+ ECFieldElement a4Neg = a4.Negate();
+ if (a4Neg.BitLength < a4.BitLength)
+ {
+ W = W.Multiply(a4Neg).Negate();
+ }
+ else
+ {
+ W = W.Multiply(a4);
+ }
+ return W;
+ }
+
+ protected virtual ECFieldElement GetJacobianModifiedW()
+ {
+ ECFieldElement[] ZZ = this.RawZCoords;
+ ECFieldElement W = ZZ[1];
+ if (W == null)
+ {
+ // NOTE: Rarely, TwicePlus will result in the need for a lazy W1 calculation here
+ ZZ[1] = W = CalculateJacobianModifiedW(ZZ[0], null);
+ }
+ return W;
+ }
+
+ protected virtual FpPoint TwiceJacobianModified(bool calculateW)
+ {
+ ECFieldElement X1 = this.RawXCoord, Y1 = this.RawYCoord, Z1 = this.RawZCoords[0], W1 = GetJacobianModifiedW();
+
+ ECFieldElement X1Squared = X1.Square();
+ ECFieldElement M = Three(X1Squared).Add(W1);
+ ECFieldElement _2Y1 = Two(Y1);
+ ECFieldElement _2Y1Squared = _2Y1.Multiply(Y1);
+ ECFieldElement S = Two(X1.Multiply(_2Y1Squared));
+ ECFieldElement X3 = M.Square().Subtract(Two(S));
+ ECFieldElement _4T = _2Y1Squared.Square();
+ ECFieldElement _8T = Two(_4T);
+ ECFieldElement Y3 = M.Multiply(S.Subtract(X3)).Subtract(_8T);
+ ECFieldElement W3 = calculateW ? Two(_8T.Multiply(W1)) : null;
+ ECFieldElement Z3 = Z1.IsOne ? _2Y1 : _2Y1.Multiply(Z1);
+
+ return new FpPoint(this.Curve, X3, Y3, new ECFieldElement[] { Z3, W3 }, IsCompressed);
+ }
+ }
+
+ public abstract class AbstractF2mPoint
+ : ECPointBase
+ {
+ protected AbstractF2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ }
+
+ protected AbstractF2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override bool SatisfiesCurveEquation()
+ {
+ ECCurve curve = Curve;
+ ECFieldElement X = this.RawXCoord, Y = this.RawYCoord, A = curve.A, B = curve.B;
+ ECFieldElement lhs, rhs;
+
+ int coord = curve.CoordinateSystem;
+ if (coord == ECCurve.COORD_LAMBDA_PROJECTIVE)
+ {
+ ECFieldElement Z = this.RawZCoords[0];
+ bool ZIsOne = Z.IsOne;
+
+ if (X.IsZero)
+ {
+ // NOTE: For x == 0, we expect the affine-y instead of the lambda-y
+ lhs = Y.Square();
+ rhs = B;
+ if (!ZIsOne)
+ {
+ ECFieldElement Z2 = Z.Square();
+ rhs = rhs.Multiply(Z2);
+ }
+ }
+ else
+ {
+ ECFieldElement L = Y, X2 = X.Square();
+ if (ZIsOne)
+ {
+ lhs = L.Square().Add(L).Add(A);
+ rhs = X2.Square().Add(B);
+ }
+ else
+ {
+ ECFieldElement Z2 = Z.Square(), Z4 = Z2.Square();
+ lhs = L.Add(Z).MultiplyPlusProduct(L, A, Z2);
+ // TODO If sqrt(b) is precomputed this can be simplified to a single square
+ rhs = X2.SquarePlusProduct(B, Z4);
+ }
+ lhs = lhs.Multiply(X2);
+ }
+ }
+ else
+ {
+ lhs = Y.Add(X).Multiply(Y);
+
+ switch (coord)
+ {
+ case ECCurve.COORD_AFFINE:
+ break;
+ case ECCurve.COORD_HOMOGENEOUS:
+ {
+ ECFieldElement Z = this.RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ ECFieldElement Z2 = Z.Square(), Z3 = Z.Multiply(Z2);
+ lhs = lhs.Multiply(Z);
+ A = A.Multiply(Z);
+ B = B.Multiply(Z3);
+ }
+ break;
+ }
+ default:
+ throw new InvalidOperationException("unsupported coordinate system");
+ }
+
+ rhs = X.Add(A).Multiply(X.Square()).Add(B);
+ }
+
+ return lhs.Equals(rhs);
+ }
+
+ public override ECPoint ScaleX(ECFieldElement scale)
+ {
+ if (this.IsInfinity)
+ return this;
+
+ switch (CurveCoordinateSystem)
+ {
+ case ECCurve.COORD_LAMBDA_AFFINE:
+ {
+ // Y is actually Lambda (X + Y/X) here
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ ECFieldElement X2 = X.Multiply(scale);
+ ECFieldElement L2 = L.Add(X).Divide(scale).Add(X2);
+
+ return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed);
+ }
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ // Y is actually Lambda (X + Y/X) here
+ ECFieldElement X = RawXCoord, L = RawYCoord, Z = RawZCoords[0];
+
+ // We scale the Z coordinate also, to avoid an inversion
+ ECFieldElement X2 = X.Multiply(scale.Square());
+ ECFieldElement L2 = L.Add(X).Add(X2);
+ ECFieldElement Z2 = Z.Multiply(scale);
+
+ return Curve.CreateRawPoint(X, L2, new ECFieldElement[] { Z2 }, IsCompressed);
+ }
+ default:
+ {
+ return base.ScaleX(scale);
+ }
+ }
+ }
+
+ public override ECPoint ScaleY(ECFieldElement scale)
+ {
+ if (this.IsInfinity)
+ return this;
+
+ switch (CurveCoordinateSystem)
+ {
+ case ECCurve.COORD_LAMBDA_AFFINE:
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ ECFieldElement L2 = L.Add(X).Multiply(scale).Add(X);
+
+ return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed);
+ }
+ default:
+ {
+ return base.ScaleY(scale);
+ }
+ }
+ }
+
+ public override ECPoint Subtract(ECPoint b)
+ {
+ if (b.IsInfinity)
+ return this;
+
+ // Add -b
+ return Add(b.Negate());
+ }
+
+ public virtual AbstractF2mPoint Tau()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+ int coord = curve.CoordinateSystem;
+
+ ECFieldElement X1 = this.RawXCoord;
+
+ switch (coord)
+ {
+ case ECCurve.COORD_AFFINE:
+ case ECCurve.COORD_LAMBDA_AFFINE:
+ {
+ ECFieldElement Y1 = this.RawYCoord;
+ return (AbstractF2mPoint)curve.CreateRawPoint(X1.Square(), Y1.Square(), IsCompressed);
+ }
+ case ECCurve.COORD_HOMOGENEOUS:
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ return (AbstractF2mPoint)curve.CreateRawPoint(X1.Square(), Y1.Square(),
+ new ECFieldElement[] { Z1.Square() }, IsCompressed);
+ }
+ default:
+ {
+ throw new InvalidOperationException("unsupported coordinate system");
+ }
+ }
+ }
+
+ public virtual AbstractF2mPoint TauPow(int pow)
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+ int coord = curve.CoordinateSystem;
+
+ ECFieldElement X1 = this.RawXCoord;
+
+ switch (coord)
+ {
+ case ECCurve.COORD_AFFINE:
+ case ECCurve.COORD_LAMBDA_AFFINE:
+ {
+ ECFieldElement Y1 = this.RawYCoord;
+ return (AbstractF2mPoint)curve.CreateRawPoint(X1.SquarePow(pow), Y1.SquarePow(pow), IsCompressed);
+ }
+ case ECCurve.COORD_HOMOGENEOUS:
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ return (AbstractF2mPoint)curve.CreateRawPoint(X1.SquarePow(pow), Y1.SquarePow(pow),
+ new ECFieldElement[] { Z1.SquarePow(pow) }, IsCompressed);
+ }
+ default:
+ {
+ throw new InvalidOperationException("unsupported coordinate system");
+ }
+ }
+ }
+ }
+
+ /**
+ * Elliptic curve points over F2m
+ */
+ public class F2mPoint
+ : AbstractF2mPoint
+ {
+ /**
+ * @param curve base curve
+ * @param x x point
+ * @param y y point
+ */
+ public F2mPoint(
+ ECCurve curve,
+ ECFieldElement x,
+ ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @param curve base curve
+ * @param x x point
+ * @param y y point
+ * @param withCompression true if encode with point compression.
+ */
+ public F2mPoint(
+ ECCurve curve,
+ ECFieldElement x,
+ ECFieldElement y,
+ bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ {
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ if (x != null)
+ {
+ // Check if x and y are elements of the same field
+ F2mFieldElement.CheckFieldElements(x, y);
+
+ // Check if x and a are elements of the same field
+ if (curve != null)
+ {
+ F2mFieldElement.CheckFieldElements(x, curve.A);
+ }
+ }
+ }
+
+ internal F2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ /**
+ * Constructor for point at infinity
+ */
+ [Obsolete("Use ECCurve.Infinity property")]
+ public F2mPoint(
+ ECCurve curve)
+ : this(curve, null, null)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new F2mPoint(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ int coord = this.CurveCoordinateSystem;
+
+ switch (coord)
+ {
+ case ECCurve.COORD_LAMBDA_AFFINE:
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+ if (ECCurve.COORD_LAMBDA_PROJECTIVE == coord)
+ {
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+ }
+ return Y;
+ }
+ default:
+ {
+ return RawYCoord;
+ }
+ }
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ {
+ return false;
+ }
+
+ ECFieldElement Y = this.RawYCoord;
+
+ switch (this.CurveCoordinateSystem)
+ {
+ case ECCurve.COORD_LAMBDA_AFFINE:
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ default:
+ {
+ return Y.Divide(X).TestBitZero();
+ }
+ }
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+ int coord = curve.CoordinateSystem;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ switch (coord)
+ {
+ case ECCurve.COORD_AFFINE:
+ {
+ ECFieldElement Y1 = this.RawYCoord;
+ ECFieldElement Y2 = b.RawYCoord;
+
+ ECFieldElement dx = X1.Add(X2), dy = Y1.Add(Y2);
+ if (dx.IsZero)
+ {
+ if (dy.IsZero)
+ {
+ return Twice();
+ }
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement L = dy.Divide(dx);
+
+ ECFieldElement X3 = L.Square().Add(L).Add(dx).Add(curve.A);
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+
+ return new F2mPoint(curve, X3, Y3, IsCompressed);
+ }
+ case ECCurve.COORD_HOMOGENEOUS:
+ {
+ ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement Y2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U1 = Y2, V1 = X2;
+ if (!Z1IsOne)
+ {
+ U1 = U1.Multiply(Z1);
+ V1 = V1.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U2 = Y1, V2 = X1;
+ if (!Z2IsOne)
+ {
+ U2 = U2.Multiply(Z2);
+ V2 = V2.Multiply(Z2);
+ }
+
+ ECFieldElement U = U1.Add(U2);
+ ECFieldElement V = V1.Add(V2);
+
+ if (V.IsZero)
+ {
+ if (U.IsZero)
+ {
+ return Twice();
+ }
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement VSq = V.Square();
+ ECFieldElement VCu = VSq.Multiply(V);
+ ECFieldElement W = Z1IsOne ? Z2 : Z2IsOne ? Z1 : Z1.Multiply(Z2);
+ ECFieldElement uv = U.Add(V);
+ ECFieldElement A = uv.MultiplyPlusProduct(U, VSq, curve.A).Multiply(W).Add(VCu);
+
+ ECFieldElement X3 = V.Multiply(A);
+ ECFieldElement VSqZ2 = Z2IsOne ? VSq : VSq.Multiply(Z2);
+ ECFieldElement Y3 = U.MultiplyPlusProduct(X1, V, Y1).MultiplyPlusProduct(VSqZ2, uv, A);
+ ECFieldElement Z3 = VCu.Multiply(W);
+
+ return new F2mPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ {
+ return Twice();
+ }
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.RawXCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ if (X3.IsZero)
+ {
+ return new F2mPoint(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new F2mPoint(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new F2mPoint(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+ default:
+ {
+ throw new InvalidOperationException("unsupported coordinate system");
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see Org.BouncyCastle.Math.EC.ECPoint#twice()
+ */
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own additive inverse
+ return curve.Infinity;
+ }
+
+ int coord = curve.CoordinateSystem;
+
+ switch (coord)
+ {
+ case ECCurve.COORD_AFFINE:
+ {
+ ECFieldElement Y1 = this.RawYCoord;
+
+ ECFieldElement L1 = Y1.Divide(X1).Add(X1);
+
+ ECFieldElement X3 = L1.Square().Add(L1).Add(curve.A);
+ ECFieldElement Y3 = X1.SquarePlusProduct(X3, L1.AddOne());
+
+ return new F2mPoint(curve, X3, Y3, IsCompressed);
+ }
+ case ECCurve.COORD_HOMOGENEOUS:
+ {
+ ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement Y1Z1 = Z1IsOne ? Y1 : Y1.Multiply(Z1);
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement S = X1Sq.Add(Y1Z1);
+ ECFieldElement V = X1Z1;
+ ECFieldElement vSquared = V.Square();
+ ECFieldElement sv = S.Add(V);
+ ECFieldElement h = sv.MultiplyPlusProduct(S, vSquared, curve.A);
+
+ ECFieldElement X3 = V.Multiply(h);
+ ECFieldElement Y3 = X1Sq.Square().MultiplyPlusProduct(V, h, sv);
+ ECFieldElement Z3 = V.Multiply(vSquared);
+
+ return new F2mPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement a = curve.A;
+ ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+ if (T.IsZero)
+ {
+ return new F2mPoint(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement b = curve.B;
+ ECFieldElement L3;
+ if (b.BitLength < (curve.FieldSize >> 1))
+ {
+ ECFieldElement t1 = L1.Add(X1).Square();
+ ECFieldElement t2;
+ if (b.IsOne)
+ {
+ t2 = aZ1Sq.Add(Z1Sq).Square();
+ }
+ else
+ {
+ // TODO Can be calculated with one square if we pre-compute sqrt(b)
+ t2 = aZ1Sq.SquarePlusProduct(b, Z1Sq.Square());
+ }
+ L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3);
+ if (a.IsZero)
+ {
+ L3 = L3.Add(Z3);
+ }
+ else if (!a.IsOne)
+ {
+ L3 = L3.Add(a.AddOne().Multiply(Z3));
+ }
+ }
+ else
+ {
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+ }
+
+ return new F2mPoint(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+ default:
+ {
+ throw new InvalidOperationException("unsupported coordinate system");
+ }
+ }
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own additive inverse
+ return b;
+ }
+
+ int coord = curve.CoordinateSystem;
+
+ switch (coord)
+ {
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ // NOTE: twicePlus() only optimized for lambda-affine argument
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ {
+ return b.Twice();
+ }
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new F2mPoint(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new F2mPoint(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+ default:
+ {
+ return Twice().Add(b);
+ }
+ }
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ ECCurve curve = this.Curve;
+ int coord = curve.CoordinateSystem;
+
+ switch (coord)
+ {
+ case ECCurve.COORD_AFFINE:
+ {
+ ECFieldElement Y = this.RawYCoord;
+ return new F2mPoint(curve, X, Y.Add(X), IsCompressed);
+ }
+ case ECCurve.COORD_HOMOGENEOUS:
+ {
+ ECFieldElement Y = this.RawYCoord, Z = this.RawZCoords[0];
+ return new F2mPoint(curve, X, Y.Add(X), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ case ECCurve.COORD_LAMBDA_AFFINE:
+ {
+ ECFieldElement L = this.RawYCoord;
+ return new F2mPoint(curve, X, L.AddOne(), IsCompressed);
+ }
+ case ECCurve.COORD_LAMBDA_PROJECTIVE:
+ {
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new F2mPoint(curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ default:
+ {
+ throw new InvalidOperationException("unsupported coordinate system");
+ }
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/ECPointMap.cs b/bc-sharp-crypto/src/math/ec/ECPointMap.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e78c8006597054c30c292f99495e7c8b47214e04
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/ECPointMap.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC
+{
+ public interface ECPointMap
+ {
+ ECPoint Map(ECPoint p);
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/LongArray.cs b/bc-sharp-crypto/src/math/ec/LongArray.cs
new file mode 100644
index 0000000000000000000000000000000000000000..84462e0eab6daa9a1c248ad3e13fc7a42bb8cf0a
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/LongArray.cs
@@ -0,0 +1,2201 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC
+{
+ internal class LongArray
+ {
+ //private static long DEInterleave_MASK = 0x5555555555555555L;
+
+ /*
+ * This expands 8 bit indices into 16 bit contents (high bit 14), by inserting 0s between bits.
+ * In a binary field, this operation is the same as squaring an 8 bit number.
+ */
+ private static readonly ushort[] INTERLEAVE2_TABLE = new ushort[]
+ {
+ 0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
+ 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
+ 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
+ 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
+ 0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
+ 0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
+ 0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
+ 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
+ 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
+ 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
+ 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
+ 0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
+ 0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
+ 0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
+ 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
+ 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
+ 0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
+ 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
+ 0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
+ 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
+ 0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
+ 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
+ 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
+ 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
+ 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
+ 0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
+ 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
+ 0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
+ 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
+ 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
+ 0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
+ 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
+ };
+
+ /*
+ * This expands 7 bit indices into 21 bit contents (high bit 18), by inserting 0s between bits.
+ */
+ private static readonly int[] INTERLEAVE3_TABLE = new int[]
+ {
+ 0x00000, 0x00001, 0x00008, 0x00009, 0x00040, 0x00041, 0x00048, 0x00049,
+ 0x00200, 0x00201, 0x00208, 0x00209, 0x00240, 0x00241, 0x00248, 0x00249,
+ 0x01000, 0x01001, 0x01008, 0x01009, 0x01040, 0x01041, 0x01048, 0x01049,
+ 0x01200, 0x01201, 0x01208, 0x01209, 0x01240, 0x01241, 0x01248, 0x01249,
+ 0x08000, 0x08001, 0x08008, 0x08009, 0x08040, 0x08041, 0x08048, 0x08049,
+ 0x08200, 0x08201, 0x08208, 0x08209, 0x08240, 0x08241, 0x08248, 0x08249,
+ 0x09000, 0x09001, 0x09008, 0x09009, 0x09040, 0x09041, 0x09048, 0x09049,
+ 0x09200, 0x09201, 0x09208, 0x09209, 0x09240, 0x09241, 0x09248, 0x09249,
+ 0x40000, 0x40001, 0x40008, 0x40009, 0x40040, 0x40041, 0x40048, 0x40049,
+ 0x40200, 0x40201, 0x40208, 0x40209, 0x40240, 0x40241, 0x40248, 0x40249,
+ 0x41000, 0x41001, 0x41008, 0x41009, 0x41040, 0x41041, 0x41048, 0x41049,
+ 0x41200, 0x41201, 0x41208, 0x41209, 0x41240, 0x41241, 0x41248, 0x41249,
+ 0x48000, 0x48001, 0x48008, 0x48009, 0x48040, 0x48041, 0x48048, 0x48049,
+ 0x48200, 0x48201, 0x48208, 0x48209, 0x48240, 0x48241, 0x48248, 0x48249,
+ 0x49000, 0x49001, 0x49008, 0x49009, 0x49040, 0x49041, 0x49048, 0x49049,
+ 0x49200, 0x49201, 0x49208, 0x49209, 0x49240, 0x49241, 0x49248, 0x49249
+ };
+
+ /*
+ * This expands 8 bit indices into 32 bit contents (high bit 28), by inserting 0s between bits.
+ */
+ private static readonly int[] INTERLEAVE4_TABLE = new int[]
+ {
+ 0x00000000, 0x00000001, 0x00000010, 0x00000011, 0x00000100, 0x00000101, 0x00000110, 0x00000111,
+ 0x00001000, 0x00001001, 0x00001010, 0x00001011, 0x00001100, 0x00001101, 0x00001110, 0x00001111,
+ 0x00010000, 0x00010001, 0x00010010, 0x00010011, 0x00010100, 0x00010101, 0x00010110, 0x00010111,
+ 0x00011000, 0x00011001, 0x00011010, 0x00011011, 0x00011100, 0x00011101, 0x00011110, 0x00011111,
+ 0x00100000, 0x00100001, 0x00100010, 0x00100011, 0x00100100, 0x00100101, 0x00100110, 0x00100111,
+ 0x00101000, 0x00101001, 0x00101010, 0x00101011, 0x00101100, 0x00101101, 0x00101110, 0x00101111,
+ 0x00110000, 0x00110001, 0x00110010, 0x00110011, 0x00110100, 0x00110101, 0x00110110, 0x00110111,
+ 0x00111000, 0x00111001, 0x00111010, 0x00111011, 0x00111100, 0x00111101, 0x00111110, 0x00111111,
+ 0x01000000, 0x01000001, 0x01000010, 0x01000011, 0x01000100, 0x01000101, 0x01000110, 0x01000111,
+ 0x01001000, 0x01001001, 0x01001010, 0x01001011, 0x01001100, 0x01001101, 0x01001110, 0x01001111,
+ 0x01010000, 0x01010001, 0x01010010, 0x01010011, 0x01010100, 0x01010101, 0x01010110, 0x01010111,
+ 0x01011000, 0x01011001, 0x01011010, 0x01011011, 0x01011100, 0x01011101, 0x01011110, 0x01011111,
+ 0x01100000, 0x01100001, 0x01100010, 0x01100011, 0x01100100, 0x01100101, 0x01100110, 0x01100111,
+ 0x01101000, 0x01101001, 0x01101010, 0x01101011, 0x01101100, 0x01101101, 0x01101110, 0x01101111,
+ 0x01110000, 0x01110001, 0x01110010, 0x01110011, 0x01110100, 0x01110101, 0x01110110, 0x01110111,
+ 0x01111000, 0x01111001, 0x01111010, 0x01111011, 0x01111100, 0x01111101, 0x01111110, 0x01111111,
+ 0x10000000, 0x10000001, 0x10000010, 0x10000011, 0x10000100, 0x10000101, 0x10000110, 0x10000111,
+ 0x10001000, 0x10001001, 0x10001010, 0x10001011, 0x10001100, 0x10001101, 0x10001110, 0x10001111,
+ 0x10010000, 0x10010001, 0x10010010, 0x10010011, 0x10010100, 0x10010101, 0x10010110, 0x10010111,
+ 0x10011000, 0x10011001, 0x10011010, 0x10011011, 0x10011100, 0x10011101, 0x10011110, 0x10011111,
+ 0x10100000, 0x10100001, 0x10100010, 0x10100011, 0x10100100, 0x10100101, 0x10100110, 0x10100111,
+ 0x10101000, 0x10101001, 0x10101010, 0x10101011, 0x10101100, 0x10101101, 0x10101110, 0x10101111,
+ 0x10110000, 0x10110001, 0x10110010, 0x10110011, 0x10110100, 0x10110101, 0x10110110, 0x10110111,
+ 0x10111000, 0x10111001, 0x10111010, 0x10111011, 0x10111100, 0x10111101, 0x10111110, 0x10111111,
+ 0x11000000, 0x11000001, 0x11000010, 0x11000011, 0x11000100, 0x11000101, 0x11000110, 0x11000111,
+ 0x11001000, 0x11001001, 0x11001010, 0x11001011, 0x11001100, 0x11001101, 0x11001110, 0x11001111,
+ 0x11010000, 0x11010001, 0x11010010, 0x11010011, 0x11010100, 0x11010101, 0x11010110, 0x11010111,
+ 0x11011000, 0x11011001, 0x11011010, 0x11011011, 0x11011100, 0x11011101, 0x11011110, 0x11011111,
+ 0x11100000, 0x11100001, 0x11100010, 0x11100011, 0x11100100, 0x11100101, 0x11100110, 0x11100111,
+ 0x11101000, 0x11101001, 0x11101010, 0x11101011, 0x11101100, 0x11101101, 0x11101110, 0x11101111,
+ 0x11110000, 0x11110001, 0x11110010, 0x11110011, 0x11110100, 0x11110101, 0x11110110, 0x11110111,
+ 0x11111000, 0x11111001, 0x11111010, 0x11111011, 0x11111100, 0x11111101, 0x11111110, 0x11111111
+ };
+
+ /*
+ * This expands 7 bit indices into 35 bit contents (high bit 30), by inserting 0s between bits.
+ */
+ private static readonly int[] INTERLEAVE5_TABLE = new int[] {
+ 0x00000000, 0x00000001, 0x00000020, 0x00000021, 0x00000400, 0x00000401, 0x00000420, 0x00000421,
+ 0x00008000, 0x00008001, 0x00008020, 0x00008021, 0x00008400, 0x00008401, 0x00008420, 0x00008421,
+ 0x00100000, 0x00100001, 0x00100020, 0x00100021, 0x00100400, 0x00100401, 0x00100420, 0x00100421,
+ 0x00108000, 0x00108001, 0x00108020, 0x00108021, 0x00108400, 0x00108401, 0x00108420, 0x00108421,
+ 0x02000000, 0x02000001, 0x02000020, 0x02000021, 0x02000400, 0x02000401, 0x02000420, 0x02000421,
+ 0x02008000, 0x02008001, 0x02008020, 0x02008021, 0x02008400, 0x02008401, 0x02008420, 0x02008421,
+ 0x02100000, 0x02100001, 0x02100020, 0x02100021, 0x02100400, 0x02100401, 0x02100420, 0x02100421,
+ 0x02108000, 0x02108001, 0x02108020, 0x02108021, 0x02108400, 0x02108401, 0x02108420, 0x02108421,
+ 0x40000000, 0x40000001, 0x40000020, 0x40000021, 0x40000400, 0x40000401, 0x40000420, 0x40000421,
+ 0x40008000, 0x40008001, 0x40008020, 0x40008021, 0x40008400, 0x40008401, 0x40008420, 0x40008421,
+ 0x40100000, 0x40100001, 0x40100020, 0x40100021, 0x40100400, 0x40100401, 0x40100420, 0x40100421,
+ 0x40108000, 0x40108001, 0x40108020, 0x40108021, 0x40108400, 0x40108401, 0x40108420, 0x40108421,
+ 0x42000000, 0x42000001, 0x42000020, 0x42000021, 0x42000400, 0x42000401, 0x42000420, 0x42000421,
+ 0x42008000, 0x42008001, 0x42008020, 0x42008021, 0x42008400, 0x42008401, 0x42008420, 0x42008421,
+ 0x42100000, 0x42100001, 0x42100020, 0x42100021, 0x42100400, 0x42100401, 0x42100420, 0x42100421,
+ 0x42108000, 0x42108001, 0x42108020, 0x42108021, 0x42108400, 0x42108401, 0x42108420, 0x42108421
+ };
+
+ /*
+ * This expands 9 bit indices into 63 bit (long) contents (high bit 56), by inserting 0s between bits.
+ */
+ private static readonly long[] INTERLEAVE7_TABLE = new long[]
+ {
+ 0x0000000000000000L, 0x0000000000000001L, 0x0000000000000080L, 0x0000000000000081L,
+ 0x0000000000004000L, 0x0000000000004001L, 0x0000000000004080L, 0x0000000000004081L,
+ 0x0000000000200000L, 0x0000000000200001L, 0x0000000000200080L, 0x0000000000200081L,
+ 0x0000000000204000L, 0x0000000000204001L, 0x0000000000204080L, 0x0000000000204081L,
+ 0x0000000010000000L, 0x0000000010000001L, 0x0000000010000080L, 0x0000000010000081L,
+ 0x0000000010004000L, 0x0000000010004001L, 0x0000000010004080L, 0x0000000010004081L,
+ 0x0000000010200000L, 0x0000000010200001L, 0x0000000010200080L, 0x0000000010200081L,
+ 0x0000000010204000L, 0x0000000010204001L, 0x0000000010204080L, 0x0000000010204081L,
+ 0x0000000800000000L, 0x0000000800000001L, 0x0000000800000080L, 0x0000000800000081L,
+ 0x0000000800004000L, 0x0000000800004001L, 0x0000000800004080L, 0x0000000800004081L,
+ 0x0000000800200000L, 0x0000000800200001L, 0x0000000800200080L, 0x0000000800200081L,
+ 0x0000000800204000L, 0x0000000800204001L, 0x0000000800204080L, 0x0000000800204081L,
+ 0x0000000810000000L, 0x0000000810000001L, 0x0000000810000080L, 0x0000000810000081L,
+ 0x0000000810004000L, 0x0000000810004001L, 0x0000000810004080L, 0x0000000810004081L,
+ 0x0000000810200000L, 0x0000000810200001L, 0x0000000810200080L, 0x0000000810200081L,
+ 0x0000000810204000L, 0x0000000810204001L, 0x0000000810204080L, 0x0000000810204081L,
+ 0x0000040000000000L, 0x0000040000000001L, 0x0000040000000080L, 0x0000040000000081L,
+ 0x0000040000004000L, 0x0000040000004001L, 0x0000040000004080L, 0x0000040000004081L,
+ 0x0000040000200000L, 0x0000040000200001L, 0x0000040000200080L, 0x0000040000200081L,
+ 0x0000040000204000L, 0x0000040000204001L, 0x0000040000204080L, 0x0000040000204081L,
+ 0x0000040010000000L, 0x0000040010000001L, 0x0000040010000080L, 0x0000040010000081L,
+ 0x0000040010004000L, 0x0000040010004001L, 0x0000040010004080L, 0x0000040010004081L,
+ 0x0000040010200000L, 0x0000040010200001L, 0x0000040010200080L, 0x0000040010200081L,
+ 0x0000040010204000L, 0x0000040010204001L, 0x0000040010204080L, 0x0000040010204081L,
+ 0x0000040800000000L, 0x0000040800000001L, 0x0000040800000080L, 0x0000040800000081L,
+ 0x0000040800004000L, 0x0000040800004001L, 0x0000040800004080L, 0x0000040800004081L,
+ 0x0000040800200000L, 0x0000040800200001L, 0x0000040800200080L, 0x0000040800200081L,
+ 0x0000040800204000L, 0x0000040800204001L, 0x0000040800204080L, 0x0000040800204081L,
+ 0x0000040810000000L, 0x0000040810000001L, 0x0000040810000080L, 0x0000040810000081L,
+ 0x0000040810004000L, 0x0000040810004001L, 0x0000040810004080L, 0x0000040810004081L,
+ 0x0000040810200000L, 0x0000040810200001L, 0x0000040810200080L, 0x0000040810200081L,
+ 0x0000040810204000L, 0x0000040810204001L, 0x0000040810204080L, 0x0000040810204081L,
+ 0x0002000000000000L, 0x0002000000000001L, 0x0002000000000080L, 0x0002000000000081L,
+ 0x0002000000004000L, 0x0002000000004001L, 0x0002000000004080L, 0x0002000000004081L,
+ 0x0002000000200000L, 0x0002000000200001L, 0x0002000000200080L, 0x0002000000200081L,
+ 0x0002000000204000L, 0x0002000000204001L, 0x0002000000204080L, 0x0002000000204081L,
+ 0x0002000010000000L, 0x0002000010000001L, 0x0002000010000080L, 0x0002000010000081L,
+ 0x0002000010004000L, 0x0002000010004001L, 0x0002000010004080L, 0x0002000010004081L,
+ 0x0002000010200000L, 0x0002000010200001L, 0x0002000010200080L, 0x0002000010200081L,
+ 0x0002000010204000L, 0x0002000010204001L, 0x0002000010204080L, 0x0002000010204081L,
+ 0x0002000800000000L, 0x0002000800000001L, 0x0002000800000080L, 0x0002000800000081L,
+ 0x0002000800004000L, 0x0002000800004001L, 0x0002000800004080L, 0x0002000800004081L,
+ 0x0002000800200000L, 0x0002000800200001L, 0x0002000800200080L, 0x0002000800200081L,
+ 0x0002000800204000L, 0x0002000800204001L, 0x0002000800204080L, 0x0002000800204081L,
+ 0x0002000810000000L, 0x0002000810000001L, 0x0002000810000080L, 0x0002000810000081L,
+ 0x0002000810004000L, 0x0002000810004001L, 0x0002000810004080L, 0x0002000810004081L,
+ 0x0002000810200000L, 0x0002000810200001L, 0x0002000810200080L, 0x0002000810200081L,
+ 0x0002000810204000L, 0x0002000810204001L, 0x0002000810204080L, 0x0002000810204081L,
+ 0x0002040000000000L, 0x0002040000000001L, 0x0002040000000080L, 0x0002040000000081L,
+ 0x0002040000004000L, 0x0002040000004001L, 0x0002040000004080L, 0x0002040000004081L,
+ 0x0002040000200000L, 0x0002040000200001L, 0x0002040000200080L, 0x0002040000200081L,
+ 0x0002040000204000L, 0x0002040000204001L, 0x0002040000204080L, 0x0002040000204081L,
+ 0x0002040010000000L, 0x0002040010000001L, 0x0002040010000080L, 0x0002040010000081L,
+ 0x0002040010004000L, 0x0002040010004001L, 0x0002040010004080L, 0x0002040010004081L,
+ 0x0002040010200000L, 0x0002040010200001L, 0x0002040010200080L, 0x0002040010200081L,
+ 0x0002040010204000L, 0x0002040010204001L, 0x0002040010204080L, 0x0002040010204081L,
+ 0x0002040800000000L, 0x0002040800000001L, 0x0002040800000080L, 0x0002040800000081L,
+ 0x0002040800004000L, 0x0002040800004001L, 0x0002040800004080L, 0x0002040800004081L,
+ 0x0002040800200000L, 0x0002040800200001L, 0x0002040800200080L, 0x0002040800200081L,
+ 0x0002040800204000L, 0x0002040800204001L, 0x0002040800204080L, 0x0002040800204081L,
+ 0x0002040810000000L, 0x0002040810000001L, 0x0002040810000080L, 0x0002040810000081L,
+ 0x0002040810004000L, 0x0002040810004001L, 0x0002040810004080L, 0x0002040810004081L,
+ 0x0002040810200000L, 0x0002040810200001L, 0x0002040810200080L, 0x0002040810200081L,
+ 0x0002040810204000L, 0x0002040810204001L, 0x0002040810204080L, 0x0002040810204081L,
+ 0x0100000000000000L, 0x0100000000000001L, 0x0100000000000080L, 0x0100000000000081L,
+ 0x0100000000004000L, 0x0100000000004001L, 0x0100000000004080L, 0x0100000000004081L,
+ 0x0100000000200000L, 0x0100000000200001L, 0x0100000000200080L, 0x0100000000200081L,
+ 0x0100000000204000L, 0x0100000000204001L, 0x0100000000204080L, 0x0100000000204081L,
+ 0x0100000010000000L, 0x0100000010000001L, 0x0100000010000080L, 0x0100000010000081L,
+ 0x0100000010004000L, 0x0100000010004001L, 0x0100000010004080L, 0x0100000010004081L,
+ 0x0100000010200000L, 0x0100000010200001L, 0x0100000010200080L, 0x0100000010200081L,
+ 0x0100000010204000L, 0x0100000010204001L, 0x0100000010204080L, 0x0100000010204081L,
+ 0x0100000800000000L, 0x0100000800000001L, 0x0100000800000080L, 0x0100000800000081L,
+ 0x0100000800004000L, 0x0100000800004001L, 0x0100000800004080L, 0x0100000800004081L,
+ 0x0100000800200000L, 0x0100000800200001L, 0x0100000800200080L, 0x0100000800200081L,
+ 0x0100000800204000L, 0x0100000800204001L, 0x0100000800204080L, 0x0100000800204081L,
+ 0x0100000810000000L, 0x0100000810000001L, 0x0100000810000080L, 0x0100000810000081L,
+ 0x0100000810004000L, 0x0100000810004001L, 0x0100000810004080L, 0x0100000810004081L,
+ 0x0100000810200000L, 0x0100000810200001L, 0x0100000810200080L, 0x0100000810200081L,
+ 0x0100000810204000L, 0x0100000810204001L, 0x0100000810204080L, 0x0100000810204081L,
+ 0x0100040000000000L, 0x0100040000000001L, 0x0100040000000080L, 0x0100040000000081L,
+ 0x0100040000004000L, 0x0100040000004001L, 0x0100040000004080L, 0x0100040000004081L,
+ 0x0100040000200000L, 0x0100040000200001L, 0x0100040000200080L, 0x0100040000200081L,
+ 0x0100040000204000L, 0x0100040000204001L, 0x0100040000204080L, 0x0100040000204081L,
+ 0x0100040010000000L, 0x0100040010000001L, 0x0100040010000080L, 0x0100040010000081L,
+ 0x0100040010004000L, 0x0100040010004001L, 0x0100040010004080L, 0x0100040010004081L,
+ 0x0100040010200000L, 0x0100040010200001L, 0x0100040010200080L, 0x0100040010200081L,
+ 0x0100040010204000L, 0x0100040010204001L, 0x0100040010204080L, 0x0100040010204081L,
+ 0x0100040800000000L, 0x0100040800000001L, 0x0100040800000080L, 0x0100040800000081L,
+ 0x0100040800004000L, 0x0100040800004001L, 0x0100040800004080L, 0x0100040800004081L,
+ 0x0100040800200000L, 0x0100040800200001L, 0x0100040800200080L, 0x0100040800200081L,
+ 0x0100040800204000L, 0x0100040800204001L, 0x0100040800204080L, 0x0100040800204081L,
+ 0x0100040810000000L, 0x0100040810000001L, 0x0100040810000080L, 0x0100040810000081L,
+ 0x0100040810004000L, 0x0100040810004001L, 0x0100040810004080L, 0x0100040810004081L,
+ 0x0100040810200000L, 0x0100040810200001L, 0x0100040810200080L, 0x0100040810200081L,
+ 0x0100040810204000L, 0x0100040810204001L, 0x0100040810204080L, 0x0100040810204081L,
+ 0x0102000000000000L, 0x0102000000000001L, 0x0102000000000080L, 0x0102000000000081L,
+ 0x0102000000004000L, 0x0102000000004001L, 0x0102000000004080L, 0x0102000000004081L,
+ 0x0102000000200000L, 0x0102000000200001L, 0x0102000000200080L, 0x0102000000200081L,
+ 0x0102000000204000L, 0x0102000000204001L, 0x0102000000204080L, 0x0102000000204081L,
+ 0x0102000010000000L, 0x0102000010000001L, 0x0102000010000080L, 0x0102000010000081L,
+ 0x0102000010004000L, 0x0102000010004001L, 0x0102000010004080L, 0x0102000010004081L,
+ 0x0102000010200000L, 0x0102000010200001L, 0x0102000010200080L, 0x0102000010200081L,
+ 0x0102000010204000L, 0x0102000010204001L, 0x0102000010204080L, 0x0102000010204081L,
+ 0x0102000800000000L, 0x0102000800000001L, 0x0102000800000080L, 0x0102000800000081L,
+ 0x0102000800004000L, 0x0102000800004001L, 0x0102000800004080L, 0x0102000800004081L,
+ 0x0102000800200000L, 0x0102000800200001L, 0x0102000800200080L, 0x0102000800200081L,
+ 0x0102000800204000L, 0x0102000800204001L, 0x0102000800204080L, 0x0102000800204081L,
+ 0x0102000810000000L, 0x0102000810000001L, 0x0102000810000080L, 0x0102000810000081L,
+ 0x0102000810004000L, 0x0102000810004001L, 0x0102000810004080L, 0x0102000810004081L,
+ 0x0102000810200000L, 0x0102000810200001L, 0x0102000810200080L, 0x0102000810200081L,
+ 0x0102000810204000L, 0x0102000810204001L, 0x0102000810204080L, 0x0102000810204081L,
+ 0x0102040000000000L, 0x0102040000000001L, 0x0102040000000080L, 0x0102040000000081L,
+ 0x0102040000004000L, 0x0102040000004001L, 0x0102040000004080L, 0x0102040000004081L,
+ 0x0102040000200000L, 0x0102040000200001L, 0x0102040000200080L, 0x0102040000200081L,
+ 0x0102040000204000L, 0x0102040000204001L, 0x0102040000204080L, 0x0102040000204081L,
+ 0x0102040010000000L, 0x0102040010000001L, 0x0102040010000080L, 0x0102040010000081L,
+ 0x0102040010004000L, 0x0102040010004001L, 0x0102040010004080L, 0x0102040010004081L,
+ 0x0102040010200000L, 0x0102040010200001L, 0x0102040010200080L, 0x0102040010200081L,
+ 0x0102040010204000L, 0x0102040010204001L, 0x0102040010204080L, 0x0102040010204081L,
+ 0x0102040800000000L, 0x0102040800000001L, 0x0102040800000080L, 0x0102040800000081L,
+ 0x0102040800004000L, 0x0102040800004001L, 0x0102040800004080L, 0x0102040800004081L,
+ 0x0102040800200000L, 0x0102040800200001L, 0x0102040800200080L, 0x0102040800200081L,
+ 0x0102040800204000L, 0x0102040800204001L, 0x0102040800204080L, 0x0102040800204081L,
+ 0x0102040810000000L, 0x0102040810000001L, 0x0102040810000080L, 0x0102040810000081L,
+ 0x0102040810004000L, 0x0102040810004001L, 0x0102040810004080L, 0x0102040810004081L,
+ 0x0102040810200000L, 0x0102040810200001L, 0x0102040810200080L, 0x0102040810200081L,
+ 0x0102040810204000L, 0x0102040810204001L, 0x0102040810204080L, 0x0102040810204081L
+ };
+
+ // For toString(); must have length 64
+ private const string ZEROES = "0000000000000000000000000000000000000000000000000000000000000000";
+
+ internal static readonly byte[] BitLengths =
+ {
+ 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
+ };
+
+ // TODO make m fixed for the LongArray, and hence compute T once and for all
+
+ private long[] m_ints;
+
+ public LongArray(int intLen)
+ {
+ m_ints = new long[intLen];
+ }
+
+ public LongArray(long[] ints)
+ {
+ m_ints = ints;
+ }
+
+ public LongArray(long[] ints, int off, int len)
+ {
+ if (off == 0 && len == ints.Length)
+ {
+ m_ints = ints;
+ }
+ else
+ {
+ m_ints = new long[len];
+ Array.Copy(ints, off, m_ints, 0, len);
+ }
+ }
+
+ public LongArray(BigInteger bigInt)
+ {
+ if (bigInt == null || bigInt.SignValue < 0)
+ {
+ throw new ArgumentException("invalid F2m field value", "bigInt");
+ }
+
+ if (bigInt.SignValue == 0)
+ {
+ m_ints = new long[] { 0L };
+ return;
+ }
+
+ byte[] barr = bigInt.ToByteArray();
+ int barrLen = barr.Length;
+ int barrStart = 0;
+ if (barr[0] == 0)
+ {
+ // First byte is 0 to enforce highest (=sign) bit is zero.
+ // In this case ignore barr[0].
+ barrLen--;
+ barrStart = 1;
+ }
+ int intLen = (barrLen + 7) / 8;
+ m_ints = new long[intLen];
+
+ int iarrJ = intLen - 1;
+ int rem = barrLen % 8 + barrStart;
+ long temp = 0;
+ int barrI = barrStart;
+ if (barrStart < rem)
+ {
+ for (; barrI < rem; barrI++)
+ {
+ temp <<= 8;
+ uint barrBarrI = barr[barrI];
+ temp |= barrBarrI;
+ }
+ m_ints[iarrJ--] = temp;
+ }
+
+ for (; iarrJ >= 0; iarrJ--)
+ {
+ temp = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ temp <<= 8;
+ uint barrBarrI = barr[barrI++];
+ temp |= barrBarrI;
+ }
+ m_ints[iarrJ] = temp;
+ }
+ }
+
+ public bool IsOne()
+ {
+ long[] a = m_ints;
+ if (a[0] != 1L)
+ {
+ return false;
+ }
+ for (int i = 1; i < a.Length; ++i)
+ {
+ if (a[i] != 0L)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public bool IsZero()
+ {
+ long[] a = m_ints;
+ for (int i = 0; i < a.Length; ++i)
+ {
+ if (a[i] != 0L)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public int GetUsedLength()
+ {
+ return GetUsedLengthFrom(m_ints.Length);
+ }
+
+ public int GetUsedLengthFrom(int from)
+ {
+ long[] a = m_ints;
+ from = System.Math.Min(from, a.Length);
+
+ if (from < 1)
+ {
+ return 0;
+ }
+
+ // Check if first element will act as sentinel
+ if (a[0] != 0)
+ {
+ while (a[--from] == 0)
+ {
+ }
+ return from + 1;
+ }
+
+ do
+ {
+ if (a[--from] != 0)
+ {
+ return from + 1;
+ }
+ }
+ while (from > 0);
+
+ return 0;
+ }
+
+ public int Degree()
+ {
+ int i = m_ints.Length;
+ long w;
+ do
+ {
+ if (i == 0)
+ {
+ return 0;
+ }
+ w = m_ints[--i];
+ }
+ while (w == 0);
+
+ return (i << 6) + BitLength(w);
+ }
+
+ private int DegreeFrom(int limit)
+ {
+ int i = (int)(((uint)limit + 62) >> 6);
+ long w;
+ do
+ {
+ if (i == 0)
+ {
+ return 0;
+ }
+ w = m_ints[--i];
+ }
+ while (w == 0);
+
+ return (i << 6) + BitLength(w);
+ }
+
+ // private int lowestCoefficient()
+ // {
+ // for (int i = 0; i < m_ints.Length; ++i)
+ // {
+ // long mi = m_ints[i];
+ // if (mi != 0)
+ // {
+ // int j = 0;
+ // while ((mi & 0xFFL) == 0)
+ // {
+ // j += 8;
+ // mi >>>= 8;
+ // }
+ // while ((mi & 1L) == 0)
+ // {
+ // ++j;
+ // mi >>>= 1;
+ // }
+ // return (i << 6) + j;
+ // }
+ // }
+ // return -1;
+ // }
+
+ private static int BitLength(long w)
+ {
+ int u = (int)((ulong)w >> 32), b;
+ if (u == 0)
+ {
+ u = (int)w;
+ b = 0;
+ }
+ else
+ {
+ b = 32;
+ }
+
+ int t = (int)((uint)u >> 16), k;
+ if (t == 0)
+ {
+ t = (int)((uint)u >> 8);
+ k = (t == 0) ? BitLengths[u] : 8 + BitLengths[t];
+ }
+ else
+ {
+ int v = (int)((uint)t >> 8);
+ k = (v == 0) ? 16 + BitLengths[t] : 24 + BitLengths[v];
+ }
+
+ return b + k;
+ }
+
+ private long[] ResizedInts(int newLen)
+ {
+ long[] newInts = new long[newLen];
+ Array.Copy(m_ints, 0, newInts, 0, System.Math.Min(m_ints.Length, newLen));
+ return newInts;
+ }
+
+ public BigInteger ToBigInteger()
+ {
+ int usedLen = GetUsedLength();
+ if (usedLen == 0)
+ {
+ return BigInteger.Zero;
+ }
+
+ long highestInt = m_ints[usedLen - 1];
+ byte[] temp = new byte[8];
+ int barrI = 0;
+ bool trailingZeroBytesDone = false;
+ for (int j = 7; j >= 0; j--)
+ {
+ byte thisByte = (byte)((ulong)highestInt >> (8 * j));
+ if (trailingZeroBytesDone || (thisByte != 0))
+ {
+ trailingZeroBytesDone = true;
+ temp[barrI++] = thisByte;
+ }
+ }
+
+ int barrLen = 8 * (usedLen - 1) + barrI;
+ byte[] barr = new byte[barrLen];
+ for (int j = 0; j < barrI; j++)
+ {
+ barr[j] = temp[j];
+ }
+ // Highest value int is done now
+
+ for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--)
+ {
+ long mi = m_ints[iarrJ];
+ for (int j = 7; j >= 0; j--)
+ {
+ barr[barrI++] = (byte)((ulong)mi >> (8 * j));
+ }
+ }
+ return new BigInteger(1, barr);
+ }
+
+ // private static long shiftUp(long[] x, int xOff, int count)
+ // {
+ // long prev = 0;
+ // for (int i = 0; i < count; ++i)
+ // {
+ // long next = x[xOff + i];
+ // x[xOff + i] = (next << 1) | prev;
+ // prev = next >>> 63;
+ // }
+ // return prev;
+ // }
+
+ private static long ShiftUp(long[] x, int xOff, int count, int shift)
+ {
+ int shiftInv = 64 - shift;
+ long prev = 0;
+ for (int i = 0; i < count; ++i)
+ {
+ long next = x[xOff + i];
+ x[xOff + i] = (next << shift) | prev;
+ prev = (long)((ulong)next >> shiftInv);
+ }
+ return prev;
+ }
+
+ private static long ShiftUp(long[] x, int xOff, long[] z, int zOff, int count, int shift)
+ {
+ int shiftInv = 64 - shift;
+ long prev = 0;
+ for (int i = 0; i < count; ++i)
+ {
+ long next = x[xOff + i];
+ z[zOff + i] = (next << shift) | prev;
+ prev = (long)((ulong)next >> shiftInv);
+ }
+ return prev;
+ }
+
+ public LongArray AddOne()
+ {
+ if (m_ints.Length == 0)
+ {
+ return new LongArray(new long[]{ 1L });
+ }
+
+ int resultLen = System.Math.Max(1, GetUsedLength());
+ long[] ints = ResizedInts(resultLen);
+ ints[0] ^= 1L;
+ return new LongArray(ints);
+ }
+
+ // private void addShiftedByBits(LongArray other, int bits)
+ // {
+ // int words = bits >>> 6;
+ // int shift = bits & 0x3F;
+ //
+ // if (shift == 0)
+ // {
+ // addShiftedByWords(other, words);
+ // return;
+ // }
+ //
+ // int otherUsedLen = other.GetUsedLength();
+ // if (otherUsedLen == 0)
+ // {
+ // return;
+ // }
+ //
+ // int minLen = otherUsedLen + words + 1;
+ // if (minLen > m_ints.Length)
+ // {
+ // m_ints = resizedInts(minLen);
+ // }
+ //
+ // long carry = addShiftedByBits(m_ints, words, other.m_ints, 0, otherUsedLen, shift);
+ // m_ints[otherUsedLen + words] ^= carry;
+ // }
+
+ private void AddShiftedByBitsSafe(LongArray other, int otherDegree, int bits)
+ {
+ int otherLen = (int)((uint)(otherDegree + 63) >> 6);
+
+ int words = (int)((uint)bits >> 6);
+ int shift = bits & 0x3F;
+
+ if (shift == 0)
+ {
+ Add(m_ints, words, other.m_ints, 0, otherLen);
+ return;
+ }
+
+ long carry = AddShiftedUp(m_ints, words, other.m_ints, 0, otherLen, shift);
+ if (carry != 0L)
+ {
+ m_ints[otherLen + words] ^= carry;
+ }
+ }
+
+ private static long AddShiftedUp(long[] x, int xOff, long[] y, int yOff, int count, int shift)
+ {
+ int shiftInv = 64 - shift;
+ long prev = 0;
+ for (int i = 0; i < count; ++i)
+ {
+ long next = y[yOff + i];
+ x[xOff + i] ^= (next << shift) | prev;
+ prev = (long)((ulong)next >> shiftInv);
+ }
+ return prev;
+ }
+
+ private static long AddShiftedDown(long[] x, int xOff, long[] y, int yOff, int count, int shift)
+ {
+ int shiftInv = 64 - shift;
+ long prev = 0;
+ int i = count;
+ while (--i >= 0)
+ {
+ long next = y[yOff + i];
+ x[xOff + i] ^= (long)((ulong)next >> shift) | prev;
+ prev = next << shiftInv;
+ }
+ return prev;
+ }
+
+ public void AddShiftedByWords(LongArray other, int words)
+ {
+ int otherUsedLen = other.GetUsedLength();
+ if (otherUsedLen == 0)
+ {
+ return;
+ }
+
+ int minLen = otherUsedLen + words;
+ if (minLen > m_ints.Length)
+ {
+ m_ints = ResizedInts(minLen);
+ }
+
+ Add(m_ints, words, other.m_ints, 0, otherUsedLen);
+ }
+
+ private static void Add(long[] x, int xOff, long[] y, int yOff, int count)
+ {
+ for (int i = 0; i < count; ++i)
+ {
+ x[xOff + i] ^= y[yOff + i];
+ }
+ }
+
+ private static void Add(long[] x, int xOff, long[] y, int yOff, long[] z, int zOff, int count)
+ {
+ for (int i = 0; i < count; ++i)
+ {
+ z[zOff + i] = x[xOff + i] ^ y[yOff + i];
+ }
+ }
+
+ private static void AddBoth(long[] x, int xOff, long[] y1, int y1Off, long[] y2, int y2Off, int count)
+ {
+ for (int i = 0; i < count; ++i)
+ {
+ x[xOff + i] ^= y1[y1Off + i] ^ y2[y2Off + i];
+ }
+ }
+
+ private static void Distribute(long[] x, int src, int dst1, int dst2, int count)
+ {
+ for (int i = 0; i < count; ++i)
+ {
+ long v = x[src + i];
+ x[dst1 + i] ^= v;
+ x[dst2 + i] ^= v;
+ }
+ }
+
+ public int Length
+ {
+ get { return m_ints.Length; }
+ }
+
+ private static void FlipWord(long[] buf, int off, int bit, long word)
+ {
+ int n = off + (int)((uint)bit >> 6);
+ int shift = bit & 0x3F;
+ if (shift == 0)
+ {
+ buf[n] ^= word;
+ }
+ else
+ {
+ buf[n] ^= word << shift;
+ word = (long)((ulong)word >> (64 - shift));
+ if (word != 0)
+ {
+ buf[++n] ^= word;
+ }
+ }
+ }
+
+ // private static long getWord(long[] buf, int off, int len, int bit)
+ // {
+ // int n = off + (bit >>> 6);
+ // int shift = bit & 0x3F;
+ // if (shift == 0)
+ // {
+ // return buf[n];
+ // }
+ // long result = buf[n] >>> shift;
+ // if (++n < len)
+ // {
+ // result |= buf[n] << (64 - shift);
+ // }
+ // return result;
+ // }
+
+ public bool TestBitZero()
+ {
+ return m_ints.Length > 0 && (m_ints[0] & 1L) != 0;
+ }
+
+ private static bool TestBit(long[] buf, int off, int n)
+ {
+ // theInt = n / 64
+ int theInt = (int)((uint)n >> 6);
+ // theBit = n % 64
+ int theBit = n & 0x3F;
+ long tester = 1L << theBit;
+ return (buf[off + theInt] & tester) != 0;
+ }
+
+ private static void FlipBit(long[] buf, int off, int n)
+ {
+ // theInt = n / 64
+ int theInt = (int)((uint)n >> 6);
+ // theBit = n % 64
+ int theBit = n & 0x3F;
+ long flipper = 1L << theBit;
+ buf[off + theInt] ^= flipper;
+ }
+
+ // private static void SetBit(long[] buf, int off, int n)
+ // {
+ // // theInt = n / 64
+ // int theInt = n >>> 6;
+ // // theBit = n % 64
+ // int theBit = n & 0x3F;
+ // long setter = 1L << theBit;
+ // buf[off + theInt] |= setter;
+ // }
+ //
+ // private static void ClearBit(long[] buf, int off, int n)
+ // {
+ // // theInt = n / 64
+ // int theInt = n >>> 6;
+ // // theBit = n % 64
+ // int theBit = n & 0x3F;
+ // long setter = 1L << theBit;
+ // buf[off + theInt] &= ~setter;
+ // }
+
+ private static void MultiplyWord(long a, long[] b, int bLen, long[] c, int cOff)
+ {
+ if ((a & 1L) != 0L)
+ {
+ Add(c, cOff, b, 0, bLen);
+ }
+ int k = 1;
+ while ((a = (long)((ulong)a >> 1)) != 0L)
+ {
+ if ((a & 1L) != 0L)
+ {
+ long carry = AddShiftedUp(c, cOff, b, 0, bLen, k);
+ if (carry != 0L)
+ {
+ c[cOff + bLen] ^= carry;
+ }
+ }
+ ++k;
+ }
+ }
+
+ public LongArray ModMultiplyLD(LongArray other, int m, int[] ks)
+ {
+ /*
+ * Find out the degree of each argument and handle the zero cases
+ */
+ int aDeg = Degree();
+ if (aDeg == 0)
+ {
+ return this;
+ }
+ int bDeg = other.Degree();
+ if (bDeg == 0)
+ {
+ return other;
+ }
+
+ /*
+ * Swap if necessary so that A is the smaller argument
+ */
+ LongArray A = this, B = other;
+ if (aDeg > bDeg)
+ {
+ A = other; B = this;
+ int tmp = aDeg; aDeg = bDeg; bDeg = tmp;
+ }
+
+ /*
+ * Establish the word lengths of the arguments and result
+ */
+ int aLen = (int)((uint)(aDeg + 63) >> 6);
+ int bLen = (int)((uint)(bDeg + 63) >> 6);
+ int cLen = (int)((uint)(aDeg + bDeg + 62) >> 6);
+
+ if (aLen == 1)
+ {
+ long a0 = A.m_ints[0];
+ if (a0 == 1L)
+ {
+ return B;
+ }
+
+ /*
+ * Fast path for small A, with performance dependent only on the number of set bits
+ */
+ long[] c0 = new long[cLen];
+ MultiplyWord(a0, B.m_ints, bLen, c0, 0);
+
+ /*
+ * Reduce the raw answer against the reduction coefficients
+ */
+ return ReduceResult(c0, 0, cLen, m, ks);
+ }
+
+ /*
+ * Determine if B will get bigger during shifting
+ */
+ int bMax = (int)((uint)(bDeg + 7 + 63) >> 6);
+
+ /*
+ * Lookup table for the offset of each B in the tables
+ */
+ int[] ti = new int[16];
+
+ /*
+ * Precompute table of all 4-bit products of B
+ */
+ long[] T0 = new long[bMax << 4];
+ int tOff = bMax;
+ ti[1] = tOff;
+ Array.Copy(B.m_ints, 0, T0, tOff, bLen);
+ for (int i = 2; i < 16; ++i)
+ {
+ ti[i] = (tOff += bMax);
+ if ((i & 1) == 0)
+ {
+ ShiftUp(T0, (int)((uint)tOff >> 1), T0, tOff, bMax, 1);
+ }
+ else
+ {
+ Add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax);
+ }
+ }
+
+ /*
+ * Second table with all 4-bit products of B shifted 4 bits
+ */
+ long[] T1 = new long[T0.Length];
+ ShiftUp(T0, 0, T1, 0, T0.Length, 4);
+ // shiftUp(T0, bMax, T1, bMax, tOff, 4);
+
+ long[] a = A.m_ints;
+ long[] c = new long[cLen];
+
+ int MASK = 0xF;
+
+ /*
+ * Lopez-Dahab algorithm
+ */
+
+ for (int k = 56; k >= 0; k -= 8)
+ {
+ for (int j = 1; j < aLen; j += 2)
+ {
+ int aVal = (int)((ulong)a[j] >> k);
+ int u = aVal & MASK;
+ int v = (int)((uint)aVal >> 4) & MASK;
+ AddBoth(c, j - 1, T0, ti[u], T1, ti[v], bMax);
+ }
+ ShiftUp(c, 0, cLen, 8);
+ }
+
+ for (int k = 56; k >= 0; k -= 8)
+ {
+ for (int j = 0; j < aLen; j += 2)
+ {
+ int aVal = (int)((ulong)a[j] >> k);
+ int u = aVal & MASK;
+ int v = (int)((uint)aVal >> 4) & MASK;
+ AddBoth(c, j, T0, ti[u], T1, ti[v], bMax);
+ }
+ if (k > 0)
+ {
+ ShiftUp(c, 0, cLen, 8);
+ }
+ }
+
+ /*
+ * Finally the raw answer is collected, reduce it against the reduction coefficients
+ */
+ return ReduceResult(c, 0, cLen, m, ks);
+ }
+
+ public LongArray ModMultiply(LongArray other, int m, int[] ks)
+ {
+ /*
+ * Find out the degree of each argument and handle the zero cases
+ */
+ int aDeg = Degree();
+ if (aDeg == 0)
+ {
+ return this;
+ }
+ int bDeg = other.Degree();
+ if (bDeg == 0)
+ {
+ return other;
+ }
+
+ /*
+ * Swap if necessary so that A is the smaller argument
+ */
+ LongArray A = this, B = other;
+ if (aDeg > bDeg)
+ {
+ A = other; B = this;
+ int tmp = aDeg; aDeg = bDeg; bDeg = tmp;
+ }
+
+ /*
+ * Establish the word lengths of the arguments and result
+ */
+ int aLen = (int)((uint)(aDeg + 63) >> 6);
+ int bLen = (int)((uint)(bDeg + 63) >> 6);
+ int cLen = (int)((uint)(aDeg + bDeg + 62) >> 6);
+
+ if (aLen == 1)
+ {
+ long a0 = A.m_ints[0];
+ if (a0 == 1L)
+ {
+ return B;
+ }
+
+ /*
+ * Fast path for small A, with performance dependent only on the number of set bits
+ */
+ long[] c0 = new long[cLen];
+ MultiplyWord(a0, B.m_ints, bLen, c0, 0);
+
+ /*
+ * Reduce the raw answer against the reduction coefficients
+ */
+ return ReduceResult(c0, 0, cLen, m, ks);
+ }
+
+ /*
+ * Determine if B will get bigger during shifting
+ */
+ int bMax = (int)((uint)(bDeg + 7 + 63) >> 6);
+
+ /*
+ * Lookup table for the offset of each B in the tables
+ */
+ int[] ti = new int[16];
+
+ /*
+ * Precompute table of all 4-bit products of B
+ */
+ long[] T0 = new long[bMax << 4];
+ int tOff = bMax;
+ ti[1] = tOff;
+ Array.Copy(B.m_ints, 0, T0, tOff, bLen);
+ for (int i = 2; i < 16; ++i)
+ {
+ ti[i] = (tOff += bMax);
+ if ((i & 1) == 0)
+ {
+ ShiftUp(T0, (int)((uint)tOff >> 1), T0, tOff, bMax, 1);
+ }
+ else
+ {
+ Add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax);
+ }
+ }
+
+ /*
+ * Second table with all 4-bit products of B shifted 4 bits
+ */
+ long[] T1 = new long[T0.Length];
+ ShiftUp(T0, 0, T1, 0, T0.Length, 4);
+ // ShiftUp(T0, bMax, T1, bMax, tOff, 4);
+
+ long[] a = A.m_ints;
+ long[] c = new long[cLen << 3];
+
+ int MASK = 0xF;
+
+ /*
+ * Lopez-Dahab (Modified) algorithm
+ */
+
+ for (int aPos = 0; aPos < aLen; ++aPos)
+ {
+ long aVal = a[aPos];
+ int cOff = aPos;
+ for (;;)
+ {
+ int u = (int)aVal & MASK;
+ aVal = (long)((ulong)aVal >> 4);
+ int v = (int)aVal & MASK;
+ AddBoth(c, cOff, T0, ti[u], T1, ti[v], bMax);
+ aVal = (long)((ulong)aVal >> 4);
+ if (aVal == 0L)
+ {
+ break;
+ }
+ cOff += cLen;
+ }
+ }
+
+ {
+ int cOff = c.Length;
+ while ((cOff -= cLen) != 0)
+ {
+ AddShiftedUp(c, cOff - cLen, c, cOff, cLen, 8);
+ }
+ }
+
+ /*
+ * Finally the raw answer is collected, reduce it against the reduction coefficients
+ */
+ return ReduceResult(c, 0, cLen, m, ks);
+ }
+
+ public LongArray ModMultiplyAlt(LongArray other, int m, int[] ks)
+ {
+ /*
+ * Find out the degree of each argument and handle the zero cases
+ */
+ int aDeg = Degree();
+ if (aDeg == 0)
+ {
+ return this;
+ }
+ int bDeg = other.Degree();
+ if (bDeg == 0)
+ {
+ return other;
+ }
+
+ /*
+ * Swap if necessary so that A is the smaller argument
+ */
+ LongArray A = this, B = other;
+ if (aDeg > bDeg)
+ {
+ A = other; B = this;
+ int tmp = aDeg; aDeg = bDeg; bDeg = tmp;
+ }
+
+ /*
+ * Establish the word lengths of the arguments and result
+ */
+ int aLen = (int)((uint)(aDeg + 63) >> 6);
+ int bLen = (int)((uint)(bDeg + 63) >> 6);
+ int cLen = (int)((uint)(aDeg + bDeg + 62) >> 6);
+
+ if (aLen == 1)
+ {
+ long a0 = A.m_ints[0];
+ if (a0 == 1L)
+ {
+ return B;
+ }
+
+ /*
+ * Fast path for small A, with performance dependent only on the number of set bits
+ */
+ long[] c0 = new long[cLen];
+ MultiplyWord(a0, B.m_ints, bLen, c0, 0);
+
+ /*
+ * Reduce the raw answer against the reduction coefficients
+ */
+ return ReduceResult(c0, 0, cLen, m, ks);
+ }
+
+ // NOTE: This works, but is slower than width 4 processing
+ // if (aLen == 2)
+ // {
+ // /*
+ // * Use common-multiplicand optimization to save ~1/4 of the adds
+ // */
+ // long a1 = A.m_ints[0], a2 = A.m_ints[1];
+ // long aa = a1 & a2; a1 ^= aa; a2 ^= aa;
+ //
+ // long[] b = B.m_ints;
+ // long[] c = new long[cLen];
+ // multiplyWord(aa, b, bLen, c, 1);
+ // add(c, 0, c, 1, cLen - 1);
+ // multiplyWord(a1, b, bLen, c, 0);
+ // multiplyWord(a2, b, bLen, c, 1);
+ //
+ // /*
+ // * Reduce the raw answer against the reduction coefficients
+ // */
+ // return ReduceResult(c, 0, cLen, m, ks);
+ // }
+
+ /*
+ * Determine the parameters of the Interleaved window algorithm: the 'width' in bits to
+ * process together, the number of evaluation 'positions' implied by that width, and the
+ * 'top' position at which the regular window algorithm stops.
+ */
+ int width, positions, top, banks;
+
+ // NOTE: width 4 is the fastest over the entire range of sizes used in current crypto
+ // width = 1; positions = 64; top = 64; banks = 4;
+ // width = 2; positions = 32; top = 64; banks = 4;
+ // width = 3; positions = 21; top = 63; banks = 3;
+ width = 4; positions = 16; top = 64; banks = 8;
+ // width = 5; positions = 13; top = 65; banks = 7;
+ // width = 7; positions = 9; top = 63; banks = 9;
+ // width = 8; positions = 8; top = 64; banks = 8;
+
+ /*
+ * Determine if B will get bigger during shifting
+ */
+ int shifts = top < 64 ? positions : positions - 1;
+ int bMax = (int)((uint)(bDeg + shifts + 63) >> 6);
+
+ int bTotal = bMax * banks, stride = width * banks;
+
+ /*
+ * Create a single temporary buffer, with an offset table to find the positions of things in it
+ */
+ int[] ci = new int[1 << width];
+ int cTotal = aLen;
+ {
+ ci[0] = cTotal;
+ cTotal += bTotal;
+ ci[1] = cTotal;
+ for (int i = 2; i < ci.Length; ++i)
+ {
+ cTotal += cLen;
+ ci[i] = cTotal;
+ }
+ cTotal += cLen;
+ }
+ // NOTE: Provide a safe dump for "high zeroes" since we are adding 'bMax' and not 'bLen'
+ ++cTotal;
+
+ long[] c = new long[cTotal];
+
+ // Prepare A in Interleaved form, according to the chosen width
+ Interleave(A.m_ints, 0, c, 0, aLen, width);
+
+ // Make a working copy of B, since we will be shifting it
+ {
+ int bOff = aLen;
+ Array.Copy(B.m_ints, 0, c, bOff, bLen);
+ for (int bank = 1; bank < banks; ++bank)
+ {
+ ShiftUp(c, aLen, c, bOff += bMax, bMax, bank);
+ }
+ }
+
+ /*
+ * The main loop analyzes the Interleaved windows in A, and for each non-zero window
+ * a single word-array XOR is performed to a carefully selected slice of 'c'. The loop is
+ * breadth-first, checking the lowest window in each word, then looping again for the
+ * next higher window position.
+ */
+ int MASK = (1 << width) - 1;
+
+ int k = 0;
+ for (;;)
+ {
+ int aPos = 0;
+ do
+ {
+ long aVal = (long)((ulong)c[aPos] >> k);
+ int bank = 0, bOff = aLen;
+ for (;;)
+ {
+ int index = (int)(aVal) & MASK;
+ if (index != 0)
+ {
+ /*
+ * Add to a 'c' buffer based on the bit-pattern of 'index'. Since A is in
+ * Interleaved form, the bits represent the current B shifted by 0, 'positions',
+ * 'positions' * 2, ..., 'positions' * ('width' - 1)
+ */
+ Add(c, aPos + ci[index], c, bOff, bMax);
+ }
+ if (++bank == banks)
+ {
+ break;
+ }
+ bOff += bMax;
+ aVal = (long)((ulong)aVal >> width);
+ }
+ }
+ while (++aPos < aLen);
+
+ if ((k += stride) >= top)
+ {
+ if (k >= 64)
+ {
+ break;
+ }
+
+ /*
+ * Adjustment for window setups with top == 63, the final bit (if any) is processed
+ * as the top-bit of a window
+ */
+ k = 64 - width;
+ MASK &= MASK << (top - k);
+ }
+
+ /*
+ * After each position has been checked for all words of A, B is shifted up 1 place
+ */
+ ShiftUp(c, aLen, bTotal, banks);
+ }
+
+ int ciPos = ci.Length;
+ while (--ciPos > 1)
+ {
+ if ((ciPos & 1L) == 0L)
+ {
+ /*
+ * For even numbers, shift contents and add to the half-position
+ */
+ AddShiftedUp(c, ci[(uint)ciPos >> 1], c, ci[ciPos], cLen, positions);
+ }
+ else
+ {
+ /*
+ * For odd numbers, 'distribute' contents to the result and the next-lowest position
+ */
+ Distribute(c, ci[ciPos], ci[ciPos - 1], ci[1], cLen);
+ }
+ }
+
+ /*
+ * Finally the raw answer is collected, reduce it against the reduction coefficients
+ */
+ return ReduceResult(c, ci[1], cLen, m, ks);
+ }
+
+ public LongArray ModReduce(int m, int[] ks)
+ {
+ long[] buf = Arrays.Clone(m_ints);
+ int rLen = ReduceInPlace(buf, 0, buf.Length, m, ks);
+ return new LongArray(buf, 0, rLen);
+ }
+
+ public LongArray Multiply(LongArray other, int m, int[] ks)
+ {
+ /*
+ * Find out the degree of each argument and handle the zero cases
+ */
+ int aDeg = Degree();
+ if (aDeg == 0)
+ {
+ return this;
+ }
+ int bDeg = other.Degree();
+ if (bDeg == 0)
+ {
+ return other;
+ }
+
+ /*
+ * Swap if necessary so that A is the smaller argument
+ */
+ LongArray A = this, B = other;
+ if (aDeg > bDeg)
+ {
+ A = other; B = this;
+ int tmp = aDeg; aDeg = bDeg; bDeg = tmp;
+ }
+
+ /*
+ * Establish the word lengths of the arguments and result
+ */
+ int aLen = (int)((uint)(aDeg + 63) >> 6);
+ int bLen = (int)((uint)(bDeg + 63) >> 6);
+ int cLen = (int)((uint)(aDeg + bDeg + 62) >> 6);
+
+ if (aLen == 1)
+ {
+ long a0 = A.m_ints[0];
+ if (a0 == 1L)
+ {
+ return B;
+ }
+
+ /*
+ * Fast path for small A, with performance dependent only on the number of set bits
+ */
+ long[] c0 = new long[cLen];
+ MultiplyWord(a0, B.m_ints, bLen, c0, 0);
+
+ /*
+ * Reduce the raw answer against the reduction coefficients
+ */
+ //return ReduceResult(c0, 0, cLen, m, ks);
+ return new LongArray(c0, 0, cLen);
+ }
+
+ /*
+ * Determine if B will get bigger during shifting
+ */
+ int bMax = (int)((uint)(bDeg + 7 + 63) >> 6);
+
+ /*
+ * Lookup table for the offset of each B in the tables
+ */
+ int[] ti = new int[16];
+
+ /*
+ * Precompute table of all 4-bit products of B
+ */
+ long[] T0 = new long[bMax << 4];
+ int tOff = bMax;
+ ti[1] = tOff;
+ Array.Copy(B.m_ints, 0, T0, tOff, bLen);
+ for (int i = 2; i < 16; ++i)
+ {
+ ti[i] = (tOff += bMax);
+ if ((i & 1) == 0)
+ {
+ ShiftUp(T0, (int)((uint)tOff >> 1), T0, tOff, bMax, 1);
+ }
+ else
+ {
+ Add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax);
+ }
+ }
+
+ /*
+ * Second table with all 4-bit products of B shifted 4 bits
+ */
+ long[] T1 = new long[T0.Length];
+ ShiftUp(T0, 0, T1, 0, T0.Length, 4);
+ // ShiftUp(T0, bMax, T1, bMax, tOff, 4);
+
+ long[] a = A.m_ints;
+ long[] c = new long[cLen << 3];
+
+ int MASK = 0xF;
+
+ /*
+ * Lopez-Dahab (Modified) algorithm
+ */
+
+ for (int aPos = 0; aPos < aLen; ++aPos)
+ {
+ long aVal = a[aPos];
+ int cOff = aPos;
+ for (; ; )
+ {
+ int u = (int)aVal & MASK;
+ aVal = (long)((ulong)aVal >> 4);
+ int v = (int)aVal & MASK;
+ AddBoth(c, cOff, T0, ti[u], T1, ti[v], bMax);
+ aVal = (long)((ulong)aVal >> 4);
+ if (aVal == 0L)
+ {
+ break;
+ }
+ cOff += cLen;
+ }
+ }
+
+ {
+ int cOff = c.Length;
+ while ((cOff -= cLen) != 0)
+ {
+ AddShiftedUp(c, cOff - cLen, c, cOff, cLen, 8);
+ }
+ }
+
+ /*
+ * Finally the raw answer is collected, reduce it against the reduction coefficients
+ */
+ //return ReduceResult(c, 0, cLen, m, ks);
+ return new LongArray(c, 0, cLen);
+ }
+
+ public void Reduce(int m, int[] ks)
+ {
+ long[] buf = m_ints;
+ int rLen = ReduceInPlace(buf, 0, buf.Length, m, ks);
+ if (rLen < buf.Length)
+ {
+ m_ints = new long[rLen];
+ Array.Copy(buf, 0, m_ints, 0, rLen);
+ }
+ }
+
+ private static LongArray ReduceResult(long[] buf, int off, int len, int m, int[] ks)
+ {
+ int rLen = ReduceInPlace(buf, off, len, m, ks);
+ return new LongArray(buf, off, rLen);
+ }
+
+ // private static void deInterleave(long[] x, int xOff, long[] z, int zOff, int count, int rounds)
+ // {
+ // for (int i = 0; i < count; ++i)
+ // {
+ // z[zOff + i] = deInterleave(x[zOff + i], rounds);
+ // }
+ // }
+ //
+ // private static long deInterleave(long x, int rounds)
+ // {
+ // while (--rounds >= 0)
+ // {
+ // x = deInterleave32(x & DEInterleave_MASK) | (deInterleave32((x >>> 1) & DEInterleave_MASK) << 32);
+ // }
+ // return x;
+ // }
+ //
+ // private static long deInterleave32(long x)
+ // {
+ // x = (x | (x >>> 1)) & 0x3333333333333333L;
+ // x = (x | (x >>> 2)) & 0x0F0F0F0F0F0F0F0FL;
+ // x = (x | (x >>> 4)) & 0x00FF00FF00FF00FFL;
+ // x = (x | (x >>> 8)) & 0x0000FFFF0000FFFFL;
+ // x = (x | (x >>> 16)) & 0x00000000FFFFFFFFL;
+ // return x;
+ // }
+
+ private static int ReduceInPlace(long[] buf, int off, int len, int m, int[] ks)
+ {
+ int mLen = (m + 63) >> 6;
+ if (len < mLen)
+ {
+ return len;
+ }
+
+ int numBits = System.Math.Min(len << 6, (m << 1) - 1); // TODO use actual degree?
+ int excessBits = (len << 6) - numBits;
+ while (excessBits >= 64)
+ {
+ --len;
+ excessBits -= 64;
+ }
+
+ int kLen = ks.Length, kMax = ks[kLen - 1], kNext = kLen > 1 ? ks[kLen - 2] : 0;
+ int wordWiseLimit = System.Math.Max(m, kMax + 64);
+ int vectorableWords = (excessBits + System.Math.Min(numBits - wordWiseLimit, m - kNext)) >> 6;
+ if (vectorableWords > 1)
+ {
+ int vectorWiseWords = len - vectorableWords;
+ ReduceVectorWise(buf, off, len, vectorWiseWords, m, ks);
+ while (len > vectorWiseWords)
+ {
+ buf[off + --len] = 0L;
+ }
+ numBits = vectorWiseWords << 6;
+ }
+
+ if (numBits > wordWiseLimit)
+ {
+ ReduceWordWise(buf, off, len, wordWiseLimit, m, ks);
+ numBits = wordWiseLimit;
+ }
+
+ if (numBits > m)
+ {
+ ReduceBitWise(buf, off, numBits, m, ks);
+ }
+
+ return mLen;
+ }
+
+ private static void ReduceBitWise(long[] buf, int off, int BitLength, int m, int[] ks)
+ {
+ while (--BitLength >= m)
+ {
+ if (TestBit(buf, off, BitLength))
+ {
+ ReduceBit(buf, off, BitLength, m, ks);
+ }
+ }
+ }
+
+ private static void ReduceBit(long[] buf, int off, int bit, int m, int[] ks)
+ {
+ FlipBit(buf, off, bit);
+ int n = bit - m;
+ int j = ks.Length;
+ while (--j >= 0)
+ {
+ FlipBit(buf, off, ks[j] + n);
+ }
+ FlipBit(buf, off, n);
+ }
+
+ private static void ReduceWordWise(long[] buf, int off, int len, int toBit, int m, int[] ks)
+ {
+ int toPos = (int)((uint)toBit >> 6);
+
+ while (--len > toPos)
+ {
+ long word = buf[off + len];
+ if (word != 0)
+ {
+ buf[off + len] = 0;
+ ReduceWord(buf, off, (len << 6), word, m, ks);
+ }
+ }
+
+ {
+ int partial = toBit & 0x3F;
+ long word = (long)((ulong)buf[off + toPos] >> partial);
+ if (word != 0)
+ {
+ buf[off + toPos] ^= word << partial;
+ ReduceWord(buf, off, toBit, word, m, ks);
+ }
+ }
+ }
+
+ private static void ReduceWord(long[] buf, int off, int bit, long word, int m, int[] ks)
+ {
+ int offset = bit - m;
+ int j = ks.Length;
+ while (--j >= 0)
+ {
+ FlipWord(buf, off, offset + ks[j], word);
+ }
+ FlipWord(buf, off, offset, word);
+ }
+
+ private static void ReduceVectorWise(long[] buf, int off, int len, int words, int m, int[] ks)
+ {
+ /*
+ * NOTE: It's important we go from highest coefficient to lowest, because for the highest
+ * one (only) we allow the ranges to partially overlap, and therefore any changes must take
+ * effect for the subsequent lower coefficients.
+ */
+ int baseBit = (words << 6) - m;
+ int j = ks.Length;
+ while (--j >= 0)
+ {
+ FlipVector(buf, off, buf, off + words, len - words, baseBit + ks[j]);
+ }
+ FlipVector(buf, off, buf, off + words, len - words, baseBit);
+ }
+
+ private static void FlipVector(long[] x, int xOff, long[] y, int yOff, int yLen, int bits)
+ {
+ xOff += (int)((uint)bits >> 6);
+ bits &= 0x3F;
+
+ if (bits == 0)
+ {
+ Add(x, xOff, y, yOff, yLen);
+ }
+ else
+ {
+ long carry = AddShiftedDown(x, xOff + 1, y, yOff, yLen, 64 - bits);
+ x[xOff] ^= carry;
+ }
+ }
+
+ public LongArray ModSquare(int m, int[] ks)
+ {
+ int len = GetUsedLength();
+ if (len == 0)
+ {
+ return this;
+ }
+
+ int _2len = len << 1;
+ long[] r = new long[_2len];
+
+ int pos = 0;
+ while (pos < _2len)
+ {
+ long mi = m_ints[(uint)pos >> 1];
+ r[pos++] = Interleave2_32to64((int)mi);
+ r[pos++] = Interleave2_32to64((int)((ulong)mi >> 32));
+ }
+
+ return new LongArray(r, 0, ReduceInPlace(r, 0, r.Length, m, ks));
+ }
+
+ public LongArray ModSquareN(int n, int m, int[] ks)
+ {
+ int len = GetUsedLength();
+ if (len == 0)
+ {
+ return this;
+ }
+
+ int mLen = (m + 63) >> 6;
+ long[] r = new long[mLen << 1];
+ Array.Copy(m_ints, 0, r, 0, len);
+
+ while (--n >= 0)
+ {
+ SquareInPlace(r, len, m, ks);
+ len = ReduceInPlace(r, 0, r.Length, m, ks);
+ }
+
+ return new LongArray(r, 0, len);
+ }
+
+ public LongArray Square(int m, int[] ks)
+ {
+ int len = GetUsedLength();
+ if (len == 0)
+ {
+ return this;
+ }
+
+ int _2len = len << 1;
+ long[] r = new long[_2len];
+
+ int pos = 0;
+ while (pos < _2len)
+ {
+ long mi = m_ints[(uint)pos >> 1];
+ r[pos++] = Interleave2_32to64((int)mi);
+ r[pos++] = Interleave2_32to64((int)((ulong)mi >> 32));
+ }
+
+ return new LongArray(r, 0, r.Length);
+ }
+
+ private static void SquareInPlace(long[] x, int xLen, int m, int[] ks)
+ {
+ int pos = xLen << 1;
+ while (--xLen >= 0)
+ {
+ long xVal = x[xLen];
+ x[--pos] = Interleave2_32to64((int)((ulong)xVal >> 32));
+ x[--pos] = Interleave2_32to64((int)xVal);
+ }
+ }
+
+ private static void Interleave(long[] x, int xOff, long[] z, int zOff, int count, int width)
+ {
+ switch (width)
+ {
+ case 3:
+ Interleave3(x, xOff, z, zOff, count);
+ break;
+ case 5:
+ Interleave5(x, xOff, z, zOff, count);
+ break;
+ case 7:
+ Interleave7(x, xOff, z, zOff, count);
+ break;
+ default:
+ Interleave2_n(x, xOff, z, zOff, count, BitLengths[width] - 1);
+ break;
+ }
+ }
+
+ private static void Interleave3(long[] x, int xOff, long[] z, int zOff, int count)
+ {
+ for (int i = 0; i < count; ++i)
+ {
+ z[zOff + i] = Interleave3(x[xOff + i]);
+ }
+ }
+
+ private static long Interleave3(long x)
+ {
+ long z = x & (1L << 63);
+ return z
+ | Interleave3_21to63((int)x & 0x1FFFFF)
+ | Interleave3_21to63((int)((ulong)x >> 21) & 0x1FFFFF) << 1
+ | Interleave3_21to63((int)((ulong)x >> 42) & 0x1FFFFF) << 2;
+
+ // int zPos = 0, wPos = 0, xPos = 0;
+ // for (;;)
+ // {
+ // z |= ((x >>> xPos) & 1L) << zPos;
+ // if (++zPos == 63)
+ // {
+ // String sz2 = Long.toBinaryString(z);
+ // return z;
+ // }
+ // if ((xPos += 21) >= 63)
+ // {
+ // xPos = ++wPos;
+ // }
+ // }
+ }
+
+ private static long Interleave3_21to63(int x)
+ {
+ int r00 = INTERLEAVE3_TABLE[x & 0x7F];
+ int r21 = INTERLEAVE3_TABLE[((uint)x >> 7) & 0x7F];
+ int r42 = INTERLEAVE3_TABLE[(uint)x >> 14];
+ return (r42 & 0xFFFFFFFFL) << 42 | (r21 & 0xFFFFFFFFL) << 21 | (r00 & 0xFFFFFFFFL);
+ }
+
+ private static void Interleave5(long[] x, int xOff, long[] z, int zOff, int count)
+ {
+ for (int i = 0; i < count; ++i)
+ {
+ z[zOff + i] = Interleave5(x[xOff + i]);
+ }
+ }
+
+ private static long Interleave5(long x)
+ {
+ return Interleave3_13to65((int)x & 0x1FFF)
+ | Interleave3_13to65((int)((ulong)x >> 13) & 0x1FFF) << 1
+ | Interleave3_13to65((int)((ulong)x >> 26) & 0x1FFF) << 2
+ | Interleave3_13to65((int)((ulong)x >> 39) & 0x1FFF) << 3
+ | Interleave3_13to65((int)((ulong)x >> 52) & 0x1FFF) << 4;
+
+ // long z = 0;
+ // int zPos = 0, wPos = 0, xPos = 0;
+ // for (;;)
+ // {
+ // z |= ((x >>> xPos) & 1L) << zPos;
+ // if (++zPos == 64)
+ // {
+ // return z;
+ // }
+ // if ((xPos += 13) >= 64)
+ // {
+ // xPos = ++wPos;
+ // }
+ // }
+ }
+
+ private static long Interleave3_13to65(int x)
+ {
+ int r00 = INTERLEAVE5_TABLE[x & 0x7F];
+ int r35 = INTERLEAVE5_TABLE[(uint)x >> 7];
+ return (r35 & 0xFFFFFFFFL) << 35 | (r00 & 0xFFFFFFFFL);
+ }
+
+ private static void Interleave7(long[] x, int xOff, long[] z, int zOff, int count)
+ {
+ for (int i = 0; i < count; ++i)
+ {
+ z[zOff + i] = Interleave7(x[xOff + i]);
+ }
+ }
+
+ private static long Interleave7(long x)
+ {
+ long z = x & (1L << 63);
+ return z
+ | INTERLEAVE7_TABLE[(int)x & 0x1FF]
+ | INTERLEAVE7_TABLE[(int)((ulong)x >> 9) & 0x1FF] << 1
+ | INTERLEAVE7_TABLE[(int)((ulong)x >> 18) & 0x1FF] << 2
+ | INTERLEAVE7_TABLE[(int)((ulong)x >> 27) & 0x1FF] << 3
+ | INTERLEAVE7_TABLE[(int)((ulong)x >> 36) & 0x1FF] << 4
+ | INTERLEAVE7_TABLE[(int)((ulong)x >> 45) & 0x1FF] << 5
+ | INTERLEAVE7_TABLE[(int)((ulong)x >> 54) & 0x1FF] << 6;
+
+ // int zPos = 0, wPos = 0, xPos = 0;
+ // for (;;)
+ // {
+ // z |= ((x >>> xPos) & 1L) << zPos;
+ // if (++zPos == 63)
+ // {
+ // return z;
+ // }
+ // if ((xPos += 9) >= 63)
+ // {
+ // xPos = ++wPos;
+ // }
+ // }
+ }
+
+ private static void Interleave2_n(long[] x, int xOff, long[] z, int zOff, int count, int rounds)
+ {
+ for (int i = 0; i < count; ++i)
+ {
+ z[zOff + i] = Interleave2_n(x[xOff + i], rounds);
+ }
+ }
+
+ private static long Interleave2_n(long x, int rounds)
+ {
+ while (rounds > 1)
+ {
+ rounds -= 2;
+ x = Interleave4_16to64((int)x & 0xFFFF)
+ | Interleave4_16to64((int)((ulong)x >> 16) & 0xFFFF) << 1
+ | Interleave4_16to64((int)((ulong)x >> 32) & 0xFFFF) << 2
+ | Interleave4_16to64((int)((ulong)x >> 48) & 0xFFFF) << 3;
+ }
+ if (rounds > 0)
+ {
+ x = Interleave2_32to64((int)x) | Interleave2_32to64((int)((ulong)x >> 32)) << 1;
+ }
+ return x;
+ }
+
+ private static long Interleave4_16to64(int x)
+ {
+ int r00 = INTERLEAVE4_TABLE[x & 0xFF];
+ int r32 = INTERLEAVE4_TABLE[(uint)x >> 8];
+ return (r32 & 0xFFFFFFFFL) << 32 | (r00 & 0xFFFFFFFFL);
+ }
+
+ private static long Interleave2_32to64(int x)
+ {
+ int r00 = INTERLEAVE2_TABLE[x & 0xFF] | INTERLEAVE2_TABLE[((uint)x >> 8) & 0xFF] << 16;
+ int r32 = INTERLEAVE2_TABLE[((uint)x >> 16) & 0xFF] | INTERLEAVE2_TABLE[(uint)x >> 24] << 16;
+ return (r32 & 0xFFFFFFFFL) << 32 | (r00 & 0xFFFFFFFFL);
+ }
+
+ // private static LongArray ExpItohTsujii2(LongArray B, int n, int m, int[] ks)
+ // {
+ // LongArray t1 = B, t3 = new LongArray(new long[]{ 1L });
+ // int scale = 1;
+ //
+ // int numTerms = n;
+ // while (numTerms > 1)
+ // {
+ // if ((numTerms & 1) != 0)
+ // {
+ // t3 = t3.ModMultiply(t1, m, ks);
+ // t1 = t1.modSquareN(scale, m, ks);
+ // }
+ //
+ // LongArray t2 = t1.modSquareN(scale, m, ks);
+ // t1 = t1.ModMultiply(t2, m, ks);
+ // numTerms >>>= 1; scale <<= 1;
+ // }
+ //
+ // return t3.ModMultiply(t1, m, ks);
+ // }
+ //
+ // private static LongArray ExpItohTsujii23(LongArray B, int n, int m, int[] ks)
+ // {
+ // LongArray t1 = B, t3 = new LongArray(new long[]{ 1L });
+ // int scale = 1;
+ //
+ // int numTerms = n;
+ // while (numTerms > 1)
+ // {
+ // bool m03 = numTerms % 3 == 0;
+ // bool m14 = !m03 && (numTerms & 1) != 0;
+ //
+ // if (m14)
+ // {
+ // t3 = t3.ModMultiply(t1, m, ks);
+ // t1 = t1.modSquareN(scale, m, ks);
+ // }
+ //
+ // LongArray t2 = t1.modSquareN(scale, m, ks);
+ // t1 = t1.ModMultiply(t2, m, ks);
+ //
+ // if (m03)
+ // {
+ // t2 = t2.modSquareN(scale, m, ks);
+ // t1 = t1.ModMultiply(t2, m, ks);
+ // numTerms /= 3; scale *= 3;
+ // }
+ // else
+ // {
+ // numTerms >>>= 1; scale <<= 1;
+ // }
+ // }
+ //
+ // return t3.ModMultiply(t1, m, ks);
+ // }
+ //
+ // private static LongArray ExpItohTsujii235(LongArray B, int n, int m, int[] ks)
+ // {
+ // LongArray t1 = B, t4 = new LongArray(new long[]{ 1L });
+ // int scale = 1;
+ //
+ // int numTerms = n;
+ // while (numTerms > 1)
+ // {
+ // if (numTerms % 5 == 0)
+ // {
+ //// t1 = ExpItohTsujii23(t1, 5, m, ks);
+ //
+ // LongArray t3 = t1;
+ // t1 = t1.modSquareN(scale, m, ks);
+ //
+ // LongArray t2 = t1.modSquareN(scale, m, ks);
+ // t1 = t1.ModMultiply(t2, m, ks);
+ // t2 = t1.modSquareN(scale << 1, m, ks);
+ // t1 = t1.ModMultiply(t2, m, ks);
+ //
+ // t1 = t1.ModMultiply(t3, m, ks);
+ //
+ // numTerms /= 5; scale *= 5;
+ // continue;
+ // }
+ //
+ // bool m03 = numTerms % 3 == 0;
+ // bool m14 = !m03 && (numTerms & 1) != 0;
+ //
+ // if (m14)
+ // {
+ // t4 = t4.ModMultiply(t1, m, ks);
+ // t1 = t1.modSquareN(scale, m, ks);
+ // }
+ //
+ // LongArray t2 = t1.modSquareN(scale, m, ks);
+ // t1 = t1.ModMultiply(t2, m, ks);
+ //
+ // if (m03)
+ // {
+ // t2 = t2.modSquareN(scale, m, ks);
+ // t1 = t1.ModMultiply(t2, m, ks);
+ // numTerms /= 3; scale *= 3;
+ // }
+ // else
+ // {
+ // numTerms >>>= 1; scale <<= 1;
+ // }
+ // }
+ //
+ // return t4.ModMultiply(t1, m, ks);
+ // }
+
+ public LongArray ModInverse(int m, int[] ks)
+ {
+ /*
+ * Fermat's Little Theorem
+ */
+ // LongArray A = this;
+ // LongArray B = A.modSquare(m, ks);
+ // LongArray R0 = B, R1 = B;
+ // for (int i = 2; i < m; ++i)
+ // {
+ // R1 = R1.modSquare(m, ks);
+ // R0 = R0.ModMultiply(R1, m, ks);
+ // }
+ //
+ // return R0;
+
+ /*
+ * Itoh-Tsujii
+ */
+ // LongArray B = modSquare(m, ks);
+ // switch (m)
+ // {
+ // case 409:
+ // return ExpItohTsujii23(B, m - 1, m, ks);
+ // case 571:
+ // return ExpItohTsujii235(B, m - 1, m, ks);
+ // case 163:
+ // case 233:
+ // case 283:
+ // default:
+ // return ExpItohTsujii2(B, m - 1, m, ks);
+ // }
+
+ /*
+ * Inversion in F2m using the extended Euclidean algorithm
+ *
+ * Input: A nonzero polynomial a(z) of degree at most m-1
+ * Output: a(z)^(-1) mod f(z)
+ */
+ int uzDegree = Degree();
+ if (uzDegree == 0)
+ {
+ throw new InvalidOperationException();
+ }
+ if (uzDegree == 1)
+ {
+ return this;
+ }
+
+ // u(z) := a(z)
+ LongArray uz = (LongArray)Copy();
+
+ int t = (m + 63) >> 6;
+
+ // v(z) := f(z)
+ LongArray vz = new LongArray(t);
+ ReduceBit(vz.m_ints, 0, m, m, ks);
+
+ // g1(z) := 1, g2(z) := 0
+ LongArray g1z = new LongArray(t);
+ g1z.m_ints[0] = 1L;
+ LongArray g2z = new LongArray(t);
+
+ int[] uvDeg = new int[]{ uzDegree, m + 1 };
+ LongArray[] uv = new LongArray[]{ uz, vz };
+
+ int[] ggDeg = new int[]{ 1, 0 };
+ LongArray[] gg = new LongArray[]{ g1z, g2z };
+
+ int b = 1;
+ int duv1 = uvDeg[b];
+ int dgg1 = ggDeg[b];
+ int j = duv1 - uvDeg[1 - b];
+
+ for (;;)
+ {
+ if (j < 0)
+ {
+ j = -j;
+ uvDeg[b] = duv1;
+ ggDeg[b] = dgg1;
+ b = 1 - b;
+ duv1 = uvDeg[b];
+ dgg1 = ggDeg[b];
+ }
+
+ uv[b].AddShiftedByBitsSafe(uv[1 - b], uvDeg[1 - b], j);
+
+ int duv2 = uv[b].DegreeFrom(duv1);
+ if (duv2 == 0)
+ {
+ return gg[1 - b];
+ }
+
+ {
+ int dgg2 = ggDeg[1 - b];
+ gg[b].AddShiftedByBitsSafe(gg[1 - b], dgg2, j);
+ dgg2 += j;
+
+ if (dgg2 > dgg1)
+ {
+ dgg1 = dgg2;
+ }
+ else if (dgg2 == dgg1)
+ {
+ dgg1 = gg[b].DegreeFrom(dgg1);
+ }
+ }
+
+ j += (duv2 - duv1);
+ duv1 = duv2;
+ }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as LongArray);
+ }
+
+ public virtual bool Equals(LongArray other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ int usedLen = GetUsedLength();
+ if (other.GetUsedLength() != usedLen)
+ {
+ return false;
+ }
+ for (int i = 0; i < usedLen; i++)
+ {
+ if (m_ints[i] != other.m_ints[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public override int GetHashCode()
+ {
+ int usedLen = GetUsedLength();
+ int hash = 1;
+ for (int i = 0; i < usedLen; i++)
+ {
+ long mi = m_ints[i];
+ hash *= 31;
+ hash ^= (int)mi;
+ hash *= 31;
+ hash ^= (int)((ulong)mi >> 32);
+ }
+ return hash;
+ }
+
+ public LongArray Copy()
+ {
+ return new LongArray(Arrays.Clone(m_ints));
+ }
+
+ public override string ToString()
+ {
+ int i = GetUsedLength();
+ if (i == 0)
+ {
+ return "0";
+ }
+
+ StringBuilder sb = new StringBuilder(Convert.ToString(m_ints[--i], 2));
+ while (--i >= 0)
+ {
+ string s = Convert.ToString(m_ints[i], 2);
+
+ // Add leading zeroes, except for highest significant word
+ int len = s.Length;
+ if (len < 64)
+ {
+ sb.Append(ZEROES.Substring(len));
+ }
+
+ sb.Append(s);
+ }
+ return sb.ToString();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/ScaleXPointMap.cs b/bc-sharp-crypto/src/math/ec/ScaleXPointMap.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f8a363b249cdedc0229b2bac18f06a8ea56bb9f8
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/ScaleXPointMap.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC
+{
+ public class ScaleXPointMap
+ : ECPointMap
+ {
+ protected readonly ECFieldElement scale;
+
+ public ScaleXPointMap(ECFieldElement scale)
+ {
+ this.scale = scale;
+ }
+
+ public virtual ECPoint Map(ECPoint p)
+ {
+ return p.ScaleX(scale);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/ScaleYPointMap.cs b/bc-sharp-crypto/src/math/ec/ScaleYPointMap.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1c4795b70c439bbc5c2a43598450703e36847b72
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/ScaleYPointMap.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC
+{
+ public class ScaleYPointMap
+ : ECPointMap
+ {
+ protected readonly ECFieldElement scale;
+
+ public ScaleYPointMap(ECFieldElement scale)
+ {
+ this.scale = scale;
+ }
+
+ public virtual ECPoint Map(ECPoint p)
+ {
+ return p.ScaleY(scale);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/abc/SimpleBigDecimal.cs b/bc-sharp-crypto/src/math/ec/abc/SimpleBigDecimal.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d5664dbfdf48130b4b66417e6434ae5ae62633b2
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/abc/SimpleBigDecimal.cs
@@ -0,0 +1,241 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Math.EC.Abc
+{
+ /**
+ * Class representing a simple version of a big decimal. A
+ * SimpleBigDecimal
is basically a
+ * {@link java.math.BigInteger BigInteger} with a few digits on the right of
+ * the decimal point. The number of (binary) digits on the right of the decimal
+ * point is called the scale
of the SimpleBigDecimal
.
+ * Unlike in {@link java.math.BigDecimal BigDecimal}, the scale is not adjusted
+ * automatically, but must be set manually. All SimpleBigDecimal
s
+ * taking part in the same arithmetic operation must have equal scale. The
+ * result of a multiplication of two SimpleBigDecimal
s returns a
+ * SimpleBigDecimal
with double scale.
+ */
+ internal class SimpleBigDecimal
+ // : Number
+ {
+ // private static final long serialVersionUID = 1L;
+
+ private readonly BigInteger bigInt;
+ private readonly int scale;
+
+ /**
+ * Returns a SimpleBigDecimal
representing the same numerical
+ * value as value
.
+ * @param value The value of the SimpleBigDecimal
to be
+ * created.
+ * @param scale The scale of the SimpleBigDecimal
to be
+ * created.
+ * @return The such created SimpleBigDecimal
.
+ */
+ public static SimpleBigDecimal GetInstance(BigInteger val, int scale)
+ {
+ return new SimpleBigDecimal(val.ShiftLeft(scale), scale);
+ }
+
+ /**
+ * Constructor for SimpleBigDecimal
. The value of the
+ * constructed SimpleBigDecimal
Equals bigInt /
+ * 2scale
.
+ * @param bigInt The bigInt
value parameter.
+ * @param scale The scale of the constructed SimpleBigDecimal
.
+ */
+ public SimpleBigDecimal(BigInteger bigInt, int scale)
+ {
+ if (scale < 0)
+ throw new ArgumentException("scale may not be negative");
+
+ this.bigInt = bigInt;
+ this.scale = scale;
+ }
+
+ private SimpleBigDecimal(SimpleBigDecimal limBigDec)
+ {
+ bigInt = limBigDec.bigInt;
+ scale = limBigDec.scale;
+ }
+
+ private void CheckScale(SimpleBigDecimal b)
+ {
+ if (scale != b.scale)
+ throw new ArgumentException("Only SimpleBigDecimal of same scale allowed in arithmetic operations");
+ }
+
+ public SimpleBigDecimal AdjustScale(int newScale)
+ {
+ if (newScale < 0)
+ throw new ArgumentException("scale may not be negative");
+
+ if (newScale == scale)
+ return this;
+
+ return new SimpleBigDecimal(bigInt.ShiftLeft(newScale - scale), newScale);
+ }
+
+ public SimpleBigDecimal Add(SimpleBigDecimal b)
+ {
+ CheckScale(b);
+ return new SimpleBigDecimal(bigInt.Add(b.bigInt), scale);
+ }
+
+ public SimpleBigDecimal Add(BigInteger b)
+ {
+ return new SimpleBigDecimal(bigInt.Add(b.ShiftLeft(scale)), scale);
+ }
+
+ public SimpleBigDecimal Negate()
+ {
+ return new SimpleBigDecimal(bigInt.Negate(), scale);
+ }
+
+ public SimpleBigDecimal Subtract(SimpleBigDecimal b)
+ {
+ return Add(b.Negate());
+ }
+
+ public SimpleBigDecimal Subtract(BigInteger b)
+ {
+ return new SimpleBigDecimal(bigInt.Subtract(b.ShiftLeft(scale)), scale);
+ }
+
+ public SimpleBigDecimal Multiply(SimpleBigDecimal b)
+ {
+ CheckScale(b);
+ return new SimpleBigDecimal(bigInt.Multiply(b.bigInt), scale + scale);
+ }
+
+ public SimpleBigDecimal Multiply(BigInteger b)
+ {
+ return new SimpleBigDecimal(bigInt.Multiply(b), scale);
+ }
+
+ public SimpleBigDecimal Divide(SimpleBigDecimal b)
+ {
+ CheckScale(b);
+ BigInteger dividend = bigInt.ShiftLeft(scale);
+ return new SimpleBigDecimal(dividend.Divide(b.bigInt), scale);
+ }
+
+ public SimpleBigDecimal Divide(BigInteger b)
+ {
+ return new SimpleBigDecimal(bigInt.Divide(b), scale);
+ }
+
+ public SimpleBigDecimal ShiftLeft(int n)
+ {
+ return new SimpleBigDecimal(bigInt.ShiftLeft(n), scale);
+ }
+
+ public int CompareTo(SimpleBigDecimal val)
+ {
+ CheckScale(val);
+ return bigInt.CompareTo(val.bigInt);
+ }
+
+ public int CompareTo(BigInteger val)
+ {
+ return bigInt.CompareTo(val.ShiftLeft(scale));
+ }
+
+ public BigInteger Floor()
+ {
+ return bigInt.ShiftRight(scale);
+ }
+
+ public BigInteger Round()
+ {
+ SimpleBigDecimal oneHalf = new SimpleBigDecimal(BigInteger.One, 1);
+ return Add(oneHalf.AdjustScale(scale)).Floor();
+ }
+
+ public int IntValue
+ {
+ get { return Floor().IntValue; }
+ }
+
+ public long LongValue
+ {
+ get { return Floor().LongValue; }
+ }
+
+// public double doubleValue()
+// {
+// return new Double(ToString()).doubleValue();
+// }
+//
+// public float floatValue()
+// {
+// return new Float(ToString()).floatValue();
+// }
+
+ public int Scale
+ {
+ get { return scale; }
+ }
+
+ public override string ToString()
+ {
+ if (scale == 0)
+ return bigInt.ToString();
+
+ BigInteger floorBigInt = Floor();
+
+ BigInteger fract = bigInt.Subtract(floorBigInt.ShiftLeft(scale));
+ if (bigInt.SignValue < 0)
+ {
+ fract = BigInteger.One.ShiftLeft(scale).Subtract(fract);
+ }
+
+ if ((floorBigInt.SignValue == -1) && (!(fract.Equals(BigInteger.Zero))))
+ {
+ floorBigInt = floorBigInt.Add(BigInteger.One);
+ }
+ string leftOfPoint = floorBigInt.ToString();
+
+ char[] fractCharArr = new char[scale];
+ string fractStr = fract.ToString(2);
+ int fractLen = fractStr.Length;
+ int zeroes = scale - fractLen;
+ for (int i = 0; i < zeroes; i++)
+ {
+ fractCharArr[i] = '0';
+ }
+ for (int j = 0; j < fractLen; j++)
+ {
+ fractCharArr[zeroes + j] = fractStr[j];
+ }
+ string rightOfPoint = new string(fractCharArr);
+
+ StringBuilder sb = new StringBuilder(leftOfPoint);
+ sb.Append(".");
+ sb.Append(rightOfPoint);
+
+ return sb.ToString();
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (this == obj)
+ return true;
+
+ SimpleBigDecimal other = obj as SimpleBigDecimal;
+
+ if (other == null)
+ return false;
+
+ return bigInt.Equals(other.bigInt)
+ && scale == other.scale;
+ }
+
+ public override int GetHashCode()
+ {
+ return bigInt.GetHashCode() ^ scale;
+ }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/abc/Tnaf.cs b/bc-sharp-crypto/src/math/ec/abc/Tnaf.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b6e792aa4c4ae58dcfc804edbb9e3fa8e0f4048f
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/abc/Tnaf.cs
@@ -0,0 +1,845 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Abc
+{
+ /**
+ * Class holding methods for point multiplication based on the window
+ * τ-adic nonadjacent form (WTNAF). The algorithms are based on the
+ * paper "Improved Algorithms for Arithmetic on Anomalous Binary Curves"
+ * by Jerome A. Solinas. The paper first appeared in the Proceedings of
+ * Crypto 1997.
+ */
+ internal class Tnaf
+ {
+ private static readonly BigInteger MinusOne = BigInteger.One.Negate();
+ private static readonly BigInteger MinusTwo = BigInteger.Two.Negate();
+ private static readonly BigInteger MinusThree = BigInteger.Three.Negate();
+ private static readonly BigInteger Four = BigInteger.ValueOf(4);
+
+ /**
+ * The window width of WTNAF. The standard value of 4 is slightly less
+ * than optimal for running time, but keeps space requirements for
+ * precomputation low. For typical curves, a value of 5 or 6 results in
+ * a better running time. When changing this value, the
+ * αu
's must be computed differently, see
+ * e.g. "Guide to Elliptic Curve Cryptography", Darrel Hankerson,
+ * Alfred Menezes, Scott Vanstone, Springer-Verlag New York Inc., 2004,
+ * p. 121-122
+ */
+ public const sbyte Width = 4;
+
+ /**
+ * 24
+ */
+ public const sbyte Pow2Width = 16;
+
+ /**
+ * The αu
's for a=0
as an array
+ * of ZTauElement
s.
+ */
+ public static readonly ZTauElement[] Alpha0 =
+ {
+ null,
+ new ZTauElement(BigInteger.One, BigInteger.Zero), null,
+ new ZTauElement(MinusThree, MinusOne), null,
+ new ZTauElement(MinusOne, MinusOne), null,
+ new ZTauElement(BigInteger.One, MinusOne), null
+ };
+
+ /**
+ * The αu
's for a=0
as an array
+ * of TNAFs.
+ */
+ public static readonly sbyte[][] Alpha0Tnaf =
+ {
+ null, new sbyte[]{1}, null, new sbyte[]{-1, 0, 1}, null, new sbyte[]{1, 0, 1}, null, new sbyte[]{-1, 0, 0, 1}
+ };
+
+ /**
+ * The αu
's for a=1
as an array
+ * of ZTauElement
s.
+ */
+ public static readonly ZTauElement[] Alpha1 =
+ {
+ null,
+ new ZTauElement(BigInteger.One, BigInteger.Zero), null,
+ new ZTauElement(MinusThree, BigInteger.One), null,
+ new ZTauElement(MinusOne, BigInteger.One), null,
+ new ZTauElement(BigInteger.One, BigInteger.One), null
+ };
+
+ /**
+ * The αu
's for a=1
as an array
+ * of TNAFs.
+ */
+ public static readonly sbyte[][] Alpha1Tnaf =
+ {
+ null, new sbyte[]{1}, null, new sbyte[]{-1, 0, 1}, null, new sbyte[]{1, 0, 1}, null, new sbyte[]{-1, 0, 0, -1}
+ };
+
+ /**
+ * Computes the norm of an element λ
of
+ * Z [τ]
.
+ * @param mu The parameter μ
of the elliptic curve.
+ * @param lambda The element λ
of
+ * Z [τ]
.
+ * @return The norm of λ
.
+ */
+ public static BigInteger Norm(sbyte mu, ZTauElement lambda)
+ {
+ BigInteger norm;
+
+ // s1 = u^2
+ BigInteger s1 = lambda.u.Multiply(lambda.u);
+
+ // s2 = u * v
+ BigInteger s2 = lambda.u.Multiply(lambda.v);
+
+ // s3 = 2 * v^2
+ BigInteger s3 = lambda.v.Multiply(lambda.v).ShiftLeft(1);
+
+ if (mu == 1)
+ {
+ norm = s1.Add(s2).Add(s3);
+ }
+ else if (mu == -1)
+ {
+ norm = s1.Subtract(s2).Add(s3);
+ }
+ else
+ {
+ throw new ArgumentException("mu must be 1 or -1");
+ }
+
+ return norm;
+ }
+
+ /**
+ * Computes the norm of an element λ
of
+ * R [τ]
, where λ = u + vτ
+ * and u
and u
are real numbers (elements of
+ * R
).
+ * @param mu The parameter μ
of the elliptic curve.
+ * @param u The real part of the element λ
of
+ * R [τ]
.
+ * @param v The τ
-adic part of the element
+ * λ
of R [τ]
.
+ * @return The norm of λ
.
+ */
+ public static SimpleBigDecimal Norm(sbyte mu, SimpleBigDecimal u, SimpleBigDecimal v)
+ {
+ SimpleBigDecimal norm;
+
+ // s1 = u^2
+ SimpleBigDecimal s1 = u.Multiply(u);
+
+ // s2 = u * v
+ SimpleBigDecimal s2 = u.Multiply(v);
+
+ // s3 = 2 * v^2
+ SimpleBigDecimal s3 = v.Multiply(v).ShiftLeft(1);
+
+ if (mu == 1)
+ {
+ norm = s1.Add(s2).Add(s3);
+ }
+ else if (mu == -1)
+ {
+ norm = s1.Subtract(s2).Add(s3);
+ }
+ else
+ {
+ throw new ArgumentException("mu must be 1 or -1");
+ }
+
+ return norm;
+ }
+
+ /**
+ * Rounds an element λ
of R [τ]
+ * to an element of Z [τ]
, such that their difference
+ * has minimal norm. λ
is given as
+ * λ = λ0 + λ1 τ
.
+ * @param lambda0 The component λ0
.
+ * @param lambda1 The component λ1
.
+ * @param mu The parameter μ
of the elliptic curve. Must
+ * equal 1 or -1.
+ * @return The rounded element of Z [τ]
.
+ * @throws ArgumentException if lambda0
and
+ * lambda1
do not have same scale.
+ */
+ public static ZTauElement Round(SimpleBigDecimal lambda0,
+ SimpleBigDecimal lambda1, sbyte mu)
+ {
+ int scale = lambda0.Scale;
+ if (lambda1.Scale != scale)
+ throw new ArgumentException("lambda0 and lambda1 do not have same scale");
+
+ if (!((mu == 1) || (mu == -1)))
+ throw new ArgumentException("mu must be 1 or -1");
+
+ BigInteger f0 = lambda0.Round();
+ BigInteger f1 = lambda1.Round();
+
+ SimpleBigDecimal eta0 = lambda0.Subtract(f0);
+ SimpleBigDecimal eta1 = lambda1.Subtract(f1);
+
+ // eta = 2*eta0 + mu*eta1
+ SimpleBigDecimal eta = eta0.Add(eta0);
+ if (mu == 1)
+ {
+ eta = eta.Add(eta1);
+ }
+ else
+ {
+ // mu == -1
+ eta = eta.Subtract(eta1);
+ }
+
+ // check1 = eta0 - 3*mu*eta1
+ // check2 = eta0 + 4*mu*eta1
+ SimpleBigDecimal threeEta1 = eta1.Add(eta1).Add(eta1);
+ SimpleBigDecimal fourEta1 = threeEta1.Add(eta1);
+ SimpleBigDecimal check1;
+ SimpleBigDecimal check2;
+ if (mu == 1)
+ {
+ check1 = eta0.Subtract(threeEta1);
+ check2 = eta0.Add(fourEta1);
+ }
+ else
+ {
+ // mu == -1
+ check1 = eta0.Add(threeEta1);
+ check2 = eta0.Subtract(fourEta1);
+ }
+
+ sbyte h0 = 0;
+ sbyte h1 = 0;
+
+ // if eta >= 1
+ if (eta.CompareTo(BigInteger.One) >= 0)
+ {
+ if (check1.CompareTo(MinusOne) < 0)
+ {
+ h1 = mu;
+ }
+ else
+ {
+ h0 = 1;
+ }
+ }
+ else
+ {
+ // eta < 1
+ if (check2.CompareTo(BigInteger.Two) >= 0)
+ {
+ h1 = mu;
+ }
+ }
+
+ // if eta < -1
+ if (eta.CompareTo(MinusOne) < 0)
+ {
+ if (check1.CompareTo(BigInteger.One) >= 0)
+ {
+ h1 = (sbyte)-mu;
+ }
+ else
+ {
+ h0 = -1;
+ }
+ }
+ else
+ {
+ // eta >= -1
+ if (check2.CompareTo(MinusTwo) < 0)
+ {
+ h1 = (sbyte)-mu;
+ }
+ }
+
+ BigInteger q0 = f0.Add(BigInteger.ValueOf(h0));
+ BigInteger q1 = f1.Add(BigInteger.ValueOf(h1));
+ return new ZTauElement(q0, q1);
+ }
+
+ /**
+ * Approximate division by n
. For an integer
+ * k
, the value λ = s k / n
is
+ * computed to c
bits of accuracy.
+ * @param k The parameter k
.
+ * @param s The curve parameter s0
or
+ * s1
.
+ * @param vm The Lucas Sequence element Vm
.
+ * @param a The parameter a
of the elliptic curve.
+ * @param m The bit length of the finite field
+ * F m
.
+ * @param c The number of bits of accuracy, i.e. the scale of the returned
+ * SimpleBigDecimal
.
+ * @return The value λ = s k / n
computed to
+ * c
bits of accuracy.
+ */
+ public static SimpleBigDecimal ApproximateDivisionByN(BigInteger k,
+ BigInteger s, BigInteger vm, sbyte a, int m, int c)
+ {
+ int _k = (m + 5)/2 + c;
+ BigInteger ns = k.ShiftRight(m - _k - 2 + a);
+
+ BigInteger gs = s.Multiply(ns);
+
+ BigInteger hs = gs.ShiftRight(m);
+
+ BigInteger js = vm.Multiply(hs);
+
+ BigInteger gsPlusJs = gs.Add(js);
+ BigInteger ls = gsPlusJs.ShiftRight(_k-c);
+ if (gsPlusJs.TestBit(_k-c-1))
+ {
+ // round up
+ ls = ls.Add(BigInteger.One);
+ }
+
+ return new SimpleBigDecimal(ls, c);
+ }
+
+ /**
+ * Computes the τ
-adic NAF (non-adjacent form) of an
+ * element λ
of Z [τ]
.
+ * @param mu The parameter μ
of the elliptic curve.
+ * @param lambda The element λ
of
+ * Z [τ]
.
+ * @return The τ
-adic NAF of λ
.
+ */
+ public static sbyte[] TauAdicNaf(sbyte mu, ZTauElement lambda)
+ {
+ if (!((mu == 1) || (mu == -1)))
+ throw new ArgumentException("mu must be 1 or -1");
+
+ BigInteger norm = Norm(mu, lambda);
+
+ // Ceiling of log2 of the norm
+ int log2Norm = norm.BitLength;
+
+ // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
+ int maxLength = log2Norm > 30 ? log2Norm + 4 : 34;
+
+ // The array holding the TNAF
+ sbyte[] u = new sbyte[maxLength];
+ int i = 0;
+
+ // The actual length of the TNAF
+ int length = 0;
+
+ BigInteger r0 = lambda.u;
+ BigInteger r1 = lambda.v;
+
+ while(!((r0.Equals(BigInteger.Zero)) && (r1.Equals(BigInteger.Zero))))
+ {
+ // If r0 is odd
+ if (r0.TestBit(0))
+ {
+ u[i] = (sbyte) BigInteger.Two.Subtract((r0.Subtract(r1.ShiftLeft(1))).Mod(Four)).IntValue;
+
+ // r0 = r0 - u[i]
+ if (u[i] == 1)
+ {
+ r0 = r0.ClearBit(0);
+ }
+ else
+ {
+ // u[i] == -1
+ r0 = r0.Add(BigInteger.One);
+ }
+ length = i;
+ }
+ else
+ {
+ u[i] = 0;
+ }
+
+ BigInteger t = r0;
+ BigInteger s = r0.ShiftRight(1);
+ if (mu == 1)
+ {
+ r0 = r1.Add(s);
+ }
+ else
+ {
+ // mu == -1
+ r0 = r1.Subtract(s);
+ }
+
+ r1 = t.ShiftRight(1).Negate();
+ i++;
+ }
+
+ length++;
+
+ // Reduce the TNAF array to its actual length
+ sbyte[] tnaf = new sbyte[length];
+ Array.Copy(u, 0, tnaf, 0, length);
+ return tnaf;
+ }
+
+ /**
+ * Applies the operation τ()
to an
+ * AbstractF2mPoint
.
+ * @param p The AbstractF2mPoint to which τ()
is applied.
+ * @return τ(p)
+ */
+ public static AbstractF2mPoint Tau(AbstractF2mPoint p)
+ {
+ return p.Tau();
+ }
+
+ /**
+ * Returns the parameter μ
of the elliptic curve.
+ * @param curve The elliptic curve from which to obtain μ
.
+ * The curve must be a Koblitz curve, i.e. a
Equals
+ * 0
or 1
and b
Equals
+ * 1
.
+ * @return μ
of the elliptic curve.
+ * @throws ArgumentException if the given ECCurve is not a Koblitz
+ * curve.
+ */
+ public static sbyte GetMu(AbstractF2mCurve curve)
+ {
+ BigInteger a = curve.A.ToBigInteger();
+
+ sbyte mu;
+ if (a.SignValue == 0)
+ {
+ mu = -1;
+ }
+ else if (a.Equals(BigInteger.One))
+ {
+ mu = 1;
+ }
+ else
+ {
+ throw new ArgumentException("No Koblitz curve (ABC), TNAF multiplication not possible");
+ }
+ return mu;
+ }
+
+ public static sbyte GetMu(ECFieldElement curveA)
+ {
+ return (sbyte)(curveA.IsZero ? -1 : 1);
+ }
+
+ public static sbyte GetMu(int curveA)
+ {
+ return (sbyte)(curveA == 0 ? -1 : 1);
+ }
+
+ /**
+ * Calculates the Lucas Sequence elements Uk-1
and
+ * Uk
or Vk-1
and
+ * Vk
.
+ * @param mu The parameter μ
of the elliptic curve.
+ * @param k The index of the second element of the Lucas Sequence to be
+ * returned.
+ * @param doV If set to true, computes Vk-1
and
+ * Vk
, otherwise Uk-1
and
+ * Uk
.
+ * @return An array with 2 elements, containing Uk-1
+ * and Uk
or Vk-1
+ * and Vk
.
+ */
+ public static BigInteger[] GetLucas(sbyte mu, int k, bool doV)
+ {
+ if (!(mu == 1 || mu == -1))
+ throw new ArgumentException("mu must be 1 or -1");
+
+ BigInteger u0;
+ BigInteger u1;
+ BigInteger u2;
+
+ if (doV)
+ {
+ u0 = BigInteger.Two;
+ u1 = BigInteger.ValueOf(mu);
+ }
+ else
+ {
+ u0 = BigInteger.Zero;
+ u1 = BigInteger.One;
+ }
+
+ for (int i = 1; i < k; i++)
+ {
+ // u2 = mu*u1 - 2*u0;
+ BigInteger s = null;
+ if (mu == 1)
+ {
+ s = u1;
+ }
+ else
+ {
+ // mu == -1
+ s = u1.Negate();
+ }
+
+ u2 = s.Subtract(u0.ShiftLeft(1));
+ u0 = u1;
+ u1 = u2;
+ // System.out.println(i + ": " + u2);
+ // System.out.println();
+ }
+
+ BigInteger[] retVal = {u0, u1};
+ return retVal;
+ }
+
+ /**
+ * Computes the auxiliary value tw
. If the width is
+ * 4, then for mu = 1
, tw = 6
and for
+ * mu = -1
, tw = 10
+ * @param mu The parameter μ
of the elliptic curve.
+ * @param w The window width of the WTNAF.
+ * @return the auxiliary value tw
+ */
+ public static BigInteger GetTw(sbyte mu, int w)
+ {
+ if (w == 4)
+ {
+ if (mu == 1)
+ {
+ return BigInteger.ValueOf(6);
+ }
+ else
+ {
+ // mu == -1
+ return BigInteger.ValueOf(10);
+ }
+ }
+ else
+ {
+ // For w <> 4, the values must be computed
+ BigInteger[] us = GetLucas(mu, w, false);
+ BigInteger twoToW = BigInteger.Zero.SetBit(w);
+ BigInteger u1invert = us[1].ModInverse(twoToW);
+ BigInteger tw;
+ tw = BigInteger.Two.Multiply(us[0]).Multiply(u1invert).Mod(twoToW);
+ //System.out.println("mu = " + mu);
+ //System.out.println("tw = " + tw);
+ return tw;
+ }
+ }
+
+ /**
+ * Computes the auxiliary values s0
and
+ * s1
used for partial modular reduction.
+ * @param curve The elliptic curve for which to compute
+ * s0
and s1
.
+ * @throws ArgumentException if curve
is not a
+ * Koblitz curve (Anomalous Binary Curve, ABC).
+ */
+ public static BigInteger[] GetSi(AbstractF2mCurve curve)
+ {
+ if (!curve.IsKoblitz)
+ throw new ArgumentException("si is defined for Koblitz curves only");
+
+ int m = curve.FieldSize;
+ int a = curve.A.ToBigInteger().IntValue;
+ sbyte mu = GetMu(a);
+ int shifts = GetShiftsForCofactor(curve.Cofactor);
+ int index = m + 3 - a;
+ BigInteger[] ui = GetLucas(mu, index, false);
+
+ if (mu == 1)
+ {
+ ui[0] = ui[0].Negate();
+ ui[1] = ui[1].Negate();
+ }
+
+ BigInteger dividend0 = BigInteger.One.Add(ui[1]).ShiftRight(shifts);
+ BigInteger dividend1 = BigInteger.One.Add(ui[0]).ShiftRight(shifts).Negate();
+
+ return new BigInteger[] { dividend0, dividend1 };
+ }
+
+ public static BigInteger[] GetSi(int fieldSize, int curveA, BigInteger cofactor)
+ {
+ sbyte mu = GetMu(curveA);
+ int shifts = GetShiftsForCofactor(cofactor);
+ int index = fieldSize + 3 - curveA;
+ BigInteger[] ui = GetLucas(mu, index, false);
+ if (mu == 1)
+ {
+ ui[0] = ui[0].Negate();
+ ui[1] = ui[1].Negate();
+ }
+
+ BigInteger dividend0 = BigInteger.One.Add(ui[1]).ShiftRight(shifts);
+ BigInteger dividend1 = BigInteger.One.Add(ui[0]).ShiftRight(shifts).Negate();
+
+ return new BigInteger[] { dividend0, dividend1 };
+ }
+
+ protected static int GetShiftsForCofactor(BigInteger h)
+ {
+ if (h != null && h.BitLength < 4)
+ {
+ int hi = h.IntValue;
+ if (hi == 2)
+ return 1;
+ if (hi == 4)
+ return 2;
+ }
+
+ throw new ArgumentException("h (Cofactor) must be 2 or 4");
+ }
+
+ /**
+ * Partial modular reduction modulo
+ * (τm - 1)/(τ - 1)
.
+ * @param k The integer to be reduced.
+ * @param m The bitlength of the underlying finite field.
+ * @param a The parameter a
of the elliptic curve.
+ * @param s The auxiliary values s0
and
+ * s1
.
+ * @param mu The parameter μ of the elliptic curve.
+ * @param c The precision (number of bits of accuracy) of the partial
+ * modular reduction.
+ * @return ρ := k partmod (τm - 1)/(τ - 1)
+ */
+ public static ZTauElement PartModReduction(BigInteger k, int m, sbyte a,
+ BigInteger[] s, sbyte mu, sbyte c)
+ {
+ // d0 = s[0] + mu*s[1]; mu is either 1 or -1
+ BigInteger d0;
+ if (mu == 1)
+ {
+ d0 = s[0].Add(s[1]);
+ }
+ else
+ {
+ d0 = s[0].Subtract(s[1]);
+ }
+
+ BigInteger[] v = GetLucas(mu, m, true);
+ BigInteger vm = v[1];
+
+ SimpleBigDecimal lambda0 = ApproximateDivisionByN(
+ k, s[0], vm, a, m, c);
+
+ SimpleBigDecimal lambda1 = ApproximateDivisionByN(
+ k, s[1], vm, a, m, c);
+
+ ZTauElement q = Round(lambda0, lambda1, mu);
+
+ // r0 = n - d0*q0 - 2*s1*q1
+ BigInteger r0 = k.Subtract(d0.Multiply(q.u)).Subtract(
+ BigInteger.ValueOf(2).Multiply(s[1]).Multiply(q.v));
+
+ // r1 = s1*q0 - s0*q1
+ BigInteger r1 = s[1].Multiply(q.u).Subtract(s[0].Multiply(q.v));
+
+ return new ZTauElement(r0, r1);
+ }
+
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint}
+ * by a BigInteger
using the reduced τ
-adic
+ * NAF (RTNAF) method.
+ * @param p The AbstractF2mPoint to Multiply.
+ * @param k The BigInteger
by which to Multiply p
.
+ * @return k * p
+ */
+ public static AbstractF2mPoint MultiplyRTnaf(AbstractF2mPoint p, BigInteger k)
+ {
+ AbstractF2mCurve curve = (AbstractF2mCurve)p.Curve;
+ int m = curve.FieldSize;
+ int a = curve.A.ToBigInteger().IntValue;
+ sbyte mu = GetMu(a);
+ BigInteger[] s = curve.GetSi();
+ ZTauElement rho = PartModReduction(k, m, (sbyte)a, s, mu, (sbyte)10);
+
+ return MultiplyTnaf(p, rho);
+ }
+
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint}
+ * by an element λ
of Z [τ]
+ * using the τ
-adic NAF (TNAF) method.
+ * @param p The AbstractF2mPoint to Multiply.
+ * @param lambda The element λ
of
+ * Z [τ]
.
+ * @return λ * p
+ */
+ public static AbstractF2mPoint MultiplyTnaf(AbstractF2mPoint p, ZTauElement lambda)
+ {
+ AbstractF2mCurve curve = (AbstractF2mCurve)p.Curve;
+ sbyte mu = GetMu(curve.A);
+ sbyte[] u = TauAdicNaf(mu, lambda);
+
+ AbstractF2mPoint q = MultiplyFromTnaf(p, u);
+
+ return q;
+ }
+
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint}
+ * by an element λ
of Z [τ]
+ * using the τ
-adic NAF (TNAF) method, given the TNAF
+ * of λ
.
+ * @param p The AbstractF2mPoint to Multiply.
+ * @param u The the TNAF of λ
..
+ * @return λ * p
+ */
+ public static AbstractF2mPoint MultiplyFromTnaf(AbstractF2mPoint p, sbyte[] u)
+ {
+ ECCurve curve = p.Curve;
+ AbstractF2mPoint q = (AbstractF2mPoint)curve.Infinity;
+ AbstractF2mPoint pNeg = (AbstractF2mPoint)p.Negate();
+ int tauCount = 0;
+ for (int i = u.Length - 1; i >= 0; i--)
+ {
+ ++tauCount;
+ sbyte ui = u[i];
+ if (ui != 0)
+ {
+ q = q.TauPow(tauCount);
+ tauCount = 0;
+
+ ECPoint x = ui > 0 ? p : pNeg;
+ q = (AbstractF2mPoint)q.Add(x);
+ }
+ }
+ if (tauCount > 0)
+ {
+ q = q.TauPow(tauCount);
+ }
+ return q;
+ }
+
+ /**
+ * Computes the [τ]
-adic window NAF of an element
+ * λ
of Z [τ]
.
+ * @param mu The parameter μ of the elliptic curve.
+ * @param lambda The element λ
of
+ * Z [τ]
of which to compute the
+ * [τ]
-adic NAF.
+ * @param width The window width of the resulting WNAF.
+ * @param pow2w 2width .
+ * @param tw The auxiliary value tw
.
+ * @param alpha The αu
's for the window width.
+ * @return The [τ]
-adic window NAF of
+ * λ
.
+ */
+ public static sbyte[] TauAdicWNaf(sbyte mu, ZTauElement lambda,
+ sbyte width, BigInteger pow2w, BigInteger tw, ZTauElement[] alpha)
+ {
+ if (!((mu == 1) || (mu == -1)))
+ throw new ArgumentException("mu must be 1 or -1");
+
+ BigInteger norm = Norm(mu, lambda);
+
+ // Ceiling of log2 of the norm
+ int log2Norm = norm.BitLength;
+
+ // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
+ int maxLength = log2Norm > 30 ? log2Norm + 4 + width : 34 + width;
+
+ // The array holding the TNAF
+ sbyte[] u = new sbyte[maxLength];
+
+ // 2^(width - 1)
+ BigInteger pow2wMin1 = pow2w.ShiftRight(1);
+
+ // Split lambda into two BigIntegers to simplify calculations
+ BigInteger r0 = lambda.u;
+ BigInteger r1 = lambda.v;
+ int i = 0;
+
+ // while lambda <> (0, 0)
+ while (!((r0.Equals(BigInteger.Zero))&&(r1.Equals(BigInteger.Zero))))
+ {
+ // if r0 is odd
+ if (r0.TestBit(0))
+ {
+ // uUnMod = r0 + r1*tw Mod 2^width
+ BigInteger uUnMod
+ = r0.Add(r1.Multiply(tw)).Mod(pow2w);
+
+ sbyte uLocal;
+ // if uUnMod >= 2^(width - 1)
+ if (uUnMod.CompareTo(pow2wMin1) >= 0)
+ {
+ uLocal = (sbyte) uUnMod.Subtract(pow2w).IntValue;
+ }
+ else
+ {
+ uLocal = (sbyte) uUnMod.IntValue;
+ }
+ // uLocal is now in [-2^(width-1), 2^(width-1)-1]
+
+ u[i] = uLocal;
+ bool s = true;
+ if (uLocal < 0)
+ {
+ s = false;
+ uLocal = (sbyte)-uLocal;
+ }
+ // uLocal is now >= 0
+
+ if (s)
+ {
+ r0 = r0.Subtract(alpha[uLocal].u);
+ r1 = r1.Subtract(alpha[uLocal].v);
+ }
+ else
+ {
+ r0 = r0.Add(alpha[uLocal].u);
+ r1 = r1.Add(alpha[uLocal].v);
+ }
+ }
+ else
+ {
+ u[i] = 0;
+ }
+
+ BigInteger t = r0;
+
+ if (mu == 1)
+ {
+ r0 = r1.Add(r0.ShiftRight(1));
+ }
+ else
+ {
+ // mu == -1
+ r0 = r1.Subtract(r0.ShiftRight(1));
+ }
+ r1 = t.ShiftRight(1).Negate();
+ i++;
+ }
+ return u;
+ }
+
+ /**
+ * Does the precomputation for WTNAF multiplication.
+ * @param p The ECPoint
for which to do the precomputation.
+ * @param a The parameter a
of the elliptic curve.
+ * @return The precomputation array for p
.
+ */
+ public static AbstractF2mPoint[] GetPreComp(AbstractF2mPoint p, sbyte a)
+ {
+ sbyte[][] alphaTnaf = (a == 0) ? Tnaf.Alpha0Tnaf : Tnaf.Alpha1Tnaf;
+
+ AbstractF2mPoint[] pu = new AbstractF2mPoint[(uint)(alphaTnaf.Length + 1) >> 1];
+ pu[0] = p;
+
+ uint precompLen = (uint)alphaTnaf.Length;
+ for (uint i = 3; i < precompLen; i += 2)
+ {
+ pu[i >> 1] = Tnaf.MultiplyFromTnaf(p, alphaTnaf[i]);
+ }
+
+ p.Curve.NormalizeAll(pu);
+
+ return pu;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/abc/ZTauElement.cs b/bc-sharp-crypto/src/math/ec/abc/ZTauElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4fcbf1bdf833a045d682bbd5620ca67f9ca41802
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/abc/ZTauElement.cs
@@ -0,0 +1,36 @@
+namespace Org.BouncyCastle.Math.EC.Abc
+{
+ /**
+ * Class representing an element of Z [τ]
. Let
+ * λ
be an element of Z [τ]
. Then
+ * λ
is given as λ = u + vτ
. The
+ * components u
and v
may be used directly, there
+ * are no accessor methods.
+ * Immutable class.
+ */
+ internal class ZTauElement
+ {
+ /**
+ * The "real" part of λ
.
+ */
+ public readonly BigInteger u;
+
+ /**
+ * The "τ
-adic" part of λ
.
+ */
+ public readonly BigInteger v;
+
+ /**
+ * Constructor for an element λ
of
+ * Z [τ]
.
+ * @param u The "real" part of λ
.
+ * @param v The "τ
-adic" part of
+ * λ
.
+ */
+ public ZTauElement(BigInteger u, BigInteger v)
+ {
+ this.u = u;
+ this.v = v;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/djb/Curve25519.cs b/bc-sharp-crypto/src/math/ec/custom/djb/Curve25519.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6ed7c0648573b78f681aeca83085791245ad840d
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/djb/Curve25519.cs
@@ -0,0 +1,77 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Djb
+{
+ internal class Curve25519
+ : AbstractFpCurve
+ {
+ public static readonly BigInteger q = Nat256.ToBigInteger(Curve25519Field.P);
+
+ private const int Curve25519_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
+
+ protected readonly Curve25519Point m_infinity;
+
+ public Curve25519()
+ : base(q)
+ {
+ this.m_infinity = new Curve25519Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1,
+ Hex.Decode("2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA984914A144")));
+ this.m_b = FromBigInteger(new BigInteger(1,
+ Hex.Decode("7B425ED097B425ED097B425ED097B425ED097B425ED097B4260B5E9C7710C864")));
+ this.m_order = new BigInteger(1, Hex.Decode("1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED"));
+ this.m_cofactor = BigInteger.ValueOf(8);
+ this.m_coord = Curve25519_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new Curve25519();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN_MODIFIED:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new Curve25519FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new Curve25519Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new Curve25519Point(this, x, y, zs, withCompression);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/djb/Curve25519Field.cs b/bc-sharp-crypto/src/math/ec/custom/djb/Curve25519Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..837821e1a694f51a4171bc6c9a6502326c1ebac2
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/djb/Curve25519Field.cs
@@ -0,0 +1,253 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Djb
+{
+ internal class Curve25519Field
+ {
+ // 2^255 - 2^4 - 2^1 - 1
+ internal static readonly uint[] P = new uint[]{ 0xFFFFFFED, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0x7FFFFFFF };
+ private const uint P7 = 0x7FFFFFFF;
+ private static readonly uint[] PExt = new uint[]{ 0x00000169, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFED, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0x3FFFFFFF };
+ private const uint PInv = 0x13;
+
+ public static void Add(uint[] x, uint[] y, uint[] z)
+ {
+ Nat256.Add(x, y, z);
+ if (Nat256.Gte(z, P))
+ {
+ SubPFrom(z);
+ }
+ }
+
+ public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ Nat.Add(16, xx, yy, zz);
+ if (Nat.Gte(16, zz, PExt))
+ {
+ SubPExtFrom(zz);
+ }
+ }
+
+ public static void AddOne(uint[] x, uint[] z)
+ {
+ Nat.Inc(8, x, z);
+ if (Nat256.Gte(z, P))
+ {
+ SubPFrom(z);
+ }
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ uint[] z = Nat256.FromBigInteger(x);
+ while (Nat256.Gte(z, P))
+ {
+ Nat256.SubFrom(P, z);
+ }
+ return z;
+ }
+
+ public static void Half(uint[] x, uint[] z)
+ {
+ if ((x[0] & 1) == 0)
+ {
+ Nat.ShiftDownBit(8, x, 0, z);
+ }
+ else
+ {
+ Nat256.Add(x, P, z);
+ Nat.ShiftDownBit(8, z, 0);
+ }
+ }
+
+ public static void Multiply(uint[] x, uint[] y, uint[] z)
+ {
+ uint[] tt = Nat256.CreateExt();
+ Nat256.Mul(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+ {
+ Nat256.MulAddTo(x, y, zz);
+ if (Nat.Gte(16, zz, PExt))
+ {
+ SubPExtFrom(zz);
+ }
+ }
+
+ public static void Negate(uint[] x, uint[] z)
+ {
+ if (Nat256.IsZero(x))
+ {
+ Nat256.Zero(z);
+ }
+ else
+ {
+ Nat256.Sub(P, x, z);
+ }
+ }
+
+ public static void Reduce(uint[] xx, uint[] z)
+ {
+ Debug.Assert(xx[15] >> 30 == 0);
+
+ uint xx07 = xx[7];
+ Nat.ShiftUpBit(8, xx, 8, xx07, z, 0);
+ uint c = Nat256.MulByWordAddTo(PInv, xx, z) << 1;
+ uint z7 = z[7];
+ c += (z7 >> 31) - (xx07 >> 31);
+ z7 &= P7;
+ z7 += Nat.AddWordTo(7, c * PInv, z);
+ z[7] = z7;
+ if (z7 >= P7 && Nat256.Gte(z, P))
+ {
+ SubPFrom(z);
+ }
+ }
+
+ public static void Reduce27(uint x, uint[] z)
+ {
+ Debug.Assert(x >> 26 == 0);
+
+ uint z7 = z[7];
+ uint c = (x << 1 | z7 >> 31);
+ z7 &= P7;
+ z7 += Nat.AddWordTo(7, c * PInv, z);
+ z[7] = z7;
+ if (z7 >= P7 && Nat256.Gte(z, P))
+ {
+ SubPFrom(z);
+ }
+ }
+
+ public static void Square(uint[] x, uint[] z)
+ {
+ uint[] tt = Nat256.CreateExt();
+ Nat256.Square(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareN(uint[] x, int n, uint[] z)
+ {
+ Debug.Assert(n > 0);
+
+ uint[] tt = Nat256.CreateExt();
+ Nat256.Square(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ Nat256.Square(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static void Subtract(uint[] x, uint[] y, uint[] z)
+ {
+ int c = Nat256.Sub(x, y, z);
+ if (c != 0)
+ {
+ AddPTo(z);
+ }
+ }
+
+ public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ int c = Nat.Sub(16, xx, yy, zz);
+ if (c != 0)
+ {
+ AddPExtTo(zz);
+ }
+ }
+
+ public static void Twice(uint[] x, uint[] z)
+ {
+ Nat.ShiftUpBit(8, x, 0, z);
+ if (Nat256.Gte(z, P))
+ {
+ SubPFrom(z);
+ }
+ }
+
+ private static uint AddPTo(uint[] z)
+ {
+ long c = (long)z[0] - PInv;
+ z[0] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c = Nat.DecAt(7, z, 1);
+ }
+ c += (long)z[7] + (P7 + 1);
+ z[7] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ private static uint AddPExtTo(uint[] zz)
+ {
+ long c = (long)zz[0] + PExt[0];
+ zz[0] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c = Nat.IncAt(8, zz, 1);
+ }
+ c += (long)zz[8] - PInv;
+ zz[8] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c = Nat.DecAt(15, zz, 9);
+ }
+ c += (long)zz[15] + (PExt[15] + 1);
+ zz[15] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ private static int SubPFrom(uint[] z)
+ {
+ long c = (long)z[0] + PInv;
+ z[0] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c = Nat.IncAt(7, z, 1);
+ }
+ c += (long)z[7] - (P7 + 1);
+ z[7] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ private static int SubPExtFrom(uint[] zz)
+ {
+ long c = (long)zz[0] - PExt[0];
+ zz[0] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c = Nat.DecAt(8, zz, 1);
+ }
+ c += (long)zz[8] + PInv;
+ zz[8] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c = Nat.IncAt(15, zz, 9);
+ }
+ c += (long)zz[15] - (PExt[15] + 1);
+ zz[15] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..732e9e468970bdb597caaf1029a5b5c1365caf95
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs
@@ -0,0 +1,233 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Djb
+{
+ internal class Curve25519FieldElement
+ : ECFieldElement
+ {
+ public static readonly BigInteger Q = Curve25519.q;
+
+ // Calculated as ECConstants.TWO.modPow(Q.shiftRight(2), Q)
+ private static readonly uint[] PRECOMP_POW2 = new uint[]{ 0x4a0ea0b0, 0xc4ee1b27, 0xad2fe478, 0x2f431806,
+ 0x3dfbd7a7, 0x2b4d0099, 0x4fc1df0b, 0x2b832480 };
+
+ protected internal readonly uint[] x;
+
+ public Curve25519FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+ throw new ArgumentException("value invalid for Curve25519FieldElement", "x");
+
+ this.x = Curve25519Field.FromBigInteger(x);
+ }
+
+ public Curve25519FieldElement()
+ {
+ this.x = Nat256.Create();
+ }
+
+ protected internal Curve25519FieldElement(uint[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat256.IsZero(x); }
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat256.IsOne(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return Nat256.GetBit(x, 0) == 1;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat256.ToBigInteger(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "Curve25519Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return Q.BitLength; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ uint[] z = Nat256.Create();
+ Curve25519Field.Add(x, ((Curve25519FieldElement)b).x, z);
+ return new Curve25519FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ uint[] z = Nat256.Create();
+ Curve25519Field.AddOne(x, z);
+ return new Curve25519FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ uint[] z = Nat256.Create();
+ Curve25519Field.Subtract(x, ((Curve25519FieldElement)b).x, z);
+ return new Curve25519FieldElement(z);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ uint[] z = Nat256.Create();
+ Curve25519Field.Multiply(x, ((Curve25519FieldElement)b).x, z);
+ return new Curve25519FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ //return Multiply(b.Invert());
+ uint[] z = Nat256.Create();
+ Mod.Invert(Curve25519Field.P, ((Curve25519FieldElement)b).x, z);
+ Curve25519Field.Multiply(z, x, z);
+ return new Curve25519FieldElement(z);
+ }
+
+ public override ECFieldElement Negate()
+ {
+ uint[] z = Nat256.Create();
+ Curve25519Field.Negate(x, z);
+ return new Curve25519FieldElement(z);
+ }
+
+ public override ECFieldElement Square()
+ {
+ uint[] z = Nat256.Create();
+ Curve25519Field.Square(x, z);
+ return new Curve25519FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ //return new Curve25519FieldElement(ToBigInteger().ModInverse(Q));
+ uint[] z = Nat256.Create();
+ Mod.Invert(Curve25519Field.P, x, z);
+ return new Curve25519FieldElement(z);
+ }
+
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public override ECFieldElement Sqrt()
+ {
+ /*
+ * Q == 8m + 5, so we use Pocklington's method for this case.
+ *
+ * First, raise this element to the exponent 2^252 - 2^1 (i.e. m + 1)
+ *
+ * Breaking up the exponent's binary representation into "repunits", we get:
+ * { 251 1s } { 1 0s }
+ *
+ * Therefore we need an addition chain containing 251 (the lengths of the repunits)
+ * We use: 1, 2, 3, 4, 7, 11, 15, 30, 60, 120, 131, [251]
+ */
+
+ uint[] x1 = this.x;
+ if (Nat256.IsZero(x1) || Nat256.IsOne(x1))
+ return this;
+
+ uint[] x2 = Nat256.Create();
+ Curve25519Field.Square(x1, x2);
+ Curve25519Field.Multiply(x2, x1, x2);
+ uint[] x3 = x2;
+ Curve25519Field.Square(x2, x3);
+ Curve25519Field.Multiply(x3, x1, x3);
+ uint[] x4 = Nat256.Create();
+ Curve25519Field.Square(x3, x4);
+ Curve25519Field.Multiply(x4, x1, x4);
+ uint[] x7 = Nat256.Create();
+ Curve25519Field.SquareN(x4, 3, x7);
+ Curve25519Field.Multiply(x7, x3, x7);
+ uint[] x11 = x3;
+ Curve25519Field.SquareN(x7, 4, x11);
+ Curve25519Field.Multiply(x11, x4, x11);
+ uint[] x15 = x7;
+ Curve25519Field.SquareN(x11, 4, x15);
+ Curve25519Field.Multiply(x15, x4, x15);
+ uint[] x30 = x4;
+ Curve25519Field.SquareN(x15, 15, x30);
+ Curve25519Field.Multiply(x30, x15, x30);
+ uint[] x60 = x15;
+ Curve25519Field.SquareN(x30, 30, x60);
+ Curve25519Field.Multiply(x60, x30, x60);
+ uint[] x120 = x30;
+ Curve25519Field.SquareN(x60, 60, x120);
+ Curve25519Field.Multiply(x120, x60, x120);
+ uint[] x131 = x60;
+ Curve25519Field.SquareN(x120, 11, x131);
+ Curve25519Field.Multiply(x131, x11, x131);
+ uint[] x251 = x11;
+ Curve25519Field.SquareN(x131, 120, x251);
+ Curve25519Field.Multiply(x251, x120, x251);
+
+ uint[] t1 = x251;
+ Curve25519Field.Square(t1, t1);
+
+ uint[] t2 = x120;
+ Curve25519Field.Square(t1, t2);
+
+ if (Nat256.Eq(x1, t2))
+ {
+ return new Curve25519FieldElement(t1);
+ }
+
+ /*
+ * If the first guess is incorrect, we multiply by a precomputed power of 2 to get the second guess,
+ * which is ((4x)^(m + 1))/2 mod Q
+ */
+ Curve25519Field.Multiply(t1, PRECOMP_POW2, t1);
+
+ Curve25519Field.Square(t1, t2);
+
+ if (Nat256.Eq(x1, t2))
+ {
+ return new Curve25519FieldElement(t1);
+ }
+
+ return null;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as Curve25519FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as Curve25519FieldElement);
+ }
+
+ public virtual bool Equals(Curve25519FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat256.Eq(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 8);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/djb/Curve25519Point.cs b/bc-sharp-crypto/src/math/ec/custom/djb/Curve25519Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..eb8fc12f21431e6813082f577c4ccce54cf1d18c
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/djb/Curve25519Point.cs
@@ -0,0 +1,313 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Djb
+{
+ internal class Curve25519Point
+ : AbstractFpPoint
+ {
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve the curve to use
+ * @param x affine x co-ordinate
+ * @param y affine y co-ordinate
+ *
+ * @deprecated Use ECCurve.CreatePoint to construct points
+ */
+ public Curve25519Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve the curve to use
+ * @param x affine x co-ordinate
+ * @param y affine y co-ordinate
+ * @param withCompression if true encode with point compression
+ *
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public Curve25519Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal Curve25519Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new Curve25519Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement GetZCoord(int index)
+ {
+ if (index == 1)
+ {
+ return GetJacobianModifiedW();
+ }
+
+ return base.GetZCoord(index);
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+ if (this == b)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ Curve25519FieldElement X1 = (Curve25519FieldElement)this.RawXCoord, Y1 = (Curve25519FieldElement)this.RawYCoord,
+ Z1 = (Curve25519FieldElement)this.RawZCoords[0];
+ Curve25519FieldElement X2 = (Curve25519FieldElement)b.RawXCoord, Y2 = (Curve25519FieldElement)b.RawYCoord,
+ Z2 = (Curve25519FieldElement)b.RawZCoords[0];
+
+ uint c;
+ uint[] tt1 = Nat256.CreateExt();
+ uint[] t2 = Nat256.Create();
+ uint[] t3 = Nat256.Create();
+ uint[] t4 = Nat256.Create();
+
+ bool Z1IsOne = Z1.IsOne;
+ uint[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ Curve25519Field.Square(Z1.x, S2);
+
+ U2 = t2;
+ Curve25519Field.Multiply(S2, X2.x, U2);
+
+ Curve25519Field.Multiply(S2, Z1.x, S2);
+ Curve25519Field.Multiply(S2, Y2.x, S2);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ uint[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ Curve25519Field.Square(Z2.x, S1);
+
+ U1 = tt1;
+ Curve25519Field.Multiply(S1, X1.x, U1);
+
+ Curve25519Field.Multiply(S1, Z2.x, S1);
+ Curve25519Field.Multiply(S1, Y1.x, S1);
+ }
+
+ uint[] H = Nat256.Create();
+ Curve25519Field.Subtract(U1, U2, H);
+
+ uint[] R = t2;
+ Curve25519Field.Subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat256.IsZero(H))
+ {
+ if (Nat256.IsZero(R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ uint[] HSquared = Nat256.Create();
+ Curve25519Field.Square(H, HSquared);
+
+ uint[] G = Nat256.Create();
+ Curve25519Field.Multiply(HSquared, H, G);
+
+ uint[] V = t3;
+ Curve25519Field.Multiply(HSquared, U1, V);
+
+ Curve25519Field.Negate(G, G);
+ Nat256.Mul(S1, G, tt1);
+
+ c = Nat256.AddBothTo(V, V, G);
+ Curve25519Field.Reduce27(c, G);
+
+ Curve25519FieldElement X3 = new Curve25519FieldElement(t4);
+ Curve25519Field.Square(R, X3.x);
+ Curve25519Field.Subtract(X3.x, G, X3.x);
+
+ Curve25519FieldElement Y3 = new Curve25519FieldElement(G);
+ Curve25519Field.Subtract(V, X3.x, Y3.x);
+ Curve25519Field.MultiplyAddToExt(Y3.x, R, tt1);
+ Curve25519Field.Reduce(tt1, Y3.x);
+
+ Curve25519FieldElement Z3 = new Curve25519FieldElement(H);
+ if (!Z1IsOne)
+ {
+ Curve25519Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ Curve25519Field.Multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ uint[] Z3Squared = (Z1IsOne && Z2IsOne) ? HSquared : null;
+
+ // TODO If the result will only be used in a subsequent addition, we don't need W3
+ Curve25519FieldElement W3 = CalculateJacobianModifiedW((Curve25519FieldElement)Z3, Z3Squared);
+
+ ECFieldElement[] zs = new ECFieldElement[] { Z3, W3 };
+
+ return new Curve25519Point(curve, X3, Y3, zs, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ return TwiceJacobianModified(true);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this == b)
+ return ThreeTimes();
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return b;
+
+ return TwiceJacobianModified(false).Add(b);
+ }
+
+ public override ECPoint ThreeTimes()
+ {
+ if (this.IsInfinity || this.RawYCoord.IsZero)
+ return this;
+
+ return TwiceJacobianModified(false).Add(this);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ return new Curve25519Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+ }
+
+ protected virtual Curve25519FieldElement CalculateJacobianModifiedW(Curve25519FieldElement Z, uint[] ZSquared)
+ {
+ Curve25519FieldElement a4 = (Curve25519FieldElement)this.Curve.A;
+ if (Z.IsOne)
+ return a4;
+
+ Curve25519FieldElement W = new Curve25519FieldElement();
+ if (ZSquared == null)
+ {
+ ZSquared = W.x;
+ Curve25519Field.Square(Z.x, ZSquared);
+ }
+ Curve25519Field.Square(ZSquared, W.x);
+ Curve25519Field.Multiply(W.x, a4.x, W.x);
+ return W;
+ }
+
+ protected virtual Curve25519FieldElement GetJacobianModifiedW()
+ {
+ ECFieldElement[] ZZ = this.RawZCoords;
+ Curve25519FieldElement W = (Curve25519FieldElement)ZZ[1];
+ if (W == null)
+ {
+ // NOTE: Rarely, TwicePlus will result in the need for a lazy W1 calculation here
+ ZZ[1] = W = CalculateJacobianModifiedW((Curve25519FieldElement)ZZ[0], null);
+ }
+ return W;
+ }
+
+ protected virtual Curve25519Point TwiceJacobianModified(bool calculateW)
+ {
+ Curve25519FieldElement X1 = (Curve25519FieldElement)this.RawXCoord, Y1 = (Curve25519FieldElement)this.RawYCoord,
+ Z1 = (Curve25519FieldElement)this.RawZCoords[0], W1 = GetJacobianModifiedW();
+
+ uint c;
+
+ uint[] M = Nat256.Create();
+ Curve25519Field.Square(X1.x, M);
+ c = Nat256.AddBothTo(M, M, M);
+ c += Nat256.AddTo(W1.x, M);
+ Curve25519Field.Reduce27(c, M);
+
+ uint[] _2Y1 = Nat256.Create();
+ Curve25519Field.Twice(Y1.x, _2Y1);
+
+ uint[] _2Y1Squared = Nat256.Create();
+ Curve25519Field.Multiply(_2Y1, Y1.x, _2Y1Squared);
+
+ uint[] S = Nat256.Create();
+ Curve25519Field.Multiply(_2Y1Squared, X1.x, S);
+ Curve25519Field.Twice(S, S);
+
+ uint[] _8T = Nat256.Create();
+ Curve25519Field.Square(_2Y1Squared, _8T);
+ Curve25519Field.Twice(_8T, _8T);
+
+ Curve25519FieldElement X3 = new Curve25519FieldElement(_2Y1Squared);
+ Curve25519Field.Square(M, X3.x);
+ Curve25519Field.Subtract(X3.x, S, X3.x);
+ Curve25519Field.Subtract(X3.x, S, X3.x);
+
+ Curve25519FieldElement Y3 = new Curve25519FieldElement(S);
+ Curve25519Field.Subtract(S, X3.x, Y3.x);
+ Curve25519Field.Multiply(Y3.x, M, Y3.x);
+ Curve25519Field.Subtract(Y3.x, _8T, Y3.x);
+
+ Curve25519FieldElement Z3 = new Curve25519FieldElement(_2Y1);
+ if (!Nat256.IsOne(Z1.x))
+ {
+ Curve25519Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ Curve25519FieldElement W3 = null;
+ if (calculateW)
+ {
+ W3 = new Curve25519FieldElement(_8T);
+ Curve25519Field.Multiply(W3.x, W1.x, W3.x);
+ Curve25519Field.Twice(W3.x, W3.x);
+ }
+
+ return new Curve25519Point(this.Curve, X3, Y3, new ECFieldElement[] { Z3, W3 }, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..70b1190c9ba615dcc4974a7d3ac6849bfd9f1f8b
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs
@@ -0,0 +1,77 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.GM
+{
+ internal class SM2P256V1Curve
+ : AbstractFpCurve
+ {
+ public static readonly BigInteger q = new BigInteger(1,
+ Hex.Decode("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF"));
+
+ private const int SM2P256V1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected readonly SM2P256V1Point m_infinity;
+
+ public SM2P256V1Curve()
+ : base(q)
+ {
+ this.m_infinity = new SM2P256V1Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1,
+ Hex.Decode("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC")));
+ this.m_b = FromBigInteger(new BigInteger(1,
+ Hex.Decode("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93")));
+ this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123"));
+ this.m_cofactor = BigInteger.One;
+ this.m_coord = SM2P256V1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SM2P256V1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SM2P256V1FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SM2P256V1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SM2P256V1Point(this, x, y, zs, withCompression);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/gm/SM2P256V1Field.cs b/bc-sharp-crypto/src/math/ec/custom/gm/SM2P256V1Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b1d232347fa77194ff8b0f80c192f2c11addfbcb
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/gm/SM2P256V1Field.cs
@@ -0,0 +1,307 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.GM
+{
+ internal class SM2P256V1Field
+ {
+ // 2^256 - 2^224 - 2^96 + 2^64 - 1
+ internal static readonly uint[] P = new uint[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFE };
+ internal static readonly uint[] PExt = new uint[]{ 00000001, 0x00000000, 0xFFFFFFFE, 0x00000001, 0x00000001,
+ 0xFFFFFFFE, 0x00000000, 0x00000002, 0xFFFFFFFE, 0xFFFFFFFD, 0x00000003, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x00000000, 0xFFFFFFFE };
+ internal const uint P7 = 0xFFFFFFFE;
+ internal const uint PExt15 = 0xFFFFFFFE;
+
+ public static void Add(uint[] x, uint[] y, uint[] z)
+ {
+ uint c = Nat256.Add(x, y, z);
+ if (c != 0 || (z[7] >= P7 && Nat256.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ uint c = Nat.Add(16, xx, yy, zz);
+ if (c != 0 || (zz[15] >= PExt15 && Nat.Gte(16, zz, PExt)))
+ {
+ Nat.SubFrom(16, PExt, zz);
+ }
+ }
+
+ public static void AddOne(uint[] x, uint[] z)
+ {
+ uint c = Nat.Inc(8, x, z);
+ if (c != 0 || (z[7] >= P7 && Nat256.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ uint[] z = Nat256.FromBigInteger(x);
+ if (z[7] >= P7 && Nat256.Gte(z, P))
+ {
+ Nat256.SubFrom(P, z);
+ }
+ return z;
+ }
+
+ public static void Half(uint[] x, uint[] z)
+ {
+ if ((x[0] & 1) == 0)
+ {
+ Nat.ShiftDownBit(8, x, 0, z);
+ }
+ else
+ {
+ uint c = Nat256.Add(x, P, z);
+ Nat.ShiftDownBit(8, z, c);
+ }
+ }
+
+ public static void Multiply(uint[] x, uint[] y, uint[] z)
+ {
+ uint[] tt = Nat256.CreateExt();
+ Nat256.Mul(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+ {
+ uint c = Nat256.MulAddTo(x, y, zz);
+ if (c != 0 || (zz[15] >= PExt15 && Nat.Gte(16, zz, PExt)))
+ {
+ Nat.SubFrom(16, PExt, zz);
+ }
+ }
+
+ public static void Negate(uint[] x, uint[] z)
+ {
+ if (Nat256.IsZero(x))
+ {
+ Nat256.Zero(z);
+ }
+ else
+ {
+ Nat256.Sub(P, x, z);
+ }
+ }
+
+ public static void Reduce(uint[] xx, uint[] z)
+ {
+ long xx08 = xx[8], xx09 = xx[9], xx10 = xx[10], xx11 = xx[11];
+ long xx12 = xx[12], xx13 = xx[13], xx14 = xx[14], xx15 = xx[15];
+
+ long t0 = xx08 + xx09;
+ long t1 = xx10 + xx11;
+ long t2 = xx12 + xx15;
+ long t3 = xx13 + xx14;
+ long t4 = t3 + (xx15 << 1);
+
+ long ts = t0 + t3;
+ long tt = t1 + t2 + ts;
+
+ long cc = 0;
+ cc += (long)xx[0] + tt + xx13 + xx14 + xx15;
+ z[0] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[1] + tt - xx08 + xx14 + xx15;
+ z[1] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[2] - ts;
+ z[2] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[3] + tt - xx09 - xx10 + xx13;
+ z[3] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[4] + tt - t1 - xx08 + xx14;
+ z[4] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[5] + t4 + xx10;
+ z[5] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[6] + xx11 + xx14 + xx15;
+ z[6] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[7] + tt + t4 + xx12;
+ z[7] = (uint)cc;
+ cc >>= 32;
+
+ Debug.Assert(cc >= 0);
+
+ Reduce32((uint)cc, z);
+ }
+
+ public static void Reduce32(uint x, uint[] z)
+ {
+ long cc = 0;
+
+ if (x != 0)
+ {
+ long xx08 = x;
+
+ cc += (long)z[0] + xx08;
+ z[0] = (uint)cc;
+ cc >>= 32;
+ if (cc != 0)
+ {
+ cc += (long)z[1];
+ z[1] = (uint)cc;
+ cc >>= 32;
+ }
+ cc += (long)z[2] - xx08;
+ z[2] = (uint)cc;
+ cc >>= 32;
+ cc += (long)z[3] + xx08;
+ z[3] = (uint)cc;
+ cc >>= 32;
+ if (cc != 0)
+ {
+ cc += (long)z[4];
+ z[4] = (uint)cc;
+ cc >>= 32;
+ cc += (long)z[5];
+ z[5] = (uint)cc;
+ cc >>= 32;
+ cc += (long)z[6];
+ z[6] = (uint)cc;
+ cc >>= 32;
+ }
+ cc += (long)z[7] + xx08;
+ z[7] = (uint)cc;
+ cc >>= 32;
+
+ Debug.Assert(cc == 0 || cc == 1);
+ }
+
+ if (cc != 0 || (z[7] >= P7 && Nat256.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static void Square(uint[] x, uint[] z)
+ {
+ uint[] tt = Nat256.CreateExt();
+ Nat256.Square(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareN(uint[] x, int n, uint[] z)
+ {
+ Debug.Assert(n > 0);
+
+ uint[] tt = Nat256.CreateExt();
+ Nat256.Square(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ Nat256.Square(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static void Subtract(uint[] x, uint[] y, uint[] z)
+ {
+ int c = Nat256.Sub(x, y, z);
+ if (c != 0)
+ {
+ SubPInvFrom(z);
+ }
+ }
+
+ public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ int c = Nat.Sub(16, xx, yy, zz);
+ if (c != 0)
+ {
+ Nat.AddTo(16, PExt, zz);
+ }
+ }
+
+ public static void Twice(uint[] x, uint[] z)
+ {
+ uint c = Nat.ShiftUpBit(8, x, 0, z);
+ if (c != 0 || (z[7] >= P7 && Nat256.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ private static void AddPInvTo(uint[] z)
+ {
+ long c = (long)z[0] + 1;
+ z[0] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (long)z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ }
+ c += (long)z[2] - 1;
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)z[3] + 1;
+ z[3] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (long)z[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (long)z[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ c += (long)z[6];
+ z[6] = (uint)c;
+ c >>= 32;
+ }
+ c += (long)z[7] + 1;
+ z[7] = (uint)c;
+ //c >>= 32;
+ }
+
+ private static void SubPInvFrom(uint[] z)
+ {
+ long c = (long)z[0] - 1;
+ z[0] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (long)z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ }
+ c += (long)z[2] + 1;
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)z[3] - 1;
+ z[3] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (long)z[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (long)z[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ c += (long)z[6];
+ z[6] = (uint)c;
+ c >>= 32;
+ }
+ c += (long)z[7] - 1;
+ z[7] = (uint)c;
+ //c >>= 32;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4f6428f9ee581d66359fd65888dca44e7e1f8837
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs
@@ -0,0 +1,211 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.GM
+{
+ internal class SM2P256V1FieldElement
+ : ECFieldElement
+ {
+ public static readonly BigInteger Q = SM2P256V1Curve.q;
+
+ protected internal readonly uint[] x;
+
+ public SM2P256V1FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+ throw new ArgumentException("value invalid for SM2P256V1FieldElement", "x");
+
+ this.x = SM2P256V1Field.FromBigInteger(x);
+ }
+
+ public SM2P256V1FieldElement()
+ {
+ this.x = Nat256.Create();
+ }
+
+ protected internal SM2P256V1FieldElement(uint[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat256.IsZero(x); }
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat256.IsOne(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return Nat256.GetBit(x, 0) == 1;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat256.ToBigInteger(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SM2P256V1Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return Q.BitLength; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ uint[] z = Nat256.Create();
+ SM2P256V1Field.Add(x, ((SM2P256V1FieldElement)b).x, z);
+ return new SM2P256V1FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ uint[] z = Nat256.Create();
+ SM2P256V1Field.AddOne(x, z);
+ return new SM2P256V1FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ uint[] z = Nat256.Create();
+ SM2P256V1Field.Subtract(x, ((SM2P256V1FieldElement)b).x, z);
+ return new SM2P256V1FieldElement(z);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ uint[] z = Nat256.Create();
+ SM2P256V1Field.Multiply(x, ((SM2P256V1FieldElement)b).x, z);
+ return new SM2P256V1FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ //return Multiply(b.Invert());
+ uint[] z = Nat256.Create();
+ Mod.Invert(SM2P256V1Field.P, ((SM2P256V1FieldElement)b).x, z);
+ SM2P256V1Field.Multiply(z, x, z);
+ return new SM2P256V1FieldElement(z);
+ }
+
+ public override ECFieldElement Negate()
+ {
+ uint[] z = Nat256.Create();
+ SM2P256V1Field.Negate(x, z);
+ return new SM2P256V1FieldElement(z);
+ }
+
+ public override ECFieldElement Square()
+ {
+ uint[] z = Nat256.Create();
+ SM2P256V1Field.Square(x, z);
+ return new SM2P256V1FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ //return new SM2P256V1FieldElement(ToBigInteger().ModInverse(Q));
+ uint[] z = Nat256.Create();
+ Mod.Invert(SM2P256V1Field.P, x, z);
+ return new SM2P256V1FieldElement(z);
+ }
+
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public override ECFieldElement Sqrt()
+ {
+ /*
+ * Raise this element to the exponent 2^254 - 2^222 - 2^94 + 2^62
+ *
+ * Breaking up the exponent's binary representation into "repunits", we get:
+ * { 31 1s } { 1 0s } { 128 1s } { 31 0s } { 1 1s } { 62 0s}
+ *
+ * We use an addition chain for the beginning: [1], 2, 3, 6, 12, [24], 30, [31]
+ */
+
+ uint[] x1 = this.x;
+ if (Nat256.IsZero(x1) || Nat256.IsOne(x1))
+ {
+ return this;
+ }
+
+ uint[] x2 = Nat256.Create();
+ SM2P256V1Field.Square(x1, x2);
+ SM2P256V1Field.Multiply(x2, x1, x2);
+ uint[] x4 = Nat256.Create();
+ SM2P256V1Field.SquareN(x2, 2, x4);
+ SM2P256V1Field.Multiply(x4, x2, x4);
+ uint[] x6 = Nat256.Create();
+ SM2P256V1Field.SquareN(x4, 2, x6);
+ SM2P256V1Field.Multiply(x6, x2, x6);
+ uint[] x12 = x2;
+ SM2P256V1Field.SquareN(x6, 6, x12);
+ SM2P256V1Field.Multiply(x12, x6, x12);
+ uint[] x24 = Nat256.Create();
+ SM2P256V1Field.SquareN(x12, 12, x24);
+ SM2P256V1Field.Multiply(x24, x12, x24);
+ uint[] x30 = x12;
+ SM2P256V1Field.SquareN(x24, 6, x30);
+ SM2P256V1Field.Multiply(x30, x6, x30);
+ uint[] x31 = x6;
+ SM2P256V1Field.Square(x30, x31);
+ SM2P256V1Field.Multiply(x31, x1, x31);
+
+ uint[] t1 = x24;
+ SM2P256V1Field.SquareN(x31, 31, t1);
+
+ uint[] x62 = x30;
+ SM2P256V1Field.Multiply(t1, x31, x62);
+
+ SM2P256V1Field.SquareN(t1, 32, t1);
+ SM2P256V1Field.Multiply(t1, x62, t1);
+ SM2P256V1Field.SquareN(t1, 62, t1);
+ SM2P256V1Field.Multiply(t1, x62, t1);
+ SM2P256V1Field.SquareN(t1, 4, t1);
+ SM2P256V1Field.Multiply(t1, x4, t1);
+ SM2P256V1Field.SquareN(t1, 32, t1);
+ SM2P256V1Field.Multiply(t1, x1, t1);
+ SM2P256V1Field.SquareN(t1, 62, t1);
+
+ uint[] t2 = x4;
+ SM2P256V1Field.Square(t1, t2);
+
+ return Nat256.Eq(x1, t2) ? new SM2P256V1FieldElement(t1) : null;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SM2P256V1FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SM2P256V1FieldElement);
+ }
+
+ public virtual bool Equals(SM2P256V1FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat256.Eq(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 8);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/gm/SM2P256V1Point.cs b/bc-sharp-crypto/src/math/ec/custom/gm/SM2P256V1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..916c90633a9c6b04c7b36134a8b70199cb524051
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/gm/SM2P256V1Point.cs
@@ -0,0 +1,279 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.GM
+{
+ internal class SM2P256V1Point
+ : AbstractFpPoint
+ {
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ *
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SM2P256V1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ * @param withCompression
+ * if true encode with point compression
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(bool)}
+ */
+ public SM2P256V1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SM2P256V1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SM2P256V1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+ if (this == b)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ SM2P256V1FieldElement X1 = (SM2P256V1FieldElement)this.RawXCoord, Y1 = (SM2P256V1FieldElement)this.RawYCoord;
+ SM2P256V1FieldElement X2 = (SM2P256V1FieldElement)b.RawXCoord, Y2 = (SM2P256V1FieldElement)b.RawYCoord;
+
+ SM2P256V1FieldElement Z1 = (SM2P256V1FieldElement)this.RawZCoords[0];
+ SM2P256V1FieldElement Z2 = (SM2P256V1FieldElement)b.RawZCoords[0];
+
+ uint c;
+ uint[] tt1 = Nat256.CreateExt();
+ uint[] t2 = Nat256.Create();
+ uint[] t3 = Nat256.Create();
+ uint[] t4 = Nat256.Create();
+
+ bool Z1IsOne = Z1.IsOne;
+ uint[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SM2P256V1Field.Square(Z1.x, S2);
+
+ U2 = t2;
+ SM2P256V1Field.Multiply(S2, X2.x, U2);
+
+ SM2P256V1Field.Multiply(S2, Z1.x, S2);
+ SM2P256V1Field.Multiply(S2, Y2.x, S2);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ uint[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SM2P256V1Field.Square(Z2.x, S1);
+
+ U1 = tt1;
+ SM2P256V1Field.Multiply(S1, X1.x, U1);
+
+ SM2P256V1Field.Multiply(S1, Z2.x, S1);
+ SM2P256V1Field.Multiply(S1, Y1.x, S1);
+ }
+
+ uint[] H = Nat256.Create();
+ SM2P256V1Field.Subtract(U1, U2, H);
+
+ uint[] R = t2;
+ SM2P256V1Field.Subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat256.IsZero(H))
+ {
+ if (Nat256.IsZero(R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ uint[] HSquared = t3;
+ SM2P256V1Field.Square(H, HSquared);
+
+ uint[] G = Nat256.Create();
+ SM2P256V1Field.Multiply(HSquared, H, G);
+
+ uint[] V = t3;
+ SM2P256V1Field.Multiply(HSquared, U1, V);
+
+ SM2P256V1Field.Negate(G, G);
+ Nat256.Mul(S1, G, tt1);
+
+ c = Nat256.AddBothTo(V, V, G);
+ SM2P256V1Field.Reduce32(c, G);
+
+ SM2P256V1FieldElement X3 = new SM2P256V1FieldElement(t4);
+ SM2P256V1Field.Square(R, X3.x);
+ SM2P256V1Field.Subtract(X3.x, G, X3.x);
+
+ SM2P256V1FieldElement Y3 = new SM2P256V1FieldElement(G);
+ SM2P256V1Field.Subtract(V, X3.x, Y3.x);
+ SM2P256V1Field.MultiplyAddToExt(Y3.x, R, tt1);
+ SM2P256V1Field.Reduce(tt1, Y3.x);
+
+ SM2P256V1FieldElement Z3 = new SM2P256V1FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SM2P256V1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SM2P256V1Field.Multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+ return new SM2P256V1Point(curve, X3, Y3, zs, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ SM2P256V1FieldElement Y1 = (SM2P256V1FieldElement)this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ SM2P256V1FieldElement X1 = (SM2P256V1FieldElement)this.RawXCoord, Z1 = (SM2P256V1FieldElement)this.RawZCoords[0];
+
+ uint c;
+ uint[] t1 = Nat256.Create();
+ uint[] t2 = Nat256.Create();
+
+ uint[] Y1Squared = Nat256.Create();
+ SM2P256V1Field.Square(Y1.x, Y1Squared);
+
+ uint[] T = Nat256.Create();
+ SM2P256V1Field.Square(Y1Squared, T);
+
+ bool Z1IsOne = Z1.IsOne;
+
+ uint[] Z1Squared = Z1.x;
+ if (!Z1IsOne)
+ {
+ Z1Squared = t2;
+ SM2P256V1Field.Square(Z1.x, Z1Squared);
+ }
+
+ SM2P256V1Field.Subtract(X1.x, Z1Squared, t1);
+
+ uint[] M = t2;
+ SM2P256V1Field.Add(X1.x, Z1Squared, M);
+ SM2P256V1Field.Multiply(M, t1, M);
+ c = Nat256.AddBothTo(M, M, M);
+ SM2P256V1Field.Reduce32(c, M);
+
+ uint[] S = Y1Squared;
+ SM2P256V1Field.Multiply(Y1Squared, X1.x, S);
+ c = Nat.ShiftUpBits(8, S, 2, 0);
+ SM2P256V1Field.Reduce32(c, S);
+
+ c = Nat.ShiftUpBits(8, T, 3, 0, t1);
+ SM2P256V1Field.Reduce32(c, t1);
+
+ SM2P256V1FieldElement X3 = new SM2P256V1FieldElement(T);
+ SM2P256V1Field.Square(M, X3.x);
+ SM2P256V1Field.Subtract(X3.x, S, X3.x);
+ SM2P256V1Field.Subtract(X3.x, S, X3.x);
+
+ SM2P256V1FieldElement Y3 = new SM2P256V1FieldElement(S);
+ SM2P256V1Field.Subtract(S, X3.x, Y3.x);
+ SM2P256V1Field.Multiply(Y3.x, M, Y3.x);
+ SM2P256V1Field.Subtract(Y3.x, t1, Y3.x);
+
+ SM2P256V1FieldElement Z3 = new SM2P256V1FieldElement(M);
+ SM2P256V1Field.Twice(Y1.x, Z3.x);
+ if (!Z1IsOne)
+ {
+ SM2P256V1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SM2P256V1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this == b)
+ return ThreeTimes();
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return b;
+
+ return Twice().Add(b);
+ }
+
+ public override ECPoint ThreeTimes()
+ {
+ if (this.IsInfinity || this.RawYCoord.IsZero)
+ return this;
+
+ // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+ return Twice().Add(this);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ return new SM2P256V1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP128R1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP128R1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9da27b4706f1d6ea6adac3946abb7d3d23055ee6
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP128R1Curve.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP128R1Curve
+ : AbstractFpCurve
+ {
+ public static readonly BigInteger q = new BigInteger(1,
+ Hex.Decode("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF"));
+
+ private const int SecP128R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected readonly SecP128R1Point m_infinity;
+
+ public SecP128R1Curve()
+ : base(q)
+ {
+ this.m_infinity = new SecP128R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1,
+ Hex.Decode("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC")));
+ this.m_b = FromBigInteger(new BigInteger(1,
+ Hex.Decode("E87579C11079F43DD824993C2CEE5ED3")));
+ this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFE0000000075A30D1B9038A115"));
+ this.m_cofactor = BigInteger.One;
+
+ this.m_coord = SecP128R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecP128R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecP128R1FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecP128R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecP128R1Point(this, x, y, zs, withCompression);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP128R1Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP128R1Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d1ac009b3f268b64323070dccd3720c484594d6a
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP128R1Field.cs
@@ -0,0 +1,218 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP128R1Field
+ {
+ // 2^128 - 2^97 - 1
+ internal static readonly uint[] P = new uint[] { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFD };
+ internal static readonly uint[] PExt = new uint[] { 0x00000001, 0x00000000, 0x00000000, 0x00000004, 0xFFFFFFFE,
+ 0xFFFFFFFF, 0x00000003, 0xFFFFFFFC };
+ private static readonly uint[] PExtInv = new uint[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFB,
+ 0x00000001, 0x00000000, 0xFFFFFFFC, 0x00000003 };
+ private const uint P3 = 0xFFFFFFFD;
+ private const uint PExt7 = 0xFFFFFFFC;
+
+ public static void Add(uint[] x, uint[] y, uint[] z)
+ {
+ uint c = Nat128.Add(x, y, z);
+ if (c != 0 || (z[3] >= P3 && Nat128.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ uint c = Nat256.Add(xx, yy, zz);
+ if (c != 0 || (zz[7] >= PExt7 && Nat256.Gte(zz, PExt)))
+ {
+ Nat.AddTo(PExtInv.Length, PExtInv, zz);
+ }
+ }
+
+ public static void AddOne(uint[] x, uint[] z)
+ {
+ uint c = Nat.Inc(4, x, z);
+ if (c != 0 || (z[3] >= P3 && Nat128.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ uint[] z = Nat128.FromBigInteger(x);
+ if (z[3] >= P3 && Nat128.Gte(z, P))
+ {
+ Nat128.SubFrom(P, z);
+ }
+ return z;
+ }
+
+ public static void Half(uint[] x, uint[] z)
+ {
+ if ((x[0] & 1) == 0)
+ {
+ Nat.ShiftDownBit(4, x, 0, z);
+ }
+ else
+ {
+ uint c = Nat128.Add(x, P, z);
+ Nat.ShiftDownBit(4, z, c);
+ }
+ }
+
+ public static void Multiply(uint[] x, uint[] y, uint[] z)
+ {
+ uint[] tt = Nat128.CreateExt();
+ Nat128.Mul(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+ {
+ uint c = Nat128.MulAddTo(x, y, zz);
+ if (c != 0 || (zz[7] >= PExt7 && Nat256.Gte(zz, PExt)))
+ {
+ Nat.AddTo(PExtInv.Length, PExtInv, zz);
+ }
+ }
+
+ public static void Negate(uint[] x, uint[] z)
+ {
+ if (Nat128.IsZero(x))
+ {
+ Nat128.Zero(z);
+ }
+ else
+ {
+ Nat128.Sub(P, x, z);
+ }
+ }
+
+ public static void Reduce(uint[] xx, uint[] z)
+ {
+ ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3];
+ ulong x4 = xx[4], x5 = xx[5], x6 = xx[6], x7 = xx[7];
+
+ x3 += x7; x6 += (x7 << 1);
+ x2 += x6; x5 += (x6 << 1);
+ x1 += x5; x4 += (x5 << 1);
+ x0 += x4; x3 += (x4 << 1);
+
+ z[0] = (uint)x0; x1 += (x0 >> 32);
+ z[1] = (uint)x1; x2 += (x1 >> 32);
+ z[2] = (uint)x2; x3 += (x2 >> 32);
+ z[3] = (uint)x3;
+
+ Reduce32((uint)(x3 >> 32), z);
+ }
+
+ public static void Reduce32(uint x, uint[] z)
+ {
+ while (x != 0)
+ {
+ ulong c, x4 = x;
+
+ c = (ulong)z[0] + x4;
+ z[0] = (uint)c; c >>= 32;
+ if (c != 0)
+ {
+ c += (ulong)z[1];
+ z[1] = (uint)c; c >>= 32;
+ c += (ulong)z[2];
+ z[2] = (uint)c; c >>= 32;
+ }
+ c += (ulong)z[3] + (x4 << 1);
+ z[3] = (uint)c; c >>= 32;
+
+ Debug.Assert(c >= 0 && c <= 2);
+
+ x = (uint)c;
+ }
+ }
+
+ public static void Square(uint[] x, uint[] z)
+ {
+ uint[] tt = Nat128.CreateExt();
+ Nat128.Square(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareN(uint[] x, int n, uint[] z)
+ {
+ Debug.Assert(n > 0);
+
+ uint[] tt = Nat128.CreateExt();
+ Nat128.Square(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ Nat128.Square(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static void Subtract(uint[] x, uint[] y, uint[] z)
+ {
+ int c = Nat128.Sub(x, y, z);
+ if (c != 0)
+ {
+ SubPInvFrom(z);
+ }
+ }
+
+ public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ int c = Nat.Sub(10, xx, yy, zz);
+ if (c != 0)
+ {
+ Nat.SubFrom(PExtInv.Length, PExtInv, zz);
+ }
+ }
+
+ public static void Twice(uint[] x, uint[] z)
+ {
+ uint c = Nat.ShiftUpBit(4, x, 0, z);
+ if (c != 0 || (z[3] >= P3 && Nat128.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ private static void AddPInvTo(uint[] z)
+ {
+ long c = (long)z[0] + 1;
+ z[0] = (uint)c; c >>= 32;
+ if (c != 0)
+ {
+ c += (long)z[1];
+ z[1] = (uint)c; c >>= 32;
+ c += (long)z[2];
+ z[2] = (uint)c; c >>= 32;
+ }
+ c += (long)z[3] + 2;
+ z[3] = (uint)c;
+ }
+
+ private static void SubPInvFrom(uint[] z)
+ {
+ long c = (long)z[0] - 1;
+ z[0] = (uint)c; c >>= 32;
+ if (c != 0)
+ {
+ c += (long)z[1];
+ z[1] = (uint)c; c >>= 32;
+ c += (long)z[2];
+ z[2] = (uint)c; c >>= 32;
+ }
+ c += (long)z[3] - 2;
+ z[3] = (uint)c;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fa7951d5dcbcdacd4ef99bddd2a1300ef8a825bc
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs
@@ -0,0 +1,198 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP128R1FieldElement
+ : ECFieldElement
+ {
+ public static readonly BigInteger Q = SecP128R1Curve.q;
+
+ protected internal readonly uint[] x;
+
+ public SecP128R1FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+ throw new ArgumentException("value invalid for SecP128R1FieldElement", "x");
+
+ this.x = SecP128R1Field.FromBigInteger(x);
+ }
+
+ public SecP128R1FieldElement()
+ {
+ this.x = Nat128.Create();
+ }
+
+ protected internal SecP128R1FieldElement(uint[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat128.IsZero(x); }
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat128.IsOne(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return Nat128.GetBit(x, 0) == 1;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat128.ToBigInteger(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecP128R1Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return Q.BitLength; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ uint[] z = Nat128.Create();
+ SecP128R1Field.Add(x, ((SecP128R1FieldElement)b).x, z);
+ return new SecP128R1FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ uint[] z = Nat128.Create();
+ SecP128R1Field.AddOne(x, z);
+ return new SecP128R1FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ uint[] z = Nat128.Create();
+ SecP128R1Field.Subtract(x, ((SecP128R1FieldElement)b).x, z);
+ return new SecP128R1FieldElement(z);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ uint[] z = Nat128.Create();
+ SecP128R1Field.Multiply(x, ((SecP128R1FieldElement)b).x, z);
+ return new SecP128R1FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ // return multiply(b.invert());
+ uint[] z = Nat128.Create();
+ Mod.Invert(SecP128R1Field.P, ((SecP128R1FieldElement)b).x, z);
+ SecP128R1Field.Multiply(z, x, z);
+ return new SecP128R1FieldElement(z);
+ }
+
+ public override ECFieldElement Negate()
+ {
+ uint[] z = Nat128.Create();
+ SecP128R1Field.Negate(x, z);
+ return new SecP128R1FieldElement(z);
+ }
+
+ public override ECFieldElement Square()
+ {
+ uint[] z = Nat128.Create();
+ SecP128R1Field.Square(x, z);
+ return new SecP128R1FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ // return new SecP128R1FieldElement(toBigInteger().modInverse(Q));
+ uint[] z = Nat128.Create();
+ Mod.Invert(SecP128R1Field.P, x, z);
+ return new SecP128R1FieldElement(z);
+ }
+
+ // D.1.4 91
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public override ECFieldElement Sqrt()
+ {
+ /*
+ * Raise this element to the exponent 2^126 - 2^95
+ *
+ * Breaking up the exponent's binary representation into "repunits", we get:
+ * { 31 1s } { 95 0s }
+ *
+ * Therefore we need an addition chain containing 31 (the length of the repunit) We use:
+ * 1, 2, 4, 8, 10, 20, 30, [31]
+ */
+
+ uint[] x1 = this.x;
+ if (Nat128.IsZero(x1) || Nat128.IsOne(x1))
+ return this;
+
+ uint[] x2 = Nat128.Create();
+ SecP128R1Field.Square(x1, x2);
+ SecP128R1Field.Multiply(x2, x1, x2);
+ uint[] x4 = Nat128.Create();
+ SecP128R1Field.SquareN(x2, 2, x4);
+ SecP128R1Field.Multiply(x4, x2, x4);
+ uint[] x8 = Nat128.Create();
+ SecP128R1Field.SquareN(x4, 4, x8);
+ SecP128R1Field.Multiply(x8, x4, x8);
+ uint[] x10 = x4;
+ SecP128R1Field.SquareN(x8, 2, x10);
+ SecP128R1Field.Multiply(x10, x2, x10);
+ uint[] x20 = x2;
+ SecP128R1Field.SquareN(x10, 10, x20);
+ SecP128R1Field.Multiply(x20, x10, x20);
+ uint[] x30 = x8;
+ SecP128R1Field.SquareN(x20, 10, x30);
+ SecP128R1Field.Multiply(x30, x10, x30);
+ uint[] x31 = x10;
+ SecP128R1Field.Square(x30, x31);
+ SecP128R1Field.Multiply(x31, x1, x31);
+
+ uint[] t1 = x31;
+ SecP128R1Field.SquareN(t1, 95, t1);
+
+ uint[] t2 = x30;
+ SecP128R1Field.Square(t1, t2);
+
+ return Nat128.Eq(x1, t2) ? new SecP128R1FieldElement(t1) : null;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecP128R1FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecP128R1FieldElement);
+ }
+
+ public virtual bool Equals(SecP128R1FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat128.Eq(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 4);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP128R1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP128R1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ae76d3cd1272e451f85731493184e261c3e541b1
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP128R1Point.cs
@@ -0,0 +1,279 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP128R1Point
+ : AbstractFpPoint
+ {
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ *
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecP128R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ * @param withCompression
+ * if true encode with point compression
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(boolean)}
+ */
+ public SecP128R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecP128R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecP128R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+ if (this == b)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ SecP128R1FieldElement X1 = (SecP128R1FieldElement)this.RawXCoord, Y1 = (SecP128R1FieldElement)this.RawYCoord;
+ SecP128R1FieldElement X2 = (SecP128R1FieldElement)b.RawXCoord, Y2 = (SecP128R1FieldElement)b.RawYCoord;
+
+ SecP128R1FieldElement Z1 = (SecP128R1FieldElement)this.RawZCoords[0];
+ SecP128R1FieldElement Z2 = (SecP128R1FieldElement)b.RawZCoords[0];
+
+ uint c;
+ uint[] tt1 = Nat128.CreateExt();
+ uint[] t2 = Nat128.Create();
+ uint[] t3 = Nat128.Create();
+ uint[] t4 = Nat128.Create();
+
+ bool Z1IsOne = Z1.IsOne;
+ uint[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SecP128R1Field.Square(Z1.x, S2);
+
+ U2 = t2;
+ SecP128R1Field.Multiply(S2, X2.x, U2);
+
+ SecP128R1Field.Multiply(S2, Z1.x, S2);
+ SecP128R1Field.Multiply(S2, Y2.x, S2);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ uint[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SecP128R1Field.Square(Z2.x, S1);
+
+ U1 = tt1;
+ SecP128R1Field.Multiply(S1, X1.x, U1);
+
+ SecP128R1Field.Multiply(S1, Z2.x, S1);
+ SecP128R1Field.Multiply(S1, Y1.x, S1);
+ }
+
+ uint[] H = Nat128.Create();
+ SecP128R1Field.Subtract(U1, U2, H);
+
+ uint[] R = t2;
+ SecP128R1Field.Subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat128.IsZero(H))
+ {
+ if (Nat128.IsZero(R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ uint[] HSquared = t3;
+ SecP128R1Field.Square(H, HSquared);
+
+ uint[] G = Nat128.Create();
+ SecP128R1Field.Multiply(HSquared, H, G);
+
+ uint[] V = t3;
+ SecP128R1Field.Multiply(HSquared, U1, V);
+
+ SecP128R1Field.Negate(G, G);
+ Nat128.Mul(S1, G, tt1);
+
+ c = Nat128.AddBothTo(V, V, G);
+ SecP128R1Field.Reduce32(c, G);
+
+ SecP128R1FieldElement X3 = new SecP128R1FieldElement(t4);
+ SecP128R1Field.Square(R, X3.x);
+ SecP128R1Field.Subtract(X3.x, G, X3.x);
+
+ SecP128R1FieldElement Y3 = new SecP128R1FieldElement(G);
+ SecP128R1Field.Subtract(V, X3.x, Y3.x);
+ SecP128R1Field.MultiplyAddToExt(Y3.x, R, tt1);
+ SecP128R1Field.Reduce(tt1, Y3.x);
+
+ SecP128R1FieldElement Z3 = new SecP128R1FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SecP128R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SecP128R1Field.Multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+ return new SecP128R1Point(curve, X3, Y3, zs, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ SecP128R1FieldElement Y1 = (SecP128R1FieldElement)this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ SecP128R1FieldElement X1 = (SecP128R1FieldElement)this.RawXCoord, Z1 = (SecP128R1FieldElement)this.RawZCoords[0];
+
+ uint c;
+ uint[] t1 = Nat128.Create();
+ uint[] t2 = Nat128.Create();
+
+ uint[] Y1Squared = Nat128.Create();
+ SecP128R1Field.Square(Y1.x, Y1Squared);
+
+ uint[] T = Nat128.Create();
+ SecP128R1Field.Square(Y1Squared, T);
+
+ bool Z1IsOne = Z1.IsOne;
+
+ uint[] Z1Squared = Z1.x;
+ if (!Z1IsOne)
+ {
+ Z1Squared = t2;
+ SecP128R1Field.Square(Z1.x, Z1Squared);
+ }
+
+ SecP128R1Field.Subtract(X1.x, Z1Squared, t1);
+
+ uint[] M = t2;
+ SecP128R1Field.Add(X1.x, Z1Squared, M);
+ SecP128R1Field.Multiply(M, t1, M);
+ c = Nat128.AddBothTo(M, M, M);
+ SecP128R1Field.Reduce32(c, M);
+
+ uint[] S = Y1Squared;
+ SecP128R1Field.Multiply(Y1Squared, X1.x, S);
+ c = Nat.ShiftUpBits(4, S, 2, 0);
+ SecP128R1Field.Reduce32(c, S);
+
+ c = Nat.ShiftUpBits(4, T, 3, 0, t1);
+ SecP128R1Field.Reduce32(c, t1);
+
+ SecP128R1FieldElement X3 = new SecP128R1FieldElement(T);
+ SecP128R1Field.Square(M, X3.x);
+ SecP128R1Field.Subtract(X3.x, S, X3.x);
+ SecP128R1Field.Subtract(X3.x, S, X3.x);
+
+ SecP128R1FieldElement Y3 = new SecP128R1FieldElement(S);
+ SecP128R1Field.Subtract(S, X3.x, Y3.x);
+ SecP128R1Field.Multiply(Y3.x, M, Y3.x);
+ SecP128R1Field.Subtract(Y3.x, t1, Y3.x);
+
+ SecP128R1FieldElement Z3 = new SecP128R1FieldElement(M);
+ SecP128R1Field.Twice(Y1.x, Z3.x);
+ if (!Z1IsOne)
+ {
+ SecP128R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SecP128R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this == b)
+ return ThreeTimes();
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return b;
+
+ return Twice().Add(b);
+ }
+
+ public override ECPoint ThreeTimes()
+ {
+ if (this.IsInfinity || this.RawYCoord.IsZero)
+ return this;
+
+ // NOTE: Be careful about recursions between twicePlus and threeTimes
+ return Twice().Add(this);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ return new SecP128R1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP160K1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160K1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7d45c62278615ef439ea8e6f9aaa19d26258e1cb
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160K1Curve.cs
@@ -0,0 +1,74 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160K1Curve
+ : AbstractFpCurve
+ {
+ public static readonly BigInteger q = SecP160R2Curve.q;
+
+ private const int SECP160K1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected readonly SecP160K1Point m_infinity;
+
+ public SecP160K1Curve()
+ : base(q)
+ {
+ this.m_infinity = new SecP160K1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.Zero);
+ this.m_b = FromBigInteger(BigInteger.ValueOf(7));
+ this.m_order = new BigInteger(1, Hex.Decode("0100000000000000000001B8FA16DFAB9ACA16B6B3"));
+ this.m_cofactor = BigInteger.One;
+ this.m_coord = SECP160K1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecP160K1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecP160R2FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecP160K1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecP160K1Point(this, x, y, zs, withCompression);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP160K1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160K1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1bcbadb33d6df59c228a7bcef9d5248d58414c91
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160K1Point.cs
@@ -0,0 +1,269 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160K1Point
+ : AbstractFpPoint
+ {
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ *
+ * @deprecated Use ECCurve.CreatePoint to construct points
+ */
+ public SecP160K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ * @param withCompression
+ * if true encode with point compression
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(bool)}
+ */
+ public SecP160K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecP160K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs,
+ bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecP160K1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ // B.3 pg 62
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+ if (this == b)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ SecP160R2FieldElement X1 = (SecP160R2FieldElement)this.RawXCoord, Y1 = (SecP160R2FieldElement)this.RawYCoord;
+ SecP160R2FieldElement X2 = (SecP160R2FieldElement)b.RawXCoord, Y2 = (SecP160R2FieldElement)b.RawYCoord;
+
+ SecP160R2FieldElement Z1 = (SecP160R2FieldElement)this.RawZCoords[0];
+ SecP160R2FieldElement Z2 = (SecP160R2FieldElement)b.RawZCoords[0];
+
+ uint c;
+ uint[] tt1 = Nat160.CreateExt();
+ uint[] t2 = Nat160.Create();
+ uint[] t3 = Nat160.Create();
+ uint[] t4 = Nat160.Create();
+
+ bool Z1IsOne = Z1.IsOne;
+ uint[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SecP160R2Field.Square(Z1.x, S2);
+
+ U2 = t2;
+ SecP160R2Field.Multiply(S2, X2.x, U2);
+
+ SecP160R2Field.Multiply(S2, Z1.x, S2);
+ SecP160R2Field.Multiply(S2, Y2.x, S2);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ uint[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SecP160R2Field.Square(Z2.x, S1);
+
+ U1 = tt1;
+ SecP160R2Field.Multiply(S1, X1.x, U1);
+
+ SecP160R2Field.Multiply(S1, Z2.x, S1);
+ SecP160R2Field.Multiply(S1, Y1.x, S1);
+ }
+
+ uint[] H = Nat160.Create();
+ SecP160R2Field.Subtract(U1, U2, H);
+
+ uint[] R = t2;
+ SecP160R2Field.Subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat160.IsZero(H))
+ {
+ if (Nat160.IsZero(R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ uint[] HSquared = t3;
+ SecP160R2Field.Square(H, HSquared);
+
+ uint[] G = Nat160.Create();
+ SecP160R2Field.Multiply(HSquared, H, G);
+
+ uint[] V = t3;
+ SecP160R2Field.Multiply(HSquared, U1, V);
+
+ SecP160R2Field.Negate(G, G);
+ Nat160.Mul(S1, G, tt1);
+
+ c = Nat160.AddBothTo(V, V, G);
+ SecP160R2Field.Reduce32(c, G);
+
+ SecP160R2FieldElement X3 = new SecP160R2FieldElement(t4);
+ SecP160R2Field.Square(R, X3.x);
+ SecP160R2Field.Subtract(X3.x, G, X3.x);
+
+ SecP160R2FieldElement Y3 = new SecP160R2FieldElement(G);
+ SecP160R2Field.Subtract(V, X3.x, Y3.x);
+ SecP160R2Field.MultiplyAddToExt(Y3.x, R, tt1);
+ SecP160R2Field.Reduce(tt1, Y3.x);
+
+ SecP160R2FieldElement Z3 = new SecP160R2FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SecP160R2Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SecP160R2Field.Multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+ return new SecP160K1Point(curve, X3, Y3, zs, IsCompressed);
+ }
+
+ // B.3 pg 62
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ SecP160R2FieldElement Y1 = (SecP160R2FieldElement)this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ SecP160R2FieldElement X1 = (SecP160R2FieldElement)this.RawXCoord, Z1 = (SecP160R2FieldElement)this.RawZCoords[0];
+
+ uint c;
+
+ uint[] Y1Squared = Nat160.Create();
+ SecP160R2Field.Square(Y1.x, Y1Squared);
+
+ uint[] T = Nat160.Create();
+ SecP160R2Field.Square(Y1Squared, T);
+
+ uint[] M = Nat160.Create();
+ SecP160R2Field.Square(X1.x, M);
+ c = Nat160.AddBothTo(M, M, M);
+ SecP160R2Field.Reduce32(c, M);
+
+ uint[] S = Y1Squared;
+ SecP160R2Field.Multiply(Y1Squared, X1.x, S);
+ c = Nat.ShiftUpBits(5, S, 2, 0);
+ SecP160R2Field.Reduce32(c, S);
+
+ uint[] t1 = Nat160.Create();
+ c = Nat.ShiftUpBits(5, T, 3, 0, t1);
+ SecP160R2Field.Reduce32(c, t1);
+
+ SecP160R2FieldElement X3 = new SecP160R2FieldElement(T);
+ SecP160R2Field.Square(M, X3.x);
+ SecP160R2Field.Subtract(X3.x, S, X3.x);
+ SecP160R2Field.Subtract(X3.x, S, X3.x);
+
+ SecP160R2FieldElement Y3 = new SecP160R2FieldElement(S);
+ SecP160R2Field.Subtract(S, X3.x, Y3.x);
+ SecP160R2Field.Multiply(Y3.x, M, Y3.x);
+ SecP160R2Field.Subtract(Y3.x, t1, Y3.x);
+
+ SecP160R2FieldElement Z3 = new SecP160R2FieldElement(M);
+ SecP160R2Field.Twice(Y1.x, Z3.x);
+ if (!Z1.IsOne)
+ {
+ SecP160R2Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SecP160K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this == b)
+ return ThreeTimes();
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return b;
+
+ return Twice().Add(b);
+ }
+
+ public override ECPoint ThreeTimes()
+ {
+ if (this.IsInfinity || this.RawYCoord.IsZero)
+ return this;
+
+ // NOTE: Be careful about recursions between TwicePlus and threeTimes
+ return Twice().Add(this);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ return new SecP160K1Point(Curve, this.RawXCoord, this.RawYCoord.Negate(), this.RawZCoords, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..87389af36afa579c4076ee951715b1ed6784f2cf
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R1Curve.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160R1Curve
+ : AbstractFpCurve
+ {
+ public static readonly BigInteger q = new BigInteger(1,
+ Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF"));
+
+ private const int SecP160R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected readonly SecP160R1Point m_infinity;
+
+ public SecP160R1Curve()
+ : base(q)
+ {
+ this.m_infinity = new SecP160R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1,
+ Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC")));
+ this.m_b = FromBigInteger(new BigInteger(1,
+ Hex.Decode("1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45")));
+ this.m_order = new BigInteger(1, Hex.Decode("0100000000000000000001F4C8F927AED3CA752257"));
+ this.m_cofactor = BigInteger.One;
+
+ this.m_coord = SecP160R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecP160R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecP160R1FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecP160R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecP160R1Point(this, x, y, zs, withCompression);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R1Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R1Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6a5a2ef64c247a421f3a5c814aefafe3357cee2b
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R1Field.cs
@@ -0,0 +1,186 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160R1Field
+ {
+ // 2^160 - 2^31 - 1
+ internal static readonly uint[] P = new uint[] { 0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
+ internal static readonly uint[] PExt = new uint[] { 0x00000001, 0x40000001, 0x00000000, 0x00000000, 0x00000000,
+ 0xFFFFFFFE, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ private static readonly uint[] PExtInv = new uint[]{ 0xFFFFFFFF, 0xBFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0x00000001, 0x00000001 };
+ private const uint P4 = 0xFFFFFFFF;
+ private const uint PExt9 = 0xFFFFFFFF;
+ private const uint PInv = 0x80000001;
+
+ public static void Add(uint[] x, uint[] y, uint[] z)
+ {
+ uint c = Nat160.Add(x, y, z);
+ if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+ {
+ Nat.AddWordTo(5, PInv, z);
+ }
+ }
+
+ public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ uint c = Nat.Add(10, xx, yy, zz);
+ if (c != 0 || (zz[9] == PExt9 && Nat.Gte(10, zz, PExt)))
+ {
+ if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.IncAt(10, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void AddOne(uint[] x, uint[] z)
+ {
+ uint c = Nat.Inc(5, x, z);
+ if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+ {
+ Nat.AddWordTo(5, PInv, z);
+ }
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ uint[] z = Nat160.FromBigInteger(x);
+ if (z[4] == P4 && Nat160.Gte(z, P))
+ {
+ Nat160.SubFrom(P, z);
+ }
+ return z;
+ }
+
+ public static void Half(uint[] x, uint[] z)
+ {
+ if ((x[0] & 1) == 0)
+ {
+ Nat.ShiftDownBit(5, x, 0, z);
+ }
+ else
+ {
+ uint c = Nat160.Add(x, P, z);
+ Nat.ShiftDownBit(5, z, c);
+ }
+ }
+
+ public static void Multiply(uint[] x, uint[] y, uint[] z)
+ {
+ uint[] tt = Nat160.CreateExt();
+ Nat160.Mul(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+ {
+ uint c = Nat160.MulAddTo(x, y, zz);
+ if (c != 0 || (zz[9] == PExt9 && Nat.Gte(10, zz, PExt)))
+ {
+ if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.IncAt(10, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void Negate(uint[] x, uint[] z)
+ {
+ if (Nat160.IsZero(x))
+ {
+ Nat160.Zero(z);
+ }
+ else
+ {
+ Nat160.Sub(P, x, z);
+ }
+ }
+
+ public static void Reduce(uint[] xx, uint[] z)
+ {
+ ulong x5 = xx[5], x6 = xx[6], x7 = xx[7], x8 = xx[8], x9 = xx[9];
+
+ ulong c = 0;
+ c += (ulong)xx[0] + x5 + (x5 << 31);
+ z[0] = (uint)c; c >>= 32;
+ c += (ulong)xx[1] + x6 + (x6 << 31);
+ z[1] = (uint)c; c >>= 32;
+ c += (ulong)xx[2] + x7 + (x7 << 31);
+ z[2] = (uint)c; c >>= 32;
+ c += (ulong)xx[3] + x8 + (x8 << 31);
+ z[3] = (uint)c; c >>= 32;
+ c += (ulong)xx[4] + x9 + (x9 << 31);
+ z[4] = (uint)c; c >>= 32;
+
+ Debug.Assert(c >> 32 == 0);
+
+ Reduce32((uint)c, z);
+ }
+
+ public static void Reduce32(uint x, uint[] z)
+ {
+ if ((x != 0 && Nat160.MulWordsAdd(PInv, x, z, 0) != 0)
+ || (z[4] == P4 && Nat160.Gte(z, P)))
+ {
+ Nat.AddWordTo(5, PInv, z);
+ }
+ }
+
+ public static void Square(uint[] x, uint[] z)
+ {
+ uint[] tt = Nat160.CreateExt();
+ Nat160.Square(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareN(uint[] x, int n, uint[] z)
+ {
+ Debug.Assert(n > 0);
+
+ uint[] tt = Nat160.CreateExt();
+ Nat160.Square(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ Nat160.Square(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static void Subtract(uint[] x, uint[] y, uint[] z)
+ {
+ int c = Nat160.Sub(x, y, z);
+ if (c != 0)
+ {
+ Nat.SubWordFrom(5, PInv, z);
+ }
+ }
+
+ public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ int c = Nat.Sub(10, xx, yy, zz);
+ if (c != 0)
+ {
+ if (Nat.SubFrom(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.DecAt(10, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void Twice(uint[] x, uint[] z)
+ {
+ uint c = Nat.ShiftUpBit(5, x, 0, z);
+ if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+ {
+ Nat.AddWordTo(5, PInv, z);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d1fc756441d3ca11651383c774f6287509b8a203
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs
@@ -0,0 +1,203 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160R1FieldElement
+ : ECFieldElement
+ {
+ public static readonly BigInteger Q = SecP160R1Curve.q;
+
+ protected internal readonly uint[] x;
+
+ public SecP160R1FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+ throw new ArgumentException("value invalid for SecP160R1FieldElement", "x");
+
+ this.x = SecP160R1Field.FromBigInteger(x);
+ }
+
+ public SecP160R1FieldElement()
+ {
+ this.x = Nat160.Create();
+ }
+
+ protected internal SecP160R1FieldElement(uint[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat160.IsZero(x); }
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat160.IsOne(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return Nat160.GetBit(x, 0) == 1;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat160.ToBigInteger(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecP160R1Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return Q.BitLength; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ uint[] z = Nat160.Create();
+ SecP160R1Field.Add(x, ((SecP160R1FieldElement)b).x, z);
+ return new SecP160R1FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ uint[] z = Nat160.Create();
+ SecP160R1Field.AddOne(x, z);
+ return new SecP160R1FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ uint[] z = Nat160.Create();
+ SecP160R1Field.Subtract(x, ((SecP160R1FieldElement)b).x, z);
+ return new SecP160R1FieldElement(z);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ uint[] z = Nat160.Create();
+ SecP160R1Field.Multiply(x, ((SecP160R1FieldElement)b).x, z);
+ return new SecP160R1FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ // return multiply(b.invert());
+ uint[] z = Nat160.Create();
+ Mod.Invert(SecP160R1Field.P, ((SecP160R1FieldElement)b).x, z);
+ SecP160R1Field.Multiply(z, x, z);
+ return new SecP160R1FieldElement(z);
+ }
+
+ public override ECFieldElement Negate()
+ {
+ uint[] z = Nat160.Create();
+ SecP160R1Field.Negate(x, z);
+ return new SecP160R1FieldElement(z);
+ }
+
+ public override ECFieldElement Square()
+ {
+ uint[] z = Nat160.Create();
+ SecP160R1Field.Square(x, z);
+ return new SecP160R1FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ // return new SecP160R1FieldElement(ToBigInteger().modInverse(Q));
+ uint[] z = Nat160.Create();
+ Mod.Invert(SecP160R1Field.P, x, z);
+ return new SecP160R1FieldElement(z);
+ }
+
+ // D.1.4 91
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public override ECFieldElement Sqrt()
+ {
+ /*
+ * Raise this element to the exponent 2^158 - 2^29
+ *
+ * Breaking up the exponent's binary representation into "repunits", we get:
+ * { 129 1s } { 29 0s }
+ *
+ * Therefore we need an addition chain containing 129 (the length of the repunit) We use:
+ * 1, 2, 4, 8, 16, 32, 64, 128, [129]
+ */
+
+ uint[] x1 = this.x;
+ if (Nat160.IsZero(x1) || Nat160.IsOne(x1))
+ {
+ return this;
+ }
+
+ uint[] x2 = Nat160.Create();
+ SecP160R1Field.Square(x1, x2);
+ SecP160R1Field.Multiply(x2, x1, x2);
+ uint[] x4 = Nat160.Create();
+ SecP160R1Field.SquareN(x2, 2, x4);
+ SecP160R1Field.Multiply(x4, x2, x4);
+ uint[] x8 = x2;
+ SecP160R1Field.SquareN(x4, 4, x8);
+ SecP160R1Field.Multiply(x8, x4, x8);
+ uint[] x16 = x4;
+ SecP160R1Field.SquareN(x8, 8, x16);
+ SecP160R1Field.Multiply(x16, x8, x16);
+ uint[] x32 = x8;
+ SecP160R1Field.SquareN(x16, 16, x32);
+ SecP160R1Field.Multiply(x32, x16, x32);
+ uint[] x64 = x16;
+ SecP160R1Field.SquareN(x32, 32, x64);
+ SecP160R1Field.Multiply(x64, x32, x64);
+ uint[] x128 = x32;
+ SecP160R1Field.SquareN(x64, 64, x128);
+ SecP160R1Field.Multiply(x128, x64, x128);
+ uint[] x129 = x64;
+ SecP160R1Field.Square(x128, x129);
+ SecP160R1Field.Multiply(x129, x1, x129);
+
+ uint[] t1 = x129;
+ SecP160R1Field.SquareN(t1, 29, t1);
+
+ uint[] t2 = x128;
+ SecP160R1Field.Square(t1, t2);
+
+ return Nat160.Eq(x1, t2) ? new SecP160R1FieldElement(t1) : null;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecP160R1FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecP160R1FieldElement);
+ }
+
+ public virtual bool Equals(SecP160R1FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat160.Eq(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 5);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f9f065de62e77d6ef09b6ed06fd2a162cb495027
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R1Point.cs
@@ -0,0 +1,279 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160R1Point
+ : AbstractFpPoint
+ {
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ *
+ * @deprecated Use ECCurve.CreatePoint to construct points
+ */
+ public SecP160R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ * @param withCompression
+ * if true encode with point compression
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(bool)}
+ */
+ public SecP160R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecP160R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecP160R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+ if (this == b)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ SecP160R1FieldElement X1 = (SecP160R1FieldElement)this.RawXCoord, Y1 = (SecP160R1FieldElement)this.RawYCoord;
+ SecP160R1FieldElement X2 = (SecP160R1FieldElement)b.RawXCoord, Y2 = (SecP160R1FieldElement)b.RawYCoord;
+
+ SecP160R1FieldElement Z1 = (SecP160R1FieldElement)this.RawZCoords[0];
+ SecP160R1FieldElement Z2 = (SecP160R1FieldElement)b.RawZCoords[0];
+
+ uint c;
+ uint[] tt1 = Nat160.CreateExt();
+ uint[] t2 = Nat160.Create();
+ uint[] t3 = Nat160.Create();
+ uint[] t4 = Nat160.Create();
+
+ bool Z1IsOne = Z1.IsOne;
+ uint[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SecP160R1Field.Square(Z1.x, S2);
+
+ U2 = t2;
+ SecP160R1Field.Multiply(S2, X2.x, U2);
+
+ SecP160R1Field.Multiply(S2, Z1.x, S2);
+ SecP160R1Field.Multiply(S2, Y2.x, S2);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ uint[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SecP160R1Field.Square(Z2.x, S1);
+
+ U1 = tt1;
+ SecP160R1Field.Multiply(S1, X1.x, U1);
+
+ SecP160R1Field.Multiply(S1, Z2.x, S1);
+ SecP160R1Field.Multiply(S1, Y1.x, S1);
+ }
+
+ uint[] H = Nat160.Create();
+ SecP160R1Field.Subtract(U1, U2, H);
+
+ uint[] R = t2;
+ SecP160R1Field.Subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat160.IsZero(H))
+ {
+ if (Nat160.IsZero(R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ uint[] HSquared = t3;
+ SecP160R1Field.Square(H, HSquared);
+
+ uint[] G = Nat160.Create();
+ SecP160R1Field.Multiply(HSquared, H, G);
+
+ uint[] V = t3;
+ SecP160R1Field.Multiply(HSquared, U1, V);
+
+ SecP160R1Field.Negate(G, G);
+ Nat160.Mul(S1, G, tt1);
+
+ c = Nat160.AddBothTo(V, V, G);
+ SecP160R1Field.Reduce32(c, G);
+
+ SecP160R1FieldElement X3 = new SecP160R1FieldElement(t4);
+ SecP160R1Field.Square(R, X3.x);
+ SecP160R1Field.Subtract(X3.x, G, X3.x);
+
+ SecP160R1FieldElement Y3 = new SecP160R1FieldElement(G);
+ SecP160R1Field.Subtract(V, X3.x, Y3.x);
+ SecP160R1Field.MultiplyAddToExt(Y3.x, R, tt1);
+ SecP160R1Field.Reduce(tt1, Y3.x);
+
+ SecP160R1FieldElement Z3 = new SecP160R1FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SecP160R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SecP160R1Field.Multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+ return new SecP160R1Point(curve, X3, Y3, zs, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ SecP160R1FieldElement Y1 = (SecP160R1FieldElement)this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ SecP160R1FieldElement X1 = (SecP160R1FieldElement)this.RawXCoord, Z1 = (SecP160R1FieldElement)this.RawZCoords[0];
+
+ uint c;
+ uint[] t1 = Nat160.Create();
+ uint[] t2 = Nat160.Create();
+
+ uint[] Y1Squared = Nat160.Create();
+ SecP160R1Field.Square(Y1.x, Y1Squared);
+
+ uint[] T = Nat160.Create();
+ SecP160R1Field.Square(Y1Squared, T);
+
+ bool Z1IsOne = Z1.IsOne;
+
+ uint[] Z1Squared = Z1.x;
+ if (!Z1IsOne)
+ {
+ Z1Squared = t2;
+ SecP160R1Field.Square(Z1.x, Z1Squared);
+ }
+
+ SecP160R1Field.Subtract(X1.x, Z1Squared, t1);
+
+ uint[] M = t2;
+ SecP160R1Field.Add(X1.x, Z1Squared, M);
+ SecP160R1Field.Multiply(M, t1, M);
+ c = Nat160.AddBothTo(M, M, M);
+ SecP160R1Field.Reduce32(c, M);
+
+ uint[] S = Y1Squared;
+ SecP160R1Field.Multiply(Y1Squared, X1.x, S);
+ c = Nat.ShiftUpBits(5, S, 2, 0);
+ SecP160R1Field.Reduce32(c, S);
+
+ c = Nat.ShiftUpBits(5, T, 3, 0, t1);
+ SecP160R1Field.Reduce32(c, t1);
+
+ SecP160R1FieldElement X3 = new SecP160R1FieldElement(T);
+ SecP160R1Field.Square(M, X3.x);
+ SecP160R1Field.Subtract(X3.x, S, X3.x);
+ SecP160R1Field.Subtract(X3.x, S, X3.x);
+
+ SecP160R1FieldElement Y3 = new SecP160R1FieldElement(S);
+ SecP160R1Field.Subtract(S, X3.x, Y3.x);
+ SecP160R1Field.Multiply(Y3.x, M, Y3.x);
+ SecP160R1Field.Subtract(Y3.x, t1, Y3.x);
+
+ SecP160R1FieldElement Z3 = new SecP160R1FieldElement(M);
+ SecP160R1Field.Twice(Y1.x, Z3.x);
+ if (!Z1IsOne)
+ {
+ SecP160R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SecP160R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this == b)
+ return ThreeTimes();
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return b;
+
+ return Twice().Add(b);
+ }
+
+ public override ECPoint ThreeTimes()
+ {
+ if (this.IsInfinity || this.RawYCoord.IsZero)
+ return this;
+
+ // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+ return Twice().Add(this);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ return new SecP160R1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R2Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R2Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..100561453c9ab09751e6d88552d834cb2426a007
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R2Curve.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160R2Curve
+ : AbstractFpCurve
+ {
+ public static readonly BigInteger q = new BigInteger(1,
+ Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73"));
+
+ private const int SecP160R2_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected readonly SecP160R2Point m_infinity;
+
+ public SecP160R2Curve()
+ : base(q)
+ {
+ this.m_infinity = new SecP160R2Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1,
+ Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70")));
+ this.m_b = FromBigInteger(new BigInteger(1,
+ Hex.Decode("B4E134D3FB59EB8BAB57274904664D5AF50388BA")));
+ this.m_order = new BigInteger(1, Hex.Decode("0100000000000000000000351EE786A818F3A1A16B"));
+ this.m_cofactor = BigInteger.One;
+
+ this.m_coord = SecP160R2_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecP160R2Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecP160R2FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecP160R2Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecP160R2Point(this, x, y, zs, withCompression);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R2Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R2Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1bef32eea13a2d900f1da7900a1f9f1d8ff45297
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R2Field.cs
@@ -0,0 +1,178 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160R2Field
+ {
+ // 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1
+ internal static readonly uint[] P = new uint[]{ 0xFFFFAC73, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ internal static readonly uint[] PExt = new uint[]{ 0x1B44BBA9, 0x0000A71A, 0x00000001, 0x00000000, 0x00000000,
+ 0xFFFF58E6, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ private static readonly uint[] PExtInv = new uint[]{ 0xE4BB4457, 0xFFFF58E5, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0x0000A719, 0x00000002 };
+ private const uint P4 = 0xFFFFFFFF;
+ private const uint PExt9 = 0xFFFFFFFF;
+ private const uint PInv33 = 0x538D;
+
+ public static void Add(uint[] x, uint[] y, uint[] z)
+ {
+ uint c = Nat160.Add(x, y, z);
+ if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+ {
+ Nat.Add33To(5, PInv33, z);
+ }
+ }
+
+ public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ uint c = Nat.Add(10, xx, yy, zz);
+ if (c != 0 || (zz[9] == PExt9 && Nat.Gte(10, zz, PExt)))
+ {
+ if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.IncAt(10, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void AddOne(uint[] x, uint[] z)
+ {
+ uint c = Nat.Inc(5, x, z);
+ if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+ {
+ Nat.Add33To(5, PInv33, z);
+ }
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ uint[] z = Nat160.FromBigInteger(x);
+ if (z[4] == P4 && Nat160.Gte(z, P))
+ {
+ Nat160.SubFrom(P, z);
+ }
+ return z;
+ }
+
+ public static void Half(uint[] x, uint[] z)
+ {
+ if ((x[0] & 1) == 0)
+ {
+ Nat.ShiftDownBit(5, x, 0, z);
+ }
+ else
+ {
+ uint c = Nat160.Add(x, P, z);
+ Nat.ShiftDownBit(5, z, c);
+ }
+ }
+
+ public static void Multiply(uint[] x, uint[] y, uint[] z)
+ {
+ uint[] tt = Nat160.CreateExt();
+ Nat160.Mul(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+ {
+ uint c = Nat160.MulAddTo(x, y, zz);
+ if (c != 0 || (zz[9] == PExt9 && Nat.Gte(10, zz, PExt)))
+ {
+ if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.IncAt(10, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void Negate(uint[] x, uint[] z)
+ {
+ if (Nat160.IsZero(x))
+ {
+ Nat160.Zero(z);
+ }
+ else
+ {
+ Nat160.Sub(P, x, z);
+ }
+ }
+
+ public static void Reduce(uint[] xx, uint[] z)
+ {
+ ulong cc = Nat160.Mul33Add(PInv33, xx, 5, xx, 0, z, 0);
+ uint c = Nat160.Mul33DWordAdd(PInv33, cc, z, 0);
+
+ Debug.Assert(c == 0 || c == 1);
+
+ if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+ {
+ Nat.Add33To(5, PInv33, z);
+ }
+ }
+
+ public static void Reduce32(uint x, uint[] z)
+ {
+ if ((x != 0 && Nat160.Mul33WordAdd(PInv33, x, z, 0) != 0)
+ || (z[4] == P4 && Nat160.Gte(z, P)))
+ {
+ Nat.Add33To(5, PInv33, z);
+ }
+ }
+
+ public static void Square(uint[] x, uint[] z)
+ {
+ uint[] tt = Nat160.CreateExt();
+ Nat160.Square(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareN(uint[] x, int n, uint[] z)
+ {
+ Debug.Assert(n > 0);
+
+ uint[] tt = Nat160.CreateExt();
+ Nat160.Square(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ Nat160.Square(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static void Subtract(uint[] x, uint[] y, uint[] z)
+ {
+ int c = Nat160.Sub(x, y, z);
+ if (c != 0)
+ {
+ Nat.Sub33From(5, PInv33, z);
+ }
+ }
+
+ public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ int c = Nat.Sub(10, xx, yy, zz);
+ if (c != 0)
+ {
+ if (Nat.SubFrom(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.DecAt(10, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void Twice(uint[] x, uint[] z)
+ {
+ uint c = Nat.ShiftUpBit(5, x, 0, z);
+ if (c != 0 || (z[4] == P4 && Nat160.Gte(z, P)))
+ {
+ Nat.Add33To(5, PInv33, z);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bdb5245b2e3c5c4cd107d6aa0ed6f02ee98c45f5
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs
@@ -0,0 +1,218 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160R2FieldElement
+ : ECFieldElement
+ {
+ public static readonly BigInteger Q = SecP160R2Curve.q;
+
+ protected internal readonly uint[] x;
+
+ public SecP160R2FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+ throw new ArgumentException("value invalid for SecP160R2FieldElement", "x");
+
+ this.x = SecP160R2Field.FromBigInteger(x);
+ }
+
+ public SecP160R2FieldElement()
+ {
+ this.x = Nat160.Create();
+ }
+
+ protected internal SecP160R2FieldElement(uint[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat160.IsZero(x); }
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat160.IsOne(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return Nat160.GetBit(x, 0) == 1;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat160.ToBigInteger(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecP160R2Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return Q.BitLength; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ uint[] z = Nat160.Create();
+ SecP160R2Field.Add(x, ((SecP160R2FieldElement)b).x, z);
+ return new SecP160R2FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ uint[] z = Nat160.Create();
+ SecP160R2Field.AddOne(x, z);
+ return new SecP160R2FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ uint[] z = Nat160.Create();
+ SecP160R2Field.Subtract(x, ((SecP160R2FieldElement)b).x, z);
+ return new SecP160R2FieldElement(z);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ uint[] z = Nat160.Create();
+ SecP160R2Field.Multiply(x, ((SecP160R2FieldElement)b).x, z);
+ return new SecP160R2FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ // return Multiply(b.invert());
+ uint[] z = Nat160.Create();
+ Mod.Invert(SecP160R2Field.P, ((SecP160R2FieldElement)b).x, z);
+ SecP160R2Field.Multiply(z, x, z);
+ return new SecP160R2FieldElement(z);
+ }
+
+ public override ECFieldElement Negate()
+ {
+ uint[] z = Nat160.Create();
+ SecP160R2Field.Negate(x, z);
+ return new SecP160R2FieldElement(z);
+ }
+
+ public override ECFieldElement Square()
+ {
+ uint[] z = Nat160.Create();
+ SecP160R2Field.Square(x, z);
+ return new SecP160R2FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ // return new SecP160R2FieldElement(ToBigInteger().modInverse(Q));
+ uint[] z = Nat160.Create();
+ Mod.Invert(SecP160R2Field.P, x, z);
+ return new SecP160R2FieldElement(z);
+ }
+
+ // D.1.4 91
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public override ECFieldElement Sqrt()
+ {
+ /*
+ * Raise this element to the exponent 2^158 - 2^30 - 2^12 - 2^10 - 2^7 - 2^6 - 2^5 - 2^1 - 2^0
+ *
+ * Breaking up the exponent's binary representation into "repunits", we get: { 127 1s } { 1
+ * 0s } { 17 1s } { 1 0s } { 1 1s } { 1 0s } { 2 1s } { 3 0s } { 3 1s } { 1 0s } { 1 1s }
+ *
+ * Therefore we need an Addition chain containing 1, 2, 3, 17, 127 (the lengths of the repunits)
+ * We use: [1], [2], [3], 4, 7, 14, [17], 31, 62, 124, [127]
+ */
+
+ uint[] x1 = this.x;
+ if (Nat160.IsZero(x1) || Nat160.IsOne(x1))
+ {
+ return this;
+ }
+
+ uint[] x2 = Nat160.Create();
+ SecP160R2Field.Square(x1, x2);
+ SecP160R2Field.Multiply(x2, x1, x2);
+ uint[] x3 = Nat160.Create();
+ SecP160R2Field.Square(x2, x3);
+ SecP160R2Field.Multiply(x3, x1, x3);
+ uint[] x4 = Nat160.Create();
+ SecP160R2Field.Square(x3, x4);
+ SecP160R2Field.Multiply(x4, x1, x4);
+ uint[] x7 = Nat160.Create();
+ SecP160R2Field.SquareN(x4, 3, x7);
+ SecP160R2Field.Multiply(x7, x3, x7);
+ uint[] x14 = x4;
+ SecP160R2Field.SquareN(x7, 7, x14);
+ SecP160R2Field.Multiply(x14, x7, x14);
+ uint[] x17 = x7;
+ SecP160R2Field.SquareN(x14, 3, x17);
+ SecP160R2Field.Multiply(x17, x3, x17);
+ uint[] x31 = Nat160.Create();
+ SecP160R2Field.SquareN(x17, 14, x31);
+ SecP160R2Field.Multiply(x31, x14, x31);
+ uint[] x62 = x14;
+ SecP160R2Field.SquareN(x31, 31, x62);
+ SecP160R2Field.Multiply(x62, x31, x62);
+ uint[] x124 = x31;
+ SecP160R2Field.SquareN(x62, 62, x124);
+ SecP160R2Field.Multiply(x124, x62, x124);
+ uint[] x127 = x62;
+ SecP160R2Field.SquareN(x124, 3, x127);
+ SecP160R2Field.Multiply(x127, x3, x127);
+
+ uint[] t1 = x127;
+ SecP160R2Field.SquareN(t1, 18, t1);
+ SecP160R2Field.Multiply(t1, x17, t1);
+ SecP160R2Field.SquareN(t1, 2, t1);
+ SecP160R2Field.Multiply(t1, x1, t1);
+ SecP160R2Field.SquareN(t1, 3, t1);
+ SecP160R2Field.Multiply(t1, x2, t1);
+ SecP160R2Field.SquareN(t1, 6, t1);
+ SecP160R2Field.Multiply(t1, x3, t1);
+ SecP160R2Field.SquareN(t1, 2, t1);
+ SecP160R2Field.Multiply(t1, x1, t1);
+
+ uint[] t2 = x2;
+ SecP160R2Field.Square(t1, t2);
+
+ return Nat160.Eq(x1, t2) ? new SecP160R2FieldElement(t1) : null;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecP160R2FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecP160R2FieldElement);
+ }
+
+ public virtual bool Equals(SecP160R2FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat160.Eq(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 5);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R2Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R2Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..343cf8c160bf3c1132ae2017ef2733222debe7a5
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP160R2Point.cs
@@ -0,0 +1,279 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP160R2Point
+ : AbstractFpPoint
+ {
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ *
+ * @deprecated Use ECCurve.CreatePoint to construct points
+ */
+ public SecP160R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ * @param withCompression
+ * if true encode with point compression
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(bool)}
+ */
+ public SecP160R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecP160R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecP160R2Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+ if (this == b)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ SecP160R2FieldElement X1 = (SecP160R2FieldElement)this.RawXCoord, Y1 = (SecP160R2FieldElement)this.RawYCoord;
+ SecP160R2FieldElement X2 = (SecP160R2FieldElement)b.RawXCoord, Y2 = (SecP160R2FieldElement)b.RawYCoord;
+
+ SecP160R2FieldElement Z1 = (SecP160R2FieldElement)this.RawZCoords[0];
+ SecP160R2FieldElement Z2 = (SecP160R2FieldElement)b.RawZCoords[0];
+
+ uint c;
+ uint[] tt1 = Nat160.CreateExt();
+ uint[] t2 = Nat160.Create();
+ uint[] t3 = Nat160.Create();
+ uint[] t4 = Nat160.Create();
+
+ bool Z1IsOne = Z1.IsOne;
+ uint[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SecP160R2Field.Square(Z1.x, S2);
+
+ U2 = t2;
+ SecP160R2Field.Multiply(S2, X2.x, U2);
+
+ SecP160R2Field.Multiply(S2, Z1.x, S2);
+ SecP160R2Field.Multiply(S2, Y2.x, S2);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ uint[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SecP160R2Field.Square(Z2.x, S1);
+
+ U1 = tt1;
+ SecP160R2Field.Multiply(S1, X1.x, U1);
+
+ SecP160R2Field.Multiply(S1, Z2.x, S1);
+ SecP160R2Field.Multiply(S1, Y1.x, S1);
+ }
+
+ uint[] H = Nat160.Create();
+ SecP160R2Field.Subtract(U1, U2, H);
+
+ uint[] R = t2;
+ SecP160R2Field.Subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat160.IsZero(H))
+ {
+ if (Nat160.IsZero(R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ uint[] HSquared = t3;
+ SecP160R2Field.Square(H, HSquared);
+
+ uint[] G = Nat160.Create();
+ SecP160R2Field.Multiply(HSquared, H, G);
+
+ uint[] V = t3;
+ SecP160R2Field.Multiply(HSquared, U1, V);
+
+ SecP160R2Field.Negate(G, G);
+ Nat160.Mul(S1, G, tt1);
+
+ c = Nat160.AddBothTo(V, V, G);
+ SecP160R2Field.Reduce32(c, G);
+
+ SecP160R2FieldElement X3 = new SecP160R2FieldElement(t4);
+ SecP160R2Field.Square(R, X3.x);
+ SecP160R2Field.Subtract(X3.x, G, X3.x);
+
+ SecP160R2FieldElement Y3 = new SecP160R2FieldElement(G);
+ SecP160R2Field.Subtract(V, X3.x, Y3.x);
+ SecP160R2Field.MultiplyAddToExt(Y3.x, R, tt1);
+ SecP160R2Field.Reduce(tt1, Y3.x);
+
+ SecP160R2FieldElement Z3 = new SecP160R2FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SecP160R2Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SecP160R2Field.Multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+ return new SecP160R2Point(curve, X3, Y3, zs, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ SecP160R2FieldElement Y1 = (SecP160R2FieldElement)this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ SecP160R2FieldElement X1 = (SecP160R2FieldElement)this.RawXCoord, Z1 = (SecP160R2FieldElement)this.RawZCoords[0];
+
+ uint c;
+ uint[] t1 = Nat160.Create();
+ uint[] t2 = Nat160.Create();
+
+ uint[] Y1Squared = Nat160.Create();
+ SecP160R2Field.Square(Y1.x, Y1Squared);
+
+ uint[] T = Nat160.Create();
+ SecP160R2Field.Square(Y1Squared, T);
+
+ bool Z1IsOne = Z1.IsOne;
+
+ uint[] Z1Squared = Z1.x;
+ if (!Z1IsOne)
+ {
+ Z1Squared = t2;
+ SecP160R2Field.Square(Z1.x, Z1Squared);
+ }
+
+ SecP160R2Field.Subtract(X1.x, Z1Squared, t1);
+
+ uint[] M = t2;
+ SecP160R2Field.Add(X1.x, Z1Squared, M);
+ SecP160R2Field.Multiply(M, t1, M);
+ c = Nat160.AddBothTo(M, M, M);
+ SecP160R2Field.Reduce32(c, M);
+
+ uint[] S = Y1Squared;
+ SecP160R2Field.Multiply(Y1Squared, X1.x, S);
+ c = Nat.ShiftUpBits(5, S, 2, 0);
+ SecP160R2Field.Reduce32(c, S);
+
+ c = Nat.ShiftUpBits(5, T, 3, 0, t1);
+ SecP160R2Field.Reduce32(c, t1);
+
+ SecP160R2FieldElement X3 = new SecP160R2FieldElement(T);
+ SecP160R2Field.Square(M, X3.x);
+ SecP160R2Field.Subtract(X3.x, S, X3.x);
+ SecP160R2Field.Subtract(X3.x, S, X3.x);
+
+ SecP160R2FieldElement Y3 = new SecP160R2FieldElement(S);
+ SecP160R2Field.Subtract(S, X3.x, Y3.x);
+ SecP160R2Field.Multiply(Y3.x, M, Y3.x);
+ SecP160R2Field.Subtract(Y3.x, t1, Y3.x);
+
+ SecP160R2FieldElement Z3 = new SecP160R2FieldElement(M);
+ SecP160R2Field.Twice(Y1.x, Z3.x);
+ if (!Z1IsOne)
+ {
+ SecP160R2Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SecP160R2Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this == b)
+ return ThreeTimes();
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return b;
+
+ return Twice().Add(b);
+ }
+
+ public override ECPoint ThreeTimes()
+ {
+ if (this.IsInfinity || this.RawYCoord.IsZero)
+ return this;
+
+ // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+ return Twice().Add(this);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ return new SecP160R2Point(Curve, this.RawXCoord, this.RawYCoord.Negate(), this.RawZCoords, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP192K1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP192K1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..81f77197e925c10f13a2cd4172e7b6088a9da3d8
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP192K1Curve.cs
@@ -0,0 +1,75 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP192K1Curve
+ : AbstractFpCurve
+ {
+ public static readonly BigInteger q = new BigInteger(1,
+ Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37"));
+
+ private const int SECP192K1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected readonly SecP192K1Point m_infinity;
+
+ public SecP192K1Curve()
+ : base(q)
+ {
+ this.m_infinity = new SecP192K1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.Zero);
+ this.m_b = FromBigInteger(BigInteger.ValueOf(3));
+ this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D"));
+ this.m_cofactor = BigInteger.One;
+ this.m_coord = SECP192K1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecP192K1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecP192K1FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecP192K1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecP192K1Point(this, x, y, zs, withCompression);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP192K1Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP192K1Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a00360360d434af7df376f4008c3035452ecbc6a
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP192K1Field.cs
@@ -0,0 +1,178 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP192K1Field
+ {
+ // 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1
+ internal static readonly uint[] P = new uint[]{ 0xFFFFEE37, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ internal static readonly uint[] PExt = new uint[]{ 0x013C4FD1, 0x00002392, 0x00000001, 0x00000000, 0x00000000,
+ 0x00000000, 0xFFFFDC6E, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ private static readonly uint[] PExtInv = new uint[]{ 0xFEC3B02F, 0xFFFFDC6D, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0x00002391, 0x00000002 };
+ private const uint P5 = 0xFFFFFFFF;
+ private const uint PExt11 = 0xFFFFFFFF;
+ private const uint PInv33 = 0x11C9;
+
+ public static void Add(uint[] x, uint[] y, uint[] z)
+ {
+ uint c = Nat192.Add(x, y, z);
+ if (c != 0 || (z[5] == P5 && Nat192.Gte(z, P)))
+ {
+ Nat.Add33To(6, PInv33, z);
+ }
+ }
+
+ public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ uint c = Nat.Add(12, xx, yy, zz);
+ if (c != 0 || (zz[11] == PExt11 && Nat.Gte(12, zz, PExt)))
+ {
+ if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.IncAt(12, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void AddOne(uint[] x, uint[] z)
+ {
+ uint c = Nat.Inc(6, x, z);
+ if (c != 0 || (z[5] == P5 && Nat192.Gte(z, P)))
+ {
+ Nat.Add33To(6, PInv33, z);
+ }
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ uint[] z = Nat192.FromBigInteger(x);
+ if (z[5] == P5 && Nat192.Gte(z, P))
+ {
+ Nat192.SubFrom(P, z);
+ }
+ return z;
+ }
+
+ public static void Half(uint[] x, uint[] z)
+ {
+ if ((x[0] & 1) == 0)
+ {
+ Nat.ShiftDownBit(6, x, 0, z);
+ }
+ else
+ {
+ uint c = Nat192.Add(x, P, z);
+ Nat.ShiftDownBit(6, z, c);
+ }
+ }
+
+ public static void Multiply(uint[] x, uint[] y, uint[] z)
+ {
+ uint[] tt = Nat192.CreateExt();
+ Nat192.Mul(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+ {
+ uint c = Nat192.MulAddTo(x, y, zz);
+ if (c != 0 || (zz[11] == PExt11 && Nat.Gte(12, zz, PExt)))
+ {
+ if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.IncAt(12, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void Negate(uint[] x, uint[] z)
+ {
+ if (Nat192.IsZero(x))
+ {
+ Nat192.Zero(z);
+ }
+ else
+ {
+ Nat192.Sub(P, x, z);
+ }
+ }
+
+ public static void Reduce(uint[] xx, uint[] z)
+ {
+ ulong cc = Nat192.Mul33Add(PInv33, xx, 6, xx, 0, z, 0);
+ uint c = Nat192.Mul33DWordAdd(PInv33, cc, z, 0);
+
+ Debug.Assert(c == 0 || c == 1);
+
+ if (c != 0 || (z[5] == P5 && Nat192.Gte(z, P)))
+ {
+ Nat.Add33To(6, PInv33, z);
+ }
+ }
+
+ public static void Reduce32(uint x, uint[] z)
+ {
+ if ((x != 0 && Nat192.Mul33WordAdd(PInv33, x, z, 0) != 0)
+ || (z[5] == P5 && Nat192.Gte(z, P)))
+ {
+ Nat.Add33To(6, PInv33, z);
+ }
+ }
+
+ public static void Square(uint[] x, uint[] z)
+ {
+ uint[] tt = Nat192.CreateExt();
+ Nat192.Square(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareN(uint[] x, int n, uint[] z)
+ {
+ Debug.Assert(n > 0);
+
+ uint[] tt = Nat192.CreateExt();
+ Nat192.Square(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ Nat192.Square(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static void Subtract(uint[] x, uint[] y, uint[] z)
+ {
+ int c = Nat192.Sub(x, y, z);
+ if (c != 0)
+ {
+ Nat.Sub33From(6, PInv33, z);
+ }
+ }
+
+ public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ int c = Nat.Sub(12, xx, yy, zz);
+ if (c != 0)
+ {
+ if (Nat.SubFrom(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.DecAt(12, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void Twice(uint[] x, uint[] z)
+ {
+ uint c = Nat.ShiftUpBit(6, x, 0, z);
+ if (c != 0 || (z[5] == P5 && Nat192.Gte(z, P)))
+ {
+ Nat.Add33To(6, PInv33, z);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..dce3770354e534283be0d18f722ce01860751c48
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs
@@ -0,0 +1,213 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP192K1FieldElement
+ : ECFieldElement
+ {
+ public static readonly BigInteger Q = SecP192K1Curve.q;
+
+ protected internal readonly uint[] x;
+
+ public SecP192K1FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+ throw new ArgumentException("value invalid for SecP192K1FieldElement", "x");
+
+ this.x = SecP192K1Field.FromBigInteger(x);
+ }
+
+ public SecP192K1FieldElement()
+ {
+ this.x = Nat192.Create();
+ }
+
+ protected internal SecP192K1FieldElement(uint[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat192.IsZero(x); }
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat192.IsOne(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return Nat192.GetBit(x, 0) == 1;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat192.ToBigInteger(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecP192K1Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return Q.BitLength; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ uint[] z = Nat192.Create();
+ SecP192K1Field.Add(x, ((SecP192K1FieldElement)b).x, z);
+ return new SecP192K1FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ uint[] z = Nat192.Create();
+ SecP192K1Field.AddOne(x, z);
+ return new SecP192K1FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ uint[] z = Nat192.Create();
+ SecP192K1Field.Subtract(x, ((SecP192K1FieldElement)b).x, z);
+ return new SecP192K1FieldElement(z);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ uint[] z = Nat192.Create();
+ SecP192K1Field.Multiply(x, ((SecP192K1FieldElement)b).x, z);
+ return new SecP192K1FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ //return Multiply(b.Invert());
+ uint[] z = Nat192.Create();
+ Mod.Invert(SecP192K1Field.P, ((SecP192K1FieldElement)b).x, z);
+ SecP192K1Field.Multiply(z, x, z);
+ return new SecP192K1FieldElement(z);
+ }
+
+ public override ECFieldElement Negate()
+ {
+ uint[] z = Nat192.Create();
+ SecP192K1Field.Negate(x, z);
+ return new SecP192K1FieldElement(z);
+ }
+
+ public override ECFieldElement Square()
+ {
+ uint[] z = Nat192.Create();
+ SecP192K1Field.Square(x, z);
+ return new SecP192K1FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ //return new SecP192K1FieldElement(ToBigInteger().ModInverse(Q));
+ uint[] z = Nat192.Create();
+ Mod.Invert(SecP192K1Field.P, x, z);
+ return new SecP192K1FieldElement(z);
+ }
+
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public override ECFieldElement Sqrt()
+ {
+ /*
+ * Raise this element to the exponent 2^190 - 2^30 - 2^10 - 2^6 - 2^5 - 2^4 - 2^1
+ *
+ * Breaking up the exponent's binary representation into "repunits", we get:
+ * { 159 1s } { 1 0s } { 19 1s } { 1 0s } { 3 1s } { 3 0s} { 3 1s } { 1 0s }
+ *
+ * Therefore we need an addition chain containing 3, 19, 159 (the lengths of the repunits)
+ * We use: 1, 2, [3], 6, 8, 16, [19], 35, 70, 140, [159]
+ */
+
+ uint[] x1 = this.x;
+ if (Nat192.IsZero(x1) || Nat192.IsOne(x1))
+ return this;
+
+ uint[] x2 = Nat192.Create();
+ SecP192K1Field.Square(x1, x2);
+ SecP192K1Field.Multiply(x2, x1, x2);
+ uint[] x3 = Nat192.Create();
+ SecP192K1Field.Square(x2, x3);
+ SecP192K1Field.Multiply(x3, x1, x3);
+ uint[] x6 = Nat192.Create();
+ SecP192K1Field.SquareN(x3, 3, x6);
+ SecP192K1Field.Multiply(x6, x3, x6);
+ uint[] x8 = x6;
+ SecP192K1Field.SquareN(x6, 2, x8);
+ SecP192K1Field.Multiply(x8, x2, x8);
+ uint[] x16 = x2;
+ SecP192K1Field.SquareN(x8, 8, x16);
+ SecP192K1Field.Multiply(x16, x8, x16);
+ uint[] x19 = x8;
+ SecP192K1Field.SquareN(x16, 3, x19);
+ SecP192K1Field.Multiply(x19, x3, x19);
+ uint[] x35 = Nat192.Create();
+ SecP192K1Field.SquareN(x19, 16, x35);
+ SecP192K1Field.Multiply(x35, x16, x35);
+ uint[] x70 = x16;
+ SecP192K1Field.SquareN(x35, 35, x70);
+ SecP192K1Field.Multiply(x70, x35, x70);
+ uint[] x140 = x35;
+ SecP192K1Field.SquareN(x70, 70, x140);
+ SecP192K1Field.Multiply(x140, x70, x140);
+ uint[] x159 = x70;
+ SecP192K1Field.SquareN(x140, 19, x159);
+ SecP192K1Field.Multiply(x159, x19, x159);
+
+ uint[] t1 = x159;
+ SecP192K1Field.SquareN(t1, 20, t1);
+ SecP192K1Field.Multiply(t1, x19, t1);
+ SecP192K1Field.SquareN(t1, 4, t1);
+ SecP192K1Field.Multiply(t1, x3, t1);
+ SecP192K1Field.SquareN(t1, 6, t1);
+ SecP192K1Field.Multiply(t1, x3, t1);
+ SecP192K1Field.Square(t1, t1);
+
+ uint[] t2 = x3;
+ SecP192K1Field.Square(t1, t2);
+
+ return Nat192.Eq(x1, t2) ? new SecP192K1FieldElement(t1) : null;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecP192K1FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecP192K1FieldElement);
+ }
+
+ public virtual bool Equals(SecP192K1FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat192.Eq(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 6);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP192K1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP192K1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..58eb09102f055a3f70b4fef80d21b51dbe3734eb
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP192K1Point.cs
@@ -0,0 +1,267 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP192K1Point
+ : AbstractFpPoint
+ {
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ *
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecP192K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ * @param withCompression
+ * if true encode with point compression
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(bool)}
+ */
+ public SecP192K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecP192K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs,
+ bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecP192K1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+ if (this == b)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ SecP192K1FieldElement X1 = (SecP192K1FieldElement)this.RawXCoord, Y1 = (SecP192K1FieldElement)this.RawYCoord;
+ SecP192K1FieldElement X2 = (SecP192K1FieldElement)b.RawXCoord, Y2 = (SecP192K1FieldElement)b.RawYCoord;
+
+ SecP192K1FieldElement Z1 = (SecP192K1FieldElement)this.RawZCoords[0];
+ SecP192K1FieldElement Z2 = (SecP192K1FieldElement)b.RawZCoords[0];
+
+ uint c;
+ uint[] tt1 = Nat192.CreateExt();
+ uint[] t2 = Nat192.Create();
+ uint[] t3 = Nat192.Create();
+ uint[] t4 = Nat192.Create();
+
+ bool Z1IsOne = Z1.IsOne;
+ uint[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SecP192K1Field.Square(Z1.x, S2);
+
+ U2 = t2;
+ SecP192K1Field.Multiply(S2, X2.x, U2);
+
+ SecP192K1Field.Multiply(S2, Z1.x, S2);
+ SecP192K1Field.Multiply(S2, Y2.x, S2);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ uint[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SecP192K1Field.Square(Z2.x, S1);
+
+ U1 = tt1;
+ SecP192K1Field.Multiply(S1, X1.x, U1);
+
+ SecP192K1Field.Multiply(S1, Z2.x, S1);
+ SecP192K1Field.Multiply(S1, Y1.x, S1);
+ }
+
+ uint[] H = Nat192.Create();
+ SecP192K1Field.Subtract(U1, U2, H);
+
+ uint[] R = t2;
+ SecP192K1Field.Subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat192.IsZero(H))
+ {
+ if (Nat192.IsZero(R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ uint[] HSquared = t3;
+ SecP192K1Field.Square(H, HSquared);
+
+ uint[] G = Nat192.Create();
+ SecP192K1Field.Multiply(HSquared, H, G);
+
+ uint[] V = t3;
+ SecP192K1Field.Multiply(HSquared, U1, V);
+
+ SecP192K1Field.Negate(G, G);
+ Nat192.Mul(S1, G, tt1);
+
+ c = Nat192.AddBothTo(V, V, G);
+ SecP192K1Field.Reduce32(c, G);
+
+ SecP192K1FieldElement X3 = new SecP192K1FieldElement(t4);
+ SecP192K1Field.Square(R, X3.x);
+ SecP192K1Field.Subtract(X3.x, G, X3.x);
+
+ SecP192K1FieldElement Y3 = new SecP192K1FieldElement(G);
+ SecP192K1Field.Subtract(V, X3.x, Y3.x);
+ SecP192K1Field.MultiplyAddToExt(Y3.x, R, tt1);
+ SecP192K1Field.Reduce(tt1, Y3.x);
+
+ SecP192K1FieldElement Z3 = new SecP192K1FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SecP192K1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SecP192K1Field.Multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+ return new SecP192K1Point(curve, X3, Y3, zs, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ SecP192K1FieldElement Y1 = (SecP192K1FieldElement)this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ SecP192K1FieldElement X1 = (SecP192K1FieldElement)this.RawXCoord, Z1 = (SecP192K1FieldElement)this.RawZCoords[0];
+
+ uint c;
+
+ uint[] Y1Squared = Nat192.Create();
+ SecP192K1Field.Square(Y1.x, Y1Squared);
+
+ uint[] T = Nat192.Create();
+ SecP192K1Field.Square(Y1Squared, T);
+
+ uint[] M = Nat192.Create();
+ SecP192K1Field.Square(X1.x, M);
+ c = Nat192.AddBothTo(M, M, M);
+ SecP192K1Field.Reduce32(c, M);
+
+ uint[] S = Y1Squared;
+ SecP192K1Field.Multiply(Y1Squared, X1.x, S);
+ c = Nat.ShiftUpBits(6, S, 2, 0);
+ SecP192K1Field.Reduce32(c, S);
+
+ uint[] t1 = Nat192.Create();
+ c = Nat.ShiftUpBits(6, T, 3, 0, t1);
+ SecP192K1Field.Reduce32(c, t1);
+
+ SecP192K1FieldElement X3 = new SecP192K1FieldElement(T);
+ SecP192K1Field.Square(M, X3.x);
+ SecP192K1Field.Subtract(X3.x, S, X3.x);
+ SecP192K1Field.Subtract(X3.x, S, X3.x);
+
+ SecP192K1FieldElement Y3 = new SecP192K1FieldElement(S);
+ SecP192K1Field.Subtract(S, X3.x, Y3.x);
+ SecP192K1Field.Multiply(Y3.x, M, Y3.x);
+ SecP192K1Field.Subtract(Y3.x, t1, Y3.x);
+
+ SecP192K1FieldElement Z3 = new SecP192K1FieldElement(M);
+ SecP192K1Field.Twice(Y1.x, Z3.x);
+ if (!Z1.IsOne)
+ {
+ SecP192K1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SecP192K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this == b)
+ return ThreeTimes();
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return b;
+
+ return Twice().Add(b);
+ }
+
+ public override ECPoint ThreeTimes()
+ {
+ if (this.IsInfinity || this.RawYCoord.IsZero)
+ return this;
+
+ // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+ return Twice().Add(this);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ return new SecP192K1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP192R1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP192R1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cb3a981c87d28d689ddcab4aebffccef9777422e
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP192R1Curve.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP192R1Curve
+ : AbstractFpCurve
+ {
+ public static readonly BigInteger q = new BigInteger(1,
+ Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"));
+
+ private const int SecP192R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected readonly SecP192R1Point m_infinity;
+
+ public SecP192R1Curve()
+ : base(q)
+ {
+ this.m_infinity = new SecP192R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1,
+ Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC")));
+ this.m_b = FromBigInteger(new BigInteger(1,
+ Hex.Decode("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1")));
+ this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831"));
+ this.m_cofactor = BigInteger.One;
+
+ this.m_coord = SecP192R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecP192R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecP192R1FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecP192R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecP192R1Point(this, x, y, zs, withCompression);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP192R1Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP192R1Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..096c2b51f782300314f6e7631bf575a547096525
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP192R1Field.cs
@@ -0,0 +1,283 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP192R1Field
+ {
+ // 2^192 - 2^64 - 1
+ internal static readonly uint[] P = new uint[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ internal static readonly uint[] PExt = new uint[]{ 0x00000001, 0x00000000, 0x00000002, 0x00000000, 0x00000001,
+ 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ private static readonly uint[] PExtInv = new uint[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFE,
+ 0xFFFFFFFF, 0x00000001, 0x00000000, 0x00000002 };
+ private const uint P5 = 0xFFFFFFFF;
+ private const uint PExt11 = 0xFFFFFFFF;
+
+ public static void Add(uint[] x, uint[] y, uint[] z)
+ {
+ uint c = Nat192.Add(x, y, z);
+ if (c != 0 || (z[5] == P5 && Nat192.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ uint c = Nat.Add(12, xx, yy, zz);
+ if (c != 0 || (zz[11] == PExt11 && Nat.Gte(12, zz, PExt)))
+ {
+ if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.IncAt(12, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void AddOne(uint[] x, uint[] z)
+ {
+ uint c = Nat.Inc(6, x, z);
+ if (c != 0 || (z[5] == P5 && Nat192.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ uint[] z = Nat192.FromBigInteger(x);
+ if (z[5] == P5 && Nat192.Gte(z, P))
+ {
+ Nat192.SubFrom(P, z);
+ }
+ return z;
+ }
+
+ public static void Half(uint[] x, uint[] z)
+ {
+ if ((x[0] & 1) == 0)
+ {
+ Nat.ShiftDownBit(6, x, 0, z);
+ }
+ else
+ {
+ uint c = Nat192.Add(x, P, z);
+ Nat.ShiftDownBit(6, z, c);
+ }
+ }
+
+ public static void Multiply(uint[] x, uint[] y, uint[] z)
+ {
+ uint[] tt = Nat192.CreateExt();
+ Nat192.Mul(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+ {
+ uint c = Nat192.MulAddTo(x, y, zz);
+ if (c != 0 || (zz[11] == PExt11 && Nat.Gte(12, zz, PExt)))
+ {
+ if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.IncAt(12, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void Negate(uint[] x, uint[] z)
+ {
+ if (Nat192.IsZero(x))
+ {
+ Nat192.Zero(z);
+ }
+ else
+ {
+ Nat192.Sub(P, x, z);
+ }
+ }
+
+ public static void Reduce(uint[] xx, uint[] z)
+ {
+ ulong xx06 = xx[6], xx07 = xx[7], xx08 = xx[8];
+ ulong xx09 = xx[9], xx10 = xx[10], xx11 = xx[11];
+
+ ulong t0 = xx06 + xx10;
+ ulong t1 = xx07 + xx11;
+
+ ulong cc = 0;
+ cc += (ulong)xx[0] + t0;
+ uint z0 = (uint)cc;
+ cc >>= 32;
+ cc += (ulong)xx[1] + t1;
+ z[1] = (uint)cc;
+ cc >>= 32;
+
+ t0 += xx08;
+ t1 += xx09;
+
+ cc += (ulong)xx[2] + t0;
+ ulong z2 = (uint)cc;
+ cc >>= 32;
+ cc += (ulong)xx[3] + t1;
+ z[3] = (uint)cc;
+ cc >>= 32;
+
+ t0 -= xx06;
+ t1 -= xx07;
+
+ cc += (ulong)xx[4] + t0;
+ z[4] = (uint)cc;
+ cc >>= 32;
+ cc += (ulong)xx[5] + t1;
+ z[5] = (uint)cc;
+ cc >>= 32;
+
+ z2 += cc;
+
+ cc += z0;
+ z[0] = (uint)cc;
+ cc >>= 32;
+ if (cc != 0)
+ {
+ cc += z[1];
+ z[1] = (uint)cc;
+ z2 += cc >> 32;
+ }
+ z[2] = (uint)z2;
+ cc = z2 >> 32;
+
+ Debug.Assert(cc == 0 || cc == 1);
+
+ if ((cc != 0 && Nat.IncAt(6, z, 3) != 0)
+ || (z[5] == P5 && Nat192.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static void Reduce32(uint x, uint[] z)
+ {
+ ulong cc = 0;
+
+ if (x != 0)
+ {
+ cc += (ulong)z[0] + x;
+ z[0] = (uint)cc;
+ cc >>= 32;
+ if (cc != 0)
+ {
+ cc += (ulong)z[1];
+ z[1] = (uint)cc;
+ cc >>= 32;
+ }
+ cc += (ulong)z[2] + x;
+ z[2] = (uint)cc;
+ cc >>= 32;
+
+ Debug.Assert(cc == 0 || cc == 1);
+ }
+
+ if ((cc != 0 && Nat.IncAt(6, z, 3) != 0)
+ || (z[5] == P5 && Nat192.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static void Square(uint[] x, uint[] z)
+ {
+ uint[] tt = Nat192.CreateExt();
+ Nat192.Square(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareN(uint[] x, int n, uint[] z)
+ {
+ Debug.Assert(n > 0);
+
+ uint[] tt = Nat192.CreateExt();
+ Nat192.Square(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ Nat192.Square(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static void Subtract(uint[] x, uint[] y, uint[] z)
+ {
+ int c = Nat192.Sub(x, y, z);
+ if (c != 0)
+ {
+ SubPInvFrom(z);
+ }
+ }
+
+ public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ int c = Nat.Sub(12, xx, yy, zz);
+ if (c != 0)
+ {
+ if (Nat.SubFrom(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.DecAt(12, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void Twice(uint[] x, uint[] z)
+ {
+ uint c = Nat.ShiftUpBit(6, x, 0, z);
+ if (c != 0 || (z[5] == P5 && Nat192.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ private static void AddPInvTo(uint[] z)
+ {
+ long c = (long)z[0] + 1;
+ z[0] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (long)z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ }
+ c += (long)z[2] + 1;
+ z[2] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ Nat.IncAt(6, z, 3);
+ }
+ }
+
+ private static void SubPInvFrom(uint[] z)
+ {
+ long c = (long)z[0] - 1;
+ z[0] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (long)z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ }
+ c += (long)z[2] - 1;
+ z[2] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ Nat.DecAt(6, z, 3);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..45bcb00f0a3870f3f3a1359e1084836ebf77ad49
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs
@@ -0,0 +1,188 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP192R1FieldElement
+ : ECFieldElement
+ {
+ public static readonly BigInteger Q = SecP192R1Curve.q;
+
+ protected internal readonly uint[] x;
+
+ public SecP192R1FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+ throw new ArgumentException("value invalid for SecP192R1FieldElement", "x");
+
+ this.x = SecP192R1Field.FromBigInteger(x);
+ }
+
+ public SecP192R1FieldElement()
+ {
+ this.x = Nat192.Create();
+ }
+
+ protected internal SecP192R1FieldElement(uint[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat192.IsZero(x); }
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat192.IsOne(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return Nat192.GetBit(x, 0) == 1;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat192.ToBigInteger(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecP192R1Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return Q.BitLength; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ uint[] z = Nat192.Create();
+ SecP192R1Field.Add(x, ((SecP192R1FieldElement)b).x, z);
+ return new SecP192R1FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ uint[] z = Nat192.Create();
+ SecP192R1Field.AddOne(x, z);
+ return new SecP192R1FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ uint[] z = Nat192.Create();
+ SecP192R1Field.Subtract(x, ((SecP192R1FieldElement)b).x, z);
+ return new SecP192R1FieldElement(z);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ uint[] z = Nat192.Create();
+ SecP192R1Field.Multiply(x, ((SecP192R1FieldElement)b).x, z);
+ return new SecP192R1FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ //return Multiply(b.Invert());
+ uint[] z = Nat192.Create();
+ Mod.Invert(SecP192R1Field.P, ((SecP192R1FieldElement)b).x, z);
+ SecP192R1Field.Multiply(z, x, z);
+ return new SecP192R1FieldElement(z);
+ }
+
+ public override ECFieldElement Negate()
+ {
+ uint[] z = Nat192.Create();
+ SecP192R1Field.Negate(x, z);
+ return new SecP192R1FieldElement(z);
+ }
+
+ public override ECFieldElement Square()
+ {
+ uint[] z = Nat192.Create();
+ SecP192R1Field.Square(x, z);
+ return new SecP192R1FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ //return new SecP192R1FieldElement(ToBigInteger().ModInverse(Q));
+ uint[] z = Nat192.Create();
+ Mod.Invert(SecP192R1Field.P, x, z);
+ return new SecP192R1FieldElement(z);
+ }
+
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public override ECFieldElement Sqrt()
+ {
+ // Raise this element to the exponent 2^190 - 2^62
+
+ uint[] x1 = this.x;
+ if (Nat192.IsZero(x1) || Nat192.IsOne(x1))
+ return this;
+
+ uint[] t1 = Nat192.Create();
+ uint[] t2 = Nat192.Create();
+
+ SecP192R1Field.Square(x1, t1);
+ SecP192R1Field.Multiply(t1, x1, t1);
+
+ SecP192R1Field.SquareN(t1, 2, t2);
+ SecP192R1Field.Multiply(t2, t1, t2);
+
+ SecP192R1Field.SquareN(t2, 4, t1);
+ SecP192R1Field.Multiply(t1, t2, t1);
+
+ SecP192R1Field.SquareN(t1, 8, t2);
+ SecP192R1Field.Multiply(t2, t1, t2);
+
+ SecP192R1Field.SquareN(t2, 16, t1);
+ SecP192R1Field.Multiply(t1, t2, t1);
+
+ SecP192R1Field.SquareN(t1, 32, t2);
+ SecP192R1Field.Multiply(t2, t1, t2);
+
+ SecP192R1Field.SquareN(t2, 64, t1);
+ SecP192R1Field.Multiply(t1, t2, t1);
+
+ SecP192R1Field.SquareN(t1, 62, t1);
+ SecP192R1Field.Square(t1, t2);
+
+ return Nat192.Eq(x1, t2) ? new SecP192R1FieldElement(t1) : null;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecP192R1FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecP192R1FieldElement);
+ }
+
+ public virtual bool Equals(SecP192R1FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat192.Eq(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 6);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP192R1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP192R1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3b53e341e72db46e2b508ec7bcd3796c924b5968
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP192R1Point.cs
@@ -0,0 +1,279 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP192R1Point
+ : AbstractFpPoint
+ {
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ *
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ * @param withCompression
+ * if true encode with point compression
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(bool)}
+ */
+ public SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecP192R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+ if (this == b)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ SecP192R1FieldElement X1 = (SecP192R1FieldElement)this.RawXCoord, Y1 = (SecP192R1FieldElement)this.RawYCoord;
+ SecP192R1FieldElement X2 = (SecP192R1FieldElement)b.RawXCoord, Y2 = (SecP192R1FieldElement)b.RawYCoord;
+
+ SecP192R1FieldElement Z1 = (SecP192R1FieldElement)this.RawZCoords[0];
+ SecP192R1FieldElement Z2 = (SecP192R1FieldElement)b.RawZCoords[0];
+
+ uint c;
+ uint[] tt1 = Nat192.CreateExt();
+ uint[] t2 = Nat192.Create();
+ uint[] t3 = Nat192.Create();
+ uint[] t4 = Nat192.Create();
+
+ bool Z1IsOne = Z1.IsOne;
+ uint[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SecP192R1Field.Square(Z1.x, S2);
+
+ U2 = t2;
+ SecP192R1Field.Multiply(S2, X2.x, U2);
+
+ SecP192R1Field.Multiply(S2, Z1.x, S2);
+ SecP192R1Field.Multiply(S2, Y2.x, S2);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ uint[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SecP192R1Field.Square(Z2.x, S1);
+
+ U1 = tt1;
+ SecP192R1Field.Multiply(S1, X1.x, U1);
+
+ SecP192R1Field.Multiply(S1, Z2.x, S1);
+ SecP192R1Field.Multiply(S1, Y1.x, S1);
+ }
+
+ uint[] H = Nat192.Create();
+ SecP192R1Field.Subtract(U1, U2, H);
+
+ uint[] R = t2;
+ SecP192R1Field.Subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat192.IsZero(H))
+ {
+ if (Nat192.IsZero(R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ uint[] HSquared = t3;
+ SecP192R1Field.Square(H, HSquared);
+
+ uint[] G = Nat192.Create();
+ SecP192R1Field.Multiply(HSquared, H, G);
+
+ uint[] V = t3;
+ SecP192R1Field.Multiply(HSquared, U1, V);
+
+ SecP192R1Field.Negate(G, G);
+ Nat192.Mul(S1, G, tt1);
+
+ c = Nat192.AddBothTo(V, V, G);
+ SecP192R1Field.Reduce32(c, G);
+
+ SecP192R1FieldElement X3 = new SecP192R1FieldElement(t4);
+ SecP192R1Field.Square(R, X3.x);
+ SecP192R1Field.Subtract(X3.x, G, X3.x);
+
+ SecP192R1FieldElement Y3 = new SecP192R1FieldElement(G);
+ SecP192R1Field.Subtract(V, X3.x, Y3.x);
+ SecP192R1Field.MultiplyAddToExt(Y3.x, R, tt1);
+ SecP192R1Field.Reduce(tt1, Y3.x);
+
+ SecP192R1FieldElement Z3 = new SecP192R1FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SecP192R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SecP192R1Field.Multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+ return new SecP192R1Point(curve, X3, Y3, zs, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ SecP192R1FieldElement Y1 = (SecP192R1FieldElement)this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ SecP192R1FieldElement X1 = (SecP192R1FieldElement)this.RawXCoord, Z1 = (SecP192R1FieldElement)this.RawZCoords[0];
+
+ uint c;
+ uint[] t1 = Nat192.Create();
+ uint[] t2 = Nat192.Create();
+
+ uint[] Y1Squared = Nat192.Create();
+ SecP192R1Field.Square(Y1.x, Y1Squared);
+
+ uint[] T = Nat192.Create();
+ SecP192R1Field.Square(Y1Squared, T);
+
+ bool Z1IsOne = Z1.IsOne;
+
+ uint[] Z1Squared = Z1.x;
+ if (!Z1IsOne)
+ {
+ Z1Squared = t2;
+ SecP192R1Field.Square(Z1.x, Z1Squared);
+ }
+
+ SecP192R1Field.Subtract(X1.x, Z1Squared, t1);
+
+ uint[] M = t2;
+ SecP192R1Field.Add(X1.x, Z1Squared, M);
+ SecP192R1Field.Multiply(M, t1, M);
+ c = Nat192.AddBothTo(M, M, M);
+ SecP192R1Field.Reduce32(c, M);
+
+ uint[] S = Y1Squared;
+ SecP192R1Field.Multiply(Y1Squared, X1.x, S);
+ c = Nat.ShiftUpBits(6, S, 2, 0);
+ SecP192R1Field.Reduce32(c, S);
+
+ c = Nat.ShiftUpBits(6, T, 3, 0, t1);
+ SecP192R1Field.Reduce32(c, t1);
+
+ SecP192R1FieldElement X3 = new SecP192R1FieldElement(T);
+ SecP192R1Field.Square(M, X3.x);
+ SecP192R1Field.Subtract(X3.x, S, X3.x);
+ SecP192R1Field.Subtract(X3.x, S, X3.x);
+
+ SecP192R1FieldElement Y3 = new SecP192R1FieldElement(S);
+ SecP192R1Field.Subtract(S, X3.x, Y3.x);
+ SecP192R1Field.Multiply(Y3.x, M, Y3.x);
+ SecP192R1Field.Subtract(Y3.x, t1, Y3.x);
+
+ SecP192R1FieldElement Z3 = new SecP192R1FieldElement(M);
+ SecP192R1Field.Twice(Y1.x, Z3.x);
+ if (!Z1IsOne)
+ {
+ SecP192R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SecP192R1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this == b)
+ return ThreeTimes();
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return b;
+
+ return Twice().Add(b);
+ }
+
+ public override ECPoint ThreeTimes()
+ {
+ if (this.IsInfinity || this.RawYCoord.IsZero)
+ return this;
+
+ // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+ return Twice().Add(this);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ return new SecP192R1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP224K1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP224K1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d4be7d8de0b892152012dc39dee883db9f6a02f8
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP224K1Curve.cs
@@ -0,0 +1,75 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP224K1Curve
+ : AbstractFpCurve
+ {
+ public static readonly BigInteger q = new BigInteger(1,
+ Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D"));
+
+ private const int SECP224K1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected readonly SecP224K1Point m_infinity;
+
+ public SecP224K1Curve()
+ : base(q)
+ {
+ this.m_infinity = new SecP224K1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.Zero);
+ this.m_b = FromBigInteger(BigInteger.ValueOf(5));
+ this.m_order = new BigInteger(1, Hex.Decode("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7"));
+ this.m_cofactor = BigInteger.One;
+ this.m_coord = SECP224K1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecP224K1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecP224K1FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecP224K1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecP224K1Point(this, x, y, zs, withCompression);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP224K1Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP224K1Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..98cf777a55c7805203084db0319600c3333ba4af
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP224K1Field.cs
@@ -0,0 +1,179 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP224K1Field
+ {
+ // 2^224 - 2^32 - 2^12 - 2^11 - 2^9 - 2^7 - 2^4 - 2 - 1
+ internal static readonly uint[] P = new uint[]{ 0xFFFFE56D, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF };
+ internal static readonly uint[] PExt = new uint[]{ 0x02C23069, 0x00003526, 0x00000001, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xFFFFCADA, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ private static readonly uint[] PExtInv = new uint[]{ 0xFD3DCF97, 0xFFFFCAD9, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0x00003525, 0x00000002 };
+ private const uint P6 = 0xFFFFFFFF;
+ private const uint PExt13 = 0xFFFFFFFF;
+ private const uint PInv33 = 0x1A93;
+
+ public static void Add(uint[] x, uint[] y, uint[] z)
+ {
+ uint c = Nat224.Add(x, y, z);
+ if (c != 0 || (z[6] == P6 && Nat224.Gte(z, P)))
+ {
+ Nat.Add33To(7, PInv33, z);
+ }
+ }
+
+ public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ uint c = Nat.Add(14, xx, yy, zz);
+ if (c != 0 || (zz[13] == PExt13 && Nat.Gte(14, zz, PExt)))
+ {
+ if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.IncAt(14, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void AddOne(uint[] x, uint[] z)
+ {
+ uint c = Nat.Inc(7, x, z);
+ if (c != 0 || (z[6] == P6 && Nat224.Gte(z, P)))
+ {
+ Nat.Add33To(7, PInv33, z);
+ }
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ uint[] z = Nat224.FromBigInteger(x);
+ if (z[6] == P6 && Nat224.Gte(z, P))
+ {
+ Nat224.SubFrom(P, z);
+ }
+ return z;
+ }
+
+ public static void Half(uint[] x, uint[] z)
+ {
+ if ((x[0] & 1) == 0)
+ {
+ Nat.ShiftDownBit(7, x, 0, z);
+ }
+ else
+ {
+ uint c = Nat224.Add(x, P, z);
+ Nat.ShiftDownBit(7, z, c);
+ }
+ }
+
+ public static void Multiply(uint[] x, uint[] y, uint[] z)
+ {
+ uint[] tt = Nat224.CreateExt();
+ Nat224.Mul(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+ {
+ uint c = Nat224.MulAddTo(x, y, zz);
+ if (c != 0 || (zz[13] == PExt13 && Nat.Gte(14, zz, PExt)))
+ {
+ if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.IncAt(14, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void Negate(uint[] x, uint[] z)
+ {
+ if (Nat224.IsZero(x))
+ {
+ Nat224.Zero(z);
+ }
+ else
+ {
+ Nat224.Sub(P, x, z);
+ }
+ }
+
+ public static void Reduce(uint[] xx, uint[] z)
+ {
+ ulong cc = Nat224.Mul33Add(PInv33, xx, 7, xx, 0, z, 0);
+ uint c = Nat224.Mul33DWordAdd(PInv33, cc, z, 0);
+
+ Debug.Assert(c == 0 || c == 1);
+
+ if (c != 0 || (z[6] == P6 && Nat224.Gte(z, P)))
+ {
+ Nat.Add33To(7, PInv33, z);
+ }
+ }
+
+ public static void Reduce32(uint x, uint[] z)
+ {
+ if ((x != 0 && Nat224.Mul33WordAdd(PInv33, x, z, 0) != 0)
+ || (z[6] == P6 && Nat224.Gte(z, P)))
+ {
+ Nat.Add33To(7, PInv33, z);
+ }
+ }
+
+ public static void Square(uint[] x, uint[] z)
+ {
+ uint[] tt = Nat224.CreateExt();
+ Nat224.Square(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareN(uint[] x, int n, uint[] z)
+ {
+ Debug.Assert(n > 0);
+
+ uint[] tt = Nat224.CreateExt();
+ Nat224.Square(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ Nat224.Square(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static void Subtract(uint[] x, uint[] y, uint[] z)
+ {
+ int c = Nat224.Sub(x, y, z);
+ if (c != 0)
+ {
+ Nat.Sub33From(7, PInv33, z);
+ }
+ }
+
+ public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ int c = Nat.Sub(14, xx, yy, zz);
+ if (c != 0)
+ {
+ if (Nat.SubFrom(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.DecAt(14, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void Twice(uint[] x, uint[] z)
+ {
+ uint c = Nat.ShiftUpBit(7, x, 0, z);
+ if (c != 0 || (z[6] == P6 && Nat224.Gte(z, P)))
+ {
+ Nat.Add33To(7, PInv33, z);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fec07436a6280e7121d282aec03c96a186ab8091
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs
@@ -0,0 +1,242 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP224K1FieldElement
+ : ECFieldElement
+ {
+ public static readonly BigInteger Q = SecP224K1Curve.q;
+
+ // Calculated as BigInteger.Two.ModPow(Q.ShiftRight(2), Q)
+ private static readonly uint[] PRECOMP_POW2 = new uint[]{ 0x33bfd202, 0xdcfad133, 0x2287624a, 0xc3811ba8,
+ 0xa85558fc, 0x1eaef5d7, 0x8edf154c };
+
+ protected internal readonly uint[] x;
+
+ public SecP224K1FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+ throw new ArgumentException("value invalid for SecP224K1FieldElement", "x");
+
+ this.x = SecP224K1Field.FromBigInteger(x);
+ }
+
+ public SecP224K1FieldElement()
+ {
+ this.x = Nat224.Create();
+ }
+
+ protected internal SecP224K1FieldElement(uint[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat224.IsZero(x); }
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat224.IsOne(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return Nat224.GetBit(x, 0) == 1;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat224.ToBigInteger(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecP224K1Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return Q.BitLength; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ uint[] z = Nat224.Create();
+ SecP224K1Field.Add(x, ((SecP224K1FieldElement)b).x, z);
+ return new SecP224K1FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ uint[] z = Nat224.Create();
+ SecP224K1Field.AddOne(x, z);
+ return new SecP224K1FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ uint[] z = Nat224.Create();
+ SecP224K1Field.Subtract(x, ((SecP224K1FieldElement)b).x, z);
+ return new SecP224K1FieldElement(z);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ uint[] z = Nat224.Create();
+ SecP224K1Field.Multiply(x, ((SecP224K1FieldElement)b).x, z);
+ return new SecP224K1FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ //return Multiply(b.Invert());
+ uint[] z = Nat224.Create();
+ Mod.Invert(SecP224K1Field.P, ((SecP224K1FieldElement)b).x, z);
+ SecP224K1Field.Multiply(z, x, z);
+ return new SecP224K1FieldElement(z);
+ }
+
+ public override ECFieldElement Negate()
+ {
+ uint[] z = Nat224.Create();
+ SecP224K1Field.Negate(x, z);
+ return new SecP224K1FieldElement(z);
+ }
+
+ public override ECFieldElement Square()
+ {
+ uint[] z = Nat224.Create();
+ SecP224K1Field.Square(x, z);
+ return new SecP224K1FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ //return new SecP224K1FieldElement(ToBigInteger().ModInverse(Q));
+ uint[] z = Nat224.Create();
+ Mod.Invert(SecP224K1Field.P, x, z);
+ return new SecP224K1FieldElement(z);
+ }
+
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public override ECFieldElement Sqrt()
+ {
+ /*
+ * Q == 8m + 5, so we use Pocklington's method for this case.
+ *
+ * First, raise this element to the exponent 2^221 - 2^29 - 2^9 - 2^8 - 2^6 - 2^4 - 2^1 (i.e. m + 1)
+ *
+ * Breaking up the exponent's binary representation into "repunits", we get:
+ * { 191 1s } { 1 0s } { 19 1s } { 2 0s } { 1 1s } { 1 0s} { 1 1s } { 1 0s} { 3 1s } { 1 0s}
+ *
+ * Therefore we need an addition chain containing 1, 3, 19, 191 (the lengths of the repunits)
+ * We use: [1], 2, [3], 4, 8, 11, [19], 23, 42, 84, 107, [191]
+ */
+
+ uint[] x1 = this.x;
+ if (Nat224.IsZero(x1) || Nat224.IsOne(x1))
+ return this;
+
+ uint[] x2 = Nat224.Create();
+ SecP224K1Field.Square(x1, x2);
+ SecP224K1Field.Multiply(x2, x1, x2);
+ uint[] x3 = x2;
+ SecP224K1Field.Square(x2, x3);
+ SecP224K1Field.Multiply(x3, x1, x3);
+ uint[] x4 = Nat224.Create();
+ SecP224K1Field.Square(x3, x4);
+ SecP224K1Field.Multiply(x4, x1, x4);
+ uint[] x8 = Nat224.Create();
+ SecP224K1Field.SquareN(x4, 4, x8);
+ SecP224K1Field.Multiply(x8, x4, x8);
+ uint[] x11 = Nat224.Create();
+ SecP224K1Field.SquareN(x8, 3, x11);
+ SecP224K1Field.Multiply(x11, x3, x11);
+ uint[] x19 = x11;
+ SecP224K1Field.SquareN(x11, 8, x19);
+ SecP224K1Field.Multiply(x19, x8, x19);
+ uint[] x23 = x8;
+ SecP224K1Field.SquareN(x19, 4, x23);
+ SecP224K1Field.Multiply(x23, x4, x23);
+ uint[] x42 = x4;
+ SecP224K1Field.SquareN(x23, 19, x42);
+ SecP224K1Field.Multiply(x42, x19, x42);
+ uint[] x84 = Nat224.Create();
+ SecP224K1Field.SquareN(x42, 42, x84);
+ SecP224K1Field.Multiply(x84, x42, x84);
+ uint[] x107 = x42;
+ SecP224K1Field.SquareN(x84, 23, x107);
+ SecP224K1Field.Multiply(x107, x23, x107);
+ uint[] x191 = x23;
+ SecP224K1Field.SquareN(x107, 84, x191);
+ SecP224K1Field.Multiply(x191, x84, x191);
+
+ uint[] t1 = x191;
+ SecP224K1Field.SquareN(t1, 20, t1);
+ SecP224K1Field.Multiply(t1, x19, t1);
+ SecP224K1Field.SquareN(t1, 3, t1);
+ SecP224K1Field.Multiply(t1, x1, t1);
+ SecP224K1Field.SquareN(t1, 2, t1);
+ SecP224K1Field.Multiply(t1, x1, t1);
+ SecP224K1Field.SquareN(t1, 4, t1);
+ SecP224K1Field.Multiply(t1, x3, t1);
+ SecP224K1Field.Square(t1, t1);
+
+ uint[] t2 = x84;
+ SecP224K1Field.Square(t1, t2);
+
+ if (Nat224.Eq(x1, t2))
+ {
+ return new SecP224K1FieldElement(t1);
+ }
+
+ /*
+ * If the first guess is incorrect, we multiply by a precomputed power of 2 to get the second guess,
+ * which is ((4x)^(m + 1))/2 mod Q
+ */
+ SecP224K1Field.Multiply(t1, PRECOMP_POW2, t1);
+
+ SecP224K1Field.Square(t1, t2);
+
+ if (Nat224.Eq(x1, t2))
+ {
+ return new SecP224K1FieldElement(t1);
+ }
+
+ return null;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecP224K1FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecP224K1FieldElement);
+ }
+
+ public virtual bool Equals(SecP224K1FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat224.Eq(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 7);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP224K1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP224K1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..98cb292745d4cdae735bfa47c7900f60b1916f26
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP224K1Point.cs
@@ -0,0 +1,267 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP224K1Point
+ : AbstractFpPoint
+ {
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ *
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ * @param withCompression
+ * if true encode with point compression
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(bool)}
+ */
+ public SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs,
+ bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecP224K1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+ if (this == b)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ SecP224K1FieldElement X1 = (SecP224K1FieldElement)this.RawXCoord, Y1 = (SecP224K1FieldElement)this.RawYCoord;
+ SecP224K1FieldElement X2 = (SecP224K1FieldElement)b.RawXCoord, Y2 = (SecP224K1FieldElement)b.RawYCoord;
+
+ SecP224K1FieldElement Z1 = (SecP224K1FieldElement)this.RawZCoords[0];
+ SecP224K1FieldElement Z2 = (SecP224K1FieldElement)b.RawZCoords[0];
+
+ uint c;
+ uint[] tt1 = Nat224.CreateExt();
+ uint[] t2 = Nat224.Create();
+ uint[] t3 = Nat224.Create();
+ uint[] t4 = Nat224.Create();
+
+ bool Z1IsOne = Z1.IsOne;
+ uint[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SecP224K1Field.Square(Z1.x, S2);
+
+ U2 = t2;
+ SecP224K1Field.Multiply(S2, X2.x, U2);
+
+ SecP224K1Field.Multiply(S2, Z1.x, S2);
+ SecP224K1Field.Multiply(S2, Y2.x, S2);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ uint[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SecP224K1Field.Square(Z2.x, S1);
+
+ U1 = tt1;
+ SecP224K1Field.Multiply(S1, X1.x, U1);
+
+ SecP224K1Field.Multiply(S1, Z2.x, S1);
+ SecP224K1Field.Multiply(S1, Y1.x, S1);
+ }
+
+ uint[] H = Nat224.Create();
+ SecP224K1Field.Subtract(U1, U2, H);
+
+ uint[] R = t2;
+ SecP224K1Field.Subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat224.IsZero(H))
+ {
+ if (Nat224.IsZero(R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ uint[] HSquared = t3;
+ SecP224K1Field.Square(H, HSquared);
+
+ uint[] G = Nat224.Create();
+ SecP224K1Field.Multiply(HSquared, H, G);
+
+ uint[] V = t3;
+ SecP224K1Field.Multiply(HSquared, U1, V);
+
+ SecP224K1Field.Negate(G, G);
+ Nat224.Mul(S1, G, tt1);
+
+ c = Nat224.AddBothTo(V, V, G);
+ SecP224K1Field.Reduce32(c, G);
+
+ SecP224K1FieldElement X3 = new SecP224K1FieldElement(t4);
+ SecP224K1Field.Square(R, X3.x);
+ SecP224K1Field.Subtract(X3.x, G, X3.x);
+
+ SecP224K1FieldElement Y3 = new SecP224K1FieldElement(G);
+ SecP224K1Field.Subtract(V, X3.x, Y3.x);
+ SecP224K1Field.MultiplyAddToExt(Y3.x, R, tt1);
+ SecP224K1Field.Reduce(tt1, Y3.x);
+
+ SecP224K1FieldElement Z3 = new SecP224K1FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SecP224K1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SecP224K1Field.Multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+ return new SecP224K1Point(curve, X3, Y3, zs, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ SecP224K1FieldElement Y1 = (SecP224K1FieldElement)this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ SecP224K1FieldElement X1 = (SecP224K1FieldElement)this.RawXCoord, Z1 = (SecP224K1FieldElement)this.RawZCoords[0];
+
+ uint c;
+
+ uint[] Y1Squared = Nat224.Create();
+ SecP224K1Field.Square(Y1.x, Y1Squared);
+
+ uint[] T = Nat224.Create();
+ SecP224K1Field.Square(Y1Squared, T);
+
+ uint[] M = Nat224.Create();
+ SecP224K1Field.Square(X1.x, M);
+ c = Nat224.AddBothTo(M, M, M);
+ SecP224K1Field.Reduce32(c, M);
+
+ uint[] S = Y1Squared;
+ SecP224K1Field.Multiply(Y1Squared, X1.x, S);
+ c = Nat.ShiftUpBits(7, S, 2, 0);
+ SecP224K1Field.Reduce32(c, S);
+
+ uint[] t1 = Nat224.Create();
+ c = Nat.ShiftUpBits(7, T, 3, 0, t1);
+ SecP224K1Field.Reduce32(c, t1);
+
+ SecP224K1FieldElement X3 = new SecP224K1FieldElement(T);
+ SecP224K1Field.Square(M, X3.x);
+ SecP224K1Field.Subtract(X3.x, S, X3.x);
+ SecP224K1Field.Subtract(X3.x, S, X3.x);
+
+ SecP224K1FieldElement Y3 = new SecP224K1FieldElement(S);
+ SecP224K1Field.Subtract(S, X3.x, Y3.x);
+ SecP224K1Field.Multiply(Y3.x, M, Y3.x);
+ SecP224K1Field.Subtract(Y3.x, t1, Y3.x);
+
+ SecP224K1FieldElement Z3 = new SecP224K1FieldElement(M);
+ SecP224K1Field.Twice(Y1.x, Z3.x);
+ if (!Z1.IsOne)
+ {
+ SecP224K1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SecP224K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this == b)
+ return ThreeTimes();
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return b;
+
+ return Twice().Add(b);
+ }
+
+ public override ECPoint ThreeTimes()
+ {
+ if (this.IsInfinity || this.RawYCoord.IsZero)
+ return this;
+
+ // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+ return Twice().Add(this);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ return new SecP224K1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP224R1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP224R1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cda8781ffb4ee528d9a526bc51572cac6e80854e
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP224R1Curve.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP224R1Curve
+ : AbstractFpCurve
+ {
+ public static readonly BigInteger q = new BigInteger(1,
+ Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001"));
+
+ private const int SecP224R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected readonly SecP224R1Point m_infinity;
+
+ public SecP224R1Curve()
+ : base(q)
+ {
+ this.m_infinity = new SecP224R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1,
+ Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE")));
+ this.m_b = FromBigInteger(new BigInteger(1,
+ Hex.Decode("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4")));
+ this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"));
+ this.m_cofactor = BigInteger.One;
+
+ this.m_coord = SecP224R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecP224R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecP224R1FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecP224R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecP224R1Point(this, x, y, zs, withCompression);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP224R1Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP224R1Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4f5c3bbda49ccd061496bcc66d3cfce46c250198
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP224R1Field.cs
@@ -0,0 +1,297 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP224R1Field
+ {
+ // 2^224 - 2^96 + 1
+ internal static readonly uint[] P = new uint[] { 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ internal static readonly uint[] PExt = new uint[]{ 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ private static readonly uint[] PExtInv = new uint[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001, 0x00000000,
+ 0x00000000, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001 };
+ private const uint P6 = 0xFFFFFFFF;
+ private const uint PExt13 = 0xFFFFFFFF;
+
+ public static void Add(uint[] x, uint[] y, uint[] z)
+ {
+ uint c = Nat224.Add(x, y, z);
+ if (c != 0 || (z[6] == P6 && Nat224.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ uint c = Nat.Add(14, xx, yy, zz);
+ if (c != 0 || (zz[13] == PExt13 && Nat.Gte(14, zz, PExt)))
+ {
+ if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.IncAt(14, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void AddOne(uint[] x, uint[] z)
+ {
+ uint c = Nat.Inc(7, x, z);
+ if (c != 0 || (z[6] == P6 && Nat224.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ uint[] z = Nat224.FromBigInteger(x);
+ if (z[6] == P6 && Nat224.Gte(z, P))
+ {
+ Nat224.SubFrom(P, z);
+ }
+ return z;
+ }
+
+ public static void Half(uint[] x, uint[] z)
+ {
+ if ((x[0] & 1) == 0)
+ {
+ Nat.ShiftDownBit(7, x, 0, z);
+ }
+ else
+ {
+ uint c = Nat224.Add(x, P, z);
+ Nat.ShiftDownBit(7, z, c);
+ }
+ }
+
+ public static void Multiply(uint[] x, uint[] y, uint[] z)
+ {
+ uint[] tt = Nat224.CreateExt();
+ Nat224.Mul(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+ {
+ uint c = Nat224.MulAddTo(x, y, zz);
+ if (c != 0 || (zz[13] == PExt13 && Nat.Gte(14, zz, PExt)))
+ {
+ if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.IncAt(14, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void Negate(uint[] x, uint[] z)
+ {
+ if (Nat224.IsZero(x))
+ {
+ Nat224.Zero(z);
+ }
+ else
+ {
+ Nat224.Sub(P, x, z);
+ }
+ }
+
+ public static void Reduce(uint[] xx, uint[] z)
+ {
+ long xx10 = xx[10], xx11 = xx[11], xx12 = xx[12], xx13 = xx[13];
+
+ const long n = 1;
+
+ long t0 = (long)xx[7] + xx11 - n;
+ long t1 = (long)xx[8] + xx12;
+ long t2 = (long)xx[9] + xx13;
+
+ long cc = 0;
+ cc += (long)xx[0] - t0;
+ long z0 = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[1] - t1;
+ z[1] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[2] - t2;
+ z[2] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[3] + t0 - xx10;
+ long z3 = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[4] + t1 - xx11;
+ z[4] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[5] + t2 - xx12;
+ z[5] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[6] + xx10 - xx13;
+ z[6] = (uint)cc;
+ cc >>= 32;
+ cc += n;
+
+ Debug.Assert(cc >= 0);
+
+ z3 += cc;
+
+ z0 -= cc;
+ z[0] = (uint)z0;
+ cc = z0 >> 32;
+ if (cc != 0)
+ {
+ cc += (long)z[1];
+ z[1] = (uint)cc;
+ cc >>= 32;
+ cc += (long)z[2];
+ z[2] = (uint)cc;
+ z3 += cc >> 32;
+ }
+ z[3] = (uint)z3;
+ cc = z3 >> 32;
+
+ Debug.Assert(cc == 0 || cc == 1);
+
+ if ((cc != 0 && Nat.IncAt(7, z, 4) != 0)
+ || (z[6] == P6 && Nat224.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static void Reduce32(uint x, uint[] z)
+ {
+ long cc = 0;
+
+ if (x != 0)
+ {
+ long xx07 = x;
+
+ cc += (long)z[0] - xx07;
+ z[0] = (uint)cc;
+ cc >>= 32;
+ if (cc != 0)
+ {
+ cc += (long)z[1];
+ z[1] = (uint)cc;
+ cc >>= 32;
+ cc += (long)z[2];
+ z[2] = (uint)cc;
+ cc >>= 32;
+ }
+ cc += (long)z[3] + xx07;
+ z[3] = (uint)cc;
+ cc >>= 32;
+
+ Debug.Assert(cc == 0 || cc == 1);
+ }
+
+ if ((cc != 0 && Nat.IncAt(7, z, 4) != 0)
+ || (z[6] == P6 && Nat224.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static void Square(uint[] x, uint[] z)
+ {
+ uint[] tt = Nat224.CreateExt();
+ Nat224.Square(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareN(uint[] x, int n, uint[] z)
+ {
+ Debug.Assert(n > 0);
+
+ uint[] tt = Nat224.CreateExt();
+ Nat224.Square(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ Nat224.Square(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static void Subtract(uint[] x, uint[] y, uint[] z)
+ {
+ int c = Nat224.Sub(x, y, z);
+ if (c != 0)
+ {
+ SubPInvFrom(z);
+ }
+ }
+
+ public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ int c = Nat.Sub(14, xx, yy, zz);
+ if (c != 0)
+ {
+ if (Nat.SubFrom(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.DecAt(14, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void Twice(uint[] x, uint[] z)
+ {
+ uint c = Nat.ShiftUpBit(7, x, 0, z);
+ if (c != 0 || (z[6] == P6 && Nat224.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ private static void AddPInvTo(uint[] z)
+ {
+ long c = (long)z[0] - 1;
+ z[0] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (long)z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ }
+ c += (long)z[3] + 1;
+ z[3] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ Nat.IncAt(7, z, 4);
+ }
+ }
+
+ private static void SubPInvFrom(uint[] z)
+ {
+ long c = (long)z[0] + 1;
+ z[0] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (long)z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ }
+ c += (long)z[3] - 1;
+ z[3] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ Nat.DecAt(7, z, 4);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2b9a06564b26ba88d52a3e098bff0e72c13d619d
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs
@@ -0,0 +1,269 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP224R1FieldElement
+ : ECFieldElement
+ {
+ public static readonly BigInteger Q = SecP224R1Curve.q;
+
+ protected internal readonly uint[] x;
+
+ public SecP224R1FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+ throw new ArgumentException("value invalid for SecP224R1FieldElement", "x");
+
+ this.x = SecP224R1Field.FromBigInteger(x);
+ }
+
+ public SecP224R1FieldElement()
+ {
+ this.x = Nat224.Create();
+ }
+
+ protected internal SecP224R1FieldElement(uint[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat224.IsZero(x); }
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat224.IsOne(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return Nat224.GetBit(x, 0) == 1;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat224.ToBigInteger(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecP224R1Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return Q.BitLength; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ uint[] z = Nat224.Create();
+ SecP224R1Field.Add(x, ((SecP224R1FieldElement)b).x, z);
+ return new SecP224R1FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ uint[] z = Nat224.Create();
+ SecP224R1Field.AddOne(x, z);
+ return new SecP224R1FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ uint[] z = Nat224.Create();
+ SecP224R1Field.Subtract(x, ((SecP224R1FieldElement)b).x, z);
+ return new SecP224R1FieldElement(z);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ uint[] z = Nat224.Create();
+ SecP224R1Field.Multiply(x, ((SecP224R1FieldElement)b).x, z);
+ return new SecP224R1FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ //return Multiply(b.Invert());
+ uint[] z = Nat224.Create();
+ Mod.Invert(SecP224R1Field.P, ((SecP224R1FieldElement)b).x, z);
+ SecP224R1Field.Multiply(z, x, z);
+ return new SecP224R1FieldElement(z);
+ }
+
+ public override ECFieldElement Negate()
+ {
+ uint[] z = Nat224.Create();
+ SecP224R1Field.Negate(x, z);
+ return new SecP224R1FieldElement(z);
+ }
+
+ public override ECFieldElement Square()
+ {
+ uint[] z = Nat224.Create();
+ SecP224R1Field.Square(x, z);
+ return new SecP224R1FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ //return new SecP224R1FieldElement(ToBigInteger().ModInverse(Q));
+ uint[] z = Nat224.Create();
+ Mod.Invert(SecP224R1Field.P, x, z);
+ return new SecP224R1FieldElement(z);
+ }
+
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public override ECFieldElement Sqrt()
+ {
+ uint[] c = this.x;
+ if (Nat224.IsZero(c) || Nat224.IsOne(c))
+ return this;
+
+ uint[] nc = Nat224.Create();
+ SecP224R1Field.Negate(c, nc);
+
+ uint[] r = Mod.Random(SecP224R1Field.P);
+ uint[] t = Nat224.Create();
+
+ if (!IsSquare(c))
+ return null;
+
+ while (!TrySqrt(nc, r, t))
+ {
+ SecP224R1Field.AddOne(r, r);
+ }
+
+ SecP224R1Field.Square(t, r);
+
+ return Nat224.Eq(c, r) ? new SecP224R1FieldElement(t) : null;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecP224R1FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecP224R1FieldElement);
+ }
+
+ public virtual bool Equals(SecP224R1FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat224.Eq(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 7);
+ }
+
+ private static bool IsSquare(uint[] x)
+ {
+ uint[] t1 = Nat224.Create();
+ uint[] t2 = Nat224.Create();
+ Nat224.Copy(x, t1);
+
+ for (int i = 0; i < 7; ++i)
+ {
+ Nat224.Copy(t1, t2);
+ SecP224R1Field.SquareN(t1, 1 << i, t1);
+ SecP224R1Field.Multiply(t1, t2, t1);
+ }
+
+ SecP224R1Field.SquareN(t1, 95, t1);
+ return Nat224.IsOne(t1);
+ }
+
+ private static void RM(uint[] nc, uint[] d0, uint[] e0, uint[] d1, uint[] e1, uint[] f1, uint[] t)
+ {
+ SecP224R1Field.Multiply(e1, e0, t);
+ SecP224R1Field.Multiply(t, nc, t);
+ SecP224R1Field.Multiply(d1, d0, f1);
+ SecP224R1Field.Add(f1, t, f1);
+ SecP224R1Field.Multiply(d1, e0, t);
+ Nat224.Copy(f1, d1);
+ SecP224R1Field.Multiply(e1, d0, e1);
+ SecP224R1Field.Add(e1, t, e1);
+ SecP224R1Field.Square(e1, f1);
+ SecP224R1Field.Multiply(f1, nc, f1);
+ }
+
+ private static void RP(uint[] nc, uint[] d1, uint[] e1, uint[] f1, uint[] t)
+ {
+ Nat224.Copy(nc, f1);
+
+ uint[] d0 = Nat224.Create();
+ uint[] e0 = Nat224.Create();
+
+ for (int i = 0; i < 7; ++i)
+ {
+ Nat224.Copy(d1, d0);
+ Nat224.Copy(e1, e0);
+
+ int j = 1 << i;
+ while (--j >= 0)
+ {
+ RS(d1, e1, f1, t);
+ }
+
+ RM(nc, d0, e0, d1, e1, f1, t);
+ }
+ }
+
+ private static void RS(uint[] d, uint[] e, uint[] f, uint[] t)
+ {
+ SecP224R1Field.Multiply(e, d, e);
+ SecP224R1Field.Twice(e, e);
+ SecP224R1Field.Square(d, t);
+ SecP224R1Field.Add(f, t, d);
+ SecP224R1Field.Multiply(f, t, f);
+ uint c = Nat.ShiftUpBits(7, f, 2, 0);
+ SecP224R1Field.Reduce32(c, f);
+ }
+
+ private static bool TrySqrt(uint[] nc, uint[] r, uint[] t)
+ {
+ uint[] d1 = Nat224.Create();
+ Nat224.Copy(r, d1);
+ uint[] e1 = Nat224.Create();
+ e1[0] = 1;
+ uint[] f1 = Nat224.Create();
+ RP(nc, d1, e1, f1, t);
+
+ uint[] d0 = Nat224.Create();
+ uint[] e0 = Nat224.Create();
+
+ for (int k = 1; k < 96; ++k)
+ {
+ Nat224.Copy(d1, d0);
+ Nat224.Copy(e1, e0);
+
+ RS(d1, e1, f1, t);
+
+ if (Nat224.IsZero(d1))
+ {
+ Mod.Invert(SecP224R1Field.P, e0, t);
+ SecP224R1Field.Multiply(t, d0, t);
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP224R1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP224R1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..73c4f194882937320bb405c6a69854fbe412d2dc
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP224R1Point.cs
@@ -0,0 +1,279 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP224R1Point
+ : AbstractFpPoint
+ {
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ *
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ * @param withCompression
+ * if true encode with point compression
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(bool)}
+ */
+ public SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecP224R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+ if (this == b)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ SecP224R1FieldElement X1 = (SecP224R1FieldElement)this.RawXCoord, Y1 = (SecP224R1FieldElement)this.RawYCoord;
+ SecP224R1FieldElement X2 = (SecP224R1FieldElement)b.RawXCoord, Y2 = (SecP224R1FieldElement)b.RawYCoord;
+
+ SecP224R1FieldElement Z1 = (SecP224R1FieldElement)this.RawZCoords[0];
+ SecP224R1FieldElement Z2 = (SecP224R1FieldElement)b.RawZCoords[0];
+
+ uint c;
+ uint[] tt1 = Nat224.CreateExt();
+ uint[] t2 = Nat224.Create();
+ uint[] t3 = Nat224.Create();
+ uint[] t4 = Nat224.Create();
+
+ bool Z1IsOne = Z1.IsOne;
+ uint[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SecP224R1Field.Square(Z1.x, S2);
+
+ U2 = t2;
+ SecP224R1Field.Multiply(S2, X2.x, U2);
+
+ SecP224R1Field.Multiply(S2, Z1.x, S2);
+ SecP224R1Field.Multiply(S2, Y2.x, S2);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ uint[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SecP224R1Field.Square(Z2.x, S1);
+
+ U1 = tt1;
+ SecP224R1Field.Multiply(S1, X1.x, U1);
+
+ SecP224R1Field.Multiply(S1, Z2.x, S1);
+ SecP224R1Field.Multiply(S1, Y1.x, S1);
+ }
+
+ uint[] H = Nat224.Create();
+ SecP224R1Field.Subtract(U1, U2, H);
+
+ uint[] R = t2;
+ SecP224R1Field.Subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat224.IsZero(H))
+ {
+ if (Nat224.IsZero(R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ uint[] HSquared = t3;
+ SecP224R1Field.Square(H, HSquared);
+
+ uint[] G = Nat224.Create();
+ SecP224R1Field.Multiply(HSquared, H, G);
+
+ uint[] V = t3;
+ SecP224R1Field.Multiply(HSquared, U1, V);
+
+ SecP224R1Field.Negate(G, G);
+ Nat224.Mul(S1, G, tt1);
+
+ c = Nat224.AddBothTo(V, V, G);
+ SecP224R1Field.Reduce32(c, G);
+
+ SecP224R1FieldElement X3 = new SecP224R1FieldElement(t4);
+ SecP224R1Field.Square(R, X3.x);
+ SecP224R1Field.Subtract(X3.x, G, X3.x);
+
+ SecP224R1FieldElement Y3 = new SecP224R1FieldElement(G);
+ SecP224R1Field.Subtract(V, X3.x, Y3.x);
+ SecP224R1Field.MultiplyAddToExt(Y3.x, R, tt1);
+ SecP224R1Field.Reduce(tt1, Y3.x);
+
+ SecP224R1FieldElement Z3 = new SecP224R1FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SecP224R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SecP224R1Field.Multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+ return new SecP224R1Point(curve, X3, Y3, zs, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ SecP224R1FieldElement Y1 = (SecP224R1FieldElement)this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ SecP224R1FieldElement X1 = (SecP224R1FieldElement)this.RawXCoord, Z1 = (SecP224R1FieldElement)this.RawZCoords[0];
+
+ uint c;
+ uint[] t1 = Nat224.Create();
+ uint[] t2 = Nat224.Create();
+
+ uint[] Y1Squared = Nat224.Create();
+ SecP224R1Field.Square(Y1.x, Y1Squared);
+
+ uint[] T = Nat224.Create();
+ SecP224R1Field.Square(Y1Squared, T);
+
+ bool Z1IsOne = Z1.IsOne;
+
+ uint[] Z1Squared = Z1.x;
+ if (!Z1IsOne)
+ {
+ Z1Squared = t2;
+ SecP224R1Field.Square(Z1.x, Z1Squared);
+ }
+
+ SecP224R1Field.Subtract(X1.x, Z1Squared, t1);
+
+ uint[] M = t2;
+ SecP224R1Field.Add(X1.x, Z1Squared, M);
+ SecP224R1Field.Multiply(M, t1, M);
+ c = Nat224.AddBothTo(M, M, M);
+ SecP224R1Field.Reduce32(c, M);
+
+ uint[] S = Y1Squared;
+ SecP224R1Field.Multiply(Y1Squared, X1.x, S);
+ c = Nat.ShiftUpBits(7, S, 2, 0);
+ SecP224R1Field.Reduce32(c, S);
+
+ c = Nat.ShiftUpBits(7, T, 3, 0, t1);
+ SecP224R1Field.Reduce32(c, t1);
+
+ SecP224R1FieldElement X3 = new SecP224R1FieldElement(T);
+ SecP224R1Field.Square(M, X3.x);
+ SecP224R1Field.Subtract(X3.x, S, X3.x);
+ SecP224R1Field.Subtract(X3.x, S, X3.x);
+
+ SecP224R1FieldElement Y3 = new SecP224R1FieldElement(S);
+ SecP224R1Field.Subtract(S, X3.x, Y3.x);
+ SecP224R1Field.Multiply(Y3.x, M, Y3.x);
+ SecP224R1Field.Subtract(Y3.x, t1, Y3.x);
+
+ SecP224R1FieldElement Z3 = new SecP224R1FieldElement(M);
+ SecP224R1Field.Twice(Y1.x, Z3.x);
+ if (!Z1IsOne)
+ {
+ SecP224R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SecP224R1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this == b)
+ return ThreeTimes();
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return b;
+
+ return Twice().Add(b);
+ }
+
+ public override ECPoint ThreeTimes()
+ {
+ if (this.IsInfinity || this.RawYCoord.IsZero)
+ return this;
+
+ // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+ return Twice().Add(this);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ return new SecP224R1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP256K1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP256K1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..59e2cefb249c474ba9b8c63045fa9a9336ff32f5
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP256K1Curve.cs
@@ -0,0 +1,75 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP256K1Curve
+ : AbstractFpCurve
+ {
+ public static readonly BigInteger q = new BigInteger(1,
+ Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"));
+
+ private const int SECP256K1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected readonly SecP256K1Point m_infinity;
+
+ public SecP256K1Curve()
+ : base(q)
+ {
+ this.m_infinity = new SecP256K1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.Zero);
+ this.m_b = FromBigInteger(BigInteger.ValueOf(7));
+ this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"));
+ this.m_cofactor = BigInteger.One;
+ this.m_coord = SECP256K1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecP256K1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecP256K1FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecP256K1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecP256K1Point(this, x, y, zs, withCompression);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP256K1Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP256K1Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b0646e93fd9093708772271307c7f4bb77caf0d6
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP256K1Field.cs
@@ -0,0 +1,180 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP256K1Field
+ {
+ // 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
+ internal static readonly uint[] P = new uint[]{ 0xFFFFFC2F, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF };
+ internal static readonly uint[] PExt = new uint[]{ 0x000E90A1, 0x000007A2, 0x00000001, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0xFFFFF85E, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF };
+ private static readonly uint[] PExtInv = new uint[]{ 0xFFF16F5F, 0xFFFFF85D, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000007A1, 0x00000002 };
+ private const uint P7 = 0xFFFFFFFF;
+ private const uint PExt15 = 0xFFFFFFFF;
+ private const uint PInv33 = 0x3D1;
+
+ public static void Add(uint[] x, uint[] y, uint[] z)
+ {
+ uint c = Nat256.Add(x, y, z);
+ if (c != 0 || (z[7] == P7 && Nat256.Gte(z, P)))
+ {
+ Nat.Add33To(8, PInv33, z);
+ }
+ }
+
+ public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ uint c = Nat.Add(16, xx, yy, zz);
+ if (c != 0 || (zz[15] == PExt15 && Nat.Gte(16, zz, PExt)))
+ {
+ if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.IncAt(16, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void AddOne(uint[] x, uint[] z)
+ {
+ uint c = Nat.Inc(8, x, z);
+ if (c != 0 || (z[7] == P7 && Nat256.Gte(z, P)))
+ {
+ Nat.Add33To(8, PInv33, z);
+ }
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ uint[] z = Nat256.FromBigInteger(x);
+ if (z[7] == P7 && Nat256.Gte(z, P))
+ {
+ Nat256.SubFrom(P, z);
+ }
+ return z;
+ }
+
+ public static void Half(uint[] x, uint[] z)
+ {
+ if ((x[0] & 1) == 0)
+ {
+ Nat.ShiftDownBit(8, x, 0, z);
+ }
+ else
+ {
+ uint c = Nat256.Add(x, P, z);
+ Nat.ShiftDownBit(8, z, c);
+ }
+ }
+
+ public static void Multiply(uint[] x, uint[] y, uint[] z)
+ {
+ uint[] tt = Nat256.CreateExt();
+ Nat256.Mul(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+ {
+ uint c = Nat256.MulAddTo(x, y, zz);
+ if (c != 0 || (zz[15] == PExt15 && Nat.Gte(16, zz, PExt)))
+ {
+ if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.IncAt(16, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void Negate(uint[] x, uint[] z)
+ {
+ if (Nat256.IsZero(x))
+ {
+ Nat256.Zero(z);
+ }
+ else
+ {
+ Nat256.Sub(P, x, z);
+ }
+ }
+
+ public static void Reduce(uint[] xx, uint[] z)
+ {
+ ulong cc = Nat256.Mul33Add(PInv33, xx, 8, xx, 0, z, 0);
+ uint c = Nat256.Mul33DWordAdd(PInv33, cc, z, 0);
+
+ Debug.Assert(c == 0 || c == 1);
+
+ if (c != 0 || (z[7] == P7 && Nat256.Gte(z, P)))
+ {
+ Nat.Add33To(8, PInv33, z);
+ }
+ }
+
+ public static void Reduce32(uint x, uint[] z)
+ {
+ if ((x != 0 && Nat256.Mul33WordAdd(PInv33, x, z, 0) != 0)
+ || (z[7] == P7 && Nat256.Gte(z, P)))
+ {
+ Nat.Add33To(8, PInv33, z);
+ }
+ }
+
+ public static void Square(uint[] x, uint[] z)
+ {
+ uint[] tt = Nat256.CreateExt();
+ Nat256.Square(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareN(uint[] x, int n, uint[] z)
+ {
+ Debug.Assert(n > 0);
+
+ uint[] tt = Nat256.CreateExt();
+ Nat256.Square(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ Nat256.Square(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static void Subtract(uint[] x, uint[] y, uint[] z)
+ {
+ int c = Nat256.Sub(x, y, z);
+ if (c != 0)
+ {
+ Nat.Sub33From(8, PInv33, z);
+ }
+ }
+
+ public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ int c = Nat.Sub(16, xx, yy, zz);
+ if (c != 0)
+ {
+ if (Nat.SubFrom(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.DecAt(16, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void Twice(uint[] x, uint[] z)
+ {
+ uint c = Nat.ShiftUpBit(8, x, 0, z);
+ if (c != 0 || (z[7] == P7 && Nat256.Gte(z, P)))
+ {
+ Nat.Add33To(8, PInv33, z);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..473113d0f1494d43da4f93e43ec6f04d8e5a77c9
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs
@@ -0,0 +1,214 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP256K1FieldElement
+ : ECFieldElement
+ {
+ public static readonly BigInteger Q = SecP256K1Curve.q;
+
+ protected internal readonly uint[] x;
+
+ public SecP256K1FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+ throw new ArgumentException("value invalid for SecP256K1FieldElement", "x");
+
+ this.x = SecP256K1Field.FromBigInteger(x);
+ }
+
+ public SecP256K1FieldElement()
+ {
+ this.x = Nat256.Create();
+ }
+
+ protected internal SecP256K1FieldElement(uint[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat256.IsZero(x); }
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat256.IsOne(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return Nat256.GetBit(x, 0) == 1;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat256.ToBigInteger(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecP256K1Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return Q.BitLength; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ uint[] z = Nat256.Create();
+ SecP256K1Field.Add(x, ((SecP256K1FieldElement)b).x, z);
+ return new SecP256K1FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ uint[] z = Nat256.Create();
+ SecP256K1Field.AddOne(x, z);
+ return new SecP256K1FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ uint[] z = Nat256.Create();
+ SecP256K1Field.Subtract(x, ((SecP256K1FieldElement)b).x, z);
+ return new SecP256K1FieldElement(z);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ uint[] z = Nat256.Create();
+ SecP256K1Field.Multiply(x, ((SecP256K1FieldElement)b).x, z);
+ return new SecP256K1FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ //return Multiply(b.Invert());
+ uint[] z = Nat256.Create();
+ Mod.Invert(SecP256K1Field.P, ((SecP256K1FieldElement)b).x, z);
+ SecP256K1Field.Multiply(z, x, z);
+ return new SecP256K1FieldElement(z);
+ }
+
+ public override ECFieldElement Negate()
+ {
+ uint[] z = Nat256.Create();
+ SecP256K1Field.Negate(x, z);
+ return new SecP256K1FieldElement(z);
+ }
+
+ public override ECFieldElement Square()
+ {
+ uint[] z = Nat256.Create();
+ SecP256K1Field.Square(x, z);
+ return new SecP256K1FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ //return new SecP256K1FieldElement(ToBigInteger().ModInverse(Q));
+ uint[] z = Nat256.Create();
+ Mod.Invert(SecP256K1Field.P, x, z);
+ return new SecP256K1FieldElement(z);
+ }
+
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public override ECFieldElement Sqrt()
+ {
+ /*
+ * Raise this element to the exponent 2^254 - 2^30 - 2^7 - 2^6 - 2^5 - 2^4 - 2^2
+ *
+ * Breaking up the exponent's binary representation into "repunits", we get:
+ * { 223 1s } { 1 0s } { 22 1s } { 4 0s } { 2 1s } { 2 0s}
+ *
+ * Therefore we need an addition chain containing 2, 22, 223 (the lengths of the repunits)
+ * We use: 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]
+ */
+
+ uint[] x1 = this.x;
+ if (Nat256.IsZero(x1) || Nat256.IsOne(x1))
+ return this;
+
+ uint[] x2 = Nat256.Create();
+ SecP256K1Field.Square(x1, x2);
+ SecP256K1Field.Multiply(x2, x1, x2);
+ uint[] x3 = Nat256.Create();
+ SecP256K1Field.Square(x2, x3);
+ SecP256K1Field.Multiply(x3, x1, x3);
+ uint[] x6 = Nat256.Create();
+ SecP256K1Field.SquareN(x3, 3, x6);
+ SecP256K1Field.Multiply(x6, x3, x6);
+ uint[] x9 = x6;
+ SecP256K1Field.SquareN(x6, 3, x9);
+ SecP256K1Field.Multiply(x9, x3, x9);
+ uint[] x11 = x9;
+ SecP256K1Field.SquareN(x9, 2, x11);
+ SecP256K1Field.Multiply(x11, x2, x11);
+ uint[] x22 = Nat256.Create();
+ SecP256K1Field.SquareN(x11, 11, x22);
+ SecP256K1Field.Multiply(x22, x11, x22);
+ uint[] x44 = x11;
+ SecP256K1Field.SquareN(x22, 22, x44);
+ SecP256K1Field.Multiply(x44, x22, x44);
+ uint[] x88 = Nat256.Create();
+ SecP256K1Field.SquareN(x44, 44, x88);
+ SecP256K1Field.Multiply(x88, x44, x88);
+ uint[] x176 = Nat256.Create();
+ SecP256K1Field.SquareN(x88, 88, x176);
+ SecP256K1Field.Multiply(x176, x88, x176);
+ uint[] x220 = x88;
+ SecP256K1Field.SquareN(x176, 44, x220);
+ SecP256K1Field.Multiply(x220, x44, x220);
+ uint[] x223 = x44;
+ SecP256K1Field.SquareN(x220, 3, x223);
+ SecP256K1Field.Multiply(x223, x3, x223);
+
+ uint[] t1 = x223;
+ SecP256K1Field.SquareN(t1, 23, t1);
+ SecP256K1Field.Multiply(t1, x22, t1);
+ SecP256K1Field.SquareN(t1, 6, t1);
+ SecP256K1Field.Multiply(t1, x2, t1);
+ SecP256K1Field.SquareN(t1, 2, t1);
+
+ uint[] t2 = x2;
+ SecP256K1Field.Square(t1, t2);
+
+ return Nat256.Eq(x1, t2) ? new SecP256K1FieldElement(t1) : null;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecP256K1FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecP256K1FieldElement);
+ }
+
+ public virtual bool Equals(SecP256K1FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat256.Eq(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 8);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP256K1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP256K1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..072a0b96931e74c66adc201bcf139cd155b0a8f5
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP256K1Point.cs
@@ -0,0 +1,267 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP256K1Point
+ : AbstractFpPoint
+ {
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ *
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecP256K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ * @param withCompression
+ * if true encode with point compression
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(bool)}
+ */
+ public SecP256K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecP256K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs,
+ bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecP256K1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+ if (this == b)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ SecP256K1FieldElement X1 = (SecP256K1FieldElement)this.RawXCoord, Y1 = (SecP256K1FieldElement)this.RawYCoord;
+ SecP256K1FieldElement X2 = (SecP256K1FieldElement)b.RawXCoord, Y2 = (SecP256K1FieldElement)b.RawYCoord;
+
+ SecP256K1FieldElement Z1 = (SecP256K1FieldElement)this.RawZCoords[0];
+ SecP256K1FieldElement Z2 = (SecP256K1FieldElement)b.RawZCoords[0];
+
+ uint c;
+ uint[] tt1 = Nat256.CreateExt();
+ uint[] t2 = Nat256.Create();
+ uint[] t3 = Nat256.Create();
+ uint[] t4 = Nat256.Create();
+
+ bool Z1IsOne = Z1.IsOne;
+ uint[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SecP256K1Field.Square(Z1.x, S2);
+
+ U2 = t2;
+ SecP256K1Field.Multiply(S2, X2.x, U2);
+
+ SecP256K1Field.Multiply(S2, Z1.x, S2);
+ SecP256K1Field.Multiply(S2, Y2.x, S2);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ uint[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SecP256K1Field.Square(Z2.x, S1);
+
+ U1 = tt1;
+ SecP256K1Field.Multiply(S1, X1.x, U1);
+
+ SecP256K1Field.Multiply(S1, Z2.x, S1);
+ SecP256K1Field.Multiply(S1, Y1.x, S1);
+ }
+
+ uint[] H = Nat256.Create();
+ SecP256K1Field.Subtract(U1, U2, H);
+
+ uint[] R = t2;
+ SecP256K1Field.Subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat256.IsZero(H))
+ {
+ if (Nat256.IsZero(R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ uint[] HSquared = t3;
+ SecP256K1Field.Square(H, HSquared);
+
+ uint[] G = Nat256.Create();
+ SecP256K1Field.Multiply(HSquared, H, G);
+
+ uint[] V = t3;
+ SecP256K1Field.Multiply(HSquared, U1, V);
+
+ SecP256K1Field.Negate(G, G);
+ Nat256.Mul(S1, G, tt1);
+
+ c = Nat256.AddBothTo(V, V, G);
+ SecP256K1Field.Reduce32(c, G);
+
+ SecP256K1FieldElement X3 = new SecP256K1FieldElement(t4);
+ SecP256K1Field.Square(R, X3.x);
+ SecP256K1Field.Subtract(X3.x, G, X3.x);
+
+ SecP256K1FieldElement Y3 = new SecP256K1FieldElement(G);
+ SecP256K1Field.Subtract(V, X3.x, Y3.x);
+ SecP256K1Field.MultiplyAddToExt(Y3.x, R, tt1);
+ SecP256K1Field.Reduce(tt1, Y3.x);
+
+ SecP256K1FieldElement Z3 = new SecP256K1FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SecP256K1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SecP256K1Field.Multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+ return new SecP256K1Point(curve, X3, Y3, zs, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ SecP256K1FieldElement Y1 = (SecP256K1FieldElement)this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ SecP256K1FieldElement X1 = (SecP256K1FieldElement)this.RawXCoord, Z1 = (SecP256K1FieldElement)this.RawZCoords[0];
+
+ uint c;
+
+ uint[] Y1Squared = Nat256.Create();
+ SecP256K1Field.Square(Y1.x, Y1Squared);
+
+ uint[] T = Nat256.Create();
+ SecP256K1Field.Square(Y1Squared, T);
+
+ uint[] M = Nat256.Create();
+ SecP256K1Field.Square(X1.x, M);
+ c = Nat256.AddBothTo(M, M, M);
+ SecP256K1Field.Reduce32(c, M);
+
+ uint[] S = Y1Squared;
+ SecP256K1Field.Multiply(Y1Squared, X1.x, S);
+ c = Nat.ShiftUpBits(8, S, 2, 0);
+ SecP256K1Field.Reduce32(c, S);
+
+ uint[] t1 = Nat256.Create();
+ c = Nat.ShiftUpBits(8, T, 3, 0, t1);
+ SecP256K1Field.Reduce32(c, t1);
+
+ SecP256K1FieldElement X3 = new SecP256K1FieldElement(T);
+ SecP256K1Field.Square(M, X3.x);
+ SecP256K1Field.Subtract(X3.x, S, X3.x);
+ SecP256K1Field.Subtract(X3.x, S, X3.x);
+
+ SecP256K1FieldElement Y3 = new SecP256K1FieldElement(S);
+ SecP256K1Field.Subtract(S, X3.x, Y3.x);
+ SecP256K1Field.Multiply(Y3.x, M, Y3.x);
+ SecP256K1Field.Subtract(Y3.x, t1, Y3.x);
+
+ SecP256K1FieldElement Z3 = new SecP256K1FieldElement(M);
+ SecP256K1Field.Twice(Y1.x, Z3.x);
+ if (!Z1.IsOne)
+ {
+ SecP256K1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SecP256K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this == b)
+ return ThreeTimes();
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return b;
+
+ return Twice().Add(b);
+ }
+
+ public override ECPoint ThreeTimes()
+ {
+ if (this.IsInfinity || this.RawYCoord.IsZero)
+ return this;
+
+ // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+ return Twice().Add(this);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ return new SecP256K1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP256R1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP256R1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6b3448f06c9076af75fd40c3bf04258f6b3a253f
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP256R1Curve.cs
@@ -0,0 +1,77 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP256R1Curve
+ : AbstractFpCurve
+ {
+ public static readonly BigInteger q = new BigInteger(1,
+ Hex.Decode("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"));
+
+ private const int SecP256R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected readonly SecP256R1Point m_infinity;
+
+ public SecP256R1Curve()
+ : base(q)
+ {
+ this.m_infinity = new SecP256R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1,
+ Hex.Decode("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC")));
+ this.m_b = FromBigInteger(new BigInteger(1,
+ Hex.Decode("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B")));
+ this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"));
+ this.m_cofactor = BigInteger.One;
+ this.m_coord = SecP256R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecP256R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecP256R1FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecP256R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecP256R1Point(this, x, y, zs, withCompression);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP256R1Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP256R1Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5b3de6d367ec9f564660448ae906839fe2cff993
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP256R1Field.cs
@@ -0,0 +1,312 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP256R1Field
+ {
+ // 2^256 - 2^224 + 2^192 + 2^96 - 1
+ internal static readonly uint[] P = new uint[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000001, 0xFFFFFFFF };
+ internal static readonly uint[] PExt = new uint[]{ 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFE, 0x00000001, 0xFFFFFFFE, 0x00000001, 0xFFFFFFFE, 0x00000001, 0x00000001, 0xFFFFFFFE,
+ 0x00000002, 0xFFFFFFFE };
+ internal const uint P7 = 0xFFFFFFFF;
+ internal const uint PExt15 = 0xFFFFFFFE;
+
+ public static void Add(uint[] x, uint[] y, uint[] z)
+ {
+ uint c = Nat256.Add(x, y, z);
+ if (c != 0 || (z[7] == P7 && Nat256.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ uint c = Nat.Add(16, xx, yy, zz);
+ if (c != 0 || (zz[15] >= PExt15 && Nat.Gte(16, zz, PExt)))
+ {
+ Nat.SubFrom(16, PExt, zz);
+ }
+ }
+
+ public static void AddOne(uint[] x, uint[] z)
+ {
+ uint c = Nat.Inc(8, x, z);
+ if (c != 0 || (z[7] == P7 && Nat256.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ uint[] z = Nat256.FromBigInteger(x);
+ if (z[7] == P7 && Nat256.Gte(z, P))
+ {
+ Nat256.SubFrom(P, z);
+ }
+ return z;
+ }
+
+ public static void Half(uint[] x, uint[] z)
+ {
+ if ((x[0] & 1) == 0)
+ {
+ Nat.ShiftDownBit(8, x, 0, z);
+ }
+ else
+ {
+ uint c = Nat256.Add(x, P, z);
+ Nat.ShiftDownBit(8, z, c);
+ }
+ }
+
+ public static void Multiply(uint[] x, uint[] y, uint[] z)
+ {
+ uint[] tt = Nat256.CreateExt();
+ Nat256.Mul(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+ {
+ uint c = Nat256.MulAddTo(x, y, zz);
+ if (c != 0 || (zz[15] >= PExt15 && Nat.Gte(16, zz, PExt)))
+ {
+ Nat.SubFrom(16, PExt, zz);
+ }
+ }
+
+ public static void Negate(uint[] x, uint[] z)
+ {
+ if (Nat256.IsZero(x))
+ {
+ Nat256.Zero(z);
+ }
+ else
+ {
+ Nat256.Sub(P, x, z);
+ }
+ }
+
+ public static void Reduce(uint[] xx, uint[] z)
+ {
+ long xx08 = xx[8], xx09 = xx[9], xx10 = xx[10], xx11 = xx[11];
+ long xx12 = xx[12], xx13 = xx[13], xx14 = xx[14], xx15 = xx[15];
+
+ const long n = 6;
+
+ xx08 -= n;
+
+ long t0 = xx08 + xx09;
+ long t1 = xx09 + xx10;
+ long t2 = xx10 + xx11 - xx15;
+ long t3 = xx11 + xx12;
+ long t4 = xx12 + xx13;
+ long t5 = xx13 + xx14;
+ long t6 = xx14 + xx15;
+ long t7 = t5 - t0;
+
+ long cc = 0;
+ cc += (long)xx[0] - t3 - t7;
+ z[0] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[1] + t1 - t4 - t6;
+ z[1] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[2] + t2 - t5;
+ z[2] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[3] + (t3 << 1) + t7 - t6;
+ z[3] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[4] + (t4 << 1) + xx14 - t1;
+ z[4] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[5] + (t5 << 1) - t2;
+ z[5] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[6] + (t6 << 1) + t7;
+ z[6] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[7] + (xx15 << 1) + xx08 - t2 - t4;
+ z[7] = (uint)cc;
+ cc >>= 32;
+ cc += n;
+
+ Debug.Assert(cc >= 0);
+
+ Reduce32((uint)cc, z);
+ }
+
+ public static void Reduce32(uint x, uint[] z)
+ {
+ long cc = 0;
+
+ if (x != 0)
+ {
+ long xx08 = x;
+
+ cc += (long)z[0] + xx08;
+ z[0] = (uint)cc;
+ cc >>= 32;
+ if (cc != 0)
+ {
+ cc += (long)z[1];
+ z[1] = (uint)cc;
+ cc >>= 32;
+ cc += (long)z[2];
+ z[2] = (uint)cc;
+ cc >>= 32;
+ }
+ cc += (long)z[3] - xx08;
+ z[3] = (uint)cc;
+ cc >>= 32;
+ if (cc != 0)
+ {
+ cc += (long)z[4];
+ z[4] = (uint)cc;
+ cc >>= 32;
+ cc += (long)z[5];
+ z[5] = (uint)cc;
+ cc >>= 32;
+ }
+ cc += (long)z[6] - xx08;
+ z[6] = (uint)cc;
+ cc >>= 32;
+ cc += (long)z[7] + xx08;
+ z[7] = (uint)cc;
+ cc >>= 32;
+
+ Debug.Assert(cc == 0 || cc == 1);
+ }
+
+ if (cc != 0 || (z[7] == P7 && Nat256.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static void Square(uint[] x, uint[] z)
+ {
+ uint[] tt = Nat256.CreateExt();
+ Nat256.Square(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareN(uint[] x, int n, uint[] z)
+ {
+ Debug.Assert(n > 0);
+
+ uint[] tt = Nat256.CreateExt();
+ Nat256.Square(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ Nat256.Square(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static void Subtract(uint[] x, uint[] y, uint[] z)
+ {
+ int c = Nat256.Sub(x, y, z);
+ if (c != 0)
+ {
+ SubPInvFrom(z);
+ }
+ }
+
+ public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ int c = Nat.Sub(16, xx, yy, zz);
+ if (c != 0)
+ {
+ Nat.AddTo(16, PExt, zz);
+ }
+ }
+
+ public static void Twice(uint[] x, uint[] z)
+ {
+ uint c = Nat.ShiftUpBit(8, x, 0, z);
+ if (c != 0 || (z[7] == P7 && Nat256.Gte(z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ private static void AddPInvTo(uint[] z)
+ {
+ long c = (long)z[0] + 1;
+ z[0] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (long)z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ }
+ c += (long)z[3] - 1;
+ z[3] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (long)z[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (long)z[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ }
+ c += (long)z[6] - 1;
+ z[6] = (uint)c;
+ c >>= 32;
+ c += (long)z[7] + 1;
+ z[7] = (uint)c;
+ //c >>= 32;
+ }
+
+ private static void SubPInvFrom(uint[] z)
+ {
+ long c = (long)z[0] - 1;
+ z[0] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (long)z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ }
+ c += (long)z[3] + 1;
+ z[3] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (long)z[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (long)z[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ }
+ c += (long)z[6] + 1;
+ z[6] = (uint)c;
+ c >>= 32;
+ c += (long)z[7] - 1;
+ z[7] = (uint)c;
+ //c >>= 32;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d7838aead9a520e5851b7b6c6ccfaf498223769c
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs
@@ -0,0 +1,188 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP256R1FieldElement
+ : ECFieldElement
+ {
+ public static readonly BigInteger Q = SecP256R1Curve.q;
+
+ protected internal readonly uint[] x;
+
+ public SecP256R1FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+ throw new ArgumentException("value invalid for SecP256R1FieldElement", "x");
+
+ this.x = SecP256R1Field.FromBigInteger(x);
+ }
+
+ public SecP256R1FieldElement()
+ {
+ this.x = Nat256.Create();
+ }
+
+ protected internal SecP256R1FieldElement(uint[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat256.IsZero(x); }
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat256.IsOne(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return Nat256.GetBit(x, 0) == 1;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat256.ToBigInteger(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecP256R1Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return Q.BitLength; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ uint[] z = Nat256.Create();
+ SecP256R1Field.Add(x, ((SecP256R1FieldElement)b).x, z);
+ return new SecP256R1FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ uint[] z = Nat256.Create();
+ SecP256R1Field.AddOne(x, z);
+ return new SecP256R1FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ uint[] z = Nat256.Create();
+ SecP256R1Field.Subtract(x, ((SecP256R1FieldElement)b).x, z);
+ return new SecP256R1FieldElement(z);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ uint[] z = Nat256.Create();
+ SecP256R1Field.Multiply(x, ((SecP256R1FieldElement)b).x, z);
+ return new SecP256R1FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ //return Multiply(b.Invert());
+ uint[] z = Nat256.Create();
+ Mod.Invert(SecP256R1Field.P, ((SecP256R1FieldElement)b).x, z);
+ SecP256R1Field.Multiply(z, x, z);
+ return new SecP256R1FieldElement(z);
+ }
+
+ public override ECFieldElement Negate()
+ {
+ uint[] z = Nat256.Create();
+ SecP256R1Field.Negate(x, z);
+ return new SecP256R1FieldElement(z);
+ }
+
+ public override ECFieldElement Square()
+ {
+ uint[] z = Nat256.Create();
+ SecP256R1Field.Square(x, z);
+ return new SecP256R1FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ //return new SecP256R1FieldElement(ToBigInteger().ModInverse(Q));
+ uint[] z = Nat256.Create();
+ Mod.Invert(SecP256R1Field.P, x, z);
+ return new SecP256R1FieldElement(z);
+ }
+
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public override ECFieldElement Sqrt()
+ {
+ // Raise this element to the exponent 2^254 - 2^222 + 2^190 + 2^94
+
+ uint[] x1 = this.x;
+ if (Nat256.IsZero(x1) || Nat256.IsOne(x1))
+ return this;
+
+ uint[] t1 = Nat256.Create();
+ uint[] t2 = Nat256.Create();
+
+ SecP256R1Field.Square(x1, t1);
+ SecP256R1Field.Multiply(t1, x1, t1);
+
+ SecP256R1Field.SquareN(t1, 2, t2);
+ SecP256R1Field.Multiply(t2, t1, t2);
+
+ SecP256R1Field.SquareN(t2, 4, t1);
+ SecP256R1Field.Multiply(t1, t2, t1);
+
+ SecP256R1Field.SquareN(t1, 8, t2);
+ SecP256R1Field.Multiply(t2, t1, t2);
+
+ SecP256R1Field.SquareN(t2, 16, t1);
+ SecP256R1Field.Multiply(t1, t2, t1);
+
+ SecP256R1Field.SquareN(t1, 32, t1);
+ SecP256R1Field.Multiply(t1, x1, t1);
+
+ SecP256R1Field.SquareN(t1, 96, t1);
+ SecP256R1Field.Multiply(t1, x1, t1);
+
+ SecP256R1Field.SquareN(t1, 94, t1);
+ SecP256R1Field.Multiply(t1, t1, t2);
+
+ return Nat256.Eq(x1, t2) ? new SecP256R1FieldElement(t1) : null;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecP256R1FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecP256R1FieldElement);
+ }
+
+ public virtual bool Equals(SecP256R1FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat256.Eq(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 8);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP256R1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP256R1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..83320824d8c2d160b6c930e49c0dc2c837768ded
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP256R1Point.cs
@@ -0,0 +1,279 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP256R1Point
+ : AbstractFpPoint
+ {
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ *
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecP256R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ * @param withCompression
+ * if true encode with point compression
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(bool)}
+ */
+ public SecP256R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecP256R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecP256R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+ if (this == b)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ SecP256R1FieldElement X1 = (SecP256R1FieldElement)this.RawXCoord, Y1 = (SecP256R1FieldElement)this.RawYCoord;
+ SecP256R1FieldElement X2 = (SecP256R1FieldElement)b.RawXCoord, Y2 = (SecP256R1FieldElement)b.RawYCoord;
+
+ SecP256R1FieldElement Z1 = (SecP256R1FieldElement)this.RawZCoords[0];
+ SecP256R1FieldElement Z2 = (SecP256R1FieldElement)b.RawZCoords[0];
+
+ uint c;
+ uint[] tt1 = Nat256.CreateExt();
+ uint[] t2 = Nat256.Create();
+ uint[] t3 = Nat256.Create();
+ uint[] t4 = Nat256.Create();
+
+ bool Z1IsOne = Z1.IsOne;
+ uint[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SecP256R1Field.Square(Z1.x, S2);
+
+ U2 = t2;
+ SecP256R1Field.Multiply(S2, X2.x, U2);
+
+ SecP256R1Field.Multiply(S2, Z1.x, S2);
+ SecP256R1Field.Multiply(S2, Y2.x, S2);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ uint[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SecP256R1Field.Square(Z2.x, S1);
+
+ U1 = tt1;
+ SecP256R1Field.Multiply(S1, X1.x, U1);
+
+ SecP256R1Field.Multiply(S1, Z2.x, S1);
+ SecP256R1Field.Multiply(S1, Y1.x, S1);
+ }
+
+ uint[] H = Nat256.Create();
+ SecP256R1Field.Subtract(U1, U2, H);
+
+ uint[] R = t2;
+ SecP256R1Field.Subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat256.IsZero(H))
+ {
+ if (Nat256.IsZero(R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ uint[] HSquared = t3;
+ SecP256R1Field.Square(H, HSquared);
+
+ uint[] G = Nat256.Create();
+ SecP256R1Field.Multiply(HSquared, H, G);
+
+ uint[] V = t3;
+ SecP256R1Field.Multiply(HSquared, U1, V);
+
+ SecP256R1Field.Negate(G, G);
+ Nat256.Mul(S1, G, tt1);
+
+ c = Nat256.AddBothTo(V, V, G);
+ SecP256R1Field.Reduce32(c, G);
+
+ SecP256R1FieldElement X3 = new SecP256R1FieldElement(t4);
+ SecP256R1Field.Square(R, X3.x);
+ SecP256R1Field.Subtract(X3.x, G, X3.x);
+
+ SecP256R1FieldElement Y3 = new SecP256R1FieldElement(G);
+ SecP256R1Field.Subtract(V, X3.x, Y3.x);
+ SecP256R1Field.MultiplyAddToExt(Y3.x, R, tt1);
+ SecP256R1Field.Reduce(tt1, Y3.x);
+
+ SecP256R1FieldElement Z3 = new SecP256R1FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SecP256R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SecP256R1Field.Multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+ return new SecP256R1Point(curve, X3, Y3, zs, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ SecP256R1FieldElement Y1 = (SecP256R1FieldElement)this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ SecP256R1FieldElement X1 = (SecP256R1FieldElement)this.RawXCoord, Z1 = (SecP256R1FieldElement)this.RawZCoords[0];
+
+ uint c;
+ uint[] t1 = Nat256.Create();
+ uint[] t2 = Nat256.Create();
+
+ uint[] Y1Squared = Nat256.Create();
+ SecP256R1Field.Square(Y1.x, Y1Squared);
+
+ uint[] T = Nat256.Create();
+ SecP256R1Field.Square(Y1Squared, T);
+
+ bool Z1IsOne = Z1.IsOne;
+
+ uint[] Z1Squared = Z1.x;
+ if (!Z1IsOne)
+ {
+ Z1Squared = t2;
+ SecP256R1Field.Square(Z1.x, Z1Squared);
+ }
+
+ SecP256R1Field.Subtract(X1.x, Z1Squared, t1);
+
+ uint[] M = t2;
+ SecP256R1Field.Add(X1.x, Z1Squared, M);
+ SecP256R1Field.Multiply(M, t1, M);
+ c = Nat256.AddBothTo(M, M, M);
+ SecP256R1Field.Reduce32(c, M);
+
+ uint[] S = Y1Squared;
+ SecP256R1Field.Multiply(Y1Squared, X1.x, S);
+ c = Nat.ShiftUpBits(8, S, 2, 0);
+ SecP256R1Field.Reduce32(c, S);
+
+ c = Nat.ShiftUpBits(8, T, 3, 0, t1);
+ SecP256R1Field.Reduce32(c, t1);
+
+ SecP256R1FieldElement X3 = new SecP256R1FieldElement(T);
+ SecP256R1Field.Square(M, X3.x);
+ SecP256R1Field.Subtract(X3.x, S, X3.x);
+ SecP256R1Field.Subtract(X3.x, S, X3.x);
+
+ SecP256R1FieldElement Y3 = new SecP256R1FieldElement(S);
+ SecP256R1Field.Subtract(S, X3.x, Y3.x);
+ SecP256R1Field.Multiply(Y3.x, M, Y3.x);
+ SecP256R1Field.Subtract(Y3.x, t1, Y3.x);
+
+ SecP256R1FieldElement Z3 = new SecP256R1FieldElement(M);
+ SecP256R1Field.Twice(Y1.x, Z3.x);
+ if (!Z1IsOne)
+ {
+ SecP256R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SecP256R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this == b)
+ return ThreeTimes();
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return b;
+
+ return Twice().Add(b);
+ }
+
+ public override ECPoint ThreeTimes()
+ {
+ if (this.IsInfinity || this.RawYCoord.IsZero)
+ return this;
+
+ // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+ return Twice().Add(this);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ return new SecP256R1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP384R1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP384R1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7fd58276a487a5e5b56a1af32758e7e8b7d1e0c6
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP384R1Curve.cs
@@ -0,0 +1,77 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP384R1Curve
+ : AbstractFpCurve
+ {
+ public static readonly BigInteger q = new BigInteger(1,
+ Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"));
+
+ private const int SecP384R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected readonly SecP384R1Point m_infinity;
+
+ public SecP384R1Curve()
+ : base(q)
+ {
+ this.m_infinity = new SecP384R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1,
+ Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC")));
+ this.m_b = FromBigInteger(new BigInteger(1,
+ Hex.Decode("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF")));
+ this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"));
+ this.m_cofactor = BigInteger.One;
+ this.m_coord = SecP384R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecP384R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecP384R1FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecP384R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecP384R1Point(this, x, y, zs, withCompression);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP384R1Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP384R1Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0780df3f03430e5a34a61d085d7da1e9d60dc02c
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP384R1Field.cs
@@ -0,0 +1,295 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP384R1Field
+ {
+ // 2^384 - 2^128 - 2^96 + 2^32 - 1
+ internal static readonly uint[] P = new uint[]{ 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ internal static readonly uint[] PExt = new uint[]{ 0x00000001, 0xFFFFFFFE, 0x00000000, 0x00000002, 0x00000000, 0xFFFFFFFE,
+ 0x00000000, 0x00000002, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFE, 0x00000001, 0x00000000,
+ 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ private static readonly uint[] PExtInv = new uint[]{ 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0x00000001,
+ 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001, 0xFFFFFFFE, 0xFFFFFFFF,
+ 0x00000001, 0x00000002 };
+ private const uint P11 = 0xFFFFFFFF;
+ private const uint PExt23 = 0xFFFFFFFF;
+
+ public static void Add(uint[] x, uint[] y, uint[] z)
+ {
+ uint c = Nat.Add(12, x, y, z);
+ if (c != 0 || (z[11] == P11 && Nat.Gte(12, z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ uint c = Nat.Add(24, xx, yy, zz);
+ if (c != 0 || (zz[23] == PExt23 && Nat.Gte(24, zz, PExt)))
+ {
+ if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.IncAt(24, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void AddOne(uint[] x, uint[] z)
+ {
+ uint c = Nat.Inc(12, x, z);
+ if (c != 0 || (z[11] == P11 && Nat.Gte(12, z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ uint[] z = Nat.FromBigInteger(384, x);
+ if (z[11] == P11 && Nat.Gte(12, z, P))
+ {
+ Nat.SubFrom(12, P, z);
+ }
+ return z;
+ }
+
+ public static void Half(uint[] x, uint[] z)
+ {
+ if ((x[0] & 1) == 0)
+ {
+ Nat.ShiftDownBit(12, x, 0, z);
+ }
+ else
+ {
+ uint c = Nat.Add(12, x, P, z);
+ Nat.ShiftDownBit(12, z, c);
+ }
+ }
+
+ public static void Multiply(uint[] x, uint[] y, uint[] z)
+ {
+ uint[] tt = Nat.Create(24);
+ Nat384.Mul(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void Negate(uint[] x, uint[] z)
+ {
+ if (Nat.IsZero(12, x))
+ {
+ Nat.Zero(12, z);
+ }
+ else
+ {
+ Nat.Sub(12, P, x, z);
+ }
+ }
+
+ public static void Reduce(uint[] xx, uint[] z)
+ {
+ long xx16 = xx[16], xx17 = xx[17], xx18 = xx[18], xx19 = xx[19];
+ long xx20 = xx[20], xx21 = xx[21], xx22 = xx[22], xx23 = xx[23];
+
+ const long n = 1;
+
+ long t0 = (long)xx[12] + xx20 - n;
+ long t1 = (long)xx[13] + xx22;
+ long t2 = (long)xx[14] + xx22 + xx23;
+ long t3 = (long)xx[15] + xx23;
+ long t4 = xx17 + xx21;
+ long t5 = xx21 - xx23;
+ long t6 = xx22 - xx23;
+ long t7 = t0 + t5;
+
+ long cc = 0;
+ cc += (long)xx[0] + t7;
+ z[0] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[1] + xx23 - t0 + t1;
+ z[1] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[2] - xx21 - t1 + t2;
+ z[2] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[3] - t2 + t3 + t7;
+ z[3] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[4] + xx16 + xx21 + t1 - t3 + t7;
+ z[4] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[5] - xx16 + t1 + t2 + t4;
+ z[5] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[6] + xx18 - xx17 + t2 + t3;
+ z[6] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[7] + xx16 + xx19 - xx18 + t3;
+ z[7] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[8] + xx16 + xx17 + xx20 - xx19;
+ z[8] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[9] + xx18 - xx20 + t4;
+ z[9] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[10] + xx18 + xx19 - t5 + t6;
+ z[10] = (uint)cc;
+ cc >>= 32;
+ cc += (long)xx[11] + xx19 + xx20 - t6;
+ z[11] = (uint)cc;
+ cc >>= 32;
+ cc += n;
+
+ Debug.Assert(cc >= 0);
+
+ Reduce32((uint)cc, z);
+ }
+
+ public static void Reduce32(uint x, uint[] z)
+ {
+ long cc = 0;
+
+ if (x != 0)
+ {
+ long xx12 = x;
+
+ cc += (long)z[0] + xx12;
+ z[0] = (uint)cc;
+ cc >>= 32;
+ cc += (long)z[1] - xx12;
+ z[1] = (uint)cc;
+ cc >>= 32;
+ if (cc != 0)
+ {
+ cc += (long)z[2];
+ z[2] = (uint)cc;
+ cc >>= 32;
+ }
+ cc += (long)z[3] + xx12;
+ z[3] = (uint)cc;
+ cc >>= 32;
+ cc += (long)z[4] + xx12;
+ z[4] = (uint)cc;
+ cc >>= 32;
+
+ Debug.Assert(cc == 0 || cc == 1);
+ }
+
+ if ((cc != 0 && Nat.IncAt(12, z, 5) != 0)
+ || (z[11] == P11 && Nat.Gte(12, z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ public static void Square(uint[] x, uint[] z)
+ {
+ uint[] tt = Nat.Create(24);
+ Nat384.Square(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareN(uint[] x, int n, uint[] z)
+ {
+ Debug.Assert(n > 0);
+
+ uint[] tt = Nat.Create(24);
+ Nat384.Square(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ Nat384.Square(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static void Subtract(uint[] x, uint[] y, uint[] z)
+ {
+ int c = Nat.Sub(12, x, y, z);
+ if (c != 0)
+ {
+ SubPInvFrom(z);
+ }
+ }
+
+ public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+ {
+ int c = Nat.Sub(24, xx, yy, zz);
+ if (c != 0)
+ {
+ if (Nat.SubFrom(PExtInv.Length, PExtInv, zz) != 0)
+ {
+ Nat.DecAt(24, zz, PExtInv.Length);
+ }
+ }
+ }
+
+ public static void Twice(uint[] x, uint[] z)
+ {
+ uint c = Nat.ShiftUpBit(12, x, 0, z);
+ if (c != 0 || (z[11] == P11 && Nat.Gte(12, z, P)))
+ {
+ AddPInvTo(z);
+ }
+ }
+
+ private static void AddPInvTo(uint[] z)
+ {
+ long c = (long)z[0] + 1;
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)z[1] - 1;
+ z[1] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (long)z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ }
+ c += (long)z[3] + 1;
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (long)z[4] + 1;
+ z[4] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ Nat.IncAt(12, z, 5);
+ }
+ }
+
+ private static void SubPInvFrom(uint[] z)
+ {
+ long c = (long)z[0] - 1;
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)z[1] + 1;
+ z[1] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ c += (long)z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ }
+ c += (long)z[3] - 1;
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (long)z[4] - 1;
+ z[4] = (uint)c;
+ c >>= 32;
+ if (c != 0)
+ {
+ Nat.DecAt(12, z, 5);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..18d48a57d2b408bd513b6ad32fa39bcb5c164523
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs
@@ -0,0 +1,210 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP384R1FieldElement
+ : ECFieldElement
+ {
+ public static readonly BigInteger Q = SecP384R1Curve.q;
+
+ protected internal readonly uint[] x;
+
+ public SecP384R1FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+ throw new ArgumentException("value invalid for SecP384R1FieldElement", "x");
+
+ this.x = SecP384R1Field.FromBigInteger(x);
+ }
+
+ public SecP384R1FieldElement()
+ {
+ this.x = Nat.Create(12);
+ }
+
+ protected internal SecP384R1FieldElement(uint[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat.IsZero(12, x); }
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat.IsOne(12, x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return Nat.GetBit(x, 0) == 1;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat.ToBigInteger(12, x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecP384R1Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return Q.BitLength; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ uint[] z = Nat.Create(12);
+ SecP384R1Field.Add(x, ((SecP384R1FieldElement)b).x, z);
+ return new SecP384R1FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ uint[] z = Nat.Create(12);
+ SecP384R1Field.AddOne(x, z);
+ return new SecP384R1FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ uint[] z = Nat.Create(12);
+ SecP384R1Field.Subtract(x, ((SecP384R1FieldElement)b).x, z);
+ return new SecP384R1FieldElement(z);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ uint[] z = Nat.Create(12);
+ SecP384R1Field.Multiply(x, ((SecP384R1FieldElement)b).x, z);
+ return new SecP384R1FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ //return Multiply(b.Invert());
+ uint[] z = Nat.Create(12);
+ Mod.Invert(SecP384R1Field.P, ((SecP384R1FieldElement)b).x, z);
+ SecP384R1Field.Multiply(z, x, z);
+ return new SecP384R1FieldElement(z);
+ }
+
+ public override ECFieldElement Negate()
+ {
+ uint[] z = Nat.Create(12);
+ SecP384R1Field.Negate(x, z);
+ return new SecP384R1FieldElement(z);
+ }
+
+ public override ECFieldElement Square()
+ {
+ uint[] z = Nat.Create(12);
+ SecP384R1Field.Square(x, z);
+ return new SecP384R1FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ //return new SecP384R1FieldElement(ToBigInteger().ModInverse(Q));
+ uint[] z = Nat.Create(12);
+ Mod.Invert(SecP384R1Field.P, x, z);
+ return new SecP384R1FieldElement(z);
+ }
+
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public override ECFieldElement Sqrt()
+ {
+ // Raise this element to the exponent 2^382 - 2^126 - 2^94 + 2^30
+
+ uint[] x1 = this.x;
+ if (Nat.IsZero(12, x1) || Nat.IsOne(12, x1))
+ return this;
+
+ uint[] t1 = Nat.Create(12);
+ uint[] t2 = Nat.Create(12);
+ uint[] t3 = Nat.Create(12);
+ uint[] t4 = Nat.Create(12);
+
+ SecP384R1Field.Square(x1, t1);
+ SecP384R1Field.Multiply(t1, x1, t1);
+
+ SecP384R1Field.SquareN(t1, 2, t2);
+ SecP384R1Field.Multiply(t2, t1, t2);
+
+ SecP384R1Field.Square(t2, t2);
+ SecP384R1Field.Multiply(t2, x1, t2);
+
+ SecP384R1Field.SquareN(t2, 5, t3);
+ SecP384R1Field.Multiply(t3, t2, t3);
+
+ SecP384R1Field.SquareN(t3, 5, t4);
+ SecP384R1Field.Multiply(t4, t2, t4);
+
+ SecP384R1Field.SquareN(t4, 15, t2);
+ SecP384R1Field.Multiply(t2, t4, t2);
+
+ SecP384R1Field.SquareN(t2, 2, t3);
+ SecP384R1Field.Multiply(t1, t3, t1);
+
+ SecP384R1Field.SquareN(t3, 28, t3);
+ SecP384R1Field.Multiply(t2, t3, t2);
+
+ SecP384R1Field.SquareN(t2, 60, t3);
+ SecP384R1Field.Multiply(t3, t2, t3);
+
+ uint[] r = t2;
+
+ SecP384R1Field.SquareN(t3, 120, r);
+ SecP384R1Field.Multiply(r, t3, r);
+
+ SecP384R1Field.SquareN(r, 15, r);
+ SecP384R1Field.Multiply(r, t4, r);
+
+ SecP384R1Field.SquareN(r, 33, r);
+ SecP384R1Field.Multiply(r, t1, r);
+
+ SecP384R1Field.SquareN(r, 64, r);
+ SecP384R1Field.Multiply(r, x1, r);
+
+ SecP384R1Field.SquareN(r, 30, t1);
+ SecP384R1Field.Square(t1, t2);
+
+ return Nat.Eq(12, x1, t2) ? new SecP384R1FieldElement(t1) : null;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecP384R1FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecP384R1FieldElement);
+ }
+
+ public virtual bool Equals(SecP384R1FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat.Eq(12, x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 12);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP384R1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP384R1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..83159ce61a5863b60c71214cc4a42d3158329d36
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP384R1Point.cs
@@ -0,0 +1,280 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP384R1Point
+ : AbstractFpPoint
+ {
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ *
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ * @param withCompression
+ * if true encode with point compression
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(bool)}
+ */
+ public SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecP384R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+ if (this == b)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ SecP384R1FieldElement X1 = (SecP384R1FieldElement)this.RawXCoord, Y1 = (SecP384R1FieldElement)this.RawYCoord;
+ SecP384R1FieldElement X2 = (SecP384R1FieldElement)b.RawXCoord, Y2 = (SecP384R1FieldElement)b.RawYCoord;
+
+ SecP384R1FieldElement Z1 = (SecP384R1FieldElement)this.RawZCoords[0];
+ SecP384R1FieldElement Z2 = (SecP384R1FieldElement)b.RawZCoords[0];
+
+ uint c;
+ uint[] tt1 = Nat.Create(24);
+ uint[] tt2 = Nat.Create(24);
+ uint[] t3 = Nat.Create(12);
+ uint[] t4 = Nat.Create(12);
+
+ bool Z1IsOne = Z1.IsOne;
+ uint[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SecP384R1Field.Square(Z1.x, S2);
+
+ U2 = tt2;
+ SecP384R1Field.Multiply(S2, X2.x, U2);
+
+ SecP384R1Field.Multiply(S2, Z1.x, S2);
+ SecP384R1Field.Multiply(S2, Y2.x, S2);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ uint[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SecP384R1Field.Square(Z2.x, S1);
+
+ U1 = tt1;
+ SecP384R1Field.Multiply(S1, X1.x, U1);
+
+ SecP384R1Field.Multiply(S1, Z2.x, S1);
+ SecP384R1Field.Multiply(S1, Y1.x, S1);
+ }
+
+ uint[] H = Nat.Create(12);
+ SecP384R1Field.Subtract(U1, U2, H);
+
+ uint[] R = Nat.Create(12);
+ SecP384R1Field.Subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat.IsZero(12, H))
+ {
+ if (Nat.IsZero(12, R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ uint[] HSquared = t3;
+ SecP384R1Field.Square(H, HSquared);
+
+ uint[] G = Nat.Create(12);
+ SecP384R1Field.Multiply(HSquared, H, G);
+
+ uint[] V = t3;
+ SecP384R1Field.Multiply(HSquared, U1, V);
+
+ SecP384R1Field.Negate(G, G);
+ Nat384.Mul(S1, G, tt1);
+
+ c = Nat.AddBothTo(12, V, V, G);
+ SecP384R1Field.Reduce32(c, G);
+
+ SecP384R1FieldElement X3 = new SecP384R1FieldElement(t4);
+ SecP384R1Field.Square(R, X3.x);
+ SecP384R1Field.Subtract(X3.x, G, X3.x);
+
+ SecP384R1FieldElement Y3 = new SecP384R1FieldElement(G);
+ SecP384R1Field.Subtract(V, X3.x, Y3.x);
+ Nat384.Mul(Y3.x, R, tt2);
+ SecP384R1Field.AddExt(tt1, tt2, tt1);
+ SecP384R1Field.Reduce(tt1, Y3.x);
+
+ SecP384R1FieldElement Z3 = new SecP384R1FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SecP384R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SecP384R1Field.Multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+ return new SecP384R1Point(curve, X3, Y3, zs, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ SecP384R1FieldElement Y1 = (SecP384R1FieldElement)this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ SecP384R1FieldElement X1 = (SecP384R1FieldElement)this.RawXCoord, Z1 = (SecP384R1FieldElement)this.RawZCoords[0];
+
+ uint c;
+ uint[] t1 = Nat.Create(12);
+ uint[] t2 = Nat.Create(12);
+
+ uint[] Y1Squared = Nat.Create(12);
+ SecP384R1Field.Square(Y1.x, Y1Squared);
+
+ uint[] T = Nat.Create(12);
+ SecP384R1Field.Square(Y1Squared, T);
+
+ bool Z1IsOne = Z1.IsOne;
+
+ uint[] Z1Squared = Z1.x;
+ if (!Z1IsOne)
+ {
+ Z1Squared = t2;
+ SecP384R1Field.Square(Z1.x, Z1Squared);
+ }
+
+ SecP384R1Field.Subtract(X1.x, Z1Squared, t1);
+
+ uint[] M = t2;
+ SecP384R1Field.Add(X1.x, Z1Squared, M);
+ SecP384R1Field.Multiply(M, t1, M);
+ c = Nat.AddBothTo(12, M, M, M);
+ SecP384R1Field.Reduce32(c, M);
+
+ uint[] S = Y1Squared;
+ SecP384R1Field.Multiply(Y1Squared, X1.x, S);
+ c = Nat.ShiftUpBits(12, S, 2, 0);
+ SecP384R1Field.Reduce32(c, S);
+
+ c = Nat.ShiftUpBits(12, T, 3, 0, t1);
+ SecP384R1Field.Reduce32(c, t1);
+
+ SecP384R1FieldElement X3 = new SecP384R1FieldElement(T);
+ SecP384R1Field.Square(M, X3.x);
+ SecP384R1Field.Subtract(X3.x, S, X3.x);
+ SecP384R1Field.Subtract(X3.x, S, X3.x);
+
+ SecP384R1FieldElement Y3 = new SecP384R1FieldElement(S);
+ SecP384R1Field.Subtract(S, X3.x, Y3.x);
+ SecP384R1Field.Multiply(Y3.x, M, Y3.x);
+ SecP384R1Field.Subtract(Y3.x, t1, Y3.x);
+
+ SecP384R1FieldElement Z3 = new SecP384R1FieldElement(M);
+ SecP384R1Field.Twice(Y1.x, Z3.x);
+ if (!Z1IsOne)
+ {
+ SecP384R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SecP384R1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this == b)
+ return ThreeTimes();
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return b;
+
+ return Twice().Add(b);
+ }
+
+ public override ECPoint ThreeTimes()
+ {
+ if (this.IsInfinity || this.RawYCoord.IsZero)
+ return this;
+
+ // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+ return Twice().Add(this);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ return new SecP384R1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP521R1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP521R1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e5083c7f0ebefe1086231fa7993e05102b26ecd7
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP521R1Curve.cs
@@ -0,0 +1,77 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP521R1Curve
+ : AbstractFpCurve
+ {
+ public static readonly BigInteger q = new BigInteger(1,
+ Hex.Decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));
+
+ private const int SecP521R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+ protected readonly SecP521R1Point m_infinity;
+
+ public SecP521R1Curve()
+ : base(q)
+ {
+ this.m_infinity = new SecP521R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1,
+ Hex.Decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC")));
+ this.m_b = FromBigInteger(new BigInteger(1,
+ Hex.Decode("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00")));
+ this.m_order = new BigInteger(1, Hex.Decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409"));
+ this.m_cofactor = BigInteger.One;
+ this.m_coord = SecP521R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecP521R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_JACOBIAN:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public virtual BigInteger Q
+ {
+ get { return q; }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return q.BitLength; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecP521R1FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecP521R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecP521R1Point(this, x, y, zs, withCompression);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP521R1Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP521R1Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b7f8eb146276e17bc3ff044e1f76e86d469d356d
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP521R1Field.cs
@@ -0,0 +1,155 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP521R1Field
+ {
+ // 2^521 - 1
+ internal static readonly uint[] P = new uint[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x1FF };
+ private const int P16 = 0x1FF;
+
+ public static void Add(uint[] x, uint[] y, uint[] z)
+ {
+ uint c = Nat.Add(16, x, y, z) + x[16] + y[16];
+ if (c > P16 || (c == P16 && Nat.Eq(16, z, P)))
+ {
+ c += Nat.Inc(16, z);
+ c &= P16;
+ }
+ z[16] = c;
+ }
+
+ public static void AddOne(uint[] x, uint[] z)
+ {
+ uint c = Nat.Inc(16, x, z) + x[16];
+ if (c > P16 || (c == P16 && Nat.Eq(16, z, P)))
+ {
+ c += Nat.Inc(16, z);
+ c &= P16;
+ }
+ z[16] = c;
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ uint[] z = Nat.FromBigInteger(521, x);
+ if (Nat.Eq(17, z, P))
+ {
+ Nat.Zero(17, z);
+ }
+ return z;
+ }
+
+ public static void Half(uint[] x, uint[] z)
+ {
+ uint x16 = x[16];
+ uint c = Nat.ShiftDownBit(16, x, x16, z);
+ z[16] = (x16 >> 1) | (c >> 23);
+ }
+
+ public static void Multiply(uint[] x, uint[] y, uint[] z)
+ {
+ uint[] tt = Nat.Create(33);
+ ImplMultiply(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void Negate(uint[] x, uint[] z)
+ {
+ if (Nat.IsZero(17, x))
+ {
+ Nat.Zero(17, z);
+ }
+ else
+ {
+ Nat.Sub(17, P, x, z);
+ }
+ }
+
+ public static void Reduce(uint[] xx, uint[] z)
+ {
+ Debug.Assert(xx[32] >> 18 == 0);
+ uint xx32 = xx[32];
+ uint c = Nat.ShiftDownBits(16, xx, 16, 9, xx32, z, 0) >> 23;
+ c += xx32 >> 9;
+ c += Nat.AddTo(16, xx, z);
+ if (c > P16 || (c == P16 && Nat.Eq(16, z, P)))
+ {
+ c += Nat.Inc(16, z);
+ c &= P16;
+ }
+ z[16] = c;
+ }
+
+ public static void Reduce23(uint[] z)
+ {
+ uint z16 = z[16];
+ uint c = Nat.AddWordTo(16, z16 >> 9, z) + (z16 & P16);
+ if (c > P16 || (c == P16 && Nat.Eq(16, z, P)))
+ {
+ c += Nat.Inc(16, z);
+ c &= P16;
+ }
+ z[16] = c;
+ }
+
+ public static void Square(uint[] x, uint[] z)
+ {
+ uint[] tt = Nat.Create(33);
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareN(uint[] x, int n, uint[] z)
+ {
+ Debug.Assert(n > 0);
+ uint[] tt = Nat.Create(33);
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ ImplSquare(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static void Subtract(uint[] x, uint[] y, uint[] z)
+ {
+ int c = Nat.Sub(16, x, y, z) + (int)(x[16] - y[16]);
+ if (c < 0)
+ {
+ c += Nat.Dec(16, z);
+ c &= P16;
+ }
+ z[16] = (uint)c;
+ }
+
+ public static void Twice(uint[] x, uint[] z)
+ {
+ uint x16 = x[16];
+ uint c = Nat.ShiftUpBit(16, x, x16 << 23, z) | (x16 << 1);
+ z[16] = c & P16;
+ }
+
+ protected static void ImplMultiply(uint[] x, uint[] y, uint[] zz)
+ {
+ Nat512.Mul(x, y, zz);
+
+ uint x16 = x[16], y16 = y[16];
+ zz[32] = Nat.Mul31BothAdd(16, x16, y, y16, x, zz, 16) + (x16 * y16);
+ }
+
+ protected static void ImplSquare(uint[] x, uint[] zz)
+ {
+ Nat512.Square(x, zz);
+
+ uint x16 = x[16];
+ zz[32] = Nat.MulWordAddTo(16, x16 << 1, x, 0, zz, 16) + (x16 * x16);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6f02a7eb581bb221458fdb5937062bb86071546c
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs
@@ -0,0 +1,167 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP521R1FieldElement
+ : ECFieldElement
+ {
+ public static readonly BigInteger Q = SecP521R1Curve.q;
+
+ protected internal readonly uint[] x;
+
+ public SecP521R1FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+ throw new ArgumentException("value invalid for SecP521R1FieldElement", "x");
+
+ this.x = SecP521R1Field.FromBigInteger(x);
+ }
+
+ public SecP521R1FieldElement()
+ {
+ this.x = Nat.Create(17);
+ }
+
+ protected internal SecP521R1FieldElement(uint[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat.IsZero(17, x); }
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat.IsOne(17, x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return Nat.GetBit(x, 0) == 1;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat.ToBigInteger(17, x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecP521R1Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return Q.BitLength; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ uint[] z = Nat.Create(17);
+ SecP521R1Field.Add(x, ((SecP521R1FieldElement)b).x, z);
+ return new SecP521R1FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ uint[] z = Nat.Create(17);
+ SecP521R1Field.AddOne(x, z);
+ return new SecP521R1FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ uint[] z = Nat.Create(17);
+ SecP521R1Field.Subtract(x, ((SecP521R1FieldElement)b).x, z);
+ return new SecP521R1FieldElement(z);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ uint[] z = Nat.Create(17);
+ SecP521R1Field.Multiply(x, ((SecP521R1FieldElement)b).x, z);
+ return new SecP521R1FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ //return Multiply(b.Invert());
+ uint[] z = Nat.Create(17);
+ Mod.Invert(SecP521R1Field.P, ((SecP521R1FieldElement)b).x, z);
+ SecP521R1Field.Multiply(z, x, z);
+ return new SecP521R1FieldElement(z);
+ }
+
+ public override ECFieldElement Negate()
+ {
+ uint[] z = Nat.Create(17);
+ SecP521R1Field.Negate(x, z);
+ return new SecP521R1FieldElement(z);
+ }
+
+ public override ECFieldElement Square()
+ {
+ uint[] z = Nat.Create(17);
+ SecP521R1Field.Square(x, z);
+ return new SecP521R1FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ //return new SecP521R1FieldElement(ToBigInteger().ModInverse(Q));
+ uint[] z = Nat.Create(17);
+ Mod.Invert(SecP521R1Field.P, x, z);
+ return new SecP521R1FieldElement(z);
+ }
+
+ /**
+ * return a sqrt root - the routine verifies that the calculation returns the right value - if
+ * none exists it returns null.
+ */
+ public override ECFieldElement Sqrt()
+ {
+ // Raise this element to the exponent 2^519
+
+ uint[] x1 = this.x;
+ if (Nat.IsZero(17, x1) || Nat.IsOne(17, x1))
+ return this;
+
+ uint[] t1 = Nat.Create(17);
+ uint[] t2 = Nat.Create(17);
+
+ SecP521R1Field.SquareN(x1, 519, t1);
+ SecP521R1Field.Square(t1, t2);
+
+ return Nat.Eq(17, x1, t2) ? new SecP521R1FieldElement(t1) : null;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecP521R1FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecP521R1FieldElement);
+ }
+
+ public virtual bool Equals(SecP521R1FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat.Eq(17, x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 17);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecP521R1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecP521R1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7ad97f76f9cdb0487c5537970422856c9629d352
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecP521R1Point.cs
@@ -0,0 +1,275 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecP521R1Point
+ : AbstractFpPoint
+ {
+ /**
+ * Create a point which encodes with point compression.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ *
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * Create a point that encodes with or without point compresion.
+ *
+ * @param curve
+ * the curve to use
+ * @param x
+ * affine x co-ordinate
+ * @param y
+ * affine y co-ordinate
+ * @param withCompression
+ * if true encode with point compression
+ *
+ * @deprecated per-point compression property will be removed, refer
+ * {@link #getEncoded(bool)}
+ */
+ public SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecP521R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+ if (this == b)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ SecP521R1FieldElement X1 = (SecP521R1FieldElement)this.RawXCoord, Y1 = (SecP521R1FieldElement)this.RawYCoord;
+ SecP521R1FieldElement X2 = (SecP521R1FieldElement)b.RawXCoord, Y2 = (SecP521R1FieldElement)b.RawYCoord;
+
+ SecP521R1FieldElement Z1 = (SecP521R1FieldElement)this.RawZCoords[0];
+ SecP521R1FieldElement Z2 = (SecP521R1FieldElement)b.RawZCoords[0];
+
+ uint[] t1 = Nat.Create(17);
+ uint[] t2 = Nat.Create(17);
+ uint[] t3 = Nat.Create(17);
+ uint[] t4 = Nat.Create(17);
+
+ bool Z1IsOne = Z1.IsOne;
+ uint[] U2, S2;
+ if (Z1IsOne)
+ {
+ U2 = X2.x;
+ S2 = Y2.x;
+ }
+ else
+ {
+ S2 = t3;
+ SecP521R1Field.Square(Z1.x, S2);
+
+ U2 = t2;
+ SecP521R1Field.Multiply(S2, X2.x, U2);
+
+ SecP521R1Field.Multiply(S2, Z1.x, S2);
+ SecP521R1Field.Multiply(S2, Y2.x, S2);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ uint[] U1, S1;
+ if (Z2IsOne)
+ {
+ U1 = X1.x;
+ S1 = Y1.x;
+ }
+ else
+ {
+ S1 = t4;
+ SecP521R1Field.Square(Z2.x, S1);
+
+ U1 = t1;
+ SecP521R1Field.Multiply(S1, X1.x, U1);
+
+ SecP521R1Field.Multiply(S1, Z2.x, S1);
+ SecP521R1Field.Multiply(S1, Y1.x, S1);
+ }
+
+ uint[] H = Nat.Create(17);
+ SecP521R1Field.Subtract(U1, U2, H);
+
+ uint[] R = t2;
+ SecP521R1Field.Subtract(S1, S2, R);
+
+ // Check if b == this or b == -this
+ if (Nat.IsZero(17, H))
+ {
+ if (Nat.IsZero(17, R))
+ {
+ // this == b, i.e. this must be doubled
+ return this.Twice();
+ }
+
+ // this == -b, i.e. the result is the point at infinity
+ return curve.Infinity;
+ }
+
+ uint[] HSquared = t3;
+ SecP521R1Field.Square(H, HSquared);
+
+ uint[] G = Nat.Create(17);
+ SecP521R1Field.Multiply(HSquared, H, G);
+
+ uint[] V = t3;
+ SecP521R1Field.Multiply(HSquared, U1, V);
+
+ SecP521R1Field.Multiply(S1, G, t1);
+
+ SecP521R1FieldElement X3 = new SecP521R1FieldElement(t4);
+ SecP521R1Field.Square(R, X3.x);
+ SecP521R1Field.Add(X3.x, G, X3.x);
+ SecP521R1Field.Subtract(X3.x, V, X3.x);
+ SecP521R1Field.Subtract(X3.x, V, X3.x);
+
+ SecP521R1FieldElement Y3 = new SecP521R1FieldElement(G);
+ SecP521R1Field.Subtract(V, X3.x, Y3.x);
+ SecP521R1Field.Multiply(Y3.x, R, t2);
+ SecP521R1Field.Subtract(t2, t1, Y3.x);
+
+ SecP521R1FieldElement Z3 = new SecP521R1FieldElement(H);
+ if (!Z1IsOne)
+ {
+ SecP521R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+ if (!Z2IsOne)
+ {
+ SecP521R1Field.Multiply(Z3.x, Z2.x, Z3.x);
+ }
+
+ ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+ return new SecP521R1Point(curve, X3, Y3, zs, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ SecP521R1FieldElement Y1 = (SecP521R1FieldElement)this.RawYCoord;
+ if (Y1.IsZero)
+ return curve.Infinity;
+
+ SecP521R1FieldElement X1 = (SecP521R1FieldElement)this.RawXCoord, Z1 = (SecP521R1FieldElement)this.RawZCoords[0];
+
+ uint[] t1 = Nat.Create(17);
+ uint[] t2 = Nat.Create(17);
+
+ uint[] Y1Squared = Nat.Create(17);
+ SecP521R1Field.Square(Y1.x, Y1Squared);
+
+ uint[] T = Nat.Create(17);
+ SecP521R1Field.Square(Y1Squared, T);
+
+ bool Z1IsOne = Z1.IsOne;
+
+ uint[] Z1Squared = Z1.x;
+ if (!Z1IsOne)
+ {
+ Z1Squared = t2;
+ SecP521R1Field.Square(Z1.x, Z1Squared);
+ }
+
+ SecP521R1Field.Subtract(X1.x, Z1Squared, t1);
+
+ uint[] M = t2;
+ SecP521R1Field.Add(X1.x, Z1Squared, M);
+ SecP521R1Field.Multiply(M, t1, M);
+ Nat.AddBothTo(17, M, M, M);
+ SecP521R1Field.Reduce23(M);
+
+ uint[] S = Y1Squared;
+ SecP521R1Field.Multiply(Y1Squared, X1.x, S);
+ Nat.ShiftUpBits(17, S, 2, 0);
+ SecP521R1Field.Reduce23(S);
+
+ Nat.ShiftUpBits(17, T, 3, 0, t1);
+ SecP521R1Field.Reduce23(t1);
+
+ SecP521R1FieldElement X3 = new SecP521R1FieldElement(T);
+ SecP521R1Field.Square(M, X3.x);
+ SecP521R1Field.Subtract(X3.x, S, X3.x);
+ SecP521R1Field.Subtract(X3.x, S, X3.x);
+
+ SecP521R1FieldElement Y3 = new SecP521R1FieldElement(S);
+ SecP521R1Field.Subtract(S, X3.x, Y3.x);
+ SecP521R1Field.Multiply(Y3.x, M, Y3.x);
+ SecP521R1Field.Subtract(Y3.x, t1, Y3.x);
+
+ SecP521R1FieldElement Z3 = new SecP521R1FieldElement(M);
+ SecP521R1Field.Twice(Y1.x, Z3.x);
+ if (!Z1IsOne)
+ {
+ SecP521R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+ }
+
+ return new SecP521R1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this == b)
+ return ThreeTimes();
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECFieldElement Y1 = this.RawYCoord;
+ if (Y1.IsZero)
+ return b;
+
+ return Twice().Add(b);
+ }
+
+ public override ECPoint ThreeTimes()
+ {
+ if (this.IsInfinity || this.RawYCoord.IsZero)
+ return this;
+
+ // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+ return Twice().Add(this);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ return new SecP521R1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT113Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT113Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..49773b66d4cdbef908505b3a8f68d23fa5b79e9b
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT113Field.cs
@@ -0,0 +1,225 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT113Field
+ {
+ private const ulong M49 = ulong.MaxValue >> 15;
+ private const ulong M57 = ulong.MaxValue >> 7;
+
+ public static void Add(ulong[] x, ulong[] y, ulong[] z)
+ {
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
+ }
+
+ public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+ {
+ zz[0] = xx[0] ^ yy[0];
+ zz[1] = xx[1] ^ yy[1];
+ zz[2] = xx[2] ^ yy[2];
+ zz[3] = xx[3] ^ yy[3];
+ }
+
+ public static void AddOne(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0] ^ 1UL;
+ z[1] = x[1];
+ }
+
+ public static ulong[] FromBigInteger(BigInteger x)
+ {
+ ulong[] z = Nat128.FromBigInteger64(x);
+ Reduce15(z, 0);
+ return z;
+ }
+
+ public static void Invert(ulong[] x, ulong[] z)
+ {
+ if (Nat128.IsZero64(x))
+ throw new InvalidOperationException();
+
+ // Itoh-Tsujii inversion
+
+ ulong[] t0 = Nat128.Create64();
+ ulong[] t1 = Nat128.Create64();
+
+ Square(x, t0);
+ Multiply(t0, x, t0);
+ Square(t0, t0);
+ Multiply(t0, x, t0);
+ SquareN(t0, 3, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, t1);
+ Multiply(t1, x, t1);
+ SquareN(t1, 7, t0);
+ Multiply(t0, t1, t0);
+ SquareN(t0, 14, t1);
+ Multiply(t1, t0, t1);
+ SquareN(t1, 28, t0);
+ Multiply(t0, t1, t0);
+ SquareN(t0, 56, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, z);
+ }
+
+ public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+ {
+ ulong[] tt = Nat128.CreateExt64();
+ ImplMultiply(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] tt = Nat128.CreateExt64();
+ ImplMultiply(x, y, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void Reduce(ulong[] xx, ulong[] z)
+ {
+ ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3];
+
+ x1 ^= (x3 << 15) ^ (x3 << 24);
+ x2 ^= (x3 >> 49) ^ (x3 >> 40);
+
+ x0 ^= (x2 << 15) ^ (x2 << 24);
+ x1 ^= (x2 >> 49) ^ (x2 >> 40);
+
+ ulong t = x1 >> 49;
+ z[0] = x0 ^ t ^ (t << 9);
+ z[1] = x1 & M49;
+ }
+
+ public static void Reduce15(ulong[] z, int zOff)
+ {
+ ulong z1 = z[zOff + 1], t = z1 >> 49;
+ z[zOff ] ^= t ^ (t << 9);
+ z[zOff + 1] = z1 & M49;
+ }
+
+ public static void Sqrt(ulong[] x, ulong[] z)
+ {
+ ulong u0 = Interleave.Unshuffle(x[0]), u1 = Interleave.Unshuffle(x[1]);
+ ulong e0 = (u0 & 0x00000000FFFFFFFFUL) | (u1 << 32);
+ ulong c0 = (u0 >> 32) | (u1 & 0xFFFFFFFF00000000UL);
+
+ z[0] = e0 ^ (c0 << 57) ^ (c0 << 5);
+ z[1] = (c0 >> 7) ^ (c0 >> 59);
+ }
+
+ public static void Square(ulong[] x, ulong[] z)
+ {
+ ulong[] tt = Nat128.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareAddToExt(ulong[] x, ulong[] zz)
+ {
+ ulong[] tt = Nat128.CreateExt64();
+ ImplSquare(x, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void SquareN(ulong[] x, int n, ulong[] z)
+ {
+ Debug.Assert(n > 0);
+
+ ulong[] tt = Nat128.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ ImplSquare(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static uint Trace(ulong[] x)
+ {
+ // Non-zero-trace bits: 0
+ return (uint)(x[0]) & 1U;
+ }
+
+ protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ /*
+ * "Three-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
+ */
+
+ ulong f0 = x[0], f1 = x[1];
+ f1 = ((f0 >> 57) ^ (f1 << 7)) & M57;
+ f0 &= M57;
+
+ ulong g0 = y[0], g1 = y[1];
+ g1 = ((g0 >> 57) ^ (g1 << 7)) & M57;
+ g0 &= M57;
+
+ ulong[] H = new ulong[6];
+
+ ImplMulw(f0, g0, H, 0); // H(0) 57/56 bits
+ ImplMulw(f1, g1, H, 2); // H(INF) 57/54 bits
+ ImplMulw(f0 ^ f1, g0 ^ g1, H, 4); // H(1) 57/56 bits
+
+ ulong r = H[1] ^ H[2];
+ ulong z0 = H[0],
+ z3 = H[3],
+ z1 = H[4] ^ z0 ^ r,
+ z2 = H[5] ^ z3 ^ r;
+
+ zz[0] = z0 ^ (z1 << 57);
+ zz[1] = (z1 >> 7) ^ (z2 << 50);
+ zz[2] = (z2 >> 14) ^ (z3 << 43);
+ zz[3] = (z3 >> 21);
+ }
+
+ protected static void ImplMulw(ulong x, ulong y, ulong[] z, int zOff)
+ {
+ Debug.Assert(x >> 57 == 0);
+ Debug.Assert(y >> 57 == 0);
+
+ ulong[] u = new ulong[8];
+ //u[0] = 0;
+ u[1] = y;
+ u[2] = u[1] << 1;
+ u[3] = u[2] ^ y;
+ u[4] = u[2] << 1;
+ u[5] = u[4] ^ y;
+ u[6] = u[3] << 1;
+ u[7] = u[6] ^ y;
+
+ uint j = (uint)x;
+ ulong g, h = 0, l = u[j & 7];
+ int k = 48;
+ do
+ {
+ j = (uint)(x >> k);
+ g = u[j & 7]
+ ^ u[(j >> 3) & 7] << 3
+ ^ u[(j >> 6) & 7] << 6;
+ l ^= (g << k);
+ h ^= (g >> -k);
+ }
+ while ((k -= 9) > 0);
+
+ h ^= ((x & 0x0100804020100800UL) & (ulong)(((long)y << 7) >> 63)) >> 8;
+
+ Debug.Assert(h >> 49 == 0);
+
+ z[zOff ] = l & M57;
+ z[zOff + 1] = (l >> 57) ^ (h << 7);
+ }
+
+ protected static void ImplSquare(ulong[] x, ulong[] zz)
+ {
+ Interleave.Expand64To128(x[0], zz, 0);
+ Interleave.Expand64To128(x[1], zz, 2);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT113FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT113FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9ba25d98762cd444e0af0b7d24dd87d6355433fb
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT113FieldElement.cs
@@ -0,0 +1,216 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT113FieldElement
+ : ECFieldElement
+ {
+ protected internal readonly ulong[] x;
+
+ public SecT113FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.BitLength > 113)
+ throw new ArgumentException("value invalid for SecT113FieldElement", "x");
+
+ this.x = SecT113Field.FromBigInteger(x);
+ }
+
+ public SecT113FieldElement()
+ {
+ this.x = Nat128.Create64();
+ }
+
+ protected internal SecT113FieldElement(ulong[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat128.IsOne64(x); }
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat128.IsZero64(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return (x[0] & 1L) != 0L;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat128.ToBigInteger64(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecT113Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 113; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ ulong[] z = Nat128.Create64();
+ SecT113Field.Add(x, ((SecT113FieldElement)b).x, z);
+ return new SecT113FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ ulong[] z = Nat128.Create64();
+ SecT113Field.AddOne(x, z);
+ return new SecT113FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ // Addition and Subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ ulong[] z = Nat128.Create64();
+ SecT113Field.Multiply(x, ((SecT113FieldElement)b).x, z);
+ return new SecT113FieldElement(z);
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return MultiplyPlusProduct(b, x, y);
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x, bx = ((SecT113FieldElement)b).x;
+ ulong[] xx = ((SecT113FieldElement)x).x, yx = ((SecT113FieldElement)y).x;
+
+ ulong[] tt = Nat128.CreateExt64();
+ SecT113Field.MultiplyAddToExt(ax, bx, tt);
+ SecT113Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat128.Create64();
+ SecT113Field.Reduce(tt, z);
+ return new SecT113FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ return Multiply(b.Invert());
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ ulong[] z = Nat128.Create64();
+ SecT113Field.Square(x, z);
+ return new SecT113FieldElement(z);
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return SquarePlusProduct(x, y);
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x;
+ ulong[] xx = ((SecT113FieldElement)x).x, yx = ((SecT113FieldElement)y).x;
+
+ ulong[] tt = Nat128.CreateExt64();
+ SecT113Field.SquareAddToExt(ax, tt);
+ SecT113Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat128.Create64();
+ SecT113Field.Reduce(tt, z);
+ return new SecT113FieldElement(z);
+ }
+
+ public override ECFieldElement SquarePow(int pow)
+ {
+ if (pow < 1)
+ return this;
+
+ ulong[] z = Nat128.Create64();
+ SecT113Field.SquareN(x, pow, z);
+ return new SecT113FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ ulong[] z = Nat128.Create64();
+ SecT113Field.Invert(x, z);
+ return new SecT113FieldElement(z);
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ ulong[] z = Nat128.Create64();
+ SecT113Field.Sqrt(x, z);
+ return new SecT113FieldElement(z);
+ }
+
+ public virtual int Representation
+ {
+ get { return F2mFieldElement.Tpb; }
+ }
+
+ public virtual int M
+ {
+ get { return 113; }
+ }
+
+ public virtual int K1
+ {
+ get { return 9; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecT113FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecT113FieldElement);
+ }
+
+ public virtual bool Equals(SecT113FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat128.Eq64(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return 113009 ^ Arrays.GetHashCode(x, 0, 2);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT113R1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT113R1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2705c94aaa6b6c466fdd030eb434beab1d1f7ac0
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT113R1Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT113R1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT113R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT113R1Point m_infinity;
+
+ public SecT113R1Curve()
+ : base(113, 9, 0, 0)
+ {
+ this.m_infinity = new SecT113R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1, Hex.Decode("003088250CA6E7C7FE649CE85820F7")));
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("00E8BEE4D3E2260744188BE0E9C723")));
+ this.m_order = new BigInteger(1, Hex.Decode("0100000000000000D9CCEC8A39E56F"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT113R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT113R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 113; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT113FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT113R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT113R1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 113; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return true; }
+ }
+
+ public virtual int K1
+ {
+ get { return 9; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT113R1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT113R1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6ecc8b01a6a0233c5ec14dfa2bfcf227db401a2e
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT113R1Point.cs
@@ -0,0 +1,281 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT113R1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT113R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT113R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT113R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT113R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ if (X3.IsZero)
+ {
+ return new SecT113R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT113R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT113R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement a = curve.A;
+ ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+ if (T.IsZero)
+ {
+ return new SecT113R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT113R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT113R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT113R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT113R1Point(Curve, X, L.Add(Z), new ECFieldElement[]{ Z }, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT113R2Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT113R2Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..abfd26d5bcbab3b87833218d1689d172e3b1147d
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT113R2Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT113R2Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT113R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT113R2Point m_infinity;
+
+ public SecT113R2Curve()
+ : base(113, 9, 0, 0)
+ {
+ this.m_infinity = new SecT113R2Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1, Hex.Decode("00689918DBEC7E5A0DD6DFC0AA55C7")));
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("0095E9A9EC9B297BD4BF36E059184F")));
+ this.m_order = new BigInteger(1, Hex.Decode("010000000000000108789B2496AF93"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT113R2_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT113R2Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 113; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT113FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT113R2Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT113R2Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 113; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return true; }
+ }
+
+ public virtual int K1
+ {
+ get { return 9; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT113R2Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT113R2Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1453d78c3b031daa0a0cab2c82bd3706208e9a33
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT113R2Point.cs
@@ -0,0 +1,291 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT113R2Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT113R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT113R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT113R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT113R2Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ {
+ return b;
+ }
+ if (b.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ if (X3.IsZero)
+ {
+ return new SecT113R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT113R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT113R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement a = curve.A;
+ ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+ if (T.IsZero)
+ {
+ return new SecT113R2Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT113R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ {
+ return b;
+ }
+ if (b.IsInfinity)
+ {
+ return Twice();
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT113R2Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT113R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT113R2Point(Curve, X, L.Add(Z), new ECFieldElement[]{ Z }, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT131Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT131Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1b6697afee2dbd1afd699cd95e3af5effe04f3f7
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT131Field.cs
@@ -0,0 +1,330 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT131Field
+ {
+ private const ulong M03 = ulong.MaxValue >> 61;
+ private const ulong M44 = ulong.MaxValue >> 20;
+
+ private static readonly ulong[] ROOT_Z = new ulong[]{ 0x26BC4D789AF13523UL, 0x26BC4D789AF135E2UL, 0x6UL };
+
+ public static void Add(ulong[] x, ulong[] y, ulong[] z)
+ {
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
+ z[2] = x[2] ^ y[2];
+ }
+
+ public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+ {
+ zz[0] = xx[0] ^ yy[0];
+ zz[1] = xx[1] ^ yy[1];
+ zz[2] = xx[2] ^ yy[2];
+ zz[3] = xx[3] ^ yy[3];
+ zz[4] = xx[4] ^ yy[4];
+ }
+
+ public static void AddOne(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0] ^ 1UL;
+ z[1] = x[1];
+ z[2] = x[2];
+ }
+
+ public static ulong[] FromBigInteger(BigInteger x)
+ {
+ ulong[] z = Nat192.FromBigInteger64(x);
+ Reduce61(z, 0);
+ return z;
+ }
+
+ public static void Invert(ulong[] x, ulong[] z)
+ {
+ if (Nat192.IsZero64(x))
+ throw new InvalidOperationException();
+
+ // Itoh-Tsujii inversion
+
+ ulong[] t0 = Nat192.Create64();
+ ulong[] t1 = Nat192.Create64();
+
+ Square(x, t0);
+ Multiply(t0, x, t0);
+ SquareN(t0, 2, t1);
+ Multiply(t1, t0, t1);
+ SquareN(t1, 4, t0);
+ Multiply(t0, t1, t0);
+ SquareN(t0, 8, t1);
+ Multiply(t1, t0, t1);
+ SquareN(t1, 16, t0);
+ Multiply(t0, t1, t0);
+ SquareN(t0, 32, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, t1);
+ Multiply(t1, x, t1);
+ SquareN(t1, 65, t0);
+ Multiply(t0, t1, t0);
+ Square(t0, z);
+ }
+
+ public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+ {
+ ulong[] tt = Nat192.CreateExt64();
+ ImplMultiply(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] tt = Nat192.CreateExt64();
+ ImplMultiply(x, y, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void Reduce(ulong[] xx, ulong[] z)
+ {
+ ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3], x4 = xx[4];
+
+ x1 ^= (x4 << 61) ^ (x4 << 63);
+ x2 ^= (x4 >> 3) ^ (x4 >> 1) ^ x4 ^ (x4 << 5);
+ x3 ^= (x4 >> 59);
+
+ x0 ^= (x3 << 61) ^ (x3 << 63);
+ x1 ^= (x3 >> 3) ^ (x3 >> 1) ^ x3 ^ (x3 << 5);
+ x2 ^= (x3 >> 59);
+
+ ulong t = x2 >> 3;
+ z[0] = x0 ^ t ^ (t << 2) ^ (t << 3) ^ (t << 8);
+ z[1] = x1 ^ (t >> 56);
+ z[2] = x2 & M03;
+ }
+
+ public static void Reduce61(ulong[] z, int zOff)
+ {
+ ulong z2 = z[zOff + 2], t = z2 >> 3;
+ z[zOff ] ^= t ^ (t << 2) ^ (t << 3) ^ (t << 8);
+ z[zOff + 1] ^= (t >> 56);
+ z[zOff + 2] = z2 & M03;
+ }
+
+ public static void Sqrt(ulong[] x, ulong[] z)
+ {
+ ulong[] odd = Nat192.Create64();
+
+ ulong u0, u1;
+ u0 = Interleave.Unshuffle(x[0]); u1 = Interleave.Unshuffle(x[1]);
+ ulong e0 = (u0 & 0x00000000FFFFFFFFUL) | (u1 << 32);
+ odd[0] = (u0 >> 32) | (u1 & 0xFFFFFFFF00000000UL);
+
+ u0 = Interleave.Unshuffle(x[2]);
+ ulong e1 = (u0 & 0x00000000FFFFFFFFUL);
+ odd[1] = (u0 >> 32);
+
+ Multiply(odd, ROOT_Z, z);
+
+ z[0] ^= e0;
+ z[1] ^= e1;
+ }
+
+ public static void Square(ulong[] x, ulong[] z)
+ {
+ ulong[] tt = Nat.Create64(5);
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareAddToExt(ulong[] x, ulong[] zz)
+ {
+ ulong[] tt = Nat.Create64(5);
+ ImplSquare(x, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void SquareN(ulong[] x, int n, ulong[] z)
+ {
+ Debug.Assert(n > 0);
+
+ ulong[] tt = Nat.Create64(5);
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ ImplSquare(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static uint Trace(ulong[] x)
+ {
+ // Non-zero-trace bits: 0, 123, 129
+ return (uint)(x[0] ^ (x[1] >> 59) ^ (x[2] >> 1)) & 1U;
+ }
+
+ protected static void ImplCompactExt(ulong[] zz)
+ {
+ ulong z0 = zz[0], z1 = zz[1], z2 = zz[2], z3 = zz[3], z4 = zz[4], z5 = zz[5];
+ zz[0] = z0 ^ (z1 << 44);
+ zz[1] = (z1 >> 20) ^ (z2 << 24);
+ zz[2] = (z2 >> 40) ^ (z3 << 4)
+ ^ (z4 << 48);
+ zz[3] = (z3 >> 60) ^ (z5 << 28)
+ ^ (z4 >> 16);
+ zz[4] = (z5 >> 36);
+ zz[5] = 0;
+ }
+
+ protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ /*
+ * "Five-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
+ */
+
+ ulong f0 = x[0], f1 = x[1], f2 = x[2];
+ f2 = ((f1 >> 24) ^ (f2 << 40)) & M44;
+ f1 = ((f0 >> 44) ^ (f1 << 20)) & M44;
+ f0 &= M44;
+
+ ulong g0 = y[0], g1 = y[1], g2 = y[2];
+ g2 = ((g1 >> 24) ^ (g2 << 40)) & M44;
+ g1 = ((g0 >> 44) ^ (g1 << 20)) & M44;
+ g0 &= M44;
+
+ ulong[] H = new ulong[10];
+
+ ImplMulw(f0, g0, H, 0); // H(0) 44/43 bits
+ ImplMulw(f2, g2, H, 2); // H(INF) 44/41 bits
+
+ ulong t0 = f0 ^ f1 ^ f2;
+ ulong t1 = g0 ^ g1 ^ g2;
+
+ ImplMulw(t0, t1, H, 4); // H(1) 44/43 bits
+
+ ulong t2 = (f1 << 1) ^ (f2 << 2);
+ ulong t3 = (g1 << 1) ^ (g2 << 2);
+
+ ImplMulw(f0 ^ t2, g0 ^ t3, H, 6); // H(t) 44/45 bits
+ ImplMulw(t0 ^ t2, t1 ^ t3, H, 8); // H(t + 1) 44/45 bits
+
+ ulong t4 = H[6] ^ H[8];
+ ulong t5 = H[7] ^ H[9];
+
+ Debug.Assert(t5 >> 44 == 0);
+
+ // Calculate V
+ ulong v0 = (t4 << 1) ^ H[6];
+ ulong v1 = t4 ^ (t5 << 1) ^ H[7];
+ ulong v2 = t5;
+
+ // Calculate U
+ ulong u0 = H[0];
+ ulong u1 = H[1] ^ H[0] ^ H[4];
+ ulong u2 = H[1] ^ H[5];
+
+ // Calculate W
+ ulong w0 = u0 ^ v0 ^ (H[2] << 4) ^ (H[2] << 1);
+ ulong w1 = u1 ^ v1 ^ (H[3] << 4) ^ (H[3] << 1);
+ ulong w2 = u2 ^ v2;
+
+ // Propagate carries
+ w1 ^= (w0 >> 44); w0 &= M44;
+ w2 ^= (w1 >> 44); w1 &= M44;
+
+ Debug.Assert((w0 & 1UL) == 0);
+
+ // Divide W by t
+
+ w0 = (w0 >> 1) ^ ((w1 & 1UL) << 43);
+ w1 = (w1 >> 1) ^ ((w2 & 1UL) << 43);
+ w2 = (w2 >> 1);
+
+ // Divide W by (t + 1)
+
+ w0 ^= (w0 << 1);
+ w0 ^= (w0 << 2);
+ w0 ^= (w0 << 4);
+ w0 ^= (w0 << 8);
+ w0 ^= (w0 << 16);
+ w0 ^= (w0 << 32);
+
+ w0 &= M44; w1 ^= (w0 >> 43);
+
+ w1 ^= (w1 << 1);
+ w1 ^= (w1 << 2);
+ w1 ^= (w1 << 4);
+ w1 ^= (w1 << 8);
+ w1 ^= (w1 << 16);
+ w1 ^= (w1 << 32);
+
+ w1 &= M44; w2 ^= (w1 >> 43);
+
+ w2 ^= (w2 << 1);
+ w2 ^= (w2 << 2);
+ w2 ^= (w2 << 4);
+ w2 ^= (w2 << 8);
+ w2 ^= (w2 << 16);
+ w2 ^= (w2 << 32);
+
+ Debug.Assert(w2 >> 42 == 0);
+
+ zz[0] = u0;
+ zz[1] = u1 ^ w0 ^ H[2];
+ zz[2] = u2 ^ w1 ^ w0 ^ H[3];
+ zz[3] = w2 ^ w1;
+ zz[4] = w2 ^ H[2];
+ zz[5] = H[3];
+
+ ImplCompactExt(zz);
+ }
+
+ protected static void ImplMulw(ulong x, ulong y, ulong[] z, int zOff)
+ {
+ Debug.Assert(x >> 45 == 0);
+ Debug.Assert(y >> 45 == 0);
+
+ ulong[] u = new ulong[8];
+ //u[0] = 0;
+ u[1] = y;
+ u[2] = u[1] << 1;
+ u[3] = u[2] ^ y;
+ u[4] = u[2] << 1;
+ u[5] = u[4] ^ y;
+ u[6] = u[3] << 1;
+ u[7] = u[6] ^ y;
+
+ uint j = (uint)x;
+ ulong g, h = 0, l = u[j & 7]
+ ^ u[(j >> 3) & 7] << 3
+ ^ u[(j >> 6) & 7] << 6;
+ int k = 33;
+ do
+ {
+ j = (uint)(x >> k);
+ g = u[j & 7]
+ ^ u[(j >> 3) & 7] << 3
+ ^ u[(j >> 6) & 7] << 6
+ ^ u[(j >> 9) & 7] << 9;
+ l ^= (g << k);
+ h ^= (g >> -k);
+ }
+ while ((k -= 12) > 0);
+
+ Debug.Assert(h >> 25 == 0);
+
+ z[zOff ] = l & M44;
+ z[zOff + 1] = (l >> 44) ^ (h << 20);
+ }
+
+ protected static void ImplSquare(ulong[] x, ulong[] zz)
+ {
+ Interleave.Expand64To128(x[0], zz, 0);
+ Interleave.Expand64To128(x[1], zz, 2);
+
+ zz[4] = Interleave.Expand8to16((uint)x[2]);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT131FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT131FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e0ecc100f8aead76e7e42d6fd761b5dc95c32bca
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT131FieldElement.cs
@@ -0,0 +1,216 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT131FieldElement
+ : ECFieldElement
+ {
+ protected readonly ulong[] x;
+
+ public SecT131FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.BitLength > 131)
+ throw new ArgumentException("value invalid for SecT131FieldElement", "x");
+
+ this.x = SecT131Field.FromBigInteger(x);
+ }
+
+ public SecT131FieldElement()
+ {
+ this.x = Nat192.Create64();
+ }
+
+ protected internal SecT131FieldElement(ulong[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat192.IsOne64(x); }
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat192.IsZero64(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return (x[0] & 1UL) != 0UL;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat192.ToBigInteger64(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecT131Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 131; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ ulong[] z = Nat192.Create64();
+ SecT131Field.Add(x, ((SecT131FieldElement)b).x, z);
+ return new SecT131FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ ulong[] z = Nat192.Create64();
+ SecT131Field.AddOne(x, z);
+ return new SecT131FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ // Addition and Subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ ulong[] z = Nat192.Create64();
+ SecT131Field.Multiply(x, ((SecT131FieldElement)b).x, z);
+ return new SecT131FieldElement(z);
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return MultiplyPlusProduct(b, x, y);
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x, bx = ((SecT131FieldElement)b).x;
+ ulong[] xx = ((SecT131FieldElement)x).x, yx = ((SecT131FieldElement)y).x;
+
+ ulong[] tt = Nat.Create64(5);
+ SecT131Field.MultiplyAddToExt(ax, bx, tt);
+ SecT131Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat192.Create64();
+ SecT131Field.Reduce(tt, z);
+ return new SecT131FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ return Multiply(b.Invert());
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ ulong[] z = Nat192.Create64();
+ SecT131Field.Square(x, z);
+ return new SecT131FieldElement(z);
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return SquarePlusProduct(x, y);
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x;
+ ulong[] xx = ((SecT131FieldElement)x).x, yx = ((SecT131FieldElement)y).x;
+
+ ulong[] tt = Nat.Create64(5);
+ SecT131Field.SquareAddToExt(ax, tt);
+ SecT131Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat192.Create64();
+ SecT131Field.Reduce(tt, z);
+ return new SecT131FieldElement(z);
+ }
+
+ public override ECFieldElement SquarePow(int pow)
+ {
+ if (pow < 1)
+ return this;
+
+ ulong[] z = Nat192.Create64();
+ SecT131Field.SquareN(x, pow, z);
+ return new SecT131FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ ulong[] z = Nat192.Create64();
+ SecT131Field.Invert(x, z);
+ return new SecT131FieldElement(z);
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ ulong[] z = Nat192.Create64();
+ SecT131Field.Sqrt(x, z);
+ return new SecT131FieldElement(z);
+ }
+
+ public virtual int Representation
+ {
+ get { return F2mFieldElement.Ppb; }
+ }
+
+ public virtual int M
+ {
+ get { return 131; }
+ }
+
+ public virtual int K1
+ {
+ get { return 2; }
+ }
+
+ public virtual int K2
+ {
+ get { return 3; }
+ }
+
+ public virtual int K3
+ {
+ get { return 8; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecT131FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecT131FieldElement);
+ }
+
+ public virtual bool Equals(SecT131FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat192.Eq64(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return 131832 ^ Arrays.GetHashCode(x, 0, 3);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT131R1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT131R1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b73964c396822c25556865173cc40fec6c3be76a
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT131R1Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT131R1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT131R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT131R1Point m_infinity;
+
+ public SecT131R1Curve()
+ : base(131, 2, 3, 8)
+ {
+ this.m_infinity = new SecT131R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1, Hex.Decode("07A11B09A76B562144418FF3FF8C2570B8")));
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("0217C05610884B63B9C6C7291678F9D341")));
+ this.m_order = new BigInteger(1, Hex.Decode("0400000000000000023123953A9464B54D"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT131R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT131R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 131; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT131FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT131R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT131R1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 131; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return false; }
+ }
+
+ public virtual int K1
+ {
+ get { return 2; }
+ }
+
+ public virtual int K2
+ {
+ get { return 3; }
+ }
+
+ public virtual int K3
+ {
+ get { return 8; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT131R1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT131R1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7afdad89cb1acc4ec49969a70d0fb0cc38c91f88
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT131R1Point.cs
@@ -0,0 +1,287 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT131R1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT131R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT131R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT131R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT131R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ if (X3.IsZero)
+ {
+ return new SecT131R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT131R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT131R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement a = curve.A;
+ ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+ if (T.IsZero)
+ {
+ return new SecT131R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT131R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ {
+ return b;
+ }
+ if (b.IsInfinity)
+ {
+ return Twice();
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT131R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT131R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT131R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT131R2Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT131R2Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..724921c94996affd768969a02963f49fed693372
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT131R2Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT131R2Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT131R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT131R2Point m_infinity;
+
+ public SecT131R2Curve()
+ : base(131, 2, 3, 8)
+ {
+ this.m_infinity = new SecT131R2Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1, Hex.Decode("03E5A88919D7CAFCBF415F07C2176573B2")));
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("04B8266A46C55657AC734CE38F018F2192")));
+ this.m_order = new BigInteger(1, Hex.Decode("0400000000000000016954A233049BA98F"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT131R2_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT131R2Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override int FieldSize
+ {
+ get { return 131; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT131FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT131R2Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT131R2Point(this, x, y, zs, withCompression);
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 131; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return false; }
+ }
+
+ public virtual int K1
+ {
+ get { return 2; }
+ }
+
+ public virtual int K2
+ {
+ get { return 3; }
+ }
+
+ public virtual int K3
+ {
+ get { return 8; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT131R2Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT131R2Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..be61561da6c2d03086778cc19c6421f9e78dfbe1
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT131R2Point.cs
@@ -0,0 +1,283 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT131R2Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT131R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT131R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT131R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT131R2Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ if (X3.IsZero)
+ {
+ return new SecT131R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT131R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT131R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement a = curve.A;
+ ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+ if (T.IsZero)
+ {
+ return new SecT131R2Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT131R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT131R2Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT131R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT131R2Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT163Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT163Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b1e9aa725dcec7f78cd80f10b125ed8d1bd3f25c
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT163Field.cs
@@ -0,0 +1,340 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT163Field
+ {
+ private const ulong M35 = ulong.MaxValue >> 29;
+ private const ulong M55 = ulong.MaxValue >> 9;
+
+ private static readonly ulong[] ROOT_Z = new ulong[]{ 0xB6DB6DB6DB6DB6B0UL, 0x492492492492DB6DUL, 0x492492492UL };
+
+ public static void Add(ulong[] x, ulong[] y, ulong[] z)
+ {
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
+ z[2] = x[2] ^ y[2];
+ }
+
+ public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+ {
+ zz[0] = xx[0] ^ yy[0];
+ zz[1] = xx[1] ^ yy[1];
+ zz[2] = xx[2] ^ yy[2];
+ zz[3] = xx[3] ^ yy[3];
+ zz[4] = xx[4] ^ yy[4];
+ zz[5] = xx[5] ^ yy[5];
+ }
+
+ public static void AddOne(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0] ^ 1UL;
+ z[1] = x[1];
+ z[2] = x[2];
+ }
+
+ public static ulong[] FromBigInteger(BigInteger x)
+ {
+ ulong[] z = Nat192.FromBigInteger64(x);
+ Reduce29(z, 0);
+ return z;
+ }
+
+ public static void Invert(ulong[] x, ulong[] z)
+ {
+ if (Nat192.IsZero64(x))
+ throw new InvalidOperationException();
+
+ // Itoh-Tsujii inversion with bases { 2, 3 }
+
+ ulong[] t0 = Nat192.Create64();
+ ulong[] t1 = Nat192.Create64();
+
+ Square(x, t0);
+
+ // 3 | 162
+ SquareN(t0, 1, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t1, 1, t1);
+ Multiply(t0, t1, t0);
+
+ // 3 | 54
+ SquareN(t0, 3, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t1, 3, t1);
+ Multiply(t0, t1, t0);
+
+ // 3 | 18
+ SquareN(t0, 9, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t1, 9, t1);
+ Multiply(t0, t1, t0);
+
+ // 3 | 6
+ SquareN(t0, 27, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t1, 27, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 2
+ SquareN(t0, 81, t1);
+ Multiply(t0, t1, z);
+ }
+
+ public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+ {
+ ulong[] tt = Nat192.CreateExt64();
+ ImplMultiply(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] tt = Nat192.CreateExt64();
+ ImplMultiply(x, y, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void Reduce(ulong[] xx, ulong[] z)
+ {
+ ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3], x4 = xx[4], x5 = xx[5];
+
+ x2 ^= (x5 << 29) ^ (x5 << 32) ^ (x5 << 35) ^ (x5 << 36);
+ x3 ^= (x5 >> 35) ^ (x5 >> 32) ^ (x5 >> 29) ^ (x5 >> 28);
+
+ x1 ^= (x4 << 29) ^ (x4 << 32) ^ (x4 << 35) ^ (x4 << 36);
+ x2 ^= (x4 >> 35) ^ (x4 >> 32) ^ (x4 >> 29) ^ (x4 >> 28);
+
+ x0 ^= (x3 << 29) ^ (x3 << 32) ^ (x3 << 35) ^ (x3 << 36);
+ x1 ^= (x3 >> 35) ^ (x3 >> 32) ^ (x3 >> 29) ^ (x3 >> 28);
+
+ ulong t = x2 >> 35;
+ z[0] = x0 ^ t ^ (t << 3) ^ (t << 6) ^ (t << 7);
+ z[1] = x1;
+ z[2] = x2 & M35;
+ }
+
+ public static void Reduce29(ulong[] z, int zOff)
+ {
+ ulong z2 = z[zOff + 2], t = z2 >> 35;
+ z[zOff ] ^= t ^ (t << 3) ^ (t << 6) ^ (t << 7);
+ z[zOff + 2] = z2 & M35;
+ }
+
+ public static void Sqrt(ulong[] x, ulong[] z)
+ {
+ ulong[] odd = Nat192.Create64();
+
+ ulong u0, u1;
+ u0 = Interleave.Unshuffle(x[0]); u1 = Interleave.Unshuffle(x[1]);
+ ulong e0 = (u0 & 0x00000000FFFFFFFFUL) | (u1 << 32);
+ odd[0] = (u0 >> 32) | (u1 & 0xFFFFFFFF00000000UL);
+
+ u0 = Interleave.Unshuffle(x[2]);
+ ulong e1 = (u0 & 0x00000000FFFFFFFFUL);
+ odd[1] = (u0 >> 32);
+
+ Multiply(odd, ROOT_Z, z);
+
+ z[0] ^= e0;
+ z[1] ^= e1;
+ }
+
+ public static void Square(ulong[] x, ulong[] z)
+ {
+ ulong[] tt = Nat192.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareAddToExt(ulong[] x, ulong[] zz)
+ {
+ ulong[] tt = Nat192.CreateExt64();
+ ImplSquare(x, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void SquareN(ulong[] x, int n, ulong[] z)
+ {
+ Debug.Assert(n > 0);
+
+ ulong[] tt = Nat192.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ ImplSquare(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static uint Trace(ulong[] x)
+ {
+ // Non-zero-trace bits: 0, 157
+ return (uint)(x[0] ^ (x[2] >> 29)) & 1U;
+ }
+
+ protected static void ImplCompactExt(ulong[] zz)
+ {
+ ulong z0 = zz[0], z1 = zz[1], z2 = zz[2], z3 = zz[3], z4 = zz[4], z5 = zz[5];
+ zz[0] = z0 ^ (z1 << 55);
+ zz[1] = (z1 >> 9) ^ (z2 << 46);
+ zz[2] = (z2 >> 18) ^ (z3 << 37);
+ zz[3] = (z3 >> 27) ^ (z4 << 28);
+ zz[4] = (z4 >> 36) ^ (z5 << 19);
+ zz[5] = (z5 >> 45);
+ }
+
+ protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ /*
+ * "Five-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
+ */
+
+ ulong f0 = x[0], f1 = x[1], f2 = x[2];
+ f2 = ((f1 >> 46) ^ (f2 << 18));
+ f1 = ((f0 >> 55) ^ (f1 << 9)) & M55;
+ f0 &= M55;
+
+ ulong g0 = y[0], g1 = y[1], g2 = y[2];
+ g2 = ((g1 >> 46) ^ (g2 << 18));
+ g1 = ((g0 >> 55) ^ (g1 << 9)) & M55;
+ g0 &= M55;
+
+ ulong[] H = new ulong[10];
+
+ ImplMulw(f0, g0, H, 0); // H(0) 55/54 bits
+ ImplMulw(f2, g2, H, 2); // H(INF) 55/50 bits
+
+ ulong t0 = f0 ^ f1 ^ f2;
+ ulong t1 = g0 ^ g1 ^ g2;
+
+ ImplMulw(t0, t1, H, 4); // H(1) 55/54 bits
+
+ ulong t2 = (f1 << 1) ^ (f2 << 2);
+ ulong t3 = (g1 << 1) ^ (g2 << 2);
+
+ ImplMulw(f0 ^ t2, g0 ^ t3, H, 6); // H(t) 55/56 bits
+ ImplMulw(t0 ^ t2, t1 ^ t3, H, 8); // H(t + 1) 55/56 bits
+
+ ulong t4 = H[6] ^ H[8];
+ ulong t5 = H[7] ^ H[9];
+
+ Debug.Assert(t5 >> 55 == 0);
+
+ // Calculate V
+ ulong v0 = (t4 << 1) ^ H[6];
+ ulong v1 = t4 ^ (t5 << 1) ^ H[7];
+ ulong v2 = t5;
+
+ // Calculate U
+ ulong u0 = H[0];
+ ulong u1 = H[1] ^ H[0] ^ H[4];
+ ulong u2 = H[1] ^ H[5];
+
+ // Calculate W
+ ulong w0 = u0 ^ v0 ^ (H[2] << 4) ^ (H[2] << 1);
+ ulong w1 = u1 ^ v1 ^ (H[3] << 4) ^ (H[3] << 1);
+ ulong w2 = u2 ^ v2;
+
+ // Propagate carries
+ w1 ^= (w0 >> 55); w0 &= M55;
+ w2 ^= (w1 >> 55); w1 &= M55;
+
+ Debug.Assert((w0 & 1UL) == 0UL);
+
+ // Divide W by t
+
+ w0 = (w0 >> 1) ^ ((w1 & 1UL) << 54);
+ w1 = (w1 >> 1) ^ ((w2 & 1UL) << 54);
+ w2 = (w2 >> 1);
+
+ // Divide W by (t + 1)
+
+ w0 ^= (w0 << 1);
+ w0 ^= (w0 << 2);
+ w0 ^= (w0 << 4);
+ w0 ^= (w0 << 8);
+ w0 ^= (w0 << 16);
+ w0 ^= (w0 << 32);
+
+ w0 &= M55; w1 ^= (w0 >> 54);
+
+ w1 ^= (w1 << 1);
+ w1 ^= (w1 << 2);
+ w1 ^= (w1 << 4);
+ w1 ^= (w1 << 8);
+ w1 ^= (w1 << 16);
+ w1 ^= (w1 << 32);
+
+ w1 &= M55; w2 ^= (w1 >> 54);
+
+ w2 ^= (w2 << 1);
+ w2 ^= (w2 << 2);
+ w2 ^= (w2 << 4);
+ w2 ^= (w2 << 8);
+ w2 ^= (w2 << 16);
+ w2 ^= (w2 << 32);
+
+ Debug.Assert(w2 >> 52 == 0);
+
+ zz[0] = u0;
+ zz[1] = u1 ^ w0 ^ H[2];
+ zz[2] = u2 ^ w1 ^ w0 ^ H[3];
+ zz[3] = w2 ^ w1;
+ zz[4] = w2 ^ H[2];
+ zz[5] = H[3];
+
+ ImplCompactExt(zz);
+ }
+
+ protected static void ImplMulw(ulong x, ulong y, ulong[] z, int zOff)
+ {
+ Debug.Assert(x >> 56 == 0);
+ Debug.Assert(y >> 56 == 0);
+
+ ulong[] u = new ulong[8];
+ //u[0] = 0;
+ u[1] = y;
+ u[2] = u[1] << 1;
+ u[3] = u[2] ^ y;
+ u[4] = u[2] << 1;
+ u[5] = u[4] ^ y;
+ u[6] = u[3] << 1;
+ u[7] = u[6] ^ y;
+
+ uint j = (uint)x;
+ ulong g, h = 0, l = u[j & 3];
+ int k = 47;
+ do
+ {
+ j = (uint)(x >> k);
+ g = u[j & 7]
+ ^ u[(j >> 3) & 7] << 3
+ ^ u[(j >> 6) & 7] << 6;
+ l ^= (g << k);
+ h ^= (g >> -k);
+ }
+ while ((k -= 9) > 0);
+
+ Debug.Assert(h >> 47 == 0);
+
+ z[zOff ] = l & M55;
+ z[zOff + 1] = (l >> 55) ^ (h << 9);
+ }
+
+ protected static void ImplSquare(ulong[] x, ulong[] zz)
+ {
+ Interleave.Expand64To128(x[0], zz, 0);
+ Interleave.Expand64To128(x[1], zz, 2);
+
+ ulong x2 = x[2];
+ zz[4] = Interleave.Expand32to64((uint)x2);
+ zz[5] = Interleave.Expand8to16((uint)(x2 >> 32));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT163FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT163FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8953fb529abf8c2864895658ac5cd4cb102c1080
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT163FieldElement.cs
@@ -0,0 +1,216 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT163FieldElement
+ : ECFieldElement
+ {
+ protected readonly ulong[] x;
+
+ public SecT163FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.BitLength > 163)
+ throw new ArgumentException("value invalid for SecT163FieldElement", "x");
+
+ this.x = SecT163Field.FromBigInteger(x);
+ }
+
+ public SecT163FieldElement()
+ {
+ this.x = Nat192.Create64();
+ }
+
+ protected internal SecT163FieldElement(ulong[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat192.IsOne64(x); }
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat192.IsZero64(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return (x[0] & 1L) != 0L;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat192.ToBigInteger64(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecT163Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 163; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ ulong[] z = Nat192.Create64();
+ SecT163Field.Add(x, ((SecT163FieldElement)b).x, z);
+ return new SecT163FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ ulong[] z = Nat192.Create64();
+ SecT163Field.AddOne(x, z);
+ return new SecT163FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ // Addition and subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ ulong[] z = Nat192.Create64();
+ SecT163Field.Multiply(x, ((SecT163FieldElement)b).x, z);
+ return new SecT163FieldElement(z);
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return MultiplyPlusProduct(b, x, y);
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x, bx = ((SecT163FieldElement)b).x;
+ ulong[] xx = ((SecT163FieldElement)x).x, yx = ((SecT163FieldElement)y).x;
+
+ ulong[] tt = Nat192.CreateExt64();
+ SecT163Field.MultiplyAddToExt(ax, bx, tt);
+ SecT163Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat192.Create64();
+ SecT163Field.Reduce(tt, z);
+ return new SecT163FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ return Multiply(b.Invert());
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ ulong[] z = Nat192.Create64();
+ SecT163Field.Square(x, z);
+ return new SecT163FieldElement(z);
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return SquarePlusProduct(x, y);
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x;
+ ulong[] xx = ((SecT163FieldElement)x).x, yx = ((SecT163FieldElement)y).x;
+
+ ulong[] tt = Nat192.CreateExt64();
+ SecT163Field.SquareAddToExt(ax, tt);
+ SecT163Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat192.Create64();
+ SecT163Field.Reduce(tt, z);
+ return new SecT163FieldElement(z);
+ }
+
+ public override ECFieldElement SquarePow(int pow)
+ {
+ if (pow < 1)
+ return this;
+
+ ulong[] z = Nat192.Create64();
+ SecT163Field.SquareN(x, pow, z);
+ return new SecT163FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ ulong[] z = Nat192.Create64();
+ SecT163Field.Invert(x, z);
+ return new SecT163FieldElement(z);
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ ulong[] z = Nat192.Create64();
+ SecT163Field.Sqrt(x, z);
+ return new SecT163FieldElement(z);
+ }
+
+ public virtual int Representation
+ {
+ get { return F2mFieldElement.Ppb; }
+ }
+
+ public virtual int M
+ {
+ get { return 163; }
+ }
+
+ public virtual int K1
+ {
+ get { return 3; }
+ }
+
+ public virtual int K2
+ {
+ get { return 6; }
+ }
+
+ public virtual int K3
+ {
+ get { return 7; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecT163FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecT163FieldElement);
+ }
+
+ public virtual bool Equals(SecT163FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat192.Eq64(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return 163763 ^ Arrays.GetHashCode(x, 0, 3);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT163K1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT163K1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..68ff646ca319671513599a190f45b03acb10aa82
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT163K1Curve.cs
@@ -0,0 +1,104 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT163K1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT163K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT163K1Point m_infinity;
+
+ public SecT163K1Curve()
+ : base(163, 3, 6, 7)
+ {
+ this.m_infinity = new SecT163K1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.One);
+ this.m_b = this.m_a;
+ this.m_order = new BigInteger(1, Hex.Decode("04000000000000000000020108A2E0CC0D99F8A5EF"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT163K1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT163K1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ protected override ECMultiplier CreateDefaultMultiplier()
+ {
+ return new WTauNafMultiplier();
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 163; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT163FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT163K1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT163K1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return true; }
+ }
+
+ public virtual int M
+ {
+ get { return 163; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return false; }
+ }
+
+ public virtual int K1
+ {
+ get { return 3; }
+ }
+
+ public virtual int K2
+ {
+ get { return 6; }
+ }
+
+ public virtual int K3
+ {
+ get { return 7; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT163K1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT163K1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8693fe1c82c08a65c45c34a0d28946dbd6b8277b
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT163K1Point.cs
@@ -0,0 +1,281 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT163K1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT163K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT163K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT163K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT163K1Point(null, this.AffineXCoord, this.AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).AddOne();
+ if (X3.IsZero)
+ {
+ return new SecT163K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT163K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT163K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(Z1Sq);
+ if (T.IsZero)
+ {
+ return new SecT163K1Point(curve, T, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement t1 = L1.Add(X1).Square();
+ ECFieldElement L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(X3);
+
+ return new SecT163K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ // NOTE: TwicePlus() only optimized for lambda-affine argument
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = Z1Sq.Add(L1Sq).Add(L1Z1);
+ ECFieldElement A = L2.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT163K1Point(curve, A, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2.AddOne(), Z3);
+
+ return new SecT163K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT163K1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT163R1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT163R1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8ae58cceff0d0f4de42691470f3a09ea0abc11a5
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT163R1Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT163R1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT163R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT163R1Point m_infinity;
+
+ public SecT163R1Curve()
+ : base(163, 3, 6, 7)
+ {
+ this.m_infinity = new SecT163R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1, Hex.Decode("07B6882CAAEFA84F9554FF8428BD88E246D2782AE2")));
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9")));
+ this.m_order = new BigInteger(1, Hex.Decode("03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT163R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT163R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 163; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT163FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT163R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT163R1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 163; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return false; }
+ }
+
+ public virtual int K1
+ {
+ get { return 3; }
+ }
+
+ public virtual int K2
+ {
+ get { return 6; }
+ }
+
+ public virtual int K3
+ {
+ get { return 7; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT163R1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT163R1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..811a09f1467b6990c55c13e815bdb9b26a96fde7
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT163R1Point.cs
@@ -0,0 +1,283 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT163R1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT163R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT163R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT163R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT163R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ if (X3.IsZero)
+ {
+ return new SecT163R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT163R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT163R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement a = curve.A;
+ ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+ if (T.IsZero)
+ {
+ return new SecT163R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT163R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT163R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT163R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT163R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT163R2Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT163R2Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5a4fa5ad13407fed34c4d4db190612c5fd736e6c
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT163R2Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT163R2Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT163R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT163R2Point m_infinity;
+
+ public SecT163R2Curve()
+ : base(163, 3, 6, 7)
+ {
+ this.m_infinity = new SecT163R2Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.One);
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("020A601907B8C953CA1481EB10512F78744A3205FD")));
+ this.m_order = new BigInteger(1, Hex.Decode("040000000000000000000292FE77E70C12A4234C33"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT163R2_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT163R2Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 163; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT163FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT163R2Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT163R2Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 163; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return false; }
+ }
+
+ public virtual int K1
+ {
+ get { return 3; }
+ }
+
+ public virtual int K2
+ {
+ get { return 6; }
+ }
+
+ public virtual int K3
+ {
+ get { return 7; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT163R2Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT163R2Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..69e24973938ce435296219c952d1601961cbee4f
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT163R2Point.cs
@@ -0,0 +1,286 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT163R2Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT163R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT163R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT163R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT163R2Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ {
+ return Twice();
+ }
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).AddOne();
+ if (X3.IsZero)
+ {
+ return new SecT163R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT163R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT163R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(Z1Sq);
+ if (T.IsZero)
+ {
+ return new SecT163R2Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT163R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ {
+ return b;
+ }
+ if (b.IsInfinity)
+ {
+ return Twice();
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = Z1Sq.Add(L1Sq).Add(L1Z1);
+ ECFieldElement A = L2.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT163R2Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2.AddOne(), Z3);
+
+ return new SecT163R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT163R2Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT193Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT193Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..41acb4f94f7f94ba660f3915a3c831852ee95137
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT193Field.cs
@@ -0,0 +1,305 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT193Field
+ {
+ private const ulong M01 = 1UL;
+ private const ulong M49 = ulong.MaxValue >> 15;
+
+ public static void Add(ulong[] x, ulong[] y, ulong[] z)
+ {
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
+ z[2] = x[2] ^ y[2];
+ z[3] = x[3] ^ y[3];
+ }
+
+ public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+ {
+ zz[0] = xx[0] ^ yy[0];
+ zz[1] = xx[1] ^ yy[1];
+ zz[2] = xx[2] ^ yy[2];
+ zz[3] = xx[3] ^ yy[3];
+ zz[4] = xx[4] ^ yy[4];
+ zz[5] = xx[5] ^ yy[5];
+ zz[6] = xx[6] ^ yy[6];
+ }
+
+ public static void AddOne(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0] ^ 1UL;
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ }
+
+ public static ulong[] FromBigInteger(BigInteger x)
+ {
+ ulong[] z = Nat256.FromBigInteger64(x);
+ Reduce63(z, 0);
+ return z;
+ }
+
+ public static void Invert(ulong[] x, ulong[] z)
+ {
+ if (Nat256.IsZero64(x))
+ throw new InvalidOperationException();
+
+ // Itoh-Tsujii inversion with bases { 2, 3 }
+
+ ulong[] t0 = Nat256.Create64();
+ ulong[] t1 = Nat256.Create64();
+
+ Square(x, t0);
+
+ // 3 | 192
+ SquareN(t0, 1, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t1, 1, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 64
+ SquareN(t0, 3, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 32
+ SquareN(t0, 6, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 16
+ SquareN(t0, 12, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 8
+ SquareN(t0, 24, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 4
+ SquareN(t0, 48, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 2
+ SquareN(t0, 96, t1);
+ Multiply(t0, t1, z);
+ }
+
+ public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplMultiply(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplMultiply(x, y, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void Reduce(ulong[] xx, ulong[] z)
+ {
+ ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3], x4 = xx[4], x5 = xx[5], x6 = xx[6];
+
+ x2 ^= (x6 << 63);
+ x3 ^= (x6 >> 1) ^ (x6 << 14);
+ x4 ^= (x6 >> 50);
+
+ x1 ^= (x5 << 63);
+ x2 ^= (x5 >> 1) ^ (x5 << 14);
+ x3 ^= (x5 >> 50);
+
+ x0 ^= (x4 << 63);
+ x1 ^= (x4 >> 1) ^ (x4 << 14);
+ x2 ^= (x4 >> 50);
+
+ ulong t = x3 >> 1;
+ z[0] = x0 ^ t ^ (t << 15);
+ z[1] = x1 ^ (t >> 49);
+ z[2] = x2;
+ z[3] = x3 & M01;
+ }
+
+ public static void Reduce63(ulong[] z, int zOff)
+ {
+ ulong z3 = z[zOff + 3], t = z3 >> 1;
+ z[zOff ] ^= t ^ (t << 15);
+ z[zOff + 1] ^= (t >> 49);
+ z[zOff + 3] = z3 & M01;
+ }
+
+ public static void Sqrt(ulong[] x, ulong[] z)
+ {
+ ulong u0, u1;
+ u0 = Interleave.Unshuffle(x[0]); u1 = Interleave.Unshuffle(x[1]);
+ ulong e0 = (u0 & 0x00000000FFFFFFFFUL) | (u1 << 32);
+ ulong c0 = (u0 >> 32) | (u1 & 0xFFFFFFFF00000000UL);
+
+ u0 = Interleave.Unshuffle(x[2]);
+ ulong e1 = (u0 & 0x00000000FFFFFFFFUL) ^ (x[3] << 32);
+ ulong c1 = (u0 >> 32);
+
+ z[0] = e0 ^ (c0 << 8);
+ z[1] = e1 ^ (c1 << 8) ^ (c0 >> 56) ^ (c0 << 33);
+ z[2] = (c1 >> 56) ^ (c1 << 33) ^ (c0 >> 31);
+ z[3] = (c1 >> 31);
+ }
+
+ public static void Square(ulong[] x, ulong[] z)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareAddToExt(ulong[] x, ulong[] zz)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplSquare(x, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void SquareN(ulong[] x, int n, ulong[] z)
+ {
+ Debug.Assert(n > 0);
+
+ ulong[] tt = Nat256.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ ImplSquare(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static uint Trace(ulong[] x)
+ {
+ // Non-zero-trace bits: 0
+ return (uint)(x[0]) & 1U;
+ }
+
+ protected static void ImplCompactExt(ulong[] zz)
+ {
+ ulong z0 = zz[0], z1 = zz[1], z2 = zz[2], z3 = zz[3], z4 = zz[4], z5 = zz[5], z6 = zz[6], z7 = zz[7];
+ zz[0] = z0 ^ (z1 << 49);
+ zz[1] = (z1 >> 15) ^ (z2 << 34);
+ zz[2] = (z2 >> 30) ^ (z3 << 19);
+ zz[3] = (z3 >> 45) ^ (z4 << 4)
+ ^ (z5 << 53);
+ zz[4] = (z4 >> 60) ^ (z6 << 38)
+ ^ (z5 >> 11);
+ zz[5] = (z6 >> 26) ^ (z7 << 23);
+ zz[6] = (z7 >> 41);
+ zz[7] = 0;
+ }
+
+ protected static void ImplExpand(ulong[] x, ulong[] z)
+ {
+ ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3];
+ z[0] = x0 & M49;
+ z[1] = ((x0 >> 49) ^ (x1 << 15)) & M49;
+ z[2] = ((x1 >> 34) ^ (x2 << 30)) & M49;
+ z[3] = ((x2 >> 19) ^ (x3 << 45));
+ }
+
+ protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ /*
+ * "Two-level seven-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
+ */
+
+ ulong[] f = new ulong[4], g = new ulong[4];
+ ImplExpand(x, f);
+ ImplExpand(y, g);
+
+ ImplMulwAcc(f[0], g[0], zz, 0);
+ ImplMulwAcc(f[1], g[1], zz, 1);
+ ImplMulwAcc(f[2], g[2], zz, 2);
+ ImplMulwAcc(f[3], g[3], zz, 3);
+
+ // U *= (1 - t^n)
+ for (int i = 5; i > 0; --i)
+ {
+ zz[i] ^= zz[i - 1];
+ }
+
+ ImplMulwAcc(f[0] ^ f[1], g[0] ^ g[1], zz, 1);
+ ImplMulwAcc(f[2] ^ f[3], g[2] ^ g[3], zz, 3);
+
+ // V *= (1 - t^2n)
+ for (int i = 7; i > 1; --i)
+ {
+ zz[i] ^= zz[i - 2];
+ }
+
+ // Double-length recursion
+ {
+ ulong c0 = f[0] ^ f[2], c1 = f[1] ^ f[3];
+ ulong d0 = g[0] ^ g[2], d1 = g[1] ^ g[3];
+ ImplMulwAcc(c0 ^ c1, d0 ^ d1, zz, 3);
+ ulong[] t = new ulong[3];
+ ImplMulwAcc(c0, d0, t, 0);
+ ImplMulwAcc(c1, d1, t, 1);
+ ulong t0 = t[0], t1 = t[1], t2 = t[2];
+ zz[2] ^= t0;
+ zz[3] ^= t0 ^ t1;
+ zz[4] ^= t2 ^ t1;
+ zz[5] ^= t2;
+ }
+
+ ImplCompactExt(zz);
+ }
+
+ protected static void ImplMulwAcc(ulong x, ulong y, ulong[] z, int zOff)
+ {
+ Debug.Assert(x >> 49 == 0);
+ Debug.Assert(y >> 49 == 0);
+
+ ulong[] u = new ulong[8];
+ //u[0] = 0;
+ u[1] = y;
+ u[2] = u[1] << 1;
+ u[3] = u[2] ^ y;
+ u[4] = u[2] << 1;
+ u[5] = u[4] ^ y;
+ u[6] = u[3] << 1;
+ u[7] = u[6] ^ y;
+
+ uint j = (uint)x;
+ ulong g, h = 0, l = u[j & 7]
+ ^ (u[(j >> 3) & 7] << 3);
+ int k = 36;
+ do
+ {
+ j = (uint)(x >> k);
+ g = u[j & 7]
+ ^ u[(j >> 3) & 7] << 3
+ ^ u[(j >> 6) & 7] << 6
+ ^ u[(j >> 9) & 7] << 9
+ ^ u[(j >> 12) & 7] << 12;
+ l ^= (g << k);
+ h ^= (g >> -k);
+ }
+ while ((k -= 15) > 0);
+
+ Debug.Assert(h >> 33 == 0);
+
+ z[zOff ] ^= l & M49;
+ z[zOff + 1] ^= (l >> 49) ^ (h << 15);
+ }
+
+ protected static void ImplSquare(ulong[] x, ulong[] zz)
+ {
+ Interleave.Expand64To128(x[0], zz, 0);
+ Interleave.Expand64To128(x[1], zz, 2);
+ Interleave.Expand64To128(x[2], zz, 4);
+ zz[6] = (x[3] & M01);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT193FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT193FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a1150b3f90199378471223400a073e5cf1d4896d
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT193FieldElement.cs
@@ -0,0 +1,216 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT193FieldElement
+ : ECFieldElement
+ {
+ protected readonly ulong[] x;
+
+ public SecT193FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.BitLength > 193)
+ throw new ArgumentException("value invalid for SecT193FieldElement", "x");
+
+ this.x = SecT193Field.FromBigInteger(x);
+ }
+
+ public SecT193FieldElement()
+ {
+ this.x = Nat256.Create64();
+ }
+
+ protected internal SecT193FieldElement(ulong[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat256.IsOne64(x); }
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat256.IsZero64(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return (x[0] & 1UL) != 0UL;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat256.ToBigInteger64(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecT193Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 193; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ ulong[] z = Nat256.Create64();
+ SecT193Field.Add(x, ((SecT193FieldElement)b).x, z);
+ return new SecT193FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT193Field.AddOne(x, z);
+ return new SecT193FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ // Addition and Subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ ulong[] z = Nat256.Create64();
+ SecT193Field.Multiply(x, ((SecT193FieldElement)b).x, z);
+ return new SecT193FieldElement(z);
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return MultiplyPlusProduct(b, x, y);
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x, bx = ((SecT193FieldElement)b).x;
+ ulong[] xx = ((SecT193FieldElement)x).x, yx = ((SecT193FieldElement)y).x;
+
+ ulong[] tt = Nat256.CreateExt64();
+ SecT193Field.MultiplyAddToExt(ax, bx, tt);
+ SecT193Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat256.Create64();
+ SecT193Field.Reduce(tt, z);
+ return new SecT193FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ return Multiply(b.Invert());
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT193Field.Square(x, z);
+ return new SecT193FieldElement(z);
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return SquarePlusProduct(x, y);
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x;
+ ulong[] xx = ((SecT193FieldElement)x).x, yx = ((SecT193FieldElement)y).x;
+
+ ulong[] tt = Nat256.CreateExt64();
+ SecT193Field.SquareAddToExt(ax, tt);
+ SecT193Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat256.Create64();
+ SecT193Field.Reduce(tt, z);
+ return new SecT193FieldElement(z);
+ }
+
+ public override ECFieldElement SquarePow(int pow)
+ {
+ if (pow < 1)
+ return this;
+
+ ulong[] z = Nat256.Create64();
+ SecT193Field.SquareN(x, pow, z);
+ return new SecT193FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT193Field.Invert(x, z);
+ return new SecT193FieldElement(z);
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT193Field.Sqrt(x, z);
+ return new SecT193FieldElement(z);
+ }
+
+ public virtual int Representation
+ {
+ get { return F2mFieldElement.Tpb; }
+ }
+
+ public virtual int M
+ {
+ get { return 193; }
+ }
+
+ public virtual int K1
+ {
+ get { return 15; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecT193FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecT193FieldElement);
+ }
+
+ public virtual bool Equals(SecT193FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat256.Eq64(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return 1930015 ^ Arrays.GetHashCode(x, 0, 4);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT193R1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT193R1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a2cb5a8ace82afdb2fda7545f5172fa1850b80b3
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT193R1Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT193R1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT193R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT193R1Point m_infinity;
+
+ public SecT193R1Curve()
+ : base(193, 15, 0, 0)
+ {
+ this.m_infinity = new SecT193R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1, Hex.Decode("0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01")));
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814")));
+ this.m_order = new BigInteger(1, Hex.Decode("01000000000000000000000000C7F34A778F443ACC920EBA49"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT193R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT193R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 193; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT193FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT193R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT193R1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 193; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return true; }
+ }
+
+ public virtual int K1
+ {
+ get { return 15; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT193R1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT193R1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..062fce9d496fe19eac03af9787d0a270b0ee007f
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT193R1Point.cs
@@ -0,0 +1,283 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT193R1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT193R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT193R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT193R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT193R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ if (X3.IsZero)
+ {
+ return new SecT193R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT193R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT193R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement a = curve.A;
+ ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+ if (T.IsZero)
+ {
+ return new SecT193R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT193R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT193R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT193R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT193R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT193R2Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT193R2Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1c84a3eacb2e0a554795a73954e3d19eb71cef03
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT193R2Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT193R2Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT193R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT193R2Point m_infinity;
+
+ public SecT193R2Curve()
+ : base(193, 15, 0, 0)
+ {
+ this.m_infinity = new SecT193R2Point(this, null, null);
+
+ this.m_a = FromBigInteger(new BigInteger(1, Hex.Decode("0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B")));
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE")));
+ this.m_order = new BigInteger(1, Hex.Decode("010000000000000000000000015AAB561B005413CCD4EE99D5"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT193R2_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT193R2Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 193; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT193FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT193R2Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT193R2Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 193; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return true; }
+ }
+
+ public virtual int K1
+ {
+ get { return 15; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT193R2Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT193R2Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..18d89e316142b086478d57dd06e8695ab70a917c
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT193R2Point.cs
@@ -0,0 +1,283 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT193R2Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT193R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT193R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT193R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT193R2Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+ if (X3.IsZero)
+ {
+ return new SecT193R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT193R2Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT193R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement a = curve.A;
+ ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+ if (T.IsZero)
+ {
+ return new SecT193R2Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT193R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT193R2Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT193R2Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT193R2Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT233Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT233Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..870dade505be21298e0196fa0d8d2e16733d9a93
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT233Field.cs
@@ -0,0 +1,317 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT233Field
+ {
+ private const ulong M41 = ulong.MaxValue >> 23;
+ private const ulong M59 = ulong.MaxValue >> 5;
+
+ public static void Add(ulong[] x, ulong[] y, ulong[] z)
+ {
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
+ z[2] = x[2] ^ y[2];
+ z[3] = x[3] ^ y[3];
+ }
+
+ public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+ {
+ zz[0] = xx[0] ^ yy[0];
+ zz[1] = xx[1] ^ yy[1];
+ zz[2] = xx[2] ^ yy[2];
+ zz[3] = xx[3] ^ yy[3];
+ zz[4] = xx[4] ^ yy[4];
+ zz[5] = xx[5] ^ yy[5];
+ zz[6] = xx[6] ^ yy[6];
+ zz[7] = xx[7] ^ yy[7];
+ }
+
+ public static void AddOne(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0] ^ 1UL;
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ }
+
+ public static ulong[] FromBigInteger(BigInteger x)
+ {
+ ulong[] z = Nat256.FromBigInteger64(x);
+ Reduce23(z, 0);
+ return z;
+ }
+
+ public static void Invert(ulong[] x, ulong[] z)
+ {
+ if (Nat256.IsZero64(x))
+ throw new InvalidOperationException();
+
+ // Itoh-Tsujii inversion
+
+ ulong[] t0 = Nat256.Create64();
+ ulong[] t1 = Nat256.Create64();
+
+ Square(x, t0);
+ Multiply(t0, x, t0);
+ Square(t0, t0);
+ Multiply(t0, x, t0);
+ SquareN(t0, 3, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, t1);
+ Multiply(t1, x, t1);
+ SquareN(t1, 7, t0);
+ Multiply(t0, t1, t0);
+ SquareN(t0, 14, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, t1);
+ Multiply(t1, x, t1);
+ SquareN(t1, 29, t0);
+ Multiply(t0, t1, t0);
+ SquareN(t0, 58, t1);
+ Multiply(t1, t0, t1);
+ SquareN(t1, 116, t0);
+ Multiply(t0, t1, t0);
+ Square(t0, z);
+ }
+
+ public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplMultiply(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplMultiply(x, y, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void Reduce(ulong[] xx, ulong[] z)
+ {
+ ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3];
+ ulong x4 = xx[4], x5 = xx[5], x6 = xx[6], x7 = xx[7];
+
+ x3 ^= (x7 << 23);
+ x4 ^= (x7 >> 41) ^ (x7 << 33);
+ x5 ^= (x7 >> 31);
+
+ x2 ^= (x6 << 23);
+ x3 ^= (x6 >> 41) ^ (x6 << 33);
+ x4 ^= (x6 >> 31);
+
+ x1 ^= (x5 << 23);
+ x2 ^= (x5 >> 41) ^ (x5 << 33);
+ x3 ^= (x5 >> 31);
+
+ x0 ^= (x4 << 23);
+ x1 ^= (x4 >> 41) ^ (x4 << 33);
+ x2 ^= (x4 >> 31);
+
+ ulong t = x3 >> 41;
+ z[0] = x0 ^ t;
+ z[1] = x1 ^ (t << 10);
+ z[2] = x2;
+ z[3] = x3 & M41;
+ }
+
+ public static void Reduce23(ulong[] z, int zOff)
+ {
+ ulong z3 = z[zOff + 3], t = z3 >> 41;
+ z[zOff ] ^= t;
+ z[zOff + 1] ^= (t << 10);
+ z[zOff + 3] = z3 & M41;
+ }
+
+ public static void Sqrt(ulong[] x, ulong[] z)
+ {
+ ulong u0, u1;
+ u0 = Interleave.Unshuffle(x[0]); u1 = Interleave.Unshuffle(x[1]);
+ ulong e0 = (u0 & 0x00000000FFFFFFFFUL) | (u1 << 32);
+ ulong c0 = (u0 >> 32) | (u1 & 0xFFFFFFFF00000000UL);
+
+ u0 = Interleave.Unshuffle(x[2]); u1 = Interleave.Unshuffle(x[3]);
+ ulong e1 = (u0 & 0x00000000FFFFFFFFUL) | (u1 << 32);
+ ulong c1 = (u0 >> 32) | (u1 & 0xFFFFFFFF00000000UL);
+
+ ulong c2;
+ c2 = (c1 >> 27);
+ c1 ^= (c0 >> 27) | (c1 << 37);
+ c0 ^= (c0 << 37);
+
+ ulong[] tt = Nat256.CreateExt64();
+
+ int[] shifts = { 32, 117, 191 };
+ for (int i = 0; i < shifts.Length; ++i)
+ {
+ int w = shifts[i] >> 6, s = shifts[i] & 63;
+ Debug.Assert(s != 0);
+ tt[w ] ^= (c0 << s);
+ tt[w + 1] ^= (c1 << s) | (c0 >> -s);
+ tt[w + 2] ^= (c2 << s) | (c1 >> -s);
+ tt[w + 3] ^= (c2 >> -s);
+ }
+
+ Reduce(tt, z);
+
+ z[0] ^= e0;
+ z[1] ^= e1;
+ }
+
+ public static void Square(ulong[] x, ulong[] z)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareAddToExt(ulong[] x, ulong[] zz)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplSquare(x, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void SquareN(ulong[] x, int n, ulong[] z)
+ {
+ Debug.Assert(n > 0);
+
+ ulong[] tt = Nat256.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ ImplSquare(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static uint Trace(ulong[] x)
+ {
+ // Non-zero-trace bits: 0, 159
+ return (uint)(x[0] ^ (x[2] >> 31)) & 1U;
+ }
+
+ protected static void ImplCompactExt(ulong[] zz)
+ {
+ ulong z0 = zz[0], z1 = zz[1], z2 = zz[2], z3 = zz[3], z4 = zz[4], z5 = zz[5], z6 = zz[6], z7 = zz[7];
+ zz[0] = z0 ^ (z1 << 59);
+ zz[1] = (z1 >> 5) ^ (z2 << 54);
+ zz[2] = (z2 >> 10) ^ (z3 << 49);
+ zz[3] = (z3 >> 15) ^ (z4 << 44);
+ zz[4] = (z4 >> 20) ^ (z5 << 39);
+ zz[5] = (z5 >> 25) ^ (z6 << 34);
+ zz[6] = (z6 >> 30) ^ (z7 << 29);
+ zz[7] = (z7 >> 35);
+ }
+
+ protected static void ImplExpand(ulong[] x, ulong[] z)
+ {
+ ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3];
+ z[0] = x0 & M59;
+ z[1] = ((x0 >> 59) ^ (x1 << 5)) & M59;
+ z[2] = ((x1 >> 54) ^ (x2 << 10)) & M59;
+ z[3] = ((x2 >> 49) ^ (x3 << 15));
+ }
+
+ protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ /*
+ * "Two-level seven-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
+ */
+
+ ulong[] f = new ulong[4], g = new ulong[4];
+ ImplExpand(x, f);
+ ImplExpand(y, g);
+
+ ImplMulwAcc(f[0], g[0], zz, 0);
+ ImplMulwAcc(f[1], g[1], zz, 1);
+ ImplMulwAcc(f[2], g[2], zz, 2);
+ ImplMulwAcc(f[3], g[3], zz, 3);
+
+ // U *= (1 - t^n)
+ for (int i = 5; i > 0; --i)
+ {
+ zz[i] ^= zz[i - 1];
+ }
+
+ ImplMulwAcc(f[0] ^ f[1], g[0] ^ g[1], zz, 1);
+ ImplMulwAcc(f[2] ^ f[3], g[2] ^ g[3], zz, 3);
+
+ // V *= (1 - t^2n)
+ for (int i = 7; i > 1; --i)
+ {
+ zz[i] ^= zz[i - 2];
+ }
+
+ // Double-length recursion
+ {
+ ulong c0 = f[0] ^ f[2], c1 = f[1] ^ f[3];
+ ulong d0 = g[0] ^ g[2], d1 = g[1] ^ g[3];
+ ImplMulwAcc(c0 ^ c1, d0 ^ d1, zz, 3);
+ ulong[] t = new ulong[3];
+ ImplMulwAcc(c0, d0, t, 0);
+ ImplMulwAcc(c1, d1, t, 1);
+ ulong t0 = t[0], t1 = t[1], t2 = t[2];
+ zz[2] ^= t0;
+ zz[3] ^= t0 ^ t1;
+ zz[4] ^= t2 ^ t1;
+ zz[5] ^= t2;
+ }
+
+ ImplCompactExt(zz);
+ }
+
+ protected static void ImplMulwAcc(ulong x, ulong y, ulong[] z, int zOff)
+ {
+ Debug.Assert(x >> 59 == 0);
+ Debug.Assert(y >> 59 == 0);
+
+ ulong[] u = new ulong[8];
+ //u[0] = 0;
+ u[1] = y;
+ u[2] = u[1] << 1;
+ u[3] = u[2] ^ y;
+ u[4] = u[2] << 1;
+ u[5] = u[4] ^ y;
+ u[6] = u[3] << 1;
+ u[7] = u[6] ^ y;
+
+ uint j = (uint)x;
+ ulong g, h = 0, l = u[j & 7]
+ ^ (u[(j >> 3) & 7] << 3);
+ int k = 54;
+ do
+ {
+ j = (uint)(x >> k);
+ g = u[j & 7]
+ ^ u[(j >> 3) & 7] << 3;
+ l ^= (g << k);
+ h ^= (g >> -k);
+ }
+ while ((k -= 6) > 0);
+
+ Debug.Assert(h >> 53 == 0);
+
+ z[zOff ] ^= l & M59;
+ z[zOff + 1] ^= (l >> 59) ^ (h << 5);
+ }
+
+ protected static void ImplSquare(ulong[] x, ulong[] zz)
+ {
+ Interleave.Expand64To128(x[0], zz, 0);
+ Interleave.Expand64To128(x[1], zz, 2);
+ Interleave.Expand64To128(x[2], zz, 4);
+
+ ulong x3 = x[3];
+ zz[6] = Interleave.Expand32to64((uint)x3);
+ zz[7] = Interleave.Expand16to32((uint)(x3 >> 32));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT233FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT233FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..91b8e2f1c80d0ea71fe8548d036465c47d1f4cb6
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT233FieldElement.cs
@@ -0,0 +1,216 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT233FieldElement
+ : ECFieldElement
+ {
+ protected readonly ulong[] x;
+
+ public SecT233FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.BitLength > 233)
+ throw new ArgumentException("value invalid for SecT233FieldElement", "x");
+
+ this.x = SecT233Field.FromBigInteger(x);
+ }
+
+ public SecT233FieldElement()
+ {
+ this.x = Nat256.Create64();
+ }
+
+ protected internal SecT233FieldElement(ulong[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat256.IsOne64(x); }
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat256.IsZero64(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return (x[0] & 1UL) != 0UL;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat256.ToBigInteger64(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecT233Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 233; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ ulong[] z = Nat256.Create64();
+ SecT233Field.Add(x, ((SecT233FieldElement)b).x, z);
+ return new SecT233FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT233Field.AddOne(x, z);
+ return new SecT233FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ // Addition and Subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ ulong[] z = Nat256.Create64();
+ SecT233Field.Multiply(x, ((SecT233FieldElement)b).x, z);
+ return new SecT233FieldElement(z);
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return MultiplyPlusProduct(b, x, y);
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x, bx = ((SecT233FieldElement)b).x;
+ ulong[] xx = ((SecT233FieldElement)x).x, yx = ((SecT233FieldElement)y).x;
+
+ ulong[] tt = Nat256.CreateExt64();
+ SecT233Field.MultiplyAddToExt(ax, bx, tt);
+ SecT233Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat256.Create64();
+ SecT233Field.Reduce(tt, z);
+ return new SecT233FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ return Multiply(b.Invert());
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT233Field.Square(x, z);
+ return new SecT233FieldElement(z);
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return SquarePlusProduct(x, y);
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x;
+ ulong[] xx = ((SecT233FieldElement)x).x, yx = ((SecT233FieldElement)y).x;
+
+ ulong[] tt = Nat256.CreateExt64();
+ SecT233Field.SquareAddToExt(ax, tt);
+ SecT233Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat256.Create64();
+ SecT233Field.Reduce(tt, z);
+ return new SecT233FieldElement(z);
+ }
+
+ public override ECFieldElement SquarePow(int pow)
+ {
+ if (pow < 1)
+ return this;
+
+ ulong[] z = Nat256.Create64();
+ SecT233Field.SquareN(x, pow, z);
+ return new SecT233FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT233Field.Invert(x, z);
+ return new SecT233FieldElement(z);
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT233Field.Sqrt(x, z);
+ return new SecT233FieldElement(z);
+ }
+
+ public virtual int Representation
+ {
+ get { return F2mFieldElement.Tpb; }
+ }
+
+ public virtual int M
+ {
+ get { return 233; }
+ }
+
+ public virtual int K1
+ {
+ get { return 74; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecT233FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecT233FieldElement);
+ }
+
+ public virtual bool Equals(SecT233FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat256.Eq64(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return 2330074 ^ Arrays.GetHashCode(x, 0, 4);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT233K1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT233K1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..72935913dc9cd8b7bcbe6270ea8d23ad18ea7b46
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT233K1Curve.cs
@@ -0,0 +1,104 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT233K1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT233K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT233K1Point m_infinity;
+
+ public SecT233K1Curve()
+ : base(233, 74, 0, 0)
+ {
+ this.m_infinity = new SecT233K1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.Zero);
+ this.m_b = FromBigInteger(BigInteger.One);
+ this.m_order = new BigInteger(1, Hex.Decode("8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF"));
+ this.m_cofactor = BigInteger.ValueOf(4);
+
+ this.m_coord = SecT233K1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT233K1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ protected override ECMultiplier CreateDefaultMultiplier()
+ {
+ return new WTauNafMultiplier();
+ }
+
+ public override int FieldSize
+ {
+ get { return 233; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT233FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT233K1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT233K1Point(this, x, y, zs, withCompression);
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return true; }
+ }
+
+ public virtual int M
+ {
+ get { return 233; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return true; }
+ }
+
+ public virtual int K1
+ {
+ get { return 74; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT233K1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT233K1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9a357ff8f069dc70c013f98f7899d2e8f3a33b15
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT233K1Point.cs
@@ -0,0 +1,295 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT233K1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT233K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT233K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT233K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT233K1Point(null, this.AffineXCoord, this.AffineYCoord); // earlier JDK
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ {
+ return curve.Infinity;
+ }
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1);
+ if (X3.IsZero)
+ {
+ return new SecT233K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT233K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT233K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ {
+ return this;
+ }
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T;
+ if (Z1IsOne)
+ {
+ T = L1.Square().Add(L1);
+ }
+ else
+ {
+ T = L1.Add(Z1).Multiply(L1);
+ }
+
+ if (T.IsZero)
+ {
+ return new SecT233K1Point(curve, T, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement t1 = L1.Add(X1).Square();
+ ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.Square();
+ ECFieldElement L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3).Add(Z3);
+
+ return new SecT233K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ // NOTE: TwicePlus() only optimized for lambda-affine argument
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = L1Sq.Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = L2plus1.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ {
+ return b.Twice();
+ }
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT233K1Point(curve, A, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT233K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT233K1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT233R1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT233R1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..db6e6e1d4a8506f19a43e65ed725cc4651162971
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT233R1Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT233R1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT233R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT233R1Point m_infinity;
+
+ public SecT233R1Curve()
+ : base(233, 74, 0, 0)
+ {
+ this.m_infinity = new SecT233R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.One);
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD")));
+ this.m_order = new BigInteger(1, Hex.Decode("01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT233R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT233R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 233; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT233FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT233R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT233R1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 233; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return true; }
+ }
+
+ public virtual int K1
+ {
+ get { return 74; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT233R1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT233R1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6347051d2785aa212130b4048444d967fca5abef
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT233R1Point.cs
@@ -0,0 +1,278 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT233R1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT233R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT233R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT233R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT233R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).AddOne();
+ if (X3.IsZero)
+ {
+ return new SecT233R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT233R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT233R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(Z1Sq);
+ if (T.IsZero)
+ {
+ return new SecT233R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT233R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = Z1Sq.Add(L1Sq).Add(L1Z1);
+ ECFieldElement A = L2.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT233R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2.AddOne(), Z3);
+
+ return new SecT233R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT233R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT239Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT239Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2e6ed2ad6f139b4177e4fa7fa5a99e03824e19e5
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT239Field.cs
@@ -0,0 +1,328 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT239Field
+ {
+ private const ulong M47 = ulong.MaxValue >> 17;
+ private const ulong M60 = ulong.MaxValue >> 4;
+
+ public static void Add(ulong[] x, ulong[] y, ulong[] z)
+ {
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
+ z[2] = x[2] ^ y[2];
+ z[3] = x[3] ^ y[3];
+ }
+
+ public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+ {
+ zz[0] = xx[0] ^ yy[0];
+ zz[1] = xx[1] ^ yy[1];
+ zz[2] = xx[2] ^ yy[2];
+ zz[3] = xx[3] ^ yy[3];
+ zz[4] = xx[4] ^ yy[4];
+ zz[5] = xx[5] ^ yy[5];
+ zz[6] = xx[6] ^ yy[6];
+ zz[7] = xx[7] ^ yy[7];
+ }
+
+ public static void AddOne(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0] ^ 1UL;
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ }
+
+ public static ulong[] FromBigInteger(BigInteger x)
+ {
+ ulong[] z = Nat256.FromBigInteger64(x);
+ Reduce17(z, 0);
+ return z;
+ }
+
+ public static void Invert(ulong[] x, ulong[] z)
+ {
+ if (Nat256.IsZero64(x))
+ throw new InvalidOperationException();
+
+ // Itoh-Tsujii inversion
+
+ ulong[] t0 = Nat256.Create64();
+ ulong[] t1 = Nat256.Create64();
+
+ Square(x, t0);
+ Multiply(t0, x, t0);
+ Square(t0, t0);
+ Multiply(t0, x, t0);
+ SquareN(t0, 3, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, t1);
+ Multiply(t1, x, t1);
+ SquareN(t1, 7, t0);
+ Multiply(t0, t1, t0);
+ SquareN(t0, 14, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, t1);
+ Multiply(t1, x, t1);
+ SquareN(t1, 29, t0);
+ Multiply(t0, t1, t0);
+ Square(t0, t0);
+ Multiply(t0, x, t0);
+ SquareN(t0, 59, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, t1);
+ Multiply(t1, x, t1);
+ SquareN(t1, 119, t0);
+ Multiply(t0, t1, t0);
+ Square(t0, z);
+ }
+
+ public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplMultiply(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplMultiply(x, y, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void Reduce(ulong[] xx, ulong[] z)
+ {
+ ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3];
+ ulong x4 = xx[4], x5 = xx[5], x6 = xx[6], x7 = xx[7];
+
+ x3 ^= (x7 << 17);
+ x4 ^= (x7 >> 47);
+ x5 ^= (x7 << 47);
+ x6 ^= (x7 >> 17);
+
+ x2 ^= (x6 << 17);
+ x3 ^= (x6 >> 47);
+ x4 ^= (x6 << 47);
+ x5 ^= (x6 >> 17);
+
+ x1 ^= (x5 << 17);
+ x2 ^= (x5 >> 47);
+ x3 ^= (x5 << 47);
+ x4 ^= (x5 >> 17);
+
+ x0 ^= (x4 << 17);
+ x1 ^= (x4 >> 47);
+ x2 ^= (x4 << 47);
+ x3 ^= (x4 >> 17);
+
+ ulong t = x3 >> 47;
+ z[0] = x0 ^ t;
+ z[1] = x1;
+ z[2] = x2 ^ (t << 30);
+ z[3] = x3 & M47;
+ }
+
+ public static void Reduce17(ulong[] z, int zOff)
+ {
+ ulong z3 = z[zOff + 3], t = z3 >> 47;
+ z[zOff ] ^= t;
+ z[zOff + 2] ^= (t << 30);
+ z[zOff + 3] = z3 & M47;
+ }
+
+ public static void Sqrt(ulong[] x, ulong[] z)
+ {
+ ulong u0, u1;
+ u0 = Interleave.Unshuffle(x[0]); u1 = Interleave.Unshuffle(x[1]);
+ ulong e0 = (u0 & 0x00000000FFFFFFFFUL) | (u1 << 32);
+ ulong c0 = (u0 >> 32) | (u1 & 0xFFFFFFFF00000000UL);
+
+ u0 = Interleave.Unshuffle(x[2]); u1 = Interleave.Unshuffle(x[3]);
+ ulong e1 = (u0 & 0x00000000FFFFFFFFUL) | (u1 << 32);
+ ulong c1 = (u0 >> 32) | (u1 & 0xFFFFFFFF00000000UL);
+
+ ulong c2, c3;
+ c3 = (c1 >> 49);
+ c2 = (c0 >> 49) | (c1 << 15);
+ c1 ^= (c0 << 15);
+
+ ulong[] tt = Nat256.CreateExt64();
+
+ int[] shifts = { 39, 120 };
+ for (int i = 0; i < shifts.Length; ++i)
+ {
+ int w = shifts[i] >> 6, s = shifts[i] & 63;
+ Debug.Assert(s != 0);
+ tt[w ] ^= (c0 << s);
+ tt[w + 1] ^= (c1 << s) | (c0 >> -s);
+ tt[w + 2] ^= (c2 << s) | (c1 >> -s);
+ tt[w + 3] ^= (c3 << s) | (c2 >> -s);
+ tt[w + 4] ^= (c3 >> -s);
+ }
+
+ Reduce(tt, z);
+
+ z[0] ^= e0;
+ z[1] ^= e1;
+ }
+
+ public static void Square(ulong[] x, ulong[] z)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareAddToExt(ulong[] x, ulong[] zz)
+ {
+ ulong[] tt = Nat256.CreateExt64();
+ ImplSquare(x, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void SquareN(ulong[] x, int n, ulong[] z)
+ {
+ Debug.Assert(n > 0);
+
+ ulong[] tt = Nat256.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ ImplSquare(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static uint Trace(ulong[] x)
+ {
+ // Non-zero-trace bits: 0, 81, 162
+ return (uint)(x[0] ^ (x[1] >> 17) ^ (x[2] >> 34)) & 1U;
+ }
+
+ protected static void ImplCompactExt(ulong[] zz)
+ {
+ ulong z0 = zz[0], z1 = zz[1], z2 = zz[2], z3 = zz[3], z4 = zz[4], z5 = zz[5], z6 = zz[6], z7 = zz[7];
+ zz[0] = z0 ^ (z1 << 60);
+ zz[1] = (z1 >> 4) ^ (z2 << 56);
+ zz[2] = (z2 >> 8) ^ (z3 << 52);
+ zz[3] = (z3 >> 12) ^ (z4 << 48);
+ zz[4] = (z4 >> 16) ^ (z5 << 44);
+ zz[5] = (z5 >> 20) ^ (z6 << 40);
+ zz[6] = (z6 >> 24) ^ (z7 << 36);
+ zz[7] = (z7 >> 28);
+ }
+
+ protected static void ImplExpand(ulong[] x, ulong[] z)
+ {
+ ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3];
+ z[0] = x0 & M60;
+ z[1] = ((x0 >> 60) ^ (x1 << 4)) & M60;
+ z[2] = ((x1 >> 56) ^ (x2 << 8)) & M60;
+ z[3] = ((x2 >> 52) ^ (x3 << 12));
+ }
+
+ protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ /*
+ * "Two-level seven-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
+ */
+
+ ulong[] f = new ulong[4], g = new ulong[4];
+ ImplExpand(x, f);
+ ImplExpand(y, g);
+
+ ImplMulwAcc(f[0], g[0], zz, 0);
+ ImplMulwAcc(f[1], g[1], zz, 1);
+ ImplMulwAcc(f[2], g[2], zz, 2);
+ ImplMulwAcc(f[3], g[3], zz, 3);
+
+ // U *= (1 - t^n)
+ for (int i = 5; i > 0; --i)
+ {
+ zz[i] ^= zz[i - 1];
+ }
+
+ ImplMulwAcc(f[0] ^ f[1], g[0] ^ g[1], zz, 1);
+ ImplMulwAcc(f[2] ^ f[3], g[2] ^ g[3], zz, 3);
+
+ // V *= (1 - t^2n)
+ for (int i = 7; i > 1; --i)
+ {
+ zz[i] ^= zz[i - 2];
+ }
+
+ // Double-length recursion
+ {
+ ulong c0 = f[0] ^ f[2], c1 = f[1] ^ f[3];
+ ulong d0 = g[0] ^ g[2], d1 = g[1] ^ g[3];
+ ImplMulwAcc(c0 ^ c1, d0 ^ d1, zz, 3);
+ ulong[] t = new ulong[3];
+ ImplMulwAcc(c0, d0, t, 0);
+ ImplMulwAcc(c1, d1, t, 1);
+ ulong t0 = t[0], t1 = t[1], t2 = t[2];
+ zz[2] ^= t0;
+ zz[3] ^= t0 ^ t1;
+ zz[4] ^= t2 ^ t1;
+ zz[5] ^= t2;
+ }
+
+ ImplCompactExt(zz);
+ }
+
+ protected static void ImplMulwAcc(ulong x, ulong y, ulong[] z, int zOff)
+ {
+ Debug.Assert(x >> 60 == 0);
+ Debug.Assert(y >> 60 == 0);
+
+ ulong[] u = new ulong[8];
+ //u[0] = 0;
+ u[1] = y;
+ u[2] = u[1] << 1;
+ u[3] = u[2] ^ y;
+ u[4] = u[2] << 1;
+ u[5] = u[4] ^ y;
+ u[6] = u[3] << 1;
+ u[7] = u[6] ^ y;
+
+ uint j = (uint)x;
+ ulong g, h = 0, l = u[j & 7]
+ ^ (u[(j >> 3) & 7] << 3);
+ int k = 54;
+ do
+ {
+ j = (uint)(x >> k);
+ g = u[j & 7]
+ ^ u[(j >> 3) & 7] << 3;
+ l ^= (g << k);
+ h ^= (g >> -k);
+ }
+ while ((k -= 6) > 0);
+
+ h ^= ((x & 0x0820820820820820L) & (ulong)(((long)y << 4) >> 63)) >> 5;
+
+ Debug.Assert(h >> 55 == 0);
+
+ z[zOff ] ^= l & M60;
+ z[zOff + 1] ^= (l >> 60) ^ (h << 4);
+ }
+
+ protected static void ImplSquare(ulong[] x, ulong[] zz)
+ {
+ Interleave.Expand64To128(x[0], zz, 0);
+ Interleave.Expand64To128(x[1], zz, 2);
+ Interleave.Expand64To128(x[2], zz, 4);
+
+ ulong x3 = x[3];
+ zz[6] = Interleave.Expand32to64((uint)x3);
+ zz[7] = Interleave.Expand16to32((uint)(x3 >> 32));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT239FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT239FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a32ffc5d28758364c280a0663c254eb6b2e8927d
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT239FieldElement.cs
@@ -0,0 +1,216 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT239FieldElement
+ : ECFieldElement
+ {
+ protected ulong[] x;
+
+ public SecT239FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.BitLength > 239)
+ throw new ArgumentException("value invalid for SecT239FieldElement", "x");
+
+ this.x = SecT239Field.FromBigInteger(x);
+ }
+
+ public SecT239FieldElement()
+ {
+ this.x = Nat256.Create64();
+ }
+
+ protected internal SecT239FieldElement(ulong[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat256.IsOne64(x); }
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat256.IsZero64(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return (x[0] & 1L) != 0L;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat256.ToBigInteger64(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecT239Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 239; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ ulong[] z = Nat256.Create64();
+ SecT239Field.Add(x, ((SecT239FieldElement)b).x, z);
+ return new SecT239FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT239Field.AddOne(x, z);
+ return new SecT239FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ // Addition and Subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ ulong[] z = Nat256.Create64();
+ SecT239Field.Multiply(x, ((SecT239FieldElement)b).x, z);
+ return new SecT239FieldElement(z);
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return MultiplyPlusProduct(b, x, y);
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x, bx = ((SecT239FieldElement)b).x;
+ ulong[] xx = ((SecT239FieldElement)x).x, yx = ((SecT239FieldElement)y).x;
+
+ ulong[] tt = Nat256.CreateExt64();
+ SecT239Field.MultiplyAddToExt(ax, bx, tt);
+ SecT239Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat256.Create64();
+ SecT239Field.Reduce(tt, z);
+ return new SecT239FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ return Multiply(b.Invert());
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT239Field.Square(x, z);
+ return new SecT239FieldElement(z);
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return SquarePlusProduct(x, y);
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x;
+ ulong[] xx = ((SecT239FieldElement)x).x, yx = ((SecT239FieldElement)y).x;
+
+ ulong[] tt = Nat256.CreateExt64();
+ SecT239Field.SquareAddToExt(ax, tt);
+ SecT239Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat256.Create64();
+ SecT239Field.Reduce(tt, z);
+ return new SecT239FieldElement(z);
+ }
+
+ public override ECFieldElement SquarePow(int pow)
+ {
+ if (pow < 1)
+ return this;
+
+ ulong[] z = Nat256.Create64();
+ SecT239Field.SquareN(x, pow, z);
+ return new SecT239FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT239Field.Invert(x, z);
+ return new SecT239FieldElement(z);
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ ulong[] z = Nat256.Create64();
+ SecT239Field.Sqrt(x, z);
+ return new SecT239FieldElement(z);
+ }
+
+ public virtual int Representation
+ {
+ get { return F2mFieldElement.Tpb; }
+ }
+
+ public virtual int M
+ {
+ get { return 239; }
+ }
+
+ public virtual int K1
+ {
+ get { return 158; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecT239FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecT239FieldElement);
+ }
+
+ public virtual bool Equals(SecT239FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat256.Eq64(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return 23900158 ^ Arrays.GetHashCode(x, 0, 4);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT239K1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT239K1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a499d48b4df7875f1a4a6bf0e1c8dcf92fe119e0
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT239K1Curve.cs
@@ -0,0 +1,104 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT239K1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT239K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT239K1Point m_infinity;
+
+ public SecT239K1Curve()
+ : base(239, 158, 0, 0)
+ {
+ this.m_infinity = new SecT239K1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.Zero);
+ this.m_b = FromBigInteger(BigInteger.One);
+ this.m_order = new BigInteger(1, Hex.Decode("2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5"));
+ this.m_cofactor = BigInteger.ValueOf(4);
+
+ this.m_coord = SecT239K1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT239K1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ protected override ECMultiplier CreateDefaultMultiplier()
+ {
+ return new WTauNafMultiplier();
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 239; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT239FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT239K1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT239K1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return true; }
+ }
+
+ public virtual int M
+ {
+ get { return 239; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return true; }
+ }
+
+ public virtual int K1
+ {
+ get { return 158; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT239K1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT239K1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fbd5117f8aed1d1e2904227a2cce2b137b4fd78b
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT239K1Point.cs
@@ -0,0 +1,290 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT239K1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT239K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT239K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT239K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT239K1Point(null, this.AffineXCoord, this.AffineYCoord); // earlier JDK
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1);
+ if (X3.IsZero)
+ {
+ return new SecT239K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT239K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT239K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T;
+ if (Z1IsOne)
+ {
+ T = L1.Square().Add(L1);
+ }
+ else
+ {
+ T = L1.Add(Z1).Multiply(L1);
+ }
+
+ if (T.IsZero)
+ {
+ return new SecT239K1Point(curve, T, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement t1 = L1.Add(X1).Square();
+ ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.Square();
+ ECFieldElement L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3).Add(Z3);
+
+ return new SecT239K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ // NOTE: TwicePlus() only optimized for lambda-affine argument
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = L1Sq.Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = L2plus1.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT239K1Point(curve, A, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT239K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT239K1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT283Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT283Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..22b7eaaab294640f72a9cf35f4d08111f194b09b
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT283Field.cs
@@ -0,0 +1,402 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT283Field
+ {
+ private const ulong M27 = ulong.MaxValue >> 37;
+ private const ulong M57 = ulong.MaxValue >> 7;
+
+ private static readonly ulong[] ROOT_Z = new ulong[]{ 0x0C30C30C30C30808UL, 0x30C30C30C30C30C3UL, 0x820820820820830CUL, 0x0820820820820820UL, 0x2082082UL };
+
+ public static void Add(ulong[] x, ulong[] y, ulong[] z)
+ {
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
+ z[2] = x[2] ^ y[2];
+ z[3] = x[3] ^ y[3];
+ z[4] = x[4] ^ y[4];
+ }
+
+ public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+ {
+ zz[0] = xx[0] ^ yy[0];
+ zz[1] = xx[1] ^ yy[1];
+ zz[2] = xx[2] ^ yy[2];
+ zz[3] = xx[3] ^ yy[3];
+ zz[4] = xx[4] ^ yy[4];
+ zz[5] = xx[5] ^ yy[5];
+ zz[6] = xx[6] ^ yy[6];
+ zz[7] = xx[7] ^ yy[7];
+ zz[8] = xx[8] ^ yy[8];
+ }
+
+ public static void AddOne(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0] ^ 1UL;
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ z[4] = x[4];
+ }
+
+ public static ulong[] FromBigInteger(BigInteger x)
+ {
+ ulong[] z = Nat320.FromBigInteger64(x);
+ Reduce37(z, 0);
+ return z;
+ }
+
+ public static void Invert(ulong[] x, ulong[] z)
+ {
+ if (Nat320.IsZero64(x))
+ throw new InvalidOperationException();
+
+ // Itoh-Tsujii inversion
+
+ ulong[] t0 = Nat320.Create64();
+ ulong[] t1 = Nat320.Create64();
+
+ Square(x, t0);
+ Multiply(t0, x, t0);
+ SquareN(t0, 2, t1);
+ Multiply(t1, t0, t1);
+ SquareN(t1, 4, t0);
+ Multiply(t0, t1, t0);
+ SquareN(t0, 8, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, t1);
+ Multiply(t1, x, t1);
+ SquareN(t1, 17, t0);
+ Multiply(t0, t1, t0);
+ Square(t0, t0);
+ Multiply(t0, x, t0);
+ SquareN(t0, 35, t1);
+ Multiply(t1, t0, t1);
+ SquareN(t1, 70, t0);
+ Multiply(t0, t1, t0);
+ Square(t0, t0);
+ Multiply(t0, x, t0);
+ SquareN(t0, 141, t1);
+ Multiply(t1, t0, t1);
+ Square(t1, z);
+ }
+
+ public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+ {
+ ulong[] tt = Nat320.CreateExt64();
+ ImplMultiply(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] tt = Nat320.CreateExt64();
+ ImplMultiply(x, y, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void Reduce(ulong[] xx, ulong[] z)
+ {
+ ulong x0 = xx[0], x1 = xx[1], x2 = xx[2], x3 = xx[3], x4 = xx[4];
+ ulong x5 = xx[5], x6 = xx[6], x7 = xx[7], x8 = xx[8];
+
+ x3 ^= (x8 << 37) ^ (x8 << 42) ^ (x8 << 44) ^ (x8 << 49);
+ x4 ^= (x8 >> 27) ^ (x8 >> 22) ^ (x8 >> 20) ^ (x8 >> 15);
+
+ x2 ^= (x7 << 37) ^ (x7 << 42) ^ (x7 << 44) ^ (x7 << 49);
+ x3 ^= (x7 >> 27) ^ (x7 >> 22) ^ (x7 >> 20) ^ (x7 >> 15);
+
+ x1 ^= (x6 << 37) ^ (x6 << 42) ^ (x6 << 44) ^ (x6 << 49);
+ x2 ^= (x6 >> 27) ^ (x6 >> 22) ^ (x6 >> 20) ^ (x6 >> 15);
+
+ x0 ^= (x5 << 37) ^ (x5 << 42) ^ (x5 << 44) ^ (x5 << 49);
+ x1 ^= (x5 >> 27) ^ (x5 >> 22) ^ (x5 >> 20) ^ (x5 >> 15);
+
+ ulong t = x4 >> 27;
+ z[0] = x0 ^ t ^ (t << 5) ^ (t << 7) ^ (t << 12);
+ z[1] = x1;
+ z[2] = x2;
+ z[3] = x3;
+ z[4] = x4 & M27;
+ }
+
+ public static void Reduce37(ulong[] z, int zOff)
+ {
+ ulong z4 = z[zOff + 4], t = z4 >> 27;
+ z[zOff ] ^= t ^ (t << 5) ^ (t << 7) ^ (t << 12);
+ z[zOff + 4] = z4 & M27;
+ }
+
+ public static void Sqrt(ulong[] x, ulong[] z)
+ {
+ ulong[] odd = Nat320.Create64();
+
+ ulong u0, u1;
+ u0 = Interleave.Unshuffle(x[0]); u1 = Interleave.Unshuffle(x[1]);
+ ulong e0 = (u0 & 0x00000000FFFFFFFFUL) | (u1 << 32);
+ odd[0] = (u0 >> 32) | (u1 & 0xFFFFFFFF00000000UL);
+
+ u0 = Interleave.Unshuffle(x[2]); u1 = Interleave.Unshuffle(x[3]);
+ ulong e1 = (u0 & 0x00000000FFFFFFFFUL) | (u1 << 32);
+ odd[1] = (u0 >> 32) | (u1 & 0xFFFFFFFF00000000UL);
+
+ u0 = Interleave.Unshuffle(x[4]);
+ ulong e2 = (u0 & 0x00000000FFFFFFFFUL);
+ odd[2] = (u0 >> 32);
+
+ Multiply(odd, ROOT_Z, z);
+
+ z[0] ^= e0;
+ z[1] ^= e1;
+ z[2] ^= e2;
+ }
+
+ public static void Square(ulong[] x, ulong[] z)
+ {
+ ulong[] tt = Nat.Create64(9);
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareAddToExt(ulong[] x, ulong[] zz)
+ {
+ ulong[] tt = Nat.Create64(9);
+ ImplSquare(x, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void SquareN(ulong[] x, int n, ulong[] z)
+ {
+ Debug.Assert(n > 0);
+
+ ulong[] tt = Nat.Create64(9);
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ ImplSquare(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static uint Trace(ulong[] x)
+ {
+ // Non-zero-trace bits: 0, 271
+ return (uint)(x[0] ^ (x[4] >> 15)) & 1U;
+ }
+
+ protected static void ImplCompactExt(ulong[] zz)
+ {
+ ulong z0 = zz[0], z1 = zz[1], z2 = zz[2], z3 = zz[3], z4 = zz[4];
+ ulong z5 = zz[5], z6 = zz[6], z7 = zz[7], z8 = zz[8], z9 = zz[9];
+ zz[0] = z0 ^ (z1 << 57);
+ zz[1] = (z1 >> 7) ^ (z2 << 50);
+ zz[2] = (z2 >> 14) ^ (z3 << 43);
+ zz[3] = (z3 >> 21) ^ (z4 << 36);
+ zz[4] = (z4 >> 28) ^ (z5 << 29);
+ zz[5] = (z5 >> 35) ^ (z6 << 22);
+ zz[6] = (z6 >> 42) ^ (z7 << 15);
+ zz[7] = (z7 >> 49) ^ (z8 << 8);
+ zz[8] = (z8 >> 56) ^ (z9 << 1);
+ zz[9] = (z9 >> 63); // Zero!
+ }
+
+ protected static void ImplExpand(ulong[] x, ulong[] z)
+ {
+ ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4];
+ z[0] = x0 & M57;
+ z[1] = ((x0 >> 57) ^ (x1 << 7)) & M57;
+ z[2] = ((x1 >> 50) ^ (x2 << 14)) & M57;
+ z[3] = ((x2 >> 43) ^ (x3 << 21)) & M57;
+ z[4] = ((x3 >> 36) ^ (x4 << 28));
+ }
+
+ //protected static void AddMs(ulong[] zz, int zOff, ulong[] p, params int[] ms)
+ //{
+ // ulong t0 = 0, t1 = 0;
+ // foreach (int m in ms)
+ // {
+ // int i = (m - 1) << 1;
+ // t0 ^= p[i ];
+ // t1 ^= p[i + 1];
+ // }
+ // zz[zOff ] ^= t0;
+ // zz[zOff + 1] ^= t1;
+ //}
+
+ protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ /*
+ * Formula (17) from "Some New Results on Binary Polynomial Multiplication",
+ * Murat Cenk and M. Anwar Hasan.
+ *
+ * The formula as given contained an error in the term t25, as noted below
+ */
+ ulong[] a = new ulong[5], b = new ulong[5];
+ ImplExpand(x, a);
+ ImplExpand(y, b);
+
+ ulong[] p = new ulong[26];
+
+ ImplMulw(a[0], b[0], p, 0); // m1
+ ImplMulw(a[1], b[1], p, 2); // m2
+ ImplMulw(a[2], b[2], p, 4); // m3
+ ImplMulw(a[3], b[3], p, 6); // m4
+ ImplMulw(a[4], b[4], p, 8); // m5
+
+ ulong u0 = a[0] ^ a[1], v0 = b[0] ^ b[1];
+ ulong u1 = a[0] ^ a[2], v1 = b[0] ^ b[2];
+ ulong u2 = a[2] ^ a[4], v2 = b[2] ^ b[4];
+ ulong u3 = a[3] ^ a[4], v3 = b[3] ^ b[4];
+
+ ImplMulw(u1 ^ a[3], v1 ^ b[3], p, 18); // m10
+ ImplMulw(u2 ^ a[1], v2 ^ b[1], p, 20); // m11
+
+ ulong A4 = u0 ^ u3 , B4 = v0 ^ v3;
+ ulong A5 = A4 ^ a[2], B5 = B4 ^ b[2];
+
+ ImplMulw(A4, B4, p, 22); // m12
+ ImplMulw(A5, B5, p, 24); // m13
+
+ ImplMulw(u0, v0, p, 10); // m6
+ ImplMulw(u1, v1, p, 12); // m7
+ ImplMulw(u2, v2, p, 14); // m8
+ ImplMulw(u3, v3, p, 16); // m9
+
+
+ // Original method, corresponding to formula (16)
+ //AddMs(zz, 0, p, 1);
+ //AddMs(zz, 1, p, 1, 2, 6);
+ //AddMs(zz, 2, p, 1, 2, 3, 7);
+ //AddMs(zz, 3, p, 1, 3, 4, 5, 8, 10, 12, 13);
+ //AddMs(zz, 4, p, 1, 2, 4, 5, 6, 9, 10, 11, 13);
+ //AddMs(zz, 5, p, 1, 2, 3, 5, 7, 11, 12, 13);
+ //AddMs(zz, 6, p, 3, 4, 5, 8);
+ //AddMs(zz, 7, p, 4, 5, 9);
+ //AddMs(zz, 8, p, 5);
+
+ // Improved method factors out common single-word terms
+ // NOTE: p1,...,p26 in the paper maps to p[0],...,p[25] here
+
+ zz[0] = p[ 0];
+ zz[9] = p[ 9];
+
+ ulong t1 = p[ 0] ^ p[ 1];
+ ulong t2 = t1 ^ p[ 2];
+ ulong t3 = t2 ^ p[10];
+
+ zz[1] = t3;
+
+ ulong t4 = p[ 3] ^ p[ 4];
+ ulong t5 = p[11] ^ p[12];
+ ulong t6 = t4 ^ t5;
+ ulong t7 = t2 ^ t6;
+
+ zz[2] = t7;
+
+ ulong t8 = t1 ^ t4;
+ ulong t9 = p[ 5] ^ p[ 6];
+ ulong t10 = t8 ^ t9;
+ ulong t11 = t10 ^ p[ 8];
+ ulong t12 = p[13] ^ p[14];
+ ulong t13 = t11 ^ t12;
+ ulong t14 = p[18] ^ p[22];
+ ulong t15 = t14 ^ p[24];
+ ulong t16 = t13 ^ t15;
+
+ zz[3] = t16;
+
+ ulong t17 = p[ 7] ^ p[ 8];
+ ulong t18 = t17 ^ p[ 9];
+ ulong t19 = t18 ^ p[17];
+
+ zz[8] = t19;
+
+ ulong t20 = t18 ^ t9;
+ ulong t21 = p[15] ^ p[16];
+ ulong t22 = t20 ^ t21;
+
+ zz[7] = t22;
+
+ ulong t23 = t22 ^ t3;
+ ulong t24 = p[19] ^ p[20];
+ // ulong t25 = p[23] ^ p[24];
+ ulong t25 = p[25] ^ p[24]; // Fixes an error in the paper: p[23] -> p{25]
+ ulong t26 = p[18] ^ p[23];
+ ulong t27 = t24 ^ t25;
+ ulong t28 = t27 ^ t26;
+ ulong t29 = t28 ^ t23;
+
+ zz[4] = t29;
+
+ ulong t30 = t7 ^ t19;
+ ulong t31 = t27 ^ t30;
+ ulong t32 = p[21] ^ p[22];
+ ulong t33 = t31 ^ t32;
+
+ zz[5] = t33;
+
+ ulong t34 = t11 ^ p[0];
+ ulong t35 = t34 ^ p[9];
+ ulong t36 = t35 ^ t12;
+ ulong t37 = t36 ^ p[21];
+ ulong t38 = t37 ^ p[23];
+ ulong t39 = t38 ^ p[25];
+
+ zz[6] = t39;
+
+ ImplCompactExt(zz);
+ }
+
+ protected static void ImplMulw(ulong x, ulong y, ulong[] z, int zOff)
+ {
+ Debug.Assert(x >> 57 == 0);
+ Debug.Assert(y >> 57 == 0);
+
+ ulong[] u = new ulong[8];
+ //u[0] = 0;
+ u[1] = y;
+ u[2] = u[1] << 1;
+ u[3] = u[2] ^ y;
+ u[4] = u[2] << 1;
+ u[5] = u[4] ^ y;
+ u[6] = u[3] << 1;
+ u[7] = u[6] ^ y;
+
+ uint j = (uint)x;
+ ulong g, h = 0, l = u[j & 7];
+ int k = 48;
+ do
+ {
+ j = (uint)(x >> k);
+ g = u[j & 7]
+ ^ u[(j >> 3) & 7] << 3
+ ^ u[(j >> 6) & 7] << 6;
+ l ^= (g << k);
+ h ^= (g >> -k);
+ }
+ while ((k -= 9) > 0);
+
+ h ^= ((x & 0x0100804020100800L) & (ulong)(((long)y << 7) >> 63)) >> 8;
+
+ Debug.Assert(h >> 49 == 0);
+
+ z[zOff ] = l & M57;
+ z[zOff + 1] = (l >> 57) ^ (h << 7);
+ }
+
+ protected static void ImplSquare(ulong[] x, ulong[] zz)
+ {
+ for (int i = 0; i < 4; ++i)
+ {
+ Interleave.Expand64To128(x[i], zz, i << 1);
+ }
+ zz[8] = Interleave.Expand32to64((uint)x[4]);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT283FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT283FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..adfd4e0ed5a355abe97cdbb80f224e2743d3612e
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT283FieldElement.cs
@@ -0,0 +1,216 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT283FieldElement
+ : ECFieldElement
+ {
+ protected readonly ulong[] x;
+
+ public SecT283FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.BitLength > 283)
+ throw new ArgumentException("value invalid for SecT283FieldElement", "x");
+
+ this.x = SecT283Field.FromBigInteger(x);
+ }
+
+ public SecT283FieldElement()
+ {
+ this.x = Nat320.Create64();
+ }
+
+ protected internal SecT283FieldElement(ulong[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat320.IsOne64(x); }
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat320.IsZero64(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return (x[0] & 1UL) != 0UL;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat320.ToBigInteger64(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecT283Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 283; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ ulong[] z = Nat320.Create64();
+ SecT283Field.Add(x, ((SecT283FieldElement)b).x, z);
+ return new SecT283FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ ulong[] z = Nat320.Create64();
+ SecT283Field.AddOne(x, z);
+ return new SecT283FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ // Addition and subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ ulong[] z = Nat320.Create64();
+ SecT283Field.Multiply(x, ((SecT283FieldElement)b).x, z);
+ return new SecT283FieldElement(z);
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return MultiplyPlusProduct(b, x, y);
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x, bx = ((SecT283FieldElement)b).x;
+ ulong[] xx = ((SecT283FieldElement)x).x, yx = ((SecT283FieldElement)y).x;
+
+ ulong[] tt = Nat.Create64(9);
+ SecT283Field.MultiplyAddToExt(ax, bx, tt);
+ SecT283Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat320.Create64();
+ SecT283Field.Reduce(tt, z);
+ return new SecT283FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ return Multiply(b.Invert());
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ ulong[] z = Nat320.Create64();
+ SecT283Field.Square(x, z);
+ return new SecT283FieldElement(z);
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return SquarePlusProduct(x, y);
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x;
+ ulong[] xx = ((SecT283FieldElement)x).x, yx = ((SecT283FieldElement)y).x;
+
+ ulong[] tt = Nat.Create64(9);
+ SecT283Field.SquareAddToExt(ax, tt);
+ SecT283Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat320.Create64();
+ SecT283Field.Reduce(tt, z);
+ return new SecT283FieldElement(z);
+ }
+
+ public override ECFieldElement SquarePow(int pow)
+ {
+ if (pow < 1)
+ return this;
+
+ ulong[] z = Nat320.Create64();
+ SecT283Field.SquareN(x, pow, z);
+ return new SecT283FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ ulong[] z = Nat320.Create64();
+ SecT283Field.Invert(x, z);
+ return new SecT283FieldElement(z);
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ ulong[] z = Nat320.Create64();
+ SecT283Field.Sqrt(x, z);
+ return new SecT283FieldElement(z);
+ }
+
+ public virtual int Representation
+ {
+ get { return F2mFieldElement.Ppb; }
+ }
+
+ public virtual int M
+ {
+ get { return 283; }
+ }
+
+ public virtual int K1
+ {
+ get { return 5; }
+ }
+
+ public virtual int K2
+ {
+ get { return 7; }
+ }
+
+ public virtual int K3
+ {
+ get { return 12; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecT283FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecT283FieldElement);
+ }
+
+ public virtual bool Equals(SecT283FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat320.Eq64(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return 2831275 ^ Arrays.GetHashCode(x, 0, 5);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT283K1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT283K1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4053287ec4205cc6f00035ccdf4c52f5f44561b0
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT283K1Curve.cs
@@ -0,0 +1,104 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT283K1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT283K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT283K1Point m_infinity;
+
+ public SecT283K1Curve()
+ : base(283, 5, 7, 12)
+ {
+ this.m_infinity = new SecT283K1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.Zero);
+ this.m_b = FromBigInteger(BigInteger.One);
+ this.m_order = new BigInteger(1, Hex.Decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61"));
+ this.m_cofactor = BigInteger.ValueOf(4);
+
+ this.m_coord = SecT283K1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT283K1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ protected override ECMultiplier CreateDefaultMultiplier()
+ {
+ return new WTauNafMultiplier();
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 283; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT283FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT283K1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT283K1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return true; }
+ }
+
+ public virtual int M
+ {
+ get { return 283; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return false; }
+ }
+
+ public virtual int K1
+ {
+ get { return 5; }
+ }
+
+ public virtual int K2
+ {
+ get { return 7; }
+ }
+
+ public virtual int K3
+ {
+ get { return 12; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT283K1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT283K1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9856894a137e94a54eb72fdba3ff9bfbe84128ac
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT283K1Point.cs
@@ -0,0 +1,289 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT283K1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT283K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT283K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT283K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT283K1Point(null, this.AffineXCoord, this.AffineYCoord); // earlier JDK
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1);
+ if (X3.IsZero)
+ {
+ return new SecT283K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT283K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT283K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T;
+ if (Z1IsOne)
+ {
+ T = L1.Square().Add(L1);
+ }
+ else
+ {
+ T = L1.Add(Z1).Multiply(L1);
+ }
+
+ if (T.IsZero)
+ {
+ return new SecT283K1Point(curve, T, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement t1 = L1.Add(X1).Square();
+ ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.Square();
+ ECFieldElement L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3).Add(Z3);
+
+ return new SecT283K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ // NOTE: TwicePlus() only optimized for lambda-affine argument
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = L1Sq.Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = L2plus1.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT283K1Point(curve, A, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT283K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT283K1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT283R1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT283R1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e659675ce2b02c2f96eb9dfebd4b92b49a02bce6
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT283R1Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT283R1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT283R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT283R1Point m_infinity;
+
+ public SecT283R1Curve()
+ : base(283, 5, 7, 12)
+ {
+ this.m_infinity = new SecT283R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.One);
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5")));
+ this.m_order = new BigInteger(1, Hex.Decode("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT283R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT283R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 283; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT283FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT283R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT283R1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 283; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return false; }
+ }
+
+ public virtual int K1
+ {
+ get { return 5; }
+ }
+
+ public virtual int K2
+ {
+ get { return 7; }
+ }
+
+ public virtual int K3
+ {
+ get { return 12; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT283R1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT283R1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4c1a7801d79e23648ce237c028e43032405a2d0d
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT283R1Point.cs
@@ -0,0 +1,278 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT283R1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT283R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT283R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT283R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT283R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).AddOne();
+ if (X3.IsZero)
+ {
+ return new SecT283R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT283R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT283R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(Z1Sq);
+ if (T.IsZero)
+ {
+ return new SecT283R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT283R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = Z1Sq.Add(L1Sq).Add(L1Z1);
+ ECFieldElement A = L2.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT283R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2.AddOne(), Z3);
+
+ return new SecT283R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT283R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT409Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT409Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..861b77aa1d905eea65937c081e03ca830d036f38
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT409Field.cs
@@ -0,0 +1,331 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT409Field
+ {
+ private const ulong M25 = ulong.MaxValue >> 39;
+ private const ulong M59 = ulong.MaxValue >> 5;
+
+ public static void Add(ulong[] x, ulong[] y, ulong[] z)
+ {
+ z[0] = x[0] ^ y[0];
+ z[1] = x[1] ^ y[1];
+ z[2] = x[2] ^ y[2];
+ z[3] = x[3] ^ y[3];
+ z[4] = x[4] ^ y[4];
+ z[5] = x[5] ^ y[5];
+ z[6] = x[6] ^ y[6];
+ }
+
+ public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+ {
+ for (int i = 0; i < 13; ++i)
+ {
+ zz[i] = xx[i] ^ yy[i];
+ }
+ }
+
+ public static void AddOne(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0] ^ 1UL;
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ z[4] = x[4];
+ z[5] = x[5];
+ z[6] = x[6];
+ }
+
+ public static ulong[] FromBigInteger(BigInteger x)
+ {
+ ulong[] z = Nat448.FromBigInteger64(x);
+ Reduce39(z, 0);
+ return z;
+ }
+
+ public static void Invert(ulong[] x, ulong[] z)
+ {
+ if (Nat448.IsZero64(x))
+ throw new InvalidOperationException();
+
+ // Itoh-Tsujii inversion with bases { 2, 3 }
+
+ ulong[] t0 = Nat448.Create64();
+ ulong[] t1 = Nat448.Create64();
+ ulong[] t2 = Nat448.Create64();
+
+ Square(x, t0);
+
+ // 3 | 408
+ SquareN(t0, 1, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t1, 1, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 136
+ SquareN(t0, 3, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 68
+ SquareN(t0, 6, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 34
+ SquareN(t0, 12, t1);
+ Multiply(t0, t1, t2);
+
+ // ! {2,3} | 17
+ SquareN(t2, 24, t0);
+ SquareN(t0, 24, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 8
+ SquareN(t0, 48, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 4
+ SquareN(t0, 96, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 2
+ SquareN(t0, 192, t1);
+ Multiply(t0, t1, t0);
+
+ Multiply(t0, t2, z);
+ }
+
+ public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+ {
+ ulong[] tt = Nat448.CreateExt64();
+ ImplMultiply(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] tt = Nat448.CreateExt64();
+ ImplMultiply(x, y, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void Reduce(ulong[] xx, ulong[] z)
+ {
+ ulong x00 = xx[0], x01 = xx[1], x02 = xx[2], x03 = xx[3];
+ ulong x04 = xx[4], x05 = xx[5], x06 = xx[6], x07 = xx[7];
+
+ ulong u = xx[12];
+ x05 ^= (u << 39);
+ x06 ^= (u >> 25) ^ (u << 62);
+ x07 ^= (u >> 2);
+
+ u = xx[11];
+ x04 ^= (u << 39);
+ x05 ^= (u >> 25) ^ (u << 62);
+ x06 ^= (u >> 2);
+
+ u = xx[10];
+ x03 ^= (u << 39);
+ x04 ^= (u >> 25) ^ (u << 62);
+ x05 ^= (u >> 2);
+
+ u = xx[9];
+ x02 ^= (u << 39);
+ x03 ^= (u >> 25) ^ (u << 62);
+ x04 ^= (u >> 2);
+
+ u = xx[8];
+ x01 ^= (u << 39);
+ x02 ^= (u >> 25) ^ (u << 62);
+ x03 ^= (u >> 2);
+
+ u = x07;
+ x00 ^= (u << 39);
+ x01 ^= (u >> 25) ^ (u << 62);
+ x02 ^= (u >> 2);
+
+ ulong t = x06 >> 25;
+ z[0] = x00 ^ t;
+ z[1] = x01 ^ (t << 23);
+ z[2] = x02;
+ z[3] = x03;
+ z[4] = x04;
+ z[5] = x05;
+ z[6] = x06 & M25;
+ }
+
+ public static void Reduce39(ulong[] z, int zOff)
+ {
+ ulong z6 = z[zOff + 6], t = z6 >> 25;
+ z[zOff ] ^= t;
+ z[zOff + 1] ^= (t << 23);
+ z[zOff + 6] = z6 & M25;
+ }
+
+ public static void Sqrt(ulong[] x, ulong[] z)
+ {
+ ulong u0, u1;
+ u0 = Interleave.Unshuffle(x[0]); u1 = Interleave.Unshuffle(x[1]);
+ ulong e0 = (u0 & 0x00000000FFFFFFFFUL) | (u1 << 32);
+ ulong c0 = (u0 >> 32) | (u1 & 0xFFFFFFFF00000000UL);
+
+ u0 = Interleave.Unshuffle(x[2]); u1 = Interleave.Unshuffle(x[3]);
+ ulong e1 = (u0 & 0x00000000FFFFFFFFUL) | (u1 << 32);
+ ulong c1 = (u0 >> 32) | (u1 & 0xFFFFFFFF00000000UL);
+
+ u0 = Interleave.Unshuffle(x[4]); u1 = Interleave.Unshuffle(x[5]);
+ ulong e2 = (u0 & 0x00000000FFFFFFFFUL) | (u1 << 32);
+ ulong c2 = (u0 >> 32) | (u1 & 0xFFFFFFFF00000000UL);
+
+ u0 = Interleave.Unshuffle(x[6]);
+ ulong e3 = (u0 & 0x00000000FFFFFFFFUL);
+ ulong c3 = (u0 >> 32);
+
+ z[0] = e0 ^ (c0 << 44);
+ z[1] = e1 ^ (c1 << 44) ^ (c0 >> 20);
+ z[2] = e2 ^ (c2 << 44) ^ (c1 >> 20);
+ z[3] = e3 ^ (c3 << 44) ^ (c2 >> 20) ^ (c0 << 13);
+ z[4] = (c3 >> 20) ^ (c1 << 13) ^ (c0 >> 51);
+ z[5] = (c2 << 13) ^ (c1 >> 51);
+ z[6] = (c3 << 13) ^ (c2 >> 51);
+
+ Debug.Assert((c3 >> 51) == 0);
+ }
+
+ public static void Square(ulong[] x, ulong[] z)
+ {
+ ulong[] tt = Nat.Create64(13);
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareAddToExt(ulong[] x, ulong[] zz)
+ {
+ ulong[] tt = Nat.Create64(13);
+ ImplSquare(x, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void SquareN(ulong[] x, int n, ulong[] z)
+ {
+ Debug.Assert(n > 0);
+
+ ulong[] tt = Nat.Create64(13);
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ ImplSquare(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static uint Trace(ulong[] x)
+ {
+ // Non-zero-trace bits: 0
+ return (uint)(x[0]) & 1U;
+ }
+
+ protected static void ImplCompactExt(ulong[] zz)
+ {
+ ulong z00 = zz[ 0], z01 = zz[ 1], z02 = zz[ 2], z03 = zz[ 3], z04 = zz[ 4], z05 = zz[ 5], z06 = zz[ 6];
+ ulong z07 = zz[ 7], z08 = zz[ 8], z09 = zz[ 9], z10 = zz[10], z11 = zz[11], z12 = zz[12], z13 = zz[13];
+ zz[ 0] = z00 ^ (z01 << 59);
+ zz[ 1] = (z01 >> 5) ^ (z02 << 54);
+ zz[ 2] = (z02 >> 10) ^ (z03 << 49);
+ zz[ 3] = (z03 >> 15) ^ (z04 << 44);
+ zz[ 4] = (z04 >> 20) ^ (z05 << 39);
+ zz[ 5] = (z05 >> 25) ^ (z06 << 34);
+ zz[ 6] = (z06 >> 30) ^ (z07 << 29);
+ zz[ 7] = (z07 >> 35) ^ (z08 << 24);
+ zz[ 8] = (z08 >> 40) ^ (z09 << 19);
+ zz[ 9] = (z09 >> 45) ^ (z10 << 14);
+ zz[10] = (z10 >> 50) ^ (z11 << 9);
+ zz[11] = (z11 >> 55) ^ (z12 << 4)
+ ^ (z13 << 63);
+ zz[12] = (z12 >> 60)
+ ^ (z13 >> 1);
+ zz[13] = 0;
+ }
+
+ protected static void ImplExpand(ulong[] x, ulong[] z)
+ {
+ ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6];
+ z[0] = x0 & M59;
+ z[1] = ((x0 >> 59) ^ (x1 << 5)) & M59;
+ z[2] = ((x1 >> 54) ^ (x2 << 10)) & M59;
+ z[3] = ((x2 >> 49) ^ (x3 << 15)) & M59;
+ z[4] = ((x3 >> 44) ^ (x4 << 20)) & M59;
+ z[5] = ((x4 >> 39) ^ (x5 << 25)) & M59;
+ z[6] = ((x5 >> 34) ^ (x6 << 30));
+ }
+
+ protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] a = new ulong[7], b = new ulong[7];
+ ImplExpand(x, a);
+ ImplExpand(y, b);
+
+ for (int i = 0; i < 7; ++i)
+ {
+ ImplMulwAcc(a, b[i], zz, i);
+ }
+
+ ImplCompactExt(zz);
+ }
+
+ protected static void ImplMulwAcc(ulong[] xs, ulong y, ulong[] z, int zOff)
+ {
+ Debug.Assert(y >> 59 == 0);
+
+ ulong[] u = new ulong[8];
+ //u[0] = 0;
+ u[1] = y;
+ u[2] = u[1] << 1;
+ u[3] = u[2] ^ y;
+ u[4] = u[2] << 1;
+ u[5] = u[4] ^ y;
+ u[6] = u[3] << 1;
+ u[7] = u[6] ^ y;
+
+ for (int i = 0; i < 7; ++i)
+ {
+ ulong x = xs[i];
+
+ Debug.Assert(x >> 59 == 0);
+
+ uint j = (uint)x;
+ ulong g, h = 0, l = u[j & 7]
+ ^ (u[(j >> 3) & 7] << 3);
+ int k = 54;
+ do
+ {
+ j = (uint)(x >> k);
+ g = u[j & 7]
+ ^ u[(j >> 3) & 7] << 3;
+ l ^= (g << k);
+ h ^= (g >> -k);
+ }
+ while ((k -= 6) > 0);
+
+ Debug.Assert(h >> 53 == 0);
+
+ z[zOff + i ] ^= l & M59;
+ z[zOff + i + 1] ^= (l >> 59) ^ (h << 5);
+ }
+ }
+
+ protected static void ImplSquare(ulong[] x, ulong[] zz)
+ {
+ for (int i = 0; i < 6; ++i)
+ {
+ Interleave.Expand64To128(x[i], zz, i << 1);
+ }
+ zz[12] = Interleave.Expand32to64((uint)x[6]);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT409FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT409FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f954f46e79a66ba06b963d537d2dda5edbbc36f2
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT409FieldElement.cs
@@ -0,0 +1,216 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT409FieldElement
+ : ECFieldElement
+ {
+ protected ulong[] x;
+
+ public SecT409FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.BitLength > 409)
+ throw new ArgumentException("value invalid for SecT409FieldElement", "x");
+
+ this.x = SecT409Field.FromBigInteger(x);
+ }
+
+ public SecT409FieldElement()
+ {
+ this.x = Nat448.Create64();
+ }
+
+ protected internal SecT409FieldElement(ulong[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat448.IsOne64(x); }
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat448.IsZero64(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return (x[0] & 1UL) != 0UL;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat448.ToBigInteger64(x);
+ }
+
+ public override string FieldName
+ {
+ get { return "SecT409Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 409; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ ulong[] z = Nat448.Create64();
+ SecT409Field.Add(x, ((SecT409FieldElement)b).x, z);
+ return new SecT409FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ ulong[] z = Nat448.Create64();
+ SecT409Field.AddOne(x, z);
+ return new SecT409FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ // Addition and subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ ulong[] z = Nat448.Create64();
+ SecT409Field.Multiply(x, ((SecT409FieldElement)b).x, z);
+ return new SecT409FieldElement(z);
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return MultiplyPlusProduct(b, x, y);
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x, bx = ((SecT409FieldElement)b).x;
+ ulong[] xx = ((SecT409FieldElement)x).x, yx = ((SecT409FieldElement)y).x;
+
+ ulong[] tt = Nat.Create64(13);
+ SecT409Field.MultiplyAddToExt(ax, bx, tt);
+ SecT409Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat448.Create64();
+ SecT409Field.Reduce(tt, z);
+ return new SecT409FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ return Multiply(b.Invert());
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ ulong[] z = Nat448.Create64();
+ SecT409Field.Square(x, z);
+ return new SecT409FieldElement(z);
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return SquarePlusProduct(x, y);
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x;
+ ulong[] xx = ((SecT409FieldElement)x).x, yx = ((SecT409FieldElement)y).x;
+
+ ulong[] tt = Nat.Create64(13);
+ SecT409Field.SquareAddToExt(ax, tt);
+ SecT409Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat448.Create64();
+ SecT409Field.Reduce(tt, z);
+ return new SecT409FieldElement(z);
+ }
+
+ public override ECFieldElement SquarePow(int pow)
+ {
+ if (pow < 1)
+ return this;
+
+ ulong[] z = Nat448.Create64();
+ SecT409Field.SquareN(x, pow, z);
+ return new SecT409FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ ulong[] z = Nat448.Create64();
+ SecT409Field.Invert(x, z);
+ return new SecT409FieldElement(z);
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ ulong[] z = Nat448.Create64();
+ SecT409Field.Sqrt(x, z);
+ return new SecT409FieldElement(z);
+ }
+
+ public virtual int Representation
+ {
+ get { return F2mFieldElement.Tpb; }
+ }
+
+ public virtual int M
+ {
+ get { return 409; }
+ }
+
+ public virtual int K1
+ {
+ get { return 87; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecT409FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecT409FieldElement);
+ }
+
+ public virtual bool Equals(SecT409FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat448.Eq64(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return 4090087 ^ Arrays.GetHashCode(x, 0, 7);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT409K1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT409K1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4f573553ecc1bb2f205ea3c781fd6b7323de6e3b
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT409K1Curve.cs
@@ -0,0 +1,104 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT409K1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT409K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT409K1Point m_infinity;
+
+ public SecT409K1Curve()
+ : base(409, 87, 0, 0)
+ {
+ this.m_infinity = new SecT409K1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.Zero);
+ this.m_b = FromBigInteger(BigInteger.One);
+ this.m_order = new BigInteger(1, Hex.Decode("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF"));
+ this.m_cofactor = BigInteger.ValueOf(4);
+
+ this.m_coord = SecT409K1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT409K1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ protected override ECMultiplier CreateDefaultMultiplier()
+ {
+ return new WTauNafMultiplier();
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 409; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT409FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT409K1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT409K1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return true; }
+ }
+
+ public virtual int M
+ {
+ get { return 409; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return true; }
+ }
+
+ public virtual int K1
+ {
+ get { return 87; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT409K1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT409K1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e67ca9a72532f1897534f012255a5da927afd9cb
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT409K1Point.cs
@@ -0,0 +1,289 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT409K1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT409K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT409K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT409K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT409K1Point(null, this.AffineXCoord, this.AffineYCoord); // earlier JDK
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1);
+ if (X3.IsZero)
+ {
+ return new SecT409K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT409K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT409K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T;
+ if (Z1IsOne)
+ {
+ T = L1.Square().Add(L1);
+ }
+ else
+ {
+ T = L1.Add(Z1).Multiply(L1);
+ }
+
+ if (T.IsZero)
+ {
+ return new SecT409K1Point(curve, T, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement t1 = L1.Add(X1).Square();
+ ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.Square();
+ ECFieldElement L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3).Add(Z3);
+
+ return new SecT409K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ // NOTE: TwicePlus() only optimized for lambda-affine argument
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = L1Sq.Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = L2plus1.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT409K1Point(curve, A, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT409K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT409K1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT409R1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT409R1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9212fb5d218788f256f0d11952d0dedbcf642925
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT409R1Curve.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT409R1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT409R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT409R1Point m_infinity;
+
+ public SecT409R1Curve()
+ : base(409, 87, 0, 0)
+ {
+ this.m_infinity = new SecT409R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.One);
+ this.m_b = FromBigInteger(new BigInteger(1, Hex.Decode("0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F")));
+ this.m_order = new BigInteger(1, Hex.Decode("010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT409R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT409R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 409; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT409FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT409R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT409R1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 409; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return true; }
+ }
+
+ public virtual int K1
+ {
+ get { return 87; }
+ }
+
+ public virtual int K2
+ {
+ get { return 0; }
+ }
+
+ public virtual int K3
+ {
+ get { return 0; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT409R1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT409R1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..92f6143dc8ad1a11f39f51527317f48d82bbb400
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT409R1Point.cs
@@ -0,0 +1,278 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT409R1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT409R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT409R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT409R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT409R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).AddOne();
+ if (X3.IsZero)
+ {
+ return new SecT409R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT409R1Point(curve, X3, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT409R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(Z1Sq);
+ if (T.IsZero)
+ {
+ return new SecT409R1Point(curve, T, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT409R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = Z1Sq.Add(L1Sq).Add(L1Z1);
+ ECFieldElement A = L2.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT409R1Point(curve, A, curve.B.Sqrt(), IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2.AddOne(), Z3);
+
+ return new SecT409R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT409R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT571Field.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT571Field.cs
new file mode 100644
index 0000000000000000000000000000000000000000..98f4f7fc296be203b74f47e14a2802b725cbf615
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT571Field.cs
@@ -0,0 +1,333 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT571Field
+ {
+ private const ulong M59 = ulong.MaxValue >> 5;
+
+ private const ulong RM = 0xEF7BDEF7BDEF7BDEUL;
+
+ private static readonly ulong[] ROOT_Z = new ulong[]{ 0x2BE1195F08CAFB99UL, 0x95F08CAF84657C23UL, 0xCAF84657C232BE11UL, 0x657C232BE1195F08UL,
+ 0xF84657C2308CAF84UL, 0x7C232BE1195F08CAUL, 0xBE1195F08CAF8465UL, 0x5F08CAF84657C232UL, 0x784657C232BE119UL };
+
+ public static void Add(ulong[] x, ulong[] y, ulong[] z)
+ {
+ for (int i = 0; i < 9; ++i)
+ {
+ z[i] = x[i] ^ y[i];
+ }
+ }
+
+ private static void Add(ulong[] x, int xOff, ulong[] y, int yOff, ulong[] z, int zOff)
+ {
+ for (int i = 0; i < 9; ++i)
+ {
+ z[zOff + i] = x[xOff + i] ^ y[yOff + i];
+ }
+ }
+
+ private static void AddBothTo(ulong[] x, int xOff, ulong[] y, int yOff, ulong[] z, int zOff)
+ {
+ for (int i = 0; i < 9; ++i)
+ {
+ z[zOff + i] ^= x[xOff + i] ^ y[yOff + i];
+ }
+ }
+
+ public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
+ {
+ for (int i = 0; i < 18; ++i)
+ {
+ zz[i] = xx[i] ^ yy[i];
+ }
+ }
+
+ public static void AddOne(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0] ^ 1UL;
+ for (int i = 1; i < 9; ++i)
+ {
+ z[i] = x[i];
+ }
+ }
+
+ public static ulong[] FromBigInteger(BigInteger x)
+ {
+ ulong[] z = Nat576.FromBigInteger64(x);
+ Reduce5(z, 0);
+ return z;
+ }
+
+ public static void Invert(ulong[] x, ulong[] z)
+ {
+ if (Nat576.IsZero64(x))
+ throw new InvalidOperationException();
+
+ // Itoh-Tsujii inversion with bases { 2, 3, 5 }
+
+ ulong[] t0 = Nat576.Create64();
+ ulong[] t1 = Nat576.Create64();
+ ulong[] t2 = Nat576.Create64();
+
+ Square(x, t2);
+
+ // 5 | 570
+ Square(t2, t0);
+ Square(t0, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t0, 2, t1);
+ Multiply(t0, t1, t0);
+ Multiply(t0, t2, t0);
+
+ // 3 | 114
+ SquareN(t0, 5, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t1, 5, t1);
+ Multiply(t0, t1, t0);
+
+ // 2 | 38
+ SquareN(t0, 15, t1);
+ Multiply(t0, t1, t2);
+
+ // ! {2,3,5} | 19
+ SquareN(t2, 30, t0);
+ SquareN(t0, 30, t1);
+ Multiply(t0, t1, t0);
+
+ // 3 | 9
+ SquareN(t0, 60, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t1, 60, t1);
+ Multiply(t0, t1, t0);
+
+ // 3 | 3
+ SquareN(t0, 180, t1);
+ Multiply(t0, t1, t0);
+ SquareN(t1, 180, t1);
+ Multiply(t0, t1, t0);
+
+ Multiply(t0, t2, z);
+ }
+
+ public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
+ {
+ ulong[] tt = Nat576.CreateExt64();
+ ImplMultiply(x, y, tt);
+ Reduce(tt, z);
+ }
+
+ public static void MultiplyAddToExt(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ ulong[] tt = Nat576.CreateExt64();
+ ImplMultiply(x, y, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void Reduce(ulong[] xx, ulong[] z)
+ {
+ ulong xx09 = xx[9];
+ ulong u = xx[17], v = xx09;
+
+ xx09 = v ^ (u >> 59) ^ (u >> 57) ^ (u >> 54) ^ (u >> 49);
+ v = xx[8] ^ (u << 5) ^ (u << 7) ^ (u << 10) ^ (u << 15);
+
+ for (int i = 16; i >= 10; --i)
+ {
+ u = xx[i];
+ z[i - 8] = v ^ (u >> 59) ^ (u >> 57) ^ (u >> 54) ^ (u >> 49);
+ v = xx[i - 9] ^ (u << 5) ^ (u << 7) ^ (u << 10) ^ (u << 15);
+ }
+
+ u = xx09;
+ z[1] = v ^ (u >> 59) ^ (u >> 57) ^ (u >> 54) ^ (u >> 49);
+ v = xx[0] ^ (u << 5) ^ (u << 7) ^ (u << 10) ^ (u << 15);
+
+ ulong x08 = z[8];
+ ulong t = x08 >> 59;
+ z[0] = v ^ t ^ (t << 2) ^ (t << 5) ^ (t << 10);
+ z[8] = x08 & M59;
+ }
+
+ public static void Reduce5(ulong[] z, int zOff)
+ {
+ ulong z8 = z[zOff + 8], t = z8 >> 59;
+ z[zOff ] ^= t ^ (t << 2) ^ (t << 5) ^ (t << 10);
+ z[zOff + 8] = z8 & M59;
+ }
+
+ public static void Sqrt(ulong[] x, ulong[] z)
+ {
+ ulong[] evn = Nat576.Create64(), odd = Nat576.Create64();
+
+ int pos = 0;
+ for (int i = 0; i < 4; ++i)
+ {
+ ulong u0 = Interleave.Unshuffle(x[pos++]);
+ ulong u1 = Interleave.Unshuffle(x[pos++]);
+ evn[i] = (u0 & 0x00000000FFFFFFFFUL) | (u1 << 32);
+ odd[i] = (u0 >> 32) | (u1 & 0xFFFFFFFF00000000UL);
+ }
+ {
+ ulong u0 = Interleave.Unshuffle(x[pos]);
+ evn[4] = (u0 & 0x00000000FFFFFFFFUL);
+ odd[4] = (u0 >> 32);
+ }
+
+ Multiply(odd, ROOT_Z, z);
+ Add(z, evn, z);
+ }
+
+ public static void Square(ulong[] x, ulong[] z)
+ {
+ ulong[] tt = Nat576.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+ }
+
+ public static void SquareAddToExt(ulong[] x, ulong[] zz)
+ {
+ ulong[] tt = Nat576.CreateExt64();
+ ImplSquare(x, tt);
+ AddExt(zz, tt, zz);
+ }
+
+ public static void SquareN(ulong[] x, int n, ulong[] z)
+ {
+ Debug.Assert(n > 0);
+
+ ulong[] tt = Nat576.CreateExt64();
+ ImplSquare(x, tt);
+ Reduce(tt, z);
+
+ while (--n > 0)
+ {
+ ImplSquare(z, tt);
+ Reduce(tt, z);
+ }
+ }
+
+ public static uint Trace(ulong[] x)
+ {
+ // Non-zero-trace bits: 0, 561, 569
+ return (uint)(x[0] ^ (x[8] >> 49) ^ (x[8] >> 57)) & 1U;
+ }
+
+ protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
+ {
+ //for (int i = 0; i < 9; ++i)
+ //{
+ // ImplMulwAcc(x, y[i], zz, i);
+ //}
+
+ /*
+ * Precompute table of all 4-bit products of y
+ */
+ ulong[] T0 = new ulong[9 << 4];
+ Array.Copy(y, 0, T0, 9, 9);
+ // Reduce5(T0, 9);
+ int tOff = 0;
+ for (int i = 7; i > 0; --i)
+ {
+ tOff += 18;
+ Nat.ShiftUpBit64(9, T0, tOff >> 1, 0UL, T0, tOff);
+ Reduce5(T0, tOff);
+ Add(T0, 9, T0, tOff, T0, tOff + 9);
+ }
+
+ /*
+ * Second table with all 4-bit products of B shifted 4 bits
+ */
+ ulong[] T1 = new ulong[T0.Length];
+ Nat.ShiftUpBits64(T0.Length, T0, 0, 4, 0L, T1, 0);
+
+ uint MASK = 0xF;
+
+ /*
+ * Lopez-Dahab algorithm
+ */
+
+ for (int k = 56; k >= 0; k -= 8)
+ {
+ for (int j = 1; j < 9; j += 2)
+ {
+ uint aVal = (uint)(x[j] >> k);
+ uint u = aVal & MASK;
+ uint v = (aVal >> 4) & MASK;
+ AddBothTo(T0, (int)(9 * u), T1, (int)(9 * v), zz, j - 1);
+ }
+ Nat.ShiftUpBits64(16, zz, 0, 8, 0L);
+ }
+
+ for (int k = 56; k >= 0; k -= 8)
+ {
+ for (int j = 0; j < 9; j += 2)
+ {
+ uint aVal = (uint)(x[j] >> k);
+ uint u = aVal & MASK;
+ uint v = (aVal >> 4) & MASK;
+ AddBothTo(T0, (int)(9 * u), T1, (int)(9 * v), zz, j);
+ }
+ if (k > 0)
+ {
+ Nat.ShiftUpBits64(18, zz, 0, 8, 0L);
+ }
+ }
+ }
+
+ protected static void ImplMulwAcc(ulong[] xs, ulong y, ulong[] z, int zOff)
+ {
+ ulong[] u = new ulong[32];
+ //u[0] = 0;
+ u[1] = y;
+ for (int i = 2; i < 32; i += 2)
+ {
+ u[i ] = u[i >> 1] << 1;
+ u[i + 1] = u[i ] ^ y;
+ }
+
+ ulong l = 0;
+ for (int i = 0; i < 9; ++i)
+ {
+ ulong x = xs[i];
+
+ uint j = (uint)x;
+
+ l ^= u[j & 31];
+
+ ulong g, h = 0;
+ int k = 60;
+ do
+ {
+ j = (uint)(x >> k);
+ g = u[j & 31];
+ l ^= (g << k);
+ h ^= (g >> -k);
+ }
+ while ((k -= 5) > 0);
+
+ for (int p = 0; p < 4; ++p)
+ {
+ x = (x & RM) >> 1;
+ h ^= x & (ulong)(((long)y << p) >> 63);
+ }
+
+ z[zOff + i] ^= l;
+
+ l = h;
+ }
+ z[zOff + 9] ^= l;
+ }
+
+ protected static void ImplSquare(ulong[] x, ulong[] zz)
+ {
+ for (int i = 0; i < 9; ++i)
+ {
+ Interleave.Expand64To128(x[i], zz, i << 1);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT571FieldElement.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT571FieldElement.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c43b8dc3aba9ac68faebfb8634d90990d2cdcc0c
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT571FieldElement.cs
@@ -0,0 +1,216 @@
+using System;
+
+using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT571FieldElement
+ : ECFieldElement
+ {
+ protected readonly ulong[] x;
+
+ public SecT571FieldElement(BigInteger x)
+ {
+ if (x == null || x.SignValue < 0 || x.BitLength > 571)
+ throw new ArgumentException("value invalid for SecT571FieldElement", "x");
+
+ this.x = SecT571Field.FromBigInteger(x);
+ }
+
+ public SecT571FieldElement()
+ {
+ this.x = Nat576.Create64();
+ }
+
+ protected internal SecT571FieldElement(ulong[] x)
+ {
+ this.x = x;
+ }
+
+ public override bool IsOne
+ {
+ get { return Nat576.IsOne64(x); }
+ }
+
+ public override bool IsZero
+ {
+ get { return Nat576.IsZero64(x); }
+ }
+
+ public override bool TestBitZero()
+ {
+ return (x[0] & 1UL) != 0UL;
+ }
+
+ public override BigInteger ToBigInteger()
+ {
+ return Nat576.ToBigInteger64(x);
+ }
+
+ public override String FieldName
+ {
+ get { return "SecT571Field"; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 571; }
+ }
+
+ public override ECFieldElement Add(ECFieldElement b)
+ {
+ ulong[] z = Nat576.Create64();
+ SecT571Field.Add(x, ((SecT571FieldElement)b).x, z);
+ return new SecT571FieldElement(z);
+ }
+
+ public override ECFieldElement AddOne()
+ {
+ ulong[] z = Nat576.Create64();
+ SecT571Field.AddOne(x, z);
+ return new SecT571FieldElement(z);
+ }
+
+ public override ECFieldElement Subtract(ECFieldElement b)
+ {
+ // Addition and subtraction are the same in F2m
+ return Add(b);
+ }
+
+ public override ECFieldElement Multiply(ECFieldElement b)
+ {
+ ulong[] z = Nat576.Create64();
+ SecT571Field.Multiply(x, ((SecT571FieldElement)b).x, z);
+ return new SecT571FieldElement(z);
+ }
+
+ public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ return MultiplyPlusProduct(b, x, y);
+ }
+
+ public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x, bx = ((SecT571FieldElement)b).x;
+ ulong[] xx = ((SecT571FieldElement)x).x, yx = ((SecT571FieldElement)y).x;
+
+ ulong[] tt = Nat576.CreateExt64();
+ SecT571Field.MultiplyAddToExt(ax, bx, tt);
+ SecT571Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat576.Create64();
+ SecT571Field.Reduce(tt, z);
+ return new SecT571FieldElement(z);
+ }
+
+ public override ECFieldElement Divide(ECFieldElement b)
+ {
+ return Multiply(b.Invert());
+ }
+
+ public override ECFieldElement Negate()
+ {
+ return this;
+ }
+
+ public override ECFieldElement Square()
+ {
+ ulong[] z = Nat576.Create64();
+ SecT571Field.Square(x, z);
+ return new SecT571FieldElement(z);
+ }
+
+ public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ return SquarePlusProduct(x, y);
+ }
+
+ public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+ {
+ ulong[] ax = this.x;
+ ulong[] xx = ((SecT571FieldElement)x).x, yx = ((SecT571FieldElement)y).x;
+
+ ulong[] tt = Nat576.CreateExt64();
+ SecT571Field.SquareAddToExt(ax, tt);
+ SecT571Field.MultiplyAddToExt(xx, yx, tt);
+
+ ulong[] z = Nat576.Create64();
+ SecT571Field.Reduce(tt, z);
+ return new SecT571FieldElement(z);
+ }
+
+ public override ECFieldElement SquarePow(int pow)
+ {
+ if (pow < 1)
+ return this;
+
+ ulong[] z = Nat576.Create64();
+ SecT571Field.SquareN(x, pow, z);
+ return new SecT571FieldElement(z);
+ }
+
+ public override ECFieldElement Invert()
+ {
+ ulong[] z = Nat576.Create64();
+ SecT571Field.Invert(x, z);
+ return new SecT571FieldElement(z);
+ }
+
+ public override ECFieldElement Sqrt()
+ {
+ ulong[] z = Nat576.Create64();
+ SecT571Field.Sqrt(x, z);
+ return new SecT571FieldElement(z);
+ }
+
+ public virtual int Representation
+ {
+ get { return F2mFieldElement.Ppb; }
+ }
+
+ public virtual int M
+ {
+ get { return 571; }
+ }
+
+ public virtual int K1
+ {
+ get { return 2; }
+ }
+
+ public virtual int K2
+ {
+ get { return 5; }
+ }
+
+ public virtual int K3
+ {
+ get { return 10; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as SecT571FieldElement);
+ }
+
+ public override bool Equals(ECFieldElement other)
+ {
+ return Equals(other as SecT571FieldElement);
+ }
+
+ public virtual bool Equals(SecT571FieldElement other)
+ {
+ if (this == other)
+ return true;
+ if (null == other)
+ return false;
+ return Nat576.Eq64(x, other.x);
+ }
+
+ public override int GetHashCode()
+ {
+ return 5711052 ^ Arrays.GetHashCode(x, 0, 9);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT571K1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT571K1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f5806f09c269e5551e46b4dd4e3168e440ebbcd6
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT571K1Curve.cs
@@ -0,0 +1,104 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT571K1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT571K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT571K1Point m_infinity;
+
+ public SecT571K1Curve()
+ : base(571, 2, 5, 10)
+ {
+ this.m_infinity = new SecT571K1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.Zero);
+ this.m_b = FromBigInteger(BigInteger.One);
+ this.m_order = new BigInteger(1, Hex.Decode("020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001"));
+ this.m_cofactor = BigInteger.ValueOf(4);
+
+ this.m_coord = SecT571K1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT571K1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ protected override ECMultiplier CreateDefaultMultiplier()
+ {
+ return new WTauNafMultiplier();
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 571; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT571FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT571K1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT571K1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return true; }
+ }
+
+ public virtual int M
+ {
+ get { return 571; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return false; }
+ }
+
+ public virtual int K1
+ {
+ get { return 2; }
+ }
+
+ public virtual int K2
+ {
+ get { return 5; }
+ }
+
+ public virtual int K3
+ {
+ get { return 10; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT571K1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT571K1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..deaaf0c74f72ff348b0e0b0d9105c01ef70d8107
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT571K1Point.cs
@@ -0,0 +1,289 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT571K1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT571K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT571K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT571K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT571K1Point(null, this.AffineXCoord, this.AffineYCoord); // earlier JDK
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1);
+ if (X3.IsZero)
+ {
+ return new SecT571K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT571K1Point(curve, X3, curve.B, IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT571K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T;
+ if (Z1IsOne)
+ {
+ T = L1.Square().Add(L1);
+ }
+ else
+ {
+ T = L1.Add(Z1).Multiply(L1);
+ }
+
+ if (T.IsZero)
+ {
+ return new SecT571K1Point(curve, T, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement t1 = L1.Add(X1).Square();
+ ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.Square();
+ ECFieldElement L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3).Add(Z3);
+
+ return new SecT571K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ // NOTE: TwicePlus() only optimized for lambda-affine argument
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = L1Sq.Add(L1Z1);
+ ECFieldElement L2plus1 = L2.AddOne();
+ ECFieldElement A = L2plus1.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT571K1Point(curve, A, curve.B, IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+ return new SecT571K1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT571K1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT571R1Curve.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT571R1Curve.cs
new file mode 100644
index 0000000000000000000000000000000000000000..082afa5bd36831359f6dbb367b9547438bafd42e
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT571R1Curve.cs
@@ -0,0 +1,102 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT571R1Curve
+ : AbstractF2mCurve
+ {
+ private const int SecT571R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
+ protected readonly SecT571R1Point m_infinity;
+
+ internal static readonly SecT571FieldElement SecT571R1_B = new SecT571FieldElement(
+ new BigInteger(1, Hex.Decode("02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A")));
+ internal static readonly SecT571FieldElement SecT571R1_B_SQRT = (SecT571FieldElement)SecT571R1_B.Sqrt();
+
+ public SecT571R1Curve()
+ : base(571, 2, 5, 10)
+ {
+ this.m_infinity = new SecT571R1Point(this, null, null);
+
+ this.m_a = FromBigInteger(BigInteger.One);
+ this.m_b = SecT571R1_B;
+ this.m_order = new BigInteger(1, Hex.Decode("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47"));
+ this.m_cofactor = BigInteger.Two;
+
+ this.m_coord = SecT571R1_DEFAULT_COORDS;
+ }
+
+ protected override ECCurve CloneCurve()
+ {
+ return new SecT571R1Curve();
+ }
+
+ public override bool SupportsCoordinateSystem(int coord)
+ {
+ switch (coord)
+ {
+ case COORD_LAMBDA_PROJECTIVE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public override ECPoint Infinity
+ {
+ get { return m_infinity; }
+ }
+
+ public override int FieldSize
+ {
+ get { return 571; }
+ }
+
+ public override ECFieldElement FromBigInteger(BigInteger x)
+ {
+ return new SecT571FieldElement(x);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+ {
+ return new SecT571R1Point(this, x, y, withCompression);
+ }
+
+ protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ {
+ return new SecT571R1Point(this, x, y, zs, withCompression);
+ }
+
+ public override bool IsKoblitz
+ {
+ get { return false; }
+ }
+
+ public virtual int M
+ {
+ get { return 571; }
+ }
+
+ public virtual bool IsTrinomial
+ {
+ get { return false; }
+ }
+
+ public virtual int K1
+ {
+ get { return 2; }
+ }
+
+ public virtual int K2
+ {
+ get { return 5; }
+ }
+
+ public virtual int K3
+ {
+ get { return 10; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/custom/sec/SecT571R1Point.cs b/bc-sharp-crypto/src/math/ec/custom/sec/SecT571R1Point.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0d1fc98b6ffab21ccc41a8f2f47b260439c36f5b
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/custom/sec/SecT571R1Point.cs
@@ -0,0 +1,278 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+ internal class SecT571R1Point
+ : AbstractF2mPoint
+ {
+ /**
+ * @deprecated Use ECCurve.createPoint to construct points
+ */
+ public SecT571R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ : this(curve, x, y, false)
+ {
+ }
+
+ /**
+ * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+ */
+ public SecT571R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+ : base(curve, x, y, withCompression)
+ {
+ if ((x == null) != (y == null))
+ throw new ArgumentException("Exactly one of the field elements is null");
+ }
+
+ internal SecT571R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+ : base(curve, x, y, zs, withCompression)
+ {
+ }
+
+ protected override ECPoint Detach()
+ {
+ return new SecT571R1Point(null, AffineXCoord, AffineYCoord);
+ }
+
+ public override ECFieldElement YCoord
+ {
+ get
+ {
+ ECFieldElement X = RawXCoord, L = RawYCoord;
+
+ if (this.IsInfinity || X.IsZero)
+ return L;
+
+ // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+ ECFieldElement Y = L.Add(X).Multiply(X);
+
+ ECFieldElement Z = RawZCoords[0];
+ if (!Z.IsOne)
+ {
+ Y = Y.Divide(Z);
+ }
+
+ return Y;
+ }
+ }
+
+ protected internal override bool CompressionYTilde
+ {
+ get
+ {
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return false;
+
+ ECFieldElement Y = this.RawYCoord;
+
+ // Y is actually Lambda (X + Y/X) here
+ return Y.TestBitZero() != X.TestBitZero();
+ }
+ }
+
+ public override ECPoint Add(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ ECFieldElement X2 = b.RawXCoord;
+
+ if (X1.IsZero)
+ {
+ if (X2.IsZero)
+ return curve.Infinity;
+
+ return b.Add(this);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement U2 = X2, S2 = L2;
+ if (!Z1IsOne)
+ {
+ U2 = U2.Multiply(Z1);
+ S2 = S2.Multiply(Z1);
+ }
+
+ bool Z2IsOne = Z2.IsOne;
+ ECFieldElement U1 = X1, S1 = L1;
+ if (!Z2IsOne)
+ {
+ U1 = U1.Multiply(Z2);
+ S1 = S1.Multiply(Z2);
+ }
+
+ ECFieldElement A = S1.Add(S2);
+ ECFieldElement B = U1.Add(U2);
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return Twice();
+
+ return curve.Infinity;
+ }
+
+ ECFieldElement X3, L3, Z3;
+ if (X2.IsZero)
+ {
+ // TODO This can probably be optimized quite a bit
+ ECPoint p = this.Normalize();
+ X1 = p.XCoord;
+ ECFieldElement Y1 = p.YCoord;
+
+ ECFieldElement Y2 = L2;
+ ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+ X3 = L.Square().Add(L).Add(X1).AddOne();
+ if (X3.IsZero)
+ {
+ return new SecT571R1Point(curve, X3, SecT571R1Curve.SecT571R1_B_SQRT, IsCompressed);
+ }
+
+ ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+ L3 = Y3.Divide(X3).Add(X3);
+ Z3 = curve.FromBigInteger(BigInteger.One);
+ }
+ else
+ {
+ B = B.Square();
+
+ ECFieldElement AU1 = A.Multiply(U1);
+ ECFieldElement AU2 = A.Multiply(U2);
+
+ X3 = AU1.Multiply(AU2);
+ if (X3.IsZero)
+ {
+ return new SecT571R1Point(curve, X3, SecT571R1Curve.SecT571R1_B_SQRT, IsCompressed);
+ }
+
+ ECFieldElement ABZ2 = A.Multiply(B);
+ if (!Z2IsOne)
+ {
+ ABZ2 = ABZ2.Multiply(Z2);
+ }
+
+ L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+ Z3 = ABZ2;
+ if (!Z1IsOne)
+ {
+ Z3 = Z3.Multiply(Z1);
+ }
+ }
+
+ return new SecT571R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Twice()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return curve.Infinity;
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+ bool Z1IsOne = Z1.IsOne;
+ ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+ ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+ ECFieldElement T = L1.Square().Add(L1Z1).Add(Z1Sq);
+ if (T.IsZero)
+ {
+ return new SecT571R1Point(curve, T, SecT571R1Curve.SecT571R1_B_SQRT, IsCompressed);
+ }
+
+ ECFieldElement X3 = T.Square();
+ ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+ ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+ ECFieldElement L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+
+ return new SecT571R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint TwicePlus(ECPoint b)
+ {
+ if (this.IsInfinity)
+ return b;
+ if (b.IsInfinity)
+ return Twice();
+
+ ECCurve curve = this.Curve;
+
+ ECFieldElement X1 = this.RawXCoord;
+ if (X1.IsZero)
+ {
+ // A point with X == 0 is it's own Additive inverse
+ return b;
+ }
+
+ ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+ if (X2.IsZero || !Z2.IsOne)
+ {
+ return Twice().Add(b);
+ }
+
+ ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+ ECFieldElement L2 = b.RawYCoord;
+
+ ECFieldElement X1Sq = X1.Square();
+ ECFieldElement L1Sq = L1.Square();
+ ECFieldElement Z1Sq = Z1.Square();
+ ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+ ECFieldElement T = Z1Sq.Add(L1Sq).Add(L1Z1);
+ ECFieldElement A = L2.Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+ ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+ ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+ if (B.IsZero)
+ {
+ if (A.IsZero)
+ return b.Twice();
+
+ return curve.Infinity;
+ }
+
+ if (A.IsZero)
+ {
+ return new SecT571R1Point(curve, A, SecT571R1Curve.SecT571R1_B_SQRT, IsCompressed);
+ }
+
+ ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+ ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+ ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2.AddOne(), Z3);
+
+ return new SecT571R1Point(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+ }
+
+ public override ECPoint Negate()
+ {
+ if (this.IsInfinity)
+ return this;
+
+ ECFieldElement X = this.RawXCoord;
+ if (X.IsZero)
+ return this;
+
+ // L is actually Lambda (X + Y/X) here
+ ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+ return new SecT571R1Point(Curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/endo/ECEndomorphism.cs b/bc-sharp-crypto/src/math/ec/endo/ECEndomorphism.cs
new file mode 100644
index 0000000000000000000000000000000000000000..dfb3213687e25e7dfd1b2f10c87e17672f5aef2b
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/endo/ECEndomorphism.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Endo
+{
+ public interface ECEndomorphism
+ {
+ ECPointMap PointMap { get; }
+
+ bool HasEfficientPointMap { get; }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/endo/GlvEndomorphism.cs b/bc-sharp-crypto/src/math/ec/endo/GlvEndomorphism.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f65bdd6134733b8f2448bb6b3e7591117d5c3005
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/endo/GlvEndomorphism.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Endo
+{
+ public interface GlvEndomorphism
+ : ECEndomorphism
+ {
+ BigInteger[] DecomposeScalar(BigInteger k);
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/endo/GlvTypeBEndomorphism.cs b/bc-sharp-crypto/src/math/ec/endo/GlvTypeBEndomorphism.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d234d88bfbbf012409313203618628f6dc3fd709
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/endo/GlvTypeBEndomorphism.cs
@@ -0,0 +1,55 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Endo
+{
+ public class GlvTypeBEndomorphism
+ : GlvEndomorphism
+ {
+ protected readonly ECCurve m_curve;
+ protected readonly GlvTypeBParameters m_parameters;
+ protected readonly ECPointMap m_pointMap;
+
+ public GlvTypeBEndomorphism(ECCurve curve, GlvTypeBParameters parameters)
+ {
+ this.m_curve = curve;
+ this.m_parameters = parameters;
+ this.m_pointMap = new ScaleXPointMap(curve.FromBigInteger(parameters.Beta));
+ }
+
+ public virtual BigInteger[] DecomposeScalar(BigInteger k)
+ {
+ int bits = m_parameters.Bits;
+ BigInteger b1 = CalculateB(k, m_parameters.G1, bits);
+ BigInteger b2 = CalculateB(k, m_parameters.G2, bits);
+
+ BigInteger[] v1 = m_parameters.V1, v2 = m_parameters.V2;
+ BigInteger a = k.Subtract((b1.Multiply(v1[0])).Add(b2.Multiply(v2[0])));
+ BigInteger b = (b1.Multiply(v1[1])).Add(b2.Multiply(v2[1])).Negate();
+
+ return new BigInteger[]{ a, b };
+ }
+
+ public virtual ECPointMap PointMap
+ {
+ get { return m_pointMap; }
+ }
+
+ public virtual bool HasEfficientPointMap
+ {
+ get { return true; }
+ }
+
+ protected virtual BigInteger CalculateB(BigInteger k, BigInteger g, int t)
+ {
+ bool negative = (g.SignValue < 0);
+ BigInteger b = k.Multiply(g.Abs());
+ bool extra = b.TestBit(t - 1);
+ b = b.ShiftRight(t);
+ if (extra)
+ {
+ b = b.Add(BigInteger.One);
+ }
+ return negative ? b.Negate() : b;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/endo/GlvTypeBParameters.cs b/bc-sharp-crypto/src/math/ec/endo/GlvTypeBParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f93dfaf2ba80c5f2b866e027fe5e17329eeb4372
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/endo/GlvTypeBParameters.cs
@@ -0,0 +1,60 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Endo
+{
+ public class GlvTypeBParameters
+ {
+ protected readonly BigInteger m_beta;
+ protected readonly BigInteger m_lambda;
+ protected readonly BigInteger[] m_v1, m_v2;
+ protected readonly BigInteger m_g1, m_g2;
+ protected readonly int m_bits;
+
+ public GlvTypeBParameters(BigInteger beta, BigInteger lambda, BigInteger[] v1, BigInteger[] v2,
+ BigInteger g1, BigInteger g2, int bits)
+ {
+ this.m_beta = beta;
+ this.m_lambda = lambda;
+ this.m_v1 = v1;
+ this.m_v2 = v2;
+ this.m_g1 = g1;
+ this.m_g2 = g2;
+ this.m_bits = bits;
+ }
+
+ public virtual BigInteger Beta
+ {
+ get { return m_beta; }
+ }
+
+ public virtual BigInteger Lambda
+ {
+ get { return m_lambda; }
+ }
+
+ public virtual BigInteger[] V1
+ {
+ get { return m_v1; }
+ }
+
+ public virtual BigInteger[] V2
+ {
+ get { return m_v2; }
+ }
+
+ public virtual BigInteger G1
+ {
+ get { return m_g1; }
+ }
+
+ public virtual BigInteger G2
+ {
+ get { return m_g2; }
+ }
+
+ public virtual int Bits
+ {
+ get { return m_bits; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/AbstractECMultiplier.cs b/bc-sharp-crypto/src/math/ec/multiplier/AbstractECMultiplier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..517881323806f4b5519915192fe889db47bc6d76
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/AbstractECMultiplier.cs
@@ -0,0 +1,24 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ public abstract class AbstractECMultiplier
+ : ECMultiplier
+ {
+ public virtual ECPoint Multiply(ECPoint p, BigInteger k)
+ {
+ int sign = k.SignValue;
+ if (sign == 0 || p.IsInfinity)
+ return p.Curve.Infinity;
+
+ ECPoint positive = MultiplyPositive(p, k.Abs());
+ ECPoint result = sign > 0 ? positive : positive.Negate();
+
+ /*
+ * Although the various multipliers ought not to produce invalid output under normal
+ * circumstances, a final check here is advised to guard against fault attacks.
+ */
+ return ECAlgorithms.ValidatePoint(result);
+ }
+
+ protected abstract ECPoint MultiplyPositive(ECPoint p, BigInteger k);
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/DoubleAddMultiplier.cs b/bc-sharp-crypto/src/math/ec/multiplier/DoubleAddMultiplier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..18a72c0a220b25e7dafcc94df3c1cf41042f0caa
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/DoubleAddMultiplier.cs
@@ -0,0 +1,24 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ public class DoubleAddMultiplier
+ : AbstractECMultiplier
+ {
+ /**
+ * Joye's double-add algorithm.
+ */
+ protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+ {
+ ECPoint[] R = new ECPoint[]{ p.Curve.Infinity, p };
+
+ int n = k.BitLength;
+ for (int i = 0; i < n; ++i)
+ {
+ int b = k.TestBit(i) ? 1 : 0;
+ int bp = 1 - b;
+ R[bp] = R[bp].TwicePlus(R[b]);
+ }
+
+ return R[0];
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/ECMultiplier.cs b/bc-sharp-crypto/src/math/ec/multiplier/ECMultiplier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8d6136b340ad86fc2830bd451706743d7da9c2d3
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/ECMultiplier.cs
@@ -0,0 +1,18 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ /**
+ * Interface for classes encapsulating a point multiplication algorithm
+ * for ECPoint
s.
+ */
+ public interface ECMultiplier
+ {
+ /**
+ * Multiplies the ECPoint p
by k
, i.e.
+ * p
is added k
times to itself.
+ * @param p The ECPoint
to be multiplied.
+ * @param k The factor by which p
is multiplied.
+ * @return p
multiplied by k
.
+ */
+ ECPoint Multiply(ECPoint p, BigInteger k);
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs b/bc-sharp-crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a8ef5a77a1cf826c2f4923a034bbeae0804b7210
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs
@@ -0,0 +1,59 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ public class FixedPointCombMultiplier
+ : AbstractECMultiplier
+ {
+ protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+ {
+ ECCurve c = p.Curve;
+ int size = FixedPointUtilities.GetCombSize(c);
+
+ if (k.BitLength > size)
+ {
+ /*
+ * TODO The comb works best when the scalars are less than the (possibly unknown) order.
+ * Still, if we want to handle larger scalars, we could allow customization of the comb
+ * size, or alternatively we could deal with the 'extra' bits either by running the comb
+ * multiple times as necessary, or by using an alternative multiplier as prelude.
+ */
+ throw new InvalidOperationException("fixed-point comb doesn't support scalars larger than the curve order");
+ }
+
+ int minWidth = GetWidthForCombSize(size);
+
+ FixedPointPreCompInfo info = FixedPointUtilities.Precompute(p, minWidth);
+ ECPoint[] lookupTable = info.PreComp;
+ int width = info.Width;
+
+ int d = (size + width - 1) / width;
+
+ ECPoint R = c.Infinity;
+
+ int top = d * width - 1;
+ for (int i = 0; i < d; ++i)
+ {
+ int index = 0;
+
+ for (int j = top - i; j >= 0; j -= d)
+ {
+ index <<= 1;
+ if (k.TestBit(j))
+ {
+ index |= 1;
+ }
+ }
+
+ R = R.TwicePlus(lookupTable[index]);
+ }
+
+ return R;
+ }
+
+ protected virtual int GetWidthForCombSize(int combSize)
+ {
+ return combSize > 257 ? 6 : 5;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs b/bc-sharp-crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..56a6326a19b826c7a592e59e82fa4c08ff493acb
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs
@@ -0,0 +1,34 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ /**
+ * Class holding precomputation data for fixed-point multiplications.
+ */
+ public class FixedPointPreCompInfo
+ : PreCompInfo
+ {
+ /**
+ * Array holding the precomputed ECPoint
s used for a fixed
+ * point multiplication.
+ */
+ protected ECPoint[] m_preComp = null;
+
+ /**
+ * The width used for the precomputation. If a larger width precomputation
+ * is already available this may be larger than was requested, so calling
+ * code should refer to the actual width.
+ */
+ protected int m_width = -1;
+
+ public virtual ECPoint[] PreComp
+ {
+ get { return m_preComp; }
+ set { this.m_preComp = value; }
+ }
+
+ public virtual int Width
+ {
+ get { return m_width; }
+ set { this.m_width = value; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/FixedPointUtilities.cs b/bc-sharp-crypto/src/math/ec/multiplier/FixedPointUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d927d010b251fe639fdfb11587138395dc1f0d38
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/FixedPointUtilities.cs
@@ -0,0 +1,72 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ public class FixedPointUtilities
+ {
+ public static readonly string PRECOMP_NAME = "bc_fixed_point";
+
+ public static int GetCombSize(ECCurve c)
+ {
+ BigInteger order = c.Order;
+ return order == null ? c.FieldSize + 1 : order.BitLength;
+ }
+
+ public static FixedPointPreCompInfo GetFixedPointPreCompInfo(PreCompInfo preCompInfo)
+ {
+ if ((preCompInfo != null) && (preCompInfo is FixedPointPreCompInfo))
+ {
+ return (FixedPointPreCompInfo)preCompInfo;
+ }
+
+ return new FixedPointPreCompInfo();
+ }
+
+ public static FixedPointPreCompInfo Precompute(ECPoint p, int minWidth)
+ {
+ ECCurve c = p.Curve;
+
+ int n = 1 << minWidth;
+ FixedPointPreCompInfo info = GetFixedPointPreCompInfo(c.GetPreCompInfo(p, PRECOMP_NAME));
+ ECPoint[] lookupTable = info.PreComp;
+
+ if (lookupTable == null || lookupTable.Length < n)
+ {
+ int bits = GetCombSize(c);
+ int d = (bits + minWidth - 1) / minWidth;
+
+ ECPoint[] pow2Table = new ECPoint[minWidth];
+ pow2Table[0] = p;
+ for (int i = 1; i < minWidth; ++i)
+ {
+ pow2Table[i] = pow2Table[i - 1].TimesPow2(d);
+ }
+
+ c.NormalizeAll(pow2Table);
+
+ lookupTable = new ECPoint[n];
+ lookupTable[0] = c.Infinity;
+
+ for (int bit = minWidth - 1; bit >= 0; --bit)
+ {
+ ECPoint pow2 = pow2Table[bit];
+
+ int step = 1 << bit;
+ for (int i = step; i < n; i += (step << 1))
+ {
+ lookupTable[i] = lookupTable[i - step].Add(pow2);
+ }
+ }
+
+ c.NormalizeAll(lookupTable);
+
+ info.PreComp = lookupTable;
+ info.Width = minWidth;
+
+ c.SetPreCompInfo(p, PRECOMP_NAME, info);
+ }
+
+ return info;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/GlvMultiplier.cs b/bc-sharp-crypto/src/math/ec/multiplier/GlvMultiplier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f19049474264046d8c52cdcd8153f1dfe52eda3d
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/GlvMultiplier.cs
@@ -0,0 +1,40 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Endo;
+
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ public class GlvMultiplier
+ : AbstractECMultiplier
+ {
+ protected readonly ECCurve curve;
+ protected readonly GlvEndomorphism glvEndomorphism;
+
+ public GlvMultiplier(ECCurve curve, GlvEndomorphism glvEndomorphism)
+ {
+ if (curve == null || curve.Order == null)
+ throw new ArgumentException("Need curve with known group order", "curve");
+
+ this.curve = curve;
+ this.glvEndomorphism = glvEndomorphism;
+ }
+
+ protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+ {
+ if (!curve.Equals(p.Curve))
+ throw new InvalidOperationException();
+
+ BigInteger n = p.Curve.Order;
+ BigInteger[] ab = glvEndomorphism.DecomposeScalar(k.Mod(n));
+ BigInteger a = ab[0], b = ab[1];
+
+ ECPointMap pointMap = glvEndomorphism.PointMap;
+ if (glvEndomorphism.HasEfficientPointMap)
+ {
+ return ECAlgorithms.ImplShamirsTrickWNaf(p, a, pointMap, b);
+ }
+
+ return ECAlgorithms.ImplShamirsTrickWNaf(p, a, pointMap.Map(p), b);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/MixedNafR2LMultiplier.cs b/bc-sharp-crypto/src/math/ec/multiplier/MixedNafR2LMultiplier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a4c201832c753a41c0bdbf53a6f1cb84a026488a
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/MixedNafR2LMultiplier.cs
@@ -0,0 +1,75 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ /**
+ * Class implementing the NAF (Non-Adjacent Form) multiplication algorithm (right-to-left) using
+ * mixed coordinates.
+ */
+ public class MixedNafR2LMultiplier
+ : AbstractECMultiplier
+ {
+ protected readonly int additionCoord, doublingCoord;
+
+ /**
+ * By default, addition will be done in Jacobian coordinates, and doubling will be done in
+ * Modified Jacobian coordinates (independent of the original coordinate system of each point).
+ */
+ public MixedNafR2LMultiplier()
+ : this(ECCurve.COORD_JACOBIAN, ECCurve.COORD_JACOBIAN_MODIFIED)
+ {
+ }
+
+ public MixedNafR2LMultiplier(int additionCoord, int doublingCoord)
+ {
+ this.additionCoord = additionCoord;
+ this.doublingCoord = doublingCoord;
+ }
+
+ protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+ {
+ ECCurve curveOrig = p.Curve;
+
+ ECCurve curveAdd = ConfigureCurve(curveOrig, additionCoord);
+ ECCurve curveDouble = ConfigureCurve(curveOrig, doublingCoord);
+
+ int[] naf = WNafUtilities.GenerateCompactNaf(k);
+
+ ECPoint Ra = curveAdd.Infinity;
+ ECPoint Td = curveDouble.ImportPoint(p);
+
+ int zeroes = 0;
+ for (int i = 0; i < naf.Length; ++i)
+ {
+ int ni = naf[i];
+ int digit = ni >> 16;
+ zeroes += ni & 0xFFFF;
+
+ Td = Td.TimesPow2(zeroes);
+
+ ECPoint Tj = curveAdd.ImportPoint(Td);
+ if (digit < 0)
+ {
+ Tj = Tj.Negate();
+ }
+
+ Ra = Ra.Add(Tj);
+
+ zeroes = 1;
+ }
+
+ return curveOrig.ImportPoint(Ra);
+ }
+
+ protected virtual ECCurve ConfigureCurve(ECCurve c, int coord)
+ {
+ if (c.CoordinateSystem == coord)
+ return c;
+
+ if (!c.SupportsCoordinateSystem(coord))
+ throw new ArgumentException("Coordinate system " + coord + " not supported by this curve", "coord");
+
+ return c.Configure().SetCoordinateSystem(coord).Create();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/MontgomeryLadderMultiplier.cs b/bc-sharp-crypto/src/math/ec/multiplier/MontgomeryLadderMultiplier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e2470a3837ca556050a446fa452a43ec06d73dd8
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/MontgomeryLadderMultiplier.cs
@@ -0,0 +1,25 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ public class MontgomeryLadderMultiplier
+ : AbstractECMultiplier
+ {
+ /**
+ * Montgomery ladder.
+ */
+ protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+ {
+ ECPoint[] R = new ECPoint[]{ p.Curve.Infinity, p };
+
+ int n = k.BitLength;
+ int i = n;
+ while (--i >= 0)
+ {
+ int b = k.TestBit(i) ? 1 : 0;
+ int bp = 1 - b;
+ R[bp] = R[bp].Add(R[b]);
+ R[b] = R[b].Twice();
+ }
+ return R[0];
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/NafL2RMultiplier.cs b/bc-sharp-crypto/src/math/ec/multiplier/NafL2RMultiplier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ac80cf905d2bd2aed77401ae63cc5e203d8df703
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/NafL2RMultiplier.cs
@@ -0,0 +1,30 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ /**
+ * Class implementing the NAF (Non-Adjacent Form) multiplication algorithm (left-to-right).
+ */
+ public class NafL2RMultiplier
+ : AbstractECMultiplier
+ {
+ protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+ {
+ int[] naf = WNafUtilities.GenerateCompactNaf(k);
+
+ ECPoint addP = p.Normalize(), subP = addP.Negate();
+
+ ECPoint R = p.Curve.Infinity;
+
+ int i = naf.Length;
+ while (--i >= 0)
+ {
+ int ni = naf[i];
+ int digit = ni >> 16, zeroes = ni & 0xFFFF;
+
+ R = R.TwicePlus(digit < 0 ? subP : addP);
+ R = R.TimesPow2(zeroes);
+ }
+
+ return R;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/NafR2LMultiplier.cs b/bc-sharp-crypto/src/math/ec/multiplier/NafR2LMultiplier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1fa69fae84d63487b0aaa4f64e4f422a0a7c77a5
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/NafR2LMultiplier.cs
@@ -0,0 +1,31 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ /**
+ * Class implementing the NAF (Non-Adjacent Form) multiplication algorithm (right-to-left).
+ */
+ public class NafR2LMultiplier
+ : AbstractECMultiplier
+ {
+ protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+ {
+ int[] naf = WNafUtilities.GenerateCompactNaf(k);
+
+ ECPoint R0 = p.Curve.Infinity, R1 = p;
+
+ int zeroes = 0;
+ for (int i = 0; i < naf.Length; ++i)
+ {
+ int ni = naf[i];
+ int digit = ni >> 16;
+ zeroes += ni & 0xFFFF;
+
+ R1 = R1.TimesPow2(zeroes);
+ R0 = R0.Add(digit < 0 ? R1.Negate() : R1);
+
+ zeroes = 1;
+ }
+
+ return R0;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/PreCompInfo.cs b/bc-sharp-crypto/src/math/ec/multiplier/PreCompInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5c3289286d8cccb33fa936a02885538771bc8f38
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/PreCompInfo.cs
@@ -0,0 +1,11 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ /**
+ * Interface for classes storing precomputation data for multiplication
+ * algorithms. Used as a Memento (see GOF patterns) for
+ * WNafMultiplier
.
+ */
+ public interface PreCompInfo
+ {
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/ReferenceMultiplier.cs b/bc-sharp-crypto/src/math/ec/multiplier/ReferenceMultiplier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4848ada394c2d07a37ef70f2c487b85716a382dd
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/ReferenceMultiplier.cs
@@ -0,0 +1,11 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ public class ReferenceMultiplier
+ : AbstractECMultiplier
+ {
+ protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+ {
+ return ECAlgorithms.ReferenceMultiply(p, k);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/WNafL2RMultiplier.cs b/bc-sharp-crypto/src/math/ec/multiplier/WNafL2RMultiplier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f671f6a5cebe5b3ad4e82ec2971ea0d57366a80a
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/WNafL2RMultiplier.cs
@@ -0,0 +1,98 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ /**
+ * Class implementing the WNAF (Window Non-Adjacent Form) multiplication
+ * algorithm.
+ */
+ public class WNafL2RMultiplier
+ : AbstractECMultiplier
+ {
+ /**
+ * Multiplies this
by an integer k
using the
+ * Window NAF method.
+ * @param k The integer by which this
is multiplied.
+ * @return A new ECPoint
which equals this
+ * multiplied by k
.
+ */
+ protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+ {
+ // Clamp the window width in the range [2, 16]
+ int width = System.Math.Max(2, System.Math.Min(16, GetWindowSize(k.BitLength)));
+
+ WNafPreCompInfo wnafPreCompInfo = WNafUtilities.Precompute(p, width, true);
+ ECPoint[] preComp = wnafPreCompInfo.PreComp;
+ ECPoint[] preCompNeg = wnafPreCompInfo.PreCompNeg;
+
+ int[] wnaf = WNafUtilities.GenerateCompactWindowNaf(width, k);
+
+ ECPoint R = p.Curve.Infinity;
+
+ int i = wnaf.Length;
+
+ /*
+ * NOTE: We try to optimize the first window using the precomputed points to substitute an
+ * addition for 2 or more doublings.
+ */
+ if (i > 1)
+ {
+ int wi = wnaf[--i];
+ int digit = wi >> 16, zeroes = wi & 0xFFFF;
+
+ int n = System.Math.Abs(digit);
+ ECPoint[] table = digit < 0 ? preCompNeg : preComp;
+
+ // Optimization can only be used for values in the lower half of the table
+ if ((n << 2) < (1 << width))
+ {
+ int highest = LongArray.BitLengths[n];
+
+ // TODO Get addition/doubling cost ratio from curve and compare to 'scale' to see if worth substituting?
+ int scale = width - highest;
+ int lowBits = n ^ (1 << (highest - 1));
+
+ int i1 = ((1 << (width - 1)) - 1);
+ int i2 = (lowBits << scale) + 1;
+ R = table[i1 >> 1].Add(table[i2 >> 1]);
+
+ zeroes -= scale;
+
+ //Console.WriteLine("Optimized: 2^" + scale + " * " + n + " = " + i1 + " + " + i2);
+ }
+ else
+ {
+ R = table[n >> 1];
+ }
+
+ R = R.TimesPow2(zeroes);
+ }
+
+ while (i > 0)
+ {
+ int wi = wnaf[--i];
+ int digit = wi >> 16, zeroes = wi & 0xFFFF;
+
+ int n = System.Math.Abs(digit);
+ ECPoint[] table = digit < 0 ? preCompNeg : preComp;
+ ECPoint r = table[n >> 1];
+
+ R = R.TwicePlus(r);
+ R = R.TimesPow2(zeroes);
+ }
+
+ return R;
+ }
+
+ /**
+ * Determine window width to use for a scalar multiplication of the given size.
+ *
+ * @param bits the bit-length of the scalar to multiply by
+ * @return the window size to use
+ */
+ protected virtual int GetWindowSize(int bits)
+ {
+ return WNafUtilities.GetWindowSize(bits);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/WNafPreCompInfo.cs b/bc-sharp-crypto/src/math/ec/multiplier/WNafPreCompInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7e0a73154e3f7122a56fe061f663b4e8af76e1fb
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/WNafPreCompInfo.cs
@@ -0,0 +1,46 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ /**
+ * Class holding precomputation data for the WNAF (Window Non-Adjacent Form)
+ * algorithm.
+ */
+ public class WNafPreCompInfo
+ : PreCompInfo
+ {
+ /**
+ * Array holding the precomputed ECPoint
s used for a Window
+ * NAF multiplication.
+ */
+ protected ECPoint[] m_preComp = null;
+
+ /**
+ * Array holding the negations of the precomputed ECPoint
s used
+ * for a Window NAF multiplication.
+ */
+ protected ECPoint[] m_preCompNeg = null;
+
+ /**
+ * Holds an ECPoint
representing Twice(this). Used for the
+ * Window NAF multiplication to create or extend the precomputed values.
+ */
+ protected ECPoint m_twice = null;
+
+ public virtual ECPoint[] PreComp
+ {
+ get { return m_preComp; }
+ set { this.m_preComp = value; }
+ }
+
+ public virtual ECPoint[] PreCompNeg
+ {
+ get { return m_preCompNeg; }
+ set { this.m_preCompNeg = value; }
+ }
+
+ public virtual ECPoint Twice
+ {
+ get { return m_twice; }
+ set { this.m_twice = value; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/WNafUtilities.cs b/bc-sharp-crypto/src/math/ec/multiplier/WNafUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7d565dfbd97206b383ab24ef3061a406b427e8ae
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/WNafUtilities.cs
@@ -0,0 +1,524 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ public abstract class WNafUtilities
+ {
+ public static readonly string PRECOMP_NAME = "bc_wnaf";
+
+ private static readonly int[] DEFAULT_WINDOW_SIZE_CUTOFFS = new int[]{ 13, 41, 121, 337, 897, 2305 };
+
+ private static readonly byte[] EMPTY_BYTES = new byte[0];
+ private static readonly int[] EMPTY_INTS = new int[0];
+ private static readonly ECPoint[] EMPTY_POINTS = new ECPoint[0];
+
+ public static int[] GenerateCompactNaf(BigInteger k)
+ {
+ if ((k.BitLength >> 16) != 0)
+ throw new ArgumentException("must have bitlength < 2^16", "k");
+ if (k.SignValue == 0)
+ return EMPTY_INTS;
+
+ BigInteger _3k = k.ShiftLeft(1).Add(k);
+
+ int bits = _3k.BitLength;
+ int[] naf = new int[bits >> 1];
+
+ BigInteger diff = _3k.Xor(k);
+
+ int highBit = bits - 1, length = 0, zeroes = 0;
+ for (int i = 1; i < highBit; ++i)
+ {
+ if (!diff.TestBit(i))
+ {
+ ++zeroes;
+ continue;
+ }
+
+ int digit = k.TestBit(i) ? -1 : 1;
+ naf[length++] = (digit << 16) | zeroes;
+ zeroes = 1;
+ ++i;
+ }
+
+ naf[length++] = (1 << 16) | zeroes;
+
+ if (naf.Length > length)
+ {
+ naf = Trim(naf, length);
+ }
+
+ return naf;
+ }
+
+ public static int[] GenerateCompactWindowNaf(int width, BigInteger k)
+ {
+ if (width == 2)
+ {
+ return GenerateCompactNaf(k);
+ }
+
+ if (width < 2 || width > 16)
+ throw new ArgumentException("must be in the range [2, 16]", "width");
+ if ((k.BitLength >> 16) != 0)
+ throw new ArgumentException("must have bitlength < 2^16", "k");
+ if (k.SignValue == 0)
+ return EMPTY_INTS;
+
+ int[] wnaf = new int[k.BitLength / width + 1];
+
+ // 2^width and a mask and sign bit set accordingly
+ int pow2 = 1 << width;
+ int mask = pow2 - 1;
+ int sign = pow2 >> 1;
+
+ bool carry = false;
+ int length = 0, pos = 0;
+
+ while (pos <= k.BitLength)
+ {
+ if (k.TestBit(pos) == carry)
+ {
+ ++pos;
+ continue;
+ }
+
+ k = k.ShiftRight(pos);
+
+ int digit = k.IntValue & mask;
+ if (carry)
+ {
+ ++digit;
+ }
+
+ carry = (digit & sign) != 0;
+ if (carry)
+ {
+ digit -= pow2;
+ }
+
+ int zeroes = length > 0 ? pos - 1 : pos;
+ wnaf[length++] = (digit << 16) | zeroes;
+ pos = width;
+ }
+
+ // Reduce the WNAF array to its actual length
+ if (wnaf.Length > length)
+ {
+ wnaf = Trim(wnaf, length);
+ }
+
+ return wnaf;
+ }
+
+ public static byte[] GenerateJsf(BigInteger g, BigInteger h)
+ {
+ int digits = System.Math.Max(g.BitLength, h.BitLength) + 1;
+ byte[] jsf = new byte[digits];
+
+ BigInteger k0 = g, k1 = h;
+ int j = 0, d0 = 0, d1 = 0;
+
+ int offset = 0;
+ while ((d0 | d1) != 0 || k0.BitLength > offset || k1.BitLength > offset)
+ {
+ int n0 = ((int)((uint)k0.IntValue >> offset) + d0) & 7;
+ int n1 = ((int)((uint)k1.IntValue >> offset) + d1) & 7;
+
+ int u0 = n0 & 1;
+ if (u0 != 0)
+ {
+ u0 -= (n0 & 2);
+ if ((n0 + u0) == 4 && (n1 & 3) == 2)
+ {
+ u0 = -u0;
+ }
+ }
+
+ int u1 = n1 & 1;
+ if (u1 != 0)
+ {
+ u1 -= (n1 & 2);
+ if ((n1 + u1) == 4 && (n0 & 3) == 2)
+ {
+ u1 = -u1;
+ }
+ }
+
+ if ((d0 << 1) == 1 + u0)
+ {
+ d0 ^= 1;
+ }
+ if ((d1 << 1) == 1 + u1)
+ {
+ d1 ^= 1;
+ }
+
+ if (++offset == 30)
+ {
+ offset = 0;
+ k0 = k0.ShiftRight(30);
+ k1 = k1.ShiftRight(30);
+ }
+
+ jsf[j++] = (byte)((u0 << 4) | (u1 & 0xF));
+ }
+
+ // Reduce the JSF array to its actual length
+ if (jsf.Length > j)
+ {
+ jsf = Trim(jsf, j);
+ }
+
+ return jsf;
+ }
+
+ public static byte[] GenerateNaf(BigInteger k)
+ {
+ if (k.SignValue == 0)
+ return EMPTY_BYTES;
+
+ BigInteger _3k = k.ShiftLeft(1).Add(k);
+
+ int digits = _3k.BitLength - 1;
+ byte[] naf = new byte[digits];
+
+ BigInteger diff = _3k.Xor(k);
+
+ for (int i = 1; i < digits; ++i)
+ {
+ if (diff.TestBit(i))
+ {
+ naf[i - 1] = (byte)(k.TestBit(i) ? -1 : 1);
+ ++i;
+ }
+ }
+
+ naf[digits - 1] = 1;
+
+ return naf;
+ }
+
+ /**
+ * Computes the Window NAF (non-adjacent Form) of an integer.
+ * @param width The width w
of the Window NAF. The width is
+ * defined as the minimal number w
, such that for any
+ * w
consecutive digits in the resulting representation, at
+ * most one is non-zero.
+ * @param k The integer of which the Window NAF is computed.
+ * @return The Window NAF of the given width, such that the following holds:
+ * k = ∑i=0 l-1 ki 2i
+ *
, where the ki
denote the elements of the
+ * returned byte[]
.
+ */
+ public static byte[] GenerateWindowNaf(int width, BigInteger k)
+ {
+ if (width == 2)
+ {
+ return GenerateNaf(k);
+ }
+
+ if (width < 2 || width > 8)
+ throw new ArgumentException("must be in the range [2, 8]", "width");
+ if (k.SignValue == 0)
+ return EMPTY_BYTES;
+
+ byte[] wnaf = new byte[k.BitLength + 1];
+
+ // 2^width and a mask and sign bit set accordingly
+ int pow2 = 1 << width;
+ int mask = pow2 - 1;
+ int sign = pow2 >> 1;
+
+ bool carry = false;
+ int length = 0, pos = 0;
+
+ while (pos <= k.BitLength)
+ {
+ if (k.TestBit(pos) == carry)
+ {
+ ++pos;
+ continue;
+ }
+
+ k = k.ShiftRight(pos);
+
+ int digit = k.IntValue & mask;
+ if (carry)
+ {
+ ++digit;
+ }
+
+ carry = (digit & sign) != 0;
+ if (carry)
+ {
+ digit -= pow2;
+ }
+
+ length += (length > 0) ? pos - 1 : pos;
+ wnaf[length++] = (byte)digit;
+ pos = width;
+ }
+
+ // Reduce the WNAF array to its actual length
+ if (wnaf.Length > length)
+ {
+ wnaf = Trim(wnaf, length);
+ }
+
+ return wnaf;
+ }
+
+ public static int GetNafWeight(BigInteger k)
+ {
+ if (k.SignValue == 0)
+ return 0;
+
+ BigInteger _3k = k.ShiftLeft(1).Add(k);
+ BigInteger diff = _3k.Xor(k);
+
+ return diff.BitCount;
+ }
+
+ public static WNafPreCompInfo GetWNafPreCompInfo(ECPoint p)
+ {
+ return GetWNafPreCompInfo(p.Curve.GetPreCompInfo(p, PRECOMP_NAME));
+ }
+
+ public static WNafPreCompInfo GetWNafPreCompInfo(PreCompInfo preCompInfo)
+ {
+ if ((preCompInfo != null) && (preCompInfo is WNafPreCompInfo))
+ {
+ return (WNafPreCompInfo)preCompInfo;
+ }
+
+ return new WNafPreCompInfo();
+ }
+
+ /**
+ * Determine window width to use for a scalar multiplication of the given size.
+ *
+ * @param bits the bit-length of the scalar to multiply by
+ * @return the window size to use
+ */
+ public static int GetWindowSize(int bits)
+ {
+ return GetWindowSize(bits, DEFAULT_WINDOW_SIZE_CUTOFFS);
+ }
+
+ /**
+ * Determine window width to use for a scalar multiplication of the given size.
+ *
+ * @param bits the bit-length of the scalar to multiply by
+ * @param windowSizeCutoffs a monotonically increasing list of bit sizes at which to increment the window width
+ * @return the window size to use
+ */
+ public static int GetWindowSize(int bits, int[] windowSizeCutoffs)
+ {
+ int w = 0;
+ for (; w < windowSizeCutoffs.Length; ++w)
+ {
+ if (bits < windowSizeCutoffs[w])
+ {
+ break;
+ }
+ }
+ return w + 2;
+ }
+
+ public static ECPoint MapPointWithPrecomp(ECPoint p, int width, bool includeNegated,
+ ECPointMap pointMap)
+ {
+ ECCurve c = p.Curve;
+ WNafPreCompInfo wnafPreCompP = Precompute(p, width, includeNegated);
+
+ ECPoint q = pointMap.Map(p);
+ WNafPreCompInfo wnafPreCompQ = GetWNafPreCompInfo(c.GetPreCompInfo(q, PRECOMP_NAME));
+
+ ECPoint twiceP = wnafPreCompP.Twice;
+ if (twiceP != null)
+ {
+ ECPoint twiceQ = pointMap.Map(twiceP);
+ wnafPreCompQ.Twice = twiceQ;
+ }
+
+ ECPoint[] preCompP = wnafPreCompP.PreComp;
+ ECPoint[] preCompQ = new ECPoint[preCompP.Length];
+ for (int i = 0; i < preCompP.Length; ++i)
+ {
+ preCompQ[i] = pointMap.Map(preCompP[i]);
+ }
+ wnafPreCompQ.PreComp = preCompQ;
+
+ if (includeNegated)
+ {
+ ECPoint[] preCompNegQ = new ECPoint[preCompQ.Length];
+ for (int i = 0; i < preCompNegQ.Length; ++i)
+ {
+ preCompNegQ[i] = preCompQ[i].Negate();
+ }
+ wnafPreCompQ.PreCompNeg = preCompNegQ;
+ }
+
+ c.SetPreCompInfo(q, PRECOMP_NAME, wnafPreCompQ);
+
+ return q;
+ }
+
+ public static WNafPreCompInfo Precompute(ECPoint p, int width, bool includeNegated)
+ {
+ ECCurve c = p.Curve;
+ WNafPreCompInfo wnafPreCompInfo = GetWNafPreCompInfo(c.GetPreCompInfo(p, PRECOMP_NAME));
+
+ int iniPreCompLen = 0, reqPreCompLen = 1 << System.Math.Max(0, width - 2);
+
+ ECPoint[] preComp = wnafPreCompInfo.PreComp;
+ if (preComp == null)
+ {
+ preComp = EMPTY_POINTS;
+ }
+ else
+ {
+ iniPreCompLen = preComp.Length;
+ }
+
+ if (iniPreCompLen < reqPreCompLen)
+ {
+ preComp = ResizeTable(preComp, reqPreCompLen);
+
+ if (reqPreCompLen == 1)
+ {
+ preComp[0] = p.Normalize();
+ }
+ else
+ {
+ int curPreCompLen = iniPreCompLen;
+ if (curPreCompLen == 0)
+ {
+ preComp[0] = p;
+ curPreCompLen = 1;
+ }
+
+ ECFieldElement iso = null;
+
+ if (reqPreCompLen == 2)
+ {
+ preComp[1] = p.ThreeTimes();
+ }
+ else
+ {
+ ECPoint twiceP = wnafPreCompInfo.Twice, last = preComp[curPreCompLen - 1];
+ if (twiceP == null)
+ {
+ twiceP = preComp[0].Twice();
+ wnafPreCompInfo.Twice = twiceP;
+
+ /*
+ * For Fp curves with Jacobian projective coordinates, use a (quasi-)isomorphism
+ * where 'twiceP' is "affine", so that the subsequent additions are cheaper. This
+ * also requires scaling the initial point's X, Y coordinates, and reversing the
+ * isomorphism as part of the subsequent normalization.
+ *
+ * NOTE: The correctness of this optimization depends on:
+ * 1) additions do not use the curve's A, B coefficients.
+ * 2) no special cases (i.e. Q +/- Q) when calculating 1P, 3P, 5P, ...
+ */
+ if (!twiceP.IsInfinity && ECAlgorithms.IsFpCurve(c) && c.FieldSize >= 64)
+ {
+ switch (c.CoordinateSystem)
+ {
+ case ECCurve.COORD_JACOBIAN:
+ case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+ case ECCurve.COORD_JACOBIAN_MODIFIED:
+ {
+ iso = twiceP.GetZCoord(0);
+ twiceP = c.CreatePoint(twiceP.XCoord.ToBigInteger(),
+ twiceP.YCoord.ToBigInteger());
+
+ ECFieldElement iso2 = iso.Square(), iso3 = iso2.Multiply(iso);
+ last = last.ScaleX(iso2).ScaleY(iso3);
+
+ if (iniPreCompLen == 0)
+ {
+ preComp[0] = last;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ while (curPreCompLen < reqPreCompLen)
+ {
+ /*
+ * Compute the new ECPoints for the precomputation array. The values 1, 3,
+ * 5, ..., 2^(width-1)-1 times p are computed
+ */
+ preComp[curPreCompLen++] = last = last.Add(twiceP);
+ }
+ }
+
+ /*
+ * Having oft-used operands in affine form makes operations faster.
+ */
+ c.NormalizeAll(preComp, iniPreCompLen, reqPreCompLen - iniPreCompLen, iso);
+ }
+ }
+
+ wnafPreCompInfo.PreComp = preComp;
+
+ if (includeNegated)
+ {
+ ECPoint[] preCompNeg = wnafPreCompInfo.PreCompNeg;
+
+ int pos;
+ if (preCompNeg == null)
+ {
+ pos = 0;
+ preCompNeg = new ECPoint[reqPreCompLen];
+ }
+ else
+ {
+ pos = preCompNeg.Length;
+ if (pos < reqPreCompLen)
+ {
+ preCompNeg = ResizeTable(preCompNeg, reqPreCompLen);
+ }
+ }
+
+ while (pos < reqPreCompLen)
+ {
+ preCompNeg[pos] = preComp[pos].Negate();
+ ++pos;
+ }
+
+ wnafPreCompInfo.PreCompNeg = preCompNeg;
+ }
+
+ c.SetPreCompInfo(p, PRECOMP_NAME, wnafPreCompInfo);
+
+ return wnafPreCompInfo;
+ }
+
+ private static byte[] Trim(byte[] a, int length)
+ {
+ byte[] result = new byte[length];
+ Array.Copy(a, 0, result, 0, result.Length);
+ return result;
+ }
+
+ private static int[] Trim(int[] a, int length)
+ {
+ int[] result = new int[length];
+ Array.Copy(a, 0, result, 0, result.Length);
+ return result;
+ }
+
+ private static ECPoint[] ResizeTable(ECPoint[] a, int length)
+ {
+ ECPoint[] result = new ECPoint[length];
+ Array.Copy(a, 0, result, 0, a.Length);
+ return result;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/WTauNafMultiplier.cs b/bc-sharp-crypto/src/math/ec/multiplier/WTauNafMultiplier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1e7ddae91e6328a5bc65537b0e976bdd882ef1ea
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/WTauNafMultiplier.cs
@@ -0,0 +1,125 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Abc;
+
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ /**
+ * Class implementing the WTNAF (Window
+ * τ
-adic Non-Adjacent Form) algorithm.
+ */
+ public class WTauNafMultiplier
+ : AbstractECMultiplier
+ {
+ // TODO Create WTauNafUtilities class and move various functionality into it
+ internal static readonly string PRECOMP_NAME = "bc_wtnaf";
+
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint}
+ * by k
using the reduced τ
-adic NAF (RTNAF)
+ * method.
+ * @param p The AbstractF2mPoint to multiply.
+ * @param k The integer by which to multiply k
.
+ * @return p
multiplied by k
.
+ */
+ protected override ECPoint MultiplyPositive(ECPoint point, BigInteger k)
+ {
+ if (!(point is AbstractF2mPoint))
+ throw new ArgumentException("Only AbstractF2mPoint can be used in WTauNafMultiplier");
+
+ AbstractF2mPoint p = (AbstractF2mPoint)point;
+ AbstractF2mCurve curve = (AbstractF2mCurve)p.Curve;
+ int m = curve.FieldSize;
+ sbyte a = (sbyte)curve.A.ToBigInteger().IntValue;
+ sbyte mu = Tnaf.GetMu(a);
+ BigInteger[] s = curve.GetSi();
+
+ ZTauElement rho = Tnaf.PartModReduction(k, m, a, s, mu, (sbyte)10);
+
+ return MultiplyWTnaf(p, rho, curve.GetPreCompInfo(p, PRECOMP_NAME), a, mu);
+ }
+
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint}
+ * by an element λ
of Z [τ]
using
+ * the τ
-adic NAF (TNAF) method.
+ * @param p The AbstractF2mPoint to multiply.
+ * @param lambda The element λ
of
+ * Z [τ]
of which to compute the
+ * [τ]
-adic NAF.
+ * @return p
multiplied by λ
.
+ */
+ private AbstractF2mPoint MultiplyWTnaf(AbstractF2mPoint p, ZTauElement lambda,
+ PreCompInfo preCompInfo, sbyte a, sbyte mu)
+ {
+ ZTauElement[] alpha = (a == 0) ? Tnaf.Alpha0 : Tnaf.Alpha1;
+
+ BigInteger tw = Tnaf.GetTw(mu, Tnaf.Width);
+
+ sbyte[]u = Tnaf.TauAdicWNaf(mu, lambda, Tnaf.Width,
+ BigInteger.ValueOf(Tnaf.Pow2Width), tw, alpha);
+
+ return MultiplyFromWTnaf(p, u, preCompInfo);
+ }
+
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint}
+ * by an element λ
of Z [τ]
+ * using the window τ
-adic NAF (TNAF) method, given the
+ * WTNAF of λ
.
+ * @param p The AbstractF2mPoint to multiply.
+ * @param u The the WTNAF of λ
..
+ * @return λ * p
+ */
+ private static AbstractF2mPoint MultiplyFromWTnaf(AbstractF2mPoint p, sbyte[] u, PreCompInfo preCompInfo)
+ {
+ AbstractF2mCurve curve = (AbstractF2mCurve)p.Curve;
+ sbyte a = (sbyte)curve.A.ToBigInteger().IntValue;
+
+ AbstractF2mPoint[] pu;
+ if ((preCompInfo == null) || !(preCompInfo is WTauNafPreCompInfo))
+ {
+ pu = Tnaf.GetPreComp(p, a);
+
+ WTauNafPreCompInfo pre = new WTauNafPreCompInfo();
+ pre.PreComp = pu;
+ curve.SetPreCompInfo(p, PRECOMP_NAME, pre);
+ }
+ else
+ {
+ pu = ((WTauNafPreCompInfo)preCompInfo).PreComp;
+ }
+
+ // TODO Include negations in precomp (optionally) and use from here
+ AbstractF2mPoint[] puNeg = new AbstractF2mPoint[pu.Length];
+ for (int i = 0; i < pu.Length; ++i)
+ {
+ puNeg[i] = (AbstractF2mPoint)pu[i].Negate();
+ }
+
+
+ // q = infinity
+ AbstractF2mPoint q = (AbstractF2mPoint) p.Curve.Infinity;
+
+ int tauCount = 0;
+ for (int i = u.Length - 1; i >= 0; i--)
+ {
+ ++tauCount;
+ int ui = u[i];
+ if (ui != 0)
+ {
+ q = q.TauPow(tauCount);
+ tauCount = 0;
+
+ ECPoint x = ui > 0 ? pu[ui >> 1] : puNeg[(-ui) >> 1];
+ q = (AbstractF2mPoint)q.Add(x);
+ }
+ }
+ if (tauCount > 0)
+ {
+ q = q.TauPow(tauCount);
+ }
+ return q;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs b/bc-sharp-crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..72659b3ec5d08c8e7011523d075e0bd4e667fe7d
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs
@@ -0,0 +1,24 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ /**
+ * Class holding precomputation data for the WTNAF (Window
+ * τ
-adic Non-Adjacent Form) algorithm.
+ */
+ public class WTauNafPreCompInfo
+ : PreCompInfo
+ {
+ /**
+ * Array holding the precomputed AbstractF2mPoint
s used for the
+ * WTNAF multiplication in
+ * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
+ * WTauNafMultiplier.multiply()}
.
+ */
+ protected AbstractF2mPoint[] m_preComp;
+
+ public virtual AbstractF2mPoint[] PreComp
+ {
+ get { return m_preComp; }
+ set { this.m_preComp = value; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/ZSignedDigitL2RMultiplier.cs b/bc-sharp-crypto/src/math/ec/multiplier/ZSignedDigitL2RMultiplier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..554ac61b3f8bd72405faef53d23d246a0ac395ea
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/ZSignedDigitL2RMultiplier.cs
@@ -0,0 +1,29 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ public class ZSignedDigitL2RMultiplier
+ : AbstractECMultiplier
+ {
+ /**
+ * 'Zeroless' Signed Digit Left-to-Right.
+ */
+ protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+ {
+ ECPoint addP = p.Normalize(), subP = addP.Negate();
+
+ ECPoint R0 = addP;
+
+ int n = k.BitLength;
+ int s = k.GetLowestSetBit();
+
+ int i = n;
+ while (--i > s)
+ {
+ R0 = R0.TwicePlus(k.TestBit(i) ? addP : subP);
+ }
+
+ R0 = R0.TimesPow2(s);
+
+ return R0;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/ec/multiplier/ZSignedDigitR2LMultiplier.cs b/bc-sharp-crypto/src/math/ec/multiplier/ZSignedDigitR2LMultiplier.cs
new file mode 100644
index 0000000000000000000000000000000000000000..91c06cbb8ddce80acaf81be77012820ac238cd02
--- /dev/null
+++ b/bc-sharp-crypto/src/math/ec/multiplier/ZSignedDigitR2LMultiplier.cs
@@ -0,0 +1,30 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+ public class ZSignedDigitR2LMultiplier
+ : AbstractECMultiplier
+ {
+ /**
+ * 'Zeroless' Signed Digit Right-to-Left.
+ */
+ protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+ {
+ ECPoint R0 = p.Curve.Infinity, R1 = p;
+
+ int n = k.BitLength;
+ int s = k.GetLowestSetBit();
+
+ R1 = R1.TimesPow2(s);
+
+ int i = s;
+ while (++i < n)
+ {
+ R0 = R0.Add(k.TestBit(i) ? R1 : R1.Negate());
+ R1 = R1.Twice();
+ }
+
+ R0 = R0.Add(R1);
+
+ return R0;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/field/FiniteFields.cs b/bc-sharp-crypto/src/math/field/FiniteFields.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7b84569fe46ed33aacb1c12e297b0e773ba56f5c
--- /dev/null
+++ b/bc-sharp-crypto/src/math/field/FiniteFields.cs
@@ -0,0 +1,54 @@
+using System;
+
+namespace Org.BouncyCastle.Math.Field
+{
+ public abstract class FiniteFields
+ {
+ internal static readonly IFiniteField GF_2 = new PrimeField(BigInteger.ValueOf(2));
+ internal static readonly IFiniteField GF_3 = new PrimeField(BigInteger.ValueOf(3));
+
+ public static IPolynomialExtensionField GetBinaryExtensionField(int[] exponents)
+ {
+ if (exponents[0] != 0)
+ {
+ throw new ArgumentException("Irreducible polynomials in GF(2) must have constant term", "exponents");
+ }
+ for (int i = 1; i < exponents.Length; ++i)
+ {
+ if (exponents[i] <= exponents[i - 1])
+ {
+ throw new ArgumentException("Polynomial exponents must be montonically increasing", "exponents");
+ }
+ }
+
+ return new GenericPolynomialExtensionField(GF_2, new GF2Polynomial(exponents));
+ }
+
+ // public static IPolynomialExtensionField GetTernaryExtensionField(Term[] terms)
+ // {
+ // return new GenericPolynomialExtensionField(GF_3, new GF3Polynomial(terms));
+ // }
+
+ public static IFiniteField GetPrimeField(BigInteger characteristic)
+ {
+ int bitLength = characteristic.BitLength;
+ if (characteristic.SignValue <= 0 || bitLength < 2)
+ {
+ throw new ArgumentException("Must be >= 2", "characteristic");
+ }
+
+ if (bitLength < 3)
+ {
+ switch (characteristic.IntValue)
+ {
+ case 2:
+ return GF_2;
+ case 3:
+ return GF_3;
+ }
+ }
+
+ return new PrimeField(characteristic);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/field/GF2Polynomial.cs b/bc-sharp-crypto/src/math/field/GF2Polynomial.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c062d508acdafda2ce09218c13c1bac33e145a0f
--- /dev/null
+++ b/bc-sharp-crypto/src/math/field/GF2Polynomial.cs
@@ -0,0 +1,46 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.Field
+{
+ internal class GF2Polynomial
+ : IPolynomial
+ {
+ protected readonly int[] exponents;
+
+ internal GF2Polynomial(int[] exponents)
+ {
+ this.exponents = Arrays.Clone(exponents);
+ }
+
+ public virtual int Degree
+ {
+ get { return exponents[exponents.Length - 1]; }
+ }
+
+ public virtual int[] GetExponentsPresent()
+ {
+ return Arrays.Clone(exponents);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ GF2Polynomial other = obj as GF2Polynomial;
+ if (null == other)
+ {
+ return false;
+ }
+ return Arrays.AreEqual(exponents, other.exponents);
+ }
+
+ public override int GetHashCode()
+ {
+ return Arrays.GetHashCode(exponents);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/field/GenericPolynomialExtensionField.cs b/bc-sharp-crypto/src/math/field/GenericPolynomialExtensionField.cs
new file mode 100644
index 0000000000000000000000000000000000000000..13ef571650f761c20d0a466e041c5d018aa52907
--- /dev/null
+++ b/bc-sharp-crypto/src/math/field/GenericPolynomialExtensionField.cs
@@ -0,0 +1,63 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.Field
+{
+ internal class GenericPolynomialExtensionField
+ : IPolynomialExtensionField
+ {
+ protected readonly IFiniteField subfield;
+ protected readonly IPolynomial minimalPolynomial;
+
+ internal GenericPolynomialExtensionField(IFiniteField subfield, IPolynomial polynomial)
+ {
+ this.subfield = subfield;
+ this.minimalPolynomial = polynomial;
+ }
+
+ public virtual BigInteger Characteristic
+ {
+ get { return subfield.Characteristic; }
+ }
+
+ public virtual int Dimension
+ {
+ get { return subfield.Dimension * minimalPolynomial.Degree; }
+ }
+
+ public virtual IFiniteField Subfield
+ {
+ get { return subfield; }
+ }
+
+ public virtual int Degree
+ {
+ get { return minimalPolynomial.Degree; }
+ }
+
+ public virtual IPolynomial MinimalPolynomial
+ {
+ get { return minimalPolynomial; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ GenericPolynomialExtensionField other = obj as GenericPolynomialExtensionField;
+ if (null == other)
+ {
+ return false;
+ }
+ return subfield.Equals(other.subfield) && minimalPolynomial.Equals(other.minimalPolynomial);
+ }
+
+ public override int GetHashCode()
+ {
+ return subfield.GetHashCode() ^ Integers.RotateLeft(minimalPolynomial.GetHashCode(), 16);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/field/IExtensionField.cs b/bc-sharp-crypto/src/math/field/IExtensionField.cs
new file mode 100644
index 0000000000000000000000000000000000000000..17f45c153ced8ec015a3bf877210d22a10904d2d
--- /dev/null
+++ b/bc-sharp-crypto/src/math/field/IExtensionField.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Org.BouncyCastle.Math.Field
+{
+ public interface IExtensionField
+ : IFiniteField
+ {
+ IFiniteField Subfield { get; }
+
+ int Degree { get; }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/field/IFiniteField.cs b/bc-sharp-crypto/src/math/field/IFiniteField.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b618be74b1f03d75a75f235ac0a7274e019dad09
--- /dev/null
+++ b/bc-sharp-crypto/src/math/field/IFiniteField.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Math.Field
+{
+ public interface IFiniteField
+ {
+ BigInteger Characteristic { get; }
+
+ int Dimension { get; }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/field/IPolynomial.cs b/bc-sharp-crypto/src/math/field/IPolynomial.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ad6dfb6623c88dc4364610f7ec4b94ed939ceed0
--- /dev/null
+++ b/bc-sharp-crypto/src/math/field/IPolynomial.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Math.Field
+{
+ public interface IPolynomial
+ {
+ int Degree { get; }
+
+ //BigInteger[] GetCoefficients();
+
+ int[] GetExponentsPresent();
+
+ //Term[] GetNonZeroTerms();
+ }
+}
diff --git a/bc-sharp-crypto/src/math/field/IPolynomialExtensionField.cs b/bc-sharp-crypto/src/math/field/IPolynomialExtensionField.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3818c1855f04b74c8c43d8d81286955f9386ef86
--- /dev/null
+++ b/bc-sharp-crypto/src/math/field/IPolynomialExtensionField.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Org.BouncyCastle.Math.Field
+{
+ public interface IPolynomialExtensionField
+ : IExtensionField
+ {
+ IPolynomial MinimalPolynomial { get; }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/field/PrimeField.cs b/bc-sharp-crypto/src/math/field/PrimeField.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f6ba629d5adfc633592391118fef9eabd08592a7
--- /dev/null
+++ b/bc-sharp-crypto/src/math/field/PrimeField.cs
@@ -0,0 +1,44 @@
+using System;
+
+namespace Org.BouncyCastle.Math.Field
+{
+ internal class PrimeField
+ : IFiniteField
+ {
+ protected readonly BigInteger characteristic;
+
+ internal PrimeField(BigInteger characteristic)
+ {
+ this.characteristic = characteristic;
+ }
+
+ public virtual BigInteger Characteristic
+ {
+ get { return characteristic; }
+ }
+
+ public virtual int Dimension
+ {
+ get { return 1; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ PrimeField other = obj as PrimeField;
+ if (null == other)
+ {
+ return false;
+ }
+ return characteristic.Equals(other.characteristic);
+ }
+
+ public override int GetHashCode()
+ {
+ return characteristic.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/raw/Interleave.cs b/bc-sharp-crypto/src/math/raw/Interleave.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d218406448f061bb0a394fc94150abc8e2699858
--- /dev/null
+++ b/bc-sharp-crypto/src/math/raw/Interleave.cs
@@ -0,0 +1,107 @@
+using System;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Interleave
+ {
+ private const ulong M32 = 0x55555555UL;
+ private const ulong M64 = 0x5555555555555555UL;
+
+ /*
+ * This expands 8 bit indices into 16 bit contents (high bit 14), by inserting 0s between bits.
+ * In a binary field, this operation is the same as squaring an 8 bit number.
+ */
+ //private static readonly ushort[] INTERLEAVE2_TABLE = new ushort[]
+ //{
+ // 0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
+ // 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
+ // 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
+ // 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
+ // 0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
+ // 0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
+ // 0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
+ // 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
+ // 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
+ // 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
+ // 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
+ // 0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
+ // 0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
+ // 0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
+ // 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
+ // 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
+ // 0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
+ // 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
+ // 0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
+ // 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
+ // 0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
+ // 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
+ // 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
+ // 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
+ // 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
+ // 0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
+ // 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
+ // 0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
+ // 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
+ // 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
+ // 0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
+ // 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
+ //};
+
+ internal static uint Expand8to16(uint x)
+ {
+ x &= 0xFFU;
+ x = (x | (x << 4)) & 0x0F0FU;
+ x = (x | (x << 2)) & 0x3333U;
+ x = (x | (x << 1)) & 0x5555U;
+ return x;
+ }
+
+ internal static uint Expand16to32(uint x)
+ {
+ x &= 0xFFFFU;
+ x = (x | (x << 8)) & 0x00FF00FFU;
+ x = (x | (x << 4)) & 0x0F0F0F0FU;
+ x = (x | (x << 2)) & 0x33333333U;
+ x = (x | (x << 1)) & 0x55555555U;
+ return x;
+ }
+
+ internal static ulong Expand32to64(uint x)
+ {
+ // "shuffle" low half to even bits and high half to odd bits
+ uint t;
+ t = (x ^ (x >> 8)) & 0x0000FF00U; x ^= (t ^ (t << 8));
+ t = (x ^ (x >> 4)) & 0x00F000F0U; x ^= (t ^ (t << 4));
+ t = (x ^ (x >> 2)) & 0x0C0C0C0CU; x ^= (t ^ (t << 2));
+ t = (x ^ (x >> 1)) & 0x22222222U; x ^= (t ^ (t << 1));
+
+ return ((x >> 1) & M32) << 32 | (x & M32);
+ }
+
+ internal static void Expand64To128(ulong x, ulong[] z, int zOff)
+ {
+ // "shuffle" low half to even bits and high half to odd bits
+ ulong t;
+ t = (x ^ (x >> 16)) & 0x00000000FFFF0000UL; x ^= (t ^ (t << 16));
+ t = (x ^ (x >> 8)) & 0x0000FF000000FF00UL; x ^= (t ^ (t << 8));
+ t = (x ^ (x >> 4)) & 0x00F000F000F000F0UL; x ^= (t ^ (t << 4));
+ t = (x ^ (x >> 2)) & 0x0C0C0C0C0C0C0C0CUL; x ^= (t ^ (t << 2));
+ t = (x ^ (x >> 1)) & 0x2222222222222222UL; x ^= (t ^ (t << 1));
+
+ z[zOff ] = (x ) & M64;
+ z[zOff + 1] = (x >> 1) & M64;
+ }
+
+ internal static ulong Unshuffle(ulong x)
+ {
+ // "unshuffle" even bits to low half and odd bits to high half
+ ulong t;
+ t = (x ^ (x >> 1)) & 0x2222222222222222UL; x ^= (t ^ (t << 1));
+ t = (x ^ (x >> 2)) & 0x0C0C0C0C0C0C0C0CUL; x ^= (t ^ (t << 2));
+ t = (x ^ (x >> 4)) & 0x00F000F000F000F0UL; x ^= (t ^ (t << 4));
+ t = (x ^ (x >> 8)) & 0x0000FF000000FF00UL; x ^= (t ^ (t << 8));
+ t = (x ^ (x >> 16)) & 0x00000000FFFF0000UL; x ^= (t ^ (t << 16));
+ return x;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/raw/Mod.cs b/bc-sharp-crypto/src/math/raw/Mod.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8d9e8fd21ad92ade107de094743ae3fe95657009
--- /dev/null
+++ b/bc-sharp-crypto/src/math/raw/Mod.cs
@@ -0,0 +1,186 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Mod
+ {
+ private static readonly SecureRandom RandomSource = new SecureRandom();
+
+ public static void Invert(uint[] p, uint[] x, uint[] z)
+ {
+ int len = p.Length;
+ if (Nat.IsZero(len, x))
+ throw new ArgumentException("cannot be 0", "x");
+ if (Nat.IsOne(len, x))
+ {
+ Array.Copy(x, 0, z, 0, len);
+ return;
+ }
+
+ uint[] u = Nat.Copy(len, x);
+ uint[] a = Nat.Create(len);
+ a[0] = 1;
+ int ac = 0;
+
+ if ((u[0] & 1) == 0)
+ {
+ InversionStep(p, u, len, a, ref ac);
+ }
+ if (Nat.IsOne(len, u))
+ {
+ InversionResult(p, ac, a, z);
+ return;
+ }
+
+ uint[] v = Nat.Copy(len, p);
+ uint[] b = Nat.Create(len);
+ int bc = 0;
+
+ int uvLen = len;
+
+ for (;;)
+ {
+ while (u[uvLen - 1] == 0 && v[uvLen - 1] == 0)
+ {
+ --uvLen;
+ }
+
+ if (Nat.Gte(len, u, v))
+ {
+ Nat.SubFrom(len, v, u);
+ Debug.Assert((u[0] & 1) == 0);
+ ac += Nat.SubFrom(len, b, a) - bc;
+ InversionStep(p, u, uvLen, a, ref ac);
+ if (Nat.IsOne(len, u))
+ {
+ InversionResult(p, ac, a, z);
+ return;
+ }
+ }
+ else
+ {
+ Nat.SubFrom(len, u, v);
+ Debug.Assert((v[0] & 1) == 0);
+ bc += Nat.SubFrom(len, a, b) - ac;
+ InversionStep(p, v, uvLen, b, ref bc);
+ if (Nat.IsOne(len, v))
+ {
+ InversionResult(p, bc, b, z);
+ return;
+ }
+ }
+ }
+ }
+
+ public static uint[] Random(uint[] p)
+ {
+ int len = p.Length;
+ uint[] s = Nat.Create(len);
+
+ uint m = p[len - 1];
+ m |= m >> 1;
+ m |= m >> 2;
+ m |= m >> 4;
+ m |= m >> 8;
+ m |= m >> 16;
+
+ do
+ {
+ byte[] bytes = new byte[len << 2];
+ RandomSource.NextBytes(bytes);
+ Pack.BE_To_UInt32(bytes, 0, s);
+ s[len - 1] &= m;
+ }
+ while (Nat.Gte(len, s, p));
+
+ return s;
+ }
+
+ public static void Add(uint[] p, uint[] x, uint[] y, uint[] z)
+ {
+ int len = p.Length;
+ uint c = Nat.Add(len, x, y, z);
+ if (c != 0)
+ {
+ Nat.SubFrom(len, p, z);
+ }
+ }
+
+ public static void Subtract(uint[] p, uint[] x, uint[] y, uint[] z)
+ {
+ int len = p.Length;
+ int c = Nat.Sub(len, x, y, z);
+ if (c != 0)
+ {
+ Nat.AddTo(len, p, z);
+ }
+ }
+
+ private static void InversionResult(uint[] p, int ac, uint[] a, uint[] z)
+ {
+ if (ac < 0)
+ {
+ Nat.Add(p.Length, a, p, z);
+ }
+ else
+ {
+ Array.Copy(a, 0, z, 0, p.Length);
+ }
+ }
+
+ private static void InversionStep(uint[] p, uint[] u, int uLen, uint[] x, ref int xc)
+ {
+ int len = p.Length;
+ int count = 0;
+ while (u[0] == 0)
+ {
+ Nat.ShiftDownWord(uLen, u, 0);
+ count += 32;
+ }
+
+ {
+ int zeroes = GetTrailingZeroes(u[0]);
+ if (zeroes > 0)
+ {
+ Nat.ShiftDownBits(uLen, u, zeroes, 0);
+ count += zeroes;
+ }
+ }
+
+ for (int i = 0; i < count; ++i)
+ {
+ if ((x[0] & 1) != 0)
+ {
+ if (xc < 0)
+ {
+ xc += (int)Nat.AddTo(len, p, x);
+ }
+ else
+ {
+ xc += Nat.SubFrom(len, p, x);
+ }
+ }
+
+ Debug.Assert(xc == 0 || xc == -1);
+ Nat.ShiftDownBit(len, x, (uint)xc);
+ }
+ }
+
+ private static int GetTrailingZeroes(uint x)
+ {
+ Debug.Assert(x != 0);
+ int count = 0;
+ while ((x & 1) == 0)
+ {
+ x >>= 1;
+ ++count;
+ }
+ return count;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/raw/Nat.cs b/bc-sharp-crypto/src/math/raw/Nat.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1f9ab00ec45280dd516ca1d59bb6b0f025b49903
--- /dev/null
+++ b/bc-sharp-crypto/src/math/raw/Nat.cs
@@ -0,0 +1,1053 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Nat
+ {
+ private const ulong M = 0xFFFFFFFFUL;
+
+ public static uint Add(int len, uint[] x, uint[] y, uint[] z)
+ {
+ ulong c = 0;
+ for (int i = 0; i < len; ++i)
+ {
+ c += (ulong)x[i] + y[i];
+ z[i] = (uint)c;
+ c >>= 32;
+ }
+ return (uint)c;
+ }
+
+ public static uint Add33At(int len, uint x, uint[] z, int zPos)
+ {
+ Debug.Assert(zPos <= (len - 2));
+ ulong c = (ulong)z[zPos + 0] + x;
+ z[zPos + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)z[zPos + 1] + 1;
+ z[zPos + 1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : IncAt(len, z, zPos + 2);
+ }
+
+ public static uint Add33At(int len, uint x, uint[] z, int zOff, int zPos)
+ {
+ Debug.Assert(zPos <= (len - 2));
+ ulong c = (ulong)z[zOff + zPos] + x;
+ z[zOff + zPos] = (uint)c;
+ c >>= 32;
+ c += (ulong)z[zOff + zPos + 1] + 1;
+ z[zOff + zPos + 1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : IncAt(len, z, zOff, zPos + 2);
+ }
+
+ public static uint Add33To(int len, uint x, uint[] z)
+ {
+ ulong c = (ulong)z[0] + x;
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)z[1] + 1;
+ z[1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : IncAt(len, z, 2);
+ }
+
+ public static uint Add33To(int len, uint x, uint[] z, int zOff)
+ {
+ ulong c = (ulong)z[zOff + 0] + x;
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)z[zOff + 1] + 1;
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : IncAt(len, z, zOff, 2);
+ }
+
+ public static uint AddBothTo(int len, uint[] x, uint[] y, uint[] z)
+ {
+ ulong c = 0;
+ for (int i = 0; i < len; ++i)
+ {
+ c += (ulong)x[i] + y[i] + z[i];
+ z[i] = (uint)c;
+ c >>= 32;
+ }
+ return (uint)c;
+ }
+
+ public static uint AddBothTo(int len, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ ulong c = 0;
+ for (int i = 0; i < len; ++i)
+ {
+ c += (ulong)x[xOff + i] + y[yOff + i] + z[zOff + i];
+ z[zOff + i] = (uint)c;
+ c >>= 32;
+ }
+ return (uint)c;
+ }
+
+ public static uint AddDWordAt(int len, ulong x, uint[] z, int zPos)
+ {
+ Debug.Assert(zPos <= (len - 2));
+ ulong c = (ulong)z[zPos + 0] + (x & M);
+ z[zPos + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)z[zPos + 1] + (x >> 32);
+ z[zPos + 1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : IncAt(len, z, zPos + 2);
+ }
+
+ public static uint AddDWordAt(int len, ulong x, uint[] z, int zOff, int zPos)
+ {
+ Debug.Assert(zPos <= (len - 2));
+ ulong c = (ulong)z[zOff + zPos] + (x & M);
+ z[zOff + zPos] = (uint)c;
+ c >>= 32;
+ c += (ulong)z[zOff + zPos + 1] + (x >> 32);
+ z[zOff + zPos + 1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : IncAt(len, z, zOff, zPos + 2);
+ }
+
+ public static uint AddDWordTo(int len, ulong x, uint[] z)
+ {
+ ulong c = (ulong)z[0] + (x & M);
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)z[1] + (x >> 32);
+ z[1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : IncAt(len, z, 2);
+ }
+
+ public static uint AddDWordTo(int len, ulong x, uint[] z, int zOff)
+ {
+ ulong c = (ulong)z[zOff + 0] + (x & M);
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)z[zOff + 1] + (x >> 32);
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : IncAt(len, z, zOff, 2);
+ }
+
+ public static uint AddTo(int len, uint[] x, uint[] z)
+ {
+ ulong c = 0;
+ for (int i = 0; i < len; ++i)
+ {
+ c += (ulong)x[i] + z[i];
+ z[i] = (uint)c;
+ c >>= 32;
+ }
+ return (uint)c;
+ }
+
+ public static uint AddTo(int len, uint[] x, int xOff, uint[] z, int zOff)
+ {
+ ulong c = 0;
+ for (int i = 0; i < len; ++i)
+ {
+ c += (ulong)x[xOff + i] + z[zOff + i];
+ z[zOff + i] = (uint)c;
+ c >>= 32;
+ }
+ return (uint)c;
+ }
+
+ public static uint AddWordAt(int len, uint x, uint[] z, int zPos)
+ {
+ Debug.Assert(zPos <= (len - 1));
+ ulong c = (ulong)x + z[zPos];
+ z[zPos] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : IncAt(len, z, zPos + 1);
+ }
+
+ public static uint AddWordAt(int len, uint x, uint[] z, int zOff, int zPos)
+ {
+ Debug.Assert(zPos <= (len - 1));
+ ulong c = (ulong)x + z[zOff + zPos];
+ z[zOff + zPos] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : IncAt(len, z, zOff, zPos + 1);
+ }
+
+ public static uint AddWordTo(int len, uint x, uint[] z)
+ {
+ ulong c = (ulong)x + z[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : IncAt(len, z, 1);
+ }
+
+ public static uint AddWordTo(int len, uint x, uint[] z, int zOff)
+ {
+ ulong c = (ulong)x + z[zOff];
+ z[zOff] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : IncAt(len, z, zOff, 1);
+ }
+
+ public static void Copy(int len, uint[] x, uint[] z)
+ {
+ Array.Copy(x, 0, z, 0, len);
+ }
+
+ public static uint[] Copy(int len, uint[] x)
+ {
+ uint[] z = new uint[len];
+ Array.Copy(x, 0, z, 0, len);
+ return z;
+ }
+
+ public static uint[] Create(int len)
+ {
+ return new uint[len];
+ }
+
+ public static ulong[] Create64(int len)
+ {
+ return new ulong[len];
+ }
+
+ public static int Dec(int len, uint[] z)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ if (--z[i] != uint.MaxValue)
+ {
+ return 0;
+ }
+ }
+ return -1;
+ }
+
+ public static int Dec(int len, uint[] x, uint[] z)
+ {
+ int i = 0;
+ while (i < len)
+ {
+ uint c = x[i] - 1;
+ z[i] = c;
+ ++i;
+ if (c != uint.MaxValue)
+ {
+ while (i < len)
+ {
+ z[i] = x[i];
+ ++i;
+ }
+ return 0;
+ }
+ }
+ return -1;
+ }
+
+ public static int DecAt(int len, uint[] z, int zPos)
+ {
+ Debug.Assert(zPos <= len);
+ for (int i = zPos; i < len; ++i)
+ {
+ if (--z[i] != uint.MaxValue)
+ {
+ return 0;
+ }
+ }
+ return -1;
+ }
+
+ public static int DecAt(int len, uint[] z, int zOff, int zPos)
+ {
+ Debug.Assert(zPos <= len);
+ for (int i = zPos; i < len; ++i)
+ {
+ if (--z[zOff + i] != uint.MaxValue)
+ {
+ return 0;
+ }
+ }
+ return -1;
+ }
+
+ public static bool Eq(int len, uint[] x, uint[] y)
+ {
+ for (int i = len - 1; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static uint[] FromBigInteger(int bits, BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > bits)
+ throw new ArgumentException();
+
+ int len = (bits + 31) >> 5;
+ uint[] z = Create(len);
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (uint)x.IntValue;
+ x = x.ShiftRight(32);
+ }
+ return z;
+ }
+
+ public static uint GetBit(uint[] x, int bit)
+ {
+ if (bit == 0)
+ {
+ return x[0] & 1;
+ }
+ int w = bit >> 5;
+ if (w < 0 || w >= x.Length)
+ {
+ return 0;
+ }
+ int b = bit & 31;
+ return (x[w] >> b) & 1;
+ }
+
+ public static bool Gte(int len, uint[] x, uint[] y)
+ {
+ for (int i = len - 1; i >= 0; --i)
+ {
+ uint x_i = x[i], y_i = y[i];
+ if (x_i < y_i)
+ return false;
+ if (x_i > y_i)
+ return true;
+ }
+ return true;
+ }
+
+ public static uint Inc(int len, uint[] z)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ if (++z[i] != uint.MinValue)
+ {
+ return 0;
+ }
+ }
+ return 1;
+ }
+
+ public static uint Inc(int len, uint[] x, uint[] z)
+ {
+ int i = 0;
+ while (i < len)
+ {
+ uint c = x[i] + 1;
+ z[i] = c;
+ ++i;
+ if (c != 0)
+ {
+ while (i < len)
+ {
+ z[i] = x[i];
+ ++i;
+ }
+ return 0;
+ }
+ }
+ return 1;
+ }
+
+ public static uint IncAt(int len, uint[] z, int zPos)
+ {
+ Debug.Assert(zPos <= len);
+ for (int i = zPos; i < len; ++i)
+ {
+ if (++z[i] != uint.MinValue)
+ {
+ return 0;
+ }
+ }
+ return 1;
+ }
+
+ public static uint IncAt(int len, uint[] z, int zOff, int zPos)
+ {
+ Debug.Assert(zPos <= len);
+ for (int i = zPos; i < len; ++i)
+ {
+ if (++z[zOff + i] != uint.MinValue)
+ {
+ return 0;
+ }
+ }
+ return 1;
+ }
+
+ public static bool IsOne(int len, uint[] x)
+ {
+ if (x[0] != 1)
+ {
+ return false;
+ }
+ for (int i = 1; i < len; ++i)
+ {
+ if (x[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsZero(int len, uint[] x)
+ {
+ if (x[0] != 0)
+ {
+ return false;
+ }
+ for (int i = 1; i < len; ++i)
+ {
+ if (x[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static void Mul(int len, uint[] x, uint[] y, uint[] zz)
+ {
+ zz[len] = (uint)MulWord(len, x[0], y, zz);
+
+ for (int i = 1; i < len; ++i)
+ {
+ zz[i + len] = (uint)MulWordAddTo(len, x[i], y, 0, zz, i);
+ }
+ }
+
+ public static void Mul(int len, uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+ {
+ zz[zzOff + len] = (uint)MulWord(len, x[xOff], y, yOff, zz, zzOff);
+
+ for (int i = 1; i < len; ++i)
+ {
+ zz[zzOff + i + len] = (uint)MulWordAddTo(len, x[xOff + i], y, yOff, zz, zzOff + i);
+ }
+ }
+
+ public static uint Mul31BothAdd(int len, uint a, uint[] x, uint b, uint[] y, uint[] z, int zOff)
+ {
+ ulong c = 0, aVal = (ulong)a, bVal = (ulong)b;
+ int i = 0;
+ do
+ {
+ c += aVal * x[i] + bVal * y[i] + z[zOff + i];
+ z[zOff + i] = (uint)c;
+ c >>= 32;
+ }
+ while (++i < len);
+ return (uint)c;
+ }
+
+ public static uint MulWord(int len, uint x, uint[] y, uint[] z)
+ {
+ ulong c = 0, xVal = (ulong)x;
+ int i = 0;
+ do
+ {
+ c += xVal * y[i];
+ z[i] = (uint)c;
+ c >>= 32;
+ }
+ while (++i < len);
+ return (uint)c;
+ }
+
+ public static uint MulWord(int len, uint x, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ ulong c = 0, xVal = (ulong)x;
+ int i = 0;
+ do
+ {
+ c += xVal * y[yOff + i];
+ z[zOff + i] = (uint)c;
+ c >>= 32;
+ }
+ while (++i < len);
+ return (uint)c;
+ }
+
+ public static uint MulWordAddTo(int len, uint x, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ ulong c = 0, xVal = (ulong)x;
+ int i = 0;
+ do
+ {
+ c += xVal * y[yOff + i] + z[zOff + i];
+ z[zOff + i] = (uint)c;
+ c >>= 32;
+ }
+ while (++i < len);
+ return (uint)c;
+ }
+
+ public static uint MulWordDwordAddAt(int len, uint x, ulong y, uint[] z, int zPos)
+ {
+ Debug.Assert(zPos <= (len - 3));
+ ulong c = 0, xVal = (ulong)x;
+ c += xVal * (uint)y + z[zPos + 0];
+ z[zPos + 0] = (uint)c;
+ c >>= 32;
+ c += xVal * (y >> 32) + z[zPos + 1];
+ z[zPos + 1] = (uint)c;
+ c >>= 32;
+ c += (ulong)z[zPos + 2];
+ z[zPos + 2] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : IncAt(len, z, zPos + 3);
+ }
+
+ public static uint ShiftDownBit(int len, uint[] z, uint c)
+ {
+ int i = len;
+ while (--i >= 0)
+ {
+ uint next = z[i];
+ z[i] = (next >> 1) | (c << 31);
+ c = next;
+ }
+ return c << 31;
+ }
+
+ public static uint ShiftDownBit(int len, uint[] z, int zOff, uint c)
+ {
+ int i = len;
+ while (--i >= 0)
+ {
+ uint next = z[zOff + i];
+ z[zOff + i] = (next >> 1) | (c << 31);
+ c = next;
+ }
+ return c << 31;
+ }
+
+ public static uint ShiftDownBit(int len, uint[] x, uint c, uint[] z)
+ {
+ int i = len;
+ while (--i >= 0)
+ {
+ uint next = x[i];
+ z[i] = (next >> 1) | (c << 31);
+ c = next;
+ }
+ return c << 31;
+ }
+
+ public static uint ShiftDownBit(int len, uint[] x, int xOff, uint c, uint[] z, int zOff)
+ {
+ int i = len;
+ while (--i >= 0)
+ {
+ uint next = x[xOff + i];
+ z[zOff + i] = (next >> 1) | (c << 31);
+ c = next;
+ }
+ return c << 31;
+ }
+
+ public static uint ShiftDownBits(int len, uint[] z, int bits, uint c)
+ {
+ Debug.Assert(bits > 0 && bits < 32);
+ int i = len;
+ while (--i >= 0)
+ {
+ uint next = z[i];
+ z[i] = (next >> bits) | (c << -bits);
+ c = next;
+ }
+ return c << -bits;
+ }
+
+ public static uint ShiftDownBits(int len, uint[] z, int zOff, int bits, uint c)
+ {
+ Debug.Assert(bits > 0 && bits < 32);
+ int i = len;
+ while (--i >= 0)
+ {
+ uint next = z[zOff + i];
+ z[zOff + i] = (next >> bits) | (c << -bits);
+ c = next;
+ }
+ return c << -bits;
+ }
+
+ public static uint ShiftDownBits(int len, uint[] x, int bits, uint c, uint[] z)
+ {
+ Debug.Assert(bits > 0 && bits < 32);
+ int i = len;
+ while (--i >= 0)
+ {
+ uint next = x[i];
+ z[i] = (next >> bits) | (c << -bits);
+ c = next;
+ }
+ return c << -bits;
+ }
+
+ public static uint ShiftDownBits(int len, uint[] x, int xOff, int bits, uint c, uint[] z, int zOff)
+ {
+ Debug.Assert(bits > 0 && bits < 32);
+ int i = len;
+ while (--i >= 0)
+ {
+ uint next = x[xOff + i];
+ z[zOff + i] = (next >> bits) | (c << -bits);
+ c = next;
+ }
+ return c << -bits;
+ }
+
+ public static uint ShiftDownWord(int len, uint[] z, uint c)
+ {
+ int i = len;
+ while (--i >= 0)
+ {
+ uint next = z[i];
+ z[i] = c;
+ c = next;
+ }
+ return c;
+ }
+
+ public static uint ShiftUpBit(int len, uint[] z, uint c)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ uint next = z[i];
+ z[i] = (next << 1) | (c >> 31);
+ c = next;
+ }
+ return c >> 31;
+ }
+
+ public static uint ShiftUpBit(int len, uint[] z, int zOff, uint c)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ uint next = z[zOff + i];
+ z[zOff + i] = (next << 1) | (c >> 31);
+ c = next;
+ }
+ return c >> 31;
+ }
+
+ public static uint ShiftUpBit(int len, uint[] x, uint c, uint[] z)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ uint next = x[i];
+ z[i] = (next << 1) | (c >> 31);
+ c = next;
+ }
+ return c >> 31;
+ }
+
+ public static uint ShiftUpBit(int len, uint[] x, int xOff, uint c, uint[] z, int zOff)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ uint next = x[xOff + i];
+ z[zOff + i] = (next << 1) | (c >> 31);
+ c = next;
+ }
+ return c >> 31;
+ }
+
+ public static ulong ShiftUpBit64(int len, ulong[] x, int xOff, ulong c, ulong[] z, int zOff)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ ulong next = x[xOff + i];
+ z[zOff + i] = (next << 1) | (c >> 63);
+ c = next;
+ }
+ return c >> 63;
+ }
+
+ public static uint ShiftUpBits(int len, uint[] z, int bits, uint c)
+ {
+ Debug.Assert(bits > 0 && bits < 32);
+ for (int i = 0; i < len; ++i)
+ {
+ uint next = z[i];
+ z[i] = (next << bits) | (c >> -bits);
+ c = next;
+ }
+ return c >> -bits;
+ }
+
+ public static uint ShiftUpBits(int len, uint[] z, int zOff, int bits, uint c)
+ {
+ Debug.Assert(bits > 0 && bits < 32);
+ for (int i = 0; i < len; ++i)
+ {
+ uint next = z[zOff + i];
+ z[zOff + i] = (next << bits) | (c >> -bits);
+ c = next;
+ }
+ return c >> -bits;
+ }
+
+ public static ulong ShiftUpBits64(int len, ulong[] z, int zOff, int bits, ulong c)
+ {
+ Debug.Assert(bits > 0 && bits < 64);
+ for (int i = 0; i < len; ++i)
+ {
+ ulong next = z[zOff + i];
+ z[zOff + i] = (next << bits) | (c >> -bits);
+ c = next;
+ }
+ return c >> -bits;
+ }
+
+ public static uint ShiftUpBits(int len, uint[] x, int bits, uint c, uint[] z)
+ {
+ Debug.Assert(bits > 0 && bits < 32);
+ for (int i = 0; i < len; ++i)
+ {
+ uint next = x[i];
+ z[i] = (next << bits) | (c >> -bits);
+ c = next;
+ }
+ return c >> -bits;
+ }
+
+ public static uint ShiftUpBits(int len, uint[] x, int xOff, int bits, uint c, uint[] z, int zOff)
+ {
+ Debug.Assert(bits > 0 && bits < 32);
+ for (int i = 0; i < len; ++i)
+ {
+ uint next = x[xOff + i];
+ z[zOff + i] = (next << bits) | (c >> -bits);
+ c = next;
+ }
+ return c >> -bits;
+ }
+
+ public static ulong ShiftUpBits64(int len, ulong[] x, int xOff, int bits, ulong c, ulong[] z, int zOff)
+ {
+ Debug.Assert(bits > 0 && bits < 64);
+ for (int i = 0; i < len; ++i)
+ {
+ ulong next = x[xOff + i];
+ z[zOff + i] = (next << bits) | (c >> -bits);
+ c = next;
+ }
+ return c >> -bits;
+ }
+
+ public static void Square(int len, uint[] x, uint[] zz)
+ {
+ int extLen = len << 1;
+ uint c = 0;
+ int j = len, k = extLen;
+ do
+ {
+ ulong xVal = (ulong)x[--j];
+ ulong p = xVal * xVal;
+ zz[--k] = (c << 31) | (uint)(p >> 33);
+ zz[--k] = (uint)(p >> 1);
+ c = (uint)p;
+ }
+ while (j > 0);
+
+ for (int i = 1; i < len; ++i)
+ {
+ c = SquareWordAdd(x, i, zz);
+ AddWordAt(extLen, c, zz, i << 1);
+ }
+
+ ShiftUpBit(extLen, zz, x[0] << 31);
+ }
+
+ public static void Square(int len, uint[] x, int xOff, uint[] zz, int zzOff)
+ {
+ int extLen = len << 1;
+ uint c = 0;
+ int j = len, k = extLen;
+ do
+ {
+ ulong xVal = (ulong)x[xOff + --j];
+ ulong p = xVal * xVal;
+ zz[zzOff + --k] = (c << 31) | (uint)(p >> 33);
+ zz[zzOff + --k] = (uint)(p >> 1);
+ c = (uint)p;
+ }
+ while (j > 0);
+
+ for (int i = 1; i < len; ++i)
+ {
+ c = SquareWordAdd(x, xOff, i, zz, zzOff);
+ AddWordAt(extLen, c, zz, zzOff, i << 1);
+ }
+
+ ShiftUpBit(extLen, zz, zzOff, x[xOff] << 31);
+ }
+
+ public static uint SquareWordAdd(uint[] x, int xPos, uint[] z)
+ {
+ ulong c = 0, xVal = (ulong)x[xPos];
+ int i = 0;
+ do
+ {
+ c += xVal * x[i] + z[xPos + i];
+ z[xPos + i] = (uint)c;
+ c >>= 32;
+ }
+ while (++i < xPos);
+ return (uint)c;
+ }
+
+ public static uint SquareWordAdd(uint[] x, int xOff, int xPos, uint[] z, int zOff)
+ {
+ ulong c = 0, xVal = (ulong)x[xOff + xPos];
+ int i = 0;
+ do
+ {
+ c += xVal * (x[xOff + i] & M) + (z[xPos + zOff] & M);
+ z[xPos + zOff] = (uint)c;
+ c >>= 32;
+ ++zOff;
+ }
+ while (++i < xPos);
+ return (uint)c;
+ }
+
+ public static int Sub(int len, uint[] x, uint[] y, uint[] z)
+ {
+ long c = 0;
+ for (int i = 0; i < len; ++i)
+ {
+ c += (long)x[i] - y[i];
+ z[i] = (uint)c;
+ c >>= 32;
+ }
+ return (int)c;
+ }
+
+ public static int Sub(int len, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ long c = 0;
+ for (int i = 0; i < len; ++i)
+ {
+ c += (long)x[xOff + i] - y[yOff + i];
+ z[zOff + i] = (uint)c;
+ c >>= 32;
+ }
+ return (int)c;
+ }
+ public static int Sub33At(int len, uint x, uint[] z, int zPos)
+ {
+ Debug.Assert(zPos <= (len - 2));
+ long c = (long)z[zPos + 0] - x;
+ z[zPos + 0] = (uint)c;
+ c >>= 32;
+ c += (long)z[zPos + 1] - 1;
+ z[zPos + 1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : DecAt(len, z, zPos + 2);
+ }
+
+ public static int Sub33At(int len, uint x, uint[] z, int zOff, int zPos)
+ {
+ Debug.Assert(zPos <= (len - 2));
+ long c = (long)z[zOff + zPos] - x;
+ z[zOff + zPos] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + zPos + 1] - 1;
+ z[zOff + zPos + 1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : DecAt(len, z, zOff, zPos + 2);
+ }
+
+ public static int Sub33From(int len, uint x, uint[] z)
+ {
+ long c = (long)z[0] - x;
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)z[1] - 1;
+ z[1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : DecAt(len, z, 2);
+ }
+
+ public static int Sub33From(int len, uint x, uint[] z, int zOff)
+ {
+ long c = (long)z[zOff + 0] - x;
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 1] - 1;
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : DecAt(len, z, zOff, 2);
+ }
+
+ public static int SubBothFrom(int len, uint[] x, uint[] y, uint[] z)
+ {
+ long c = 0;
+ for (int i = 0; i < len; ++i)
+ {
+ c += (long)z[i] - x[i] - y[i];
+ z[i] = (uint)c;
+ c >>= 32;
+ }
+ return (int)c;
+ }
+
+ public static int SubBothFrom(int len, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ long c = 0;
+ for (int i = 0; i < len; ++i)
+ {
+ c += (long)z[zOff + i] - x[xOff + i] - y[yOff + i];
+ z[zOff + i] = (uint)c;
+ c >>= 32;
+ }
+ return (int)c;
+ }
+
+ public static int SubDWordAt(int len, ulong x, uint[] z, int zPos)
+ {
+ Debug.Assert(zPos <= (len - 2));
+ long c = (long)z[zPos + 0] - (long)(x & M);
+ z[zPos + 0] = (uint)c;
+ c >>= 32;
+ c += (long)z[zPos + 1] - (long)(x >> 32);
+ z[zPos + 1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : DecAt(len, z, zPos + 2);
+ }
+
+ public static int SubDWordAt(int len, ulong x, uint[] z, int zOff, int zPos)
+ {
+ Debug.Assert(zPos <= (len - 2));
+ long c = (long)z[zOff + zPos] - (long)(x & M);
+ z[zOff + zPos] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + zPos + 1] - (long)(x >> 32);
+ z[zOff + zPos + 1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : DecAt(len, z, zOff, zPos + 2);
+ }
+
+ public static int SubDWordFrom(int len, ulong x, uint[] z)
+ {
+ long c = (long)z[0] - (long)(x & M);
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)z[1] - (long)(x >> 32);
+ z[1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : DecAt(len, z, 2);
+ }
+
+ public static int SubDWordFrom(int len, ulong x, uint[] z, int zOff)
+ {
+ long c = (long)z[zOff + 0] - (long)(x & M);
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 1] - (long)(x >> 32);
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : DecAt(len, z, zOff, 2);
+ }
+
+ public static int SubFrom(int len, uint[] x, uint[] z)
+ {
+ long c = 0;
+ for (int i = 0; i < len; ++i)
+ {
+ c += (long)z[i] - x[i];
+ z[i] = (uint)c;
+ c >>= 32;
+ }
+ return (int)c;
+ }
+
+ public static int SubFrom(int len, uint[] x, int xOff, uint[] z, int zOff)
+ {
+ long c = 0;
+ for (int i = 0; i < len; ++i)
+ {
+ c += (long)z[zOff + i] - x[xOff + i];
+ z[zOff + i] = (uint)c;
+ c >>= 32;
+ }
+ return (int)c;
+ }
+
+ public static int SubWordAt(int len, uint x, uint[] z, int zPos)
+ {
+ Debug.Assert(zPos <= (len - 1));
+ long c = (long)z[zPos] - x;
+ z[zPos] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : DecAt(len, z, zPos + 1);
+ }
+
+ public static int SubWordAt(int len, uint x, uint[] z, int zOff, int zPos)
+ {
+ Debug.Assert(zPos <= (len - 1));
+ long c = (long)z[zOff + zPos] - x;
+ z[zOff + zPos] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : DecAt(len, z, zOff, zPos + 1);
+ }
+
+ public static int SubWordFrom(int len, uint x, uint[] z)
+ {
+ long c = (long)z[0] - x;
+ z[0] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : DecAt(len, z, 1);
+ }
+
+ public static int SubWordFrom(int len, uint x, uint[] z, int zOff)
+ {
+ long c = (long)z[zOff + 0] - x;
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : DecAt(len, z, zOff, 1);
+ }
+
+ public static BigInteger ToBigInteger(int len, uint[] x)
+ {
+ byte[] bs = new byte[len << 2];
+ for (int i = 0; i < len; ++i)
+ {
+ uint x_i = x[i];
+ if (x_i != 0)
+ {
+ Pack.UInt32_To_BE(x_i, bs, (len - 1 - i) << 2);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+
+ public static void Zero(int len, uint[] z)
+ {
+ for (int i = 0; i < len; ++i)
+ {
+ z[i] = 0;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/raw/Nat128.cs b/bc-sharp-crypto/src/math/raw/Nat128.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1d3b64d3220c3fd6d8934eac3805b79cae70ab81
--- /dev/null
+++ b/bc-sharp-crypto/src/math/raw/Nat128.cs
@@ -0,0 +1,856 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Nat128
+ {
+ private const ulong M = 0xFFFFFFFFUL;
+
+ public static uint Add(uint[] x, uint[] y, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddBothTo(uint[] x, uint[] y, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + y[0] + z[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + y[1] + z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + y[2] + z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + y[3] + z[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddTo(uint[] x, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + z[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + z[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddTo(uint[] x, int xOff, uint[] z, int zOff, uint cIn)
+ {
+ ulong c = cIn;
+ c += (ulong)x[xOff + 0] + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 1] + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 2] + z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 3] + z[zOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddToEachOther(uint[] u, int uOff, uint[] v, int vOff)
+ {
+ ulong c = 0;
+ c += (ulong)u[uOff + 0] + v[vOff + 0];
+ u[uOff + 0] = (uint)c;
+ v[vOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 1] + v[vOff + 1];
+ u[uOff + 1] = (uint)c;
+ v[vOff + 1] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 2] + v[vOff + 2];
+ u[uOff + 2] = (uint)c;
+ v[vOff + 2] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 3] + v[vOff + 3];
+ u[uOff + 3] = (uint)c;
+ v[vOff + 3] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static void Copy(uint[] x, uint[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ }
+
+ public static void Copy64(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ }
+
+ public static uint[] Create()
+ {
+ return new uint[4];
+ }
+
+ public static ulong[] Create64()
+ {
+ return new ulong[2];
+ }
+
+ public static uint[] CreateExt()
+ {
+ return new uint[8];
+ }
+
+ public static ulong[] CreateExt64()
+ {
+ return new ulong[4];
+ }
+
+ public static bool Diff(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ bool pos = Gte(x, xOff, y, yOff);
+ if (pos)
+ {
+ Sub(x, xOff, y, yOff, z, zOff);
+ }
+ else
+ {
+ Sub(y, yOff, x, xOff, z, zOff);
+ }
+ return pos;
+ }
+
+ public static bool Eq(uint[] x, uint[] y)
+ {
+ for (int i = 3; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ return false;
+ }
+ return true;
+ }
+
+ public static bool Eq64(ulong[] x, ulong[] y)
+ {
+ for (int i = 1; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ return false;
+ }
+ return true;
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > 128)
+ throw new ArgumentException();
+
+ uint[] z = Create();
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (uint)x.IntValue;
+ x = x.ShiftRight(32);
+ }
+ return z;
+ }
+
+ public static ulong[] FromBigInteger64(BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > 128)
+ throw new ArgumentException();
+
+ ulong[] z = Create64();
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (ulong)x.LongValue;
+ x = x.ShiftRight(64);
+ }
+ return z;
+ }
+
+ public static uint GetBit(uint[] x, int bit)
+ {
+ if (bit == 0)
+ {
+ return x[0] & 1;
+ }
+ if ((bit & 127) != bit)
+ {
+ return 0;
+ }
+ int w = bit >> 5;
+ int b = bit & 31;
+ return (x[w] >> b) & 1;
+ }
+
+ public static bool Gte(uint[] x, uint[] y)
+ {
+ for (int i = 3; i >= 0; --i)
+ {
+ uint x_i = x[i], y_i = y[i];
+ if (x_i < y_i)
+ return false;
+ if (x_i > y_i)
+ return true;
+ }
+ return true;
+ }
+
+ public static bool Gte(uint[] x, int xOff, uint[] y, int yOff)
+ {
+ for (int i = 3; i >= 0; --i)
+ {
+ uint x_i = x[xOff + i], y_i = y[yOff + i];
+ if (x_i < y_i)
+ return false;
+ if (x_i > y_i)
+ return true;
+ }
+ return true;
+ }
+
+ public static bool IsOne(uint[] x)
+ {
+ if (x[0] != 1)
+ {
+ return false;
+ }
+ for (int i = 1; i < 4; ++i)
+ {
+ if (x[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsOne64(ulong[] x)
+ {
+ if (x[0] != 1UL)
+ {
+ return false;
+ }
+ for (int i = 1; i < 2; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsZero(uint[] x)
+ {
+ for (int i = 0; i < 4; ++i)
+ {
+ if (x[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsZero64(ulong[] x)
+ {
+ for (int i = 0; i < 2; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static void Mul(uint[] x, uint[] y, uint[] zz)
+ {
+ ulong y_0 = y[0];
+ ulong y_1 = y[1];
+ ulong y_2 = y[2];
+ ulong y_3 = y[3];
+
+ {
+ ulong c = 0, x_0 = x[0];
+ c += x_0 * y_0;
+ zz[0] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_1;
+ zz[1] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_2;
+ zz[2] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_3;
+ zz[3] = (uint)c;
+ c >>= 32;
+ zz[4] = (uint)c;
+ }
+
+ for (int i = 1; i < 4; ++i)
+ {
+ ulong c = 0, x_i = x[i];
+ c += x_i * y_0 + zz[i + 0];
+ zz[i + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[i + 1];
+ zz[i + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[i + 2];
+ zz[i + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[i + 3];
+ zz[i + 3] = (uint)c;
+ c >>= 32;
+ zz[i + 4] = (uint)c;
+ }
+ }
+
+ public static void Mul(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+ {
+ ulong y_0 = y[yOff + 0];
+ ulong y_1 = y[yOff + 1];
+ ulong y_2 = y[yOff + 2];
+ ulong y_3 = y[yOff + 3];
+
+ {
+ ulong c = 0, x_0 = x[xOff + 0];
+ c += x_0 * y_0;
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_1;
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_2;
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_3;
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ zz[zzOff + 4] = (uint)c;
+ }
+
+ for (int i = 1; i < 4; ++i)
+ {
+ ++zzOff;
+ ulong c = 0, x_i = x[xOff + i];
+ c += x_i * y_0 + zz[zzOff + 0];
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[zzOff + 1];
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[zzOff + 2];
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[zzOff + 3];
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ zz[zzOff + 4] = (uint)c;
+ }
+ }
+
+ public static uint MulAddTo(uint[] x, uint[] y, uint[] zz)
+ {
+ ulong y_0 = y[0];
+ ulong y_1 = y[1];
+ ulong y_2 = y[2];
+ ulong y_3 = y[3];
+
+ ulong zc = 0;
+ for (int i = 0; i < 4; ++i)
+ {
+ ulong c = 0, x_i = x[i];
+ c += x_i * y_0 + zz[i + 0];
+ zz[i + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[i + 1];
+ zz[i + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[i + 2];
+ zz[i + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[i + 3];
+ zz[i + 3] = (uint)c;
+ c >>= 32;
+ c += zc + zz[i + 4];
+ zz[i + 4] = (uint)c;
+ zc = c >> 32;
+ }
+ return (uint)zc;
+ }
+
+ public static uint MulAddTo(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+ {
+ ulong y_0 = y[yOff + 0];
+ ulong y_1 = y[yOff + 1];
+ ulong y_2 = y[yOff + 2];
+ ulong y_3 = y[yOff + 3];
+
+ ulong zc = 0;
+ for (int i = 0; i < 4; ++i)
+ {
+ ulong c = 0, x_i = x[xOff + i];
+ c += x_i * y_0 + zz[zzOff + 0];
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[zzOff + 1];
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[zzOff + 2];
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[zzOff + 3];
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += zc + zz[zzOff + 4];
+ zz[zzOff + 4] = (uint)c;
+ zc = c >> 32;
+ ++zzOff;
+ }
+ return (uint)zc;
+ }
+
+ public static ulong Mul33Add(uint w, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ Debug.Assert(w >> 31 == 0);
+
+ ulong c = 0, wVal = w;
+ ulong x0 = x[xOff + 0];
+ c += wVal * x0 + y[yOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ ulong x1 = x[xOff + 1];
+ c += wVal * x1 + x0 + y[yOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ ulong x2 = x[xOff + 2];
+ c += wVal * x2 + x1 + y[yOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ ulong x3 = x[xOff + 3];
+ c += wVal * x3 + x2 + y[yOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += x3;
+ return c;
+ }
+
+ public static uint MulWordAddExt(uint x, uint[] yy, int yyOff, uint[] zz, int zzOff)
+ {
+ Debug.Assert(yyOff <= 4);
+ Debug.Assert(zzOff <= 4);
+
+ ulong c = 0, xVal = x;
+ c += xVal * yy[yyOff + 0] + zz[zzOff + 0];
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += xVal * yy[yyOff + 1] + zz[zzOff + 1];
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += xVal * yy[yyOff + 2] + zz[zzOff + 2];
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += xVal * yy[yyOff + 3] + zz[zzOff + 3];
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint Mul33DWordAdd(uint x, ulong y, uint[] z, int zOff)
+ {
+ Debug.Assert(x >> 31 == 0);
+ Debug.Assert(zOff <= 0);
+ ulong c = 0, xVal = x;
+ ulong y00 = y & M;
+ c += xVal * y00 + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ ulong y01 = y >> 32;
+ c += xVal * y01 + y00 + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += y01 + z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint Mul33WordAdd(uint x, uint y, uint[] z, int zOff)
+ {
+ Debug.Assert(x >> 31 == 0);
+ Debug.Assert(zOff <= 1);
+ ulong c = 0, yVal = y;
+ c += yVal * x + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += yVal + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(4, z, zOff, 3);
+ }
+
+ public static uint MulWordDwordAdd(uint x, ulong y, uint[] z, int zOff)
+ {
+ Debug.Assert(zOff <= 1);
+ ulong c = 0, xVal = x;
+ c += xVal * y + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += xVal * (y >> 32) + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(4, z, zOff, 3);
+ }
+
+ public static uint MulWordsAdd(uint x, uint y, uint[] z, int zOff)
+ {
+ Debug.Assert(zOff <= 2);
+
+ ulong c = 0, xVal = x, yVal = y;
+ c += yVal * xVal + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(4, z, zOff, 2);
+ }
+
+ public static uint MulWord(uint x, uint[] y, uint[] z, int zOff)
+ {
+ ulong c = 0, xVal = x;
+ int i = 0;
+ do
+ {
+ c += xVal * y[i];
+ z[zOff + i] = (uint)c;
+ c >>= 32;
+ }
+ while (++i < 4);
+ return (uint)c;
+ }
+
+ public static void Square(uint[] x, uint[] zz)
+ {
+ ulong x_0 = x[0];
+ ulong zz_1;
+
+ uint c = 0, w;
+ {
+ int i = 3, j = 8;
+ do
+ {
+ ulong xVal = x[i--];
+ ulong p = xVal * xVal;
+ zz[--j] = (c << 31) | (uint)(p >> 33);
+ zz[--j] = (uint)(p >> 1);
+ c = (uint)p;
+ }
+ while (i > 0);
+
+ {
+ ulong p = x_0 * x_0;
+ zz_1 = (ulong)(c << 31) | (p >> 33);
+ zz[0] = (uint)p;
+ c = (uint)(p >> 32) & 1;
+ }
+ }
+
+ ulong x_1 = x[1];
+ ulong zz_2 = zz[2];
+
+ {
+ zz_1 += x_1 * x_0;
+ w = (uint)zz_1;
+ zz[1] = (w << 1) | c;
+ c = w >> 31;
+ zz_2 += zz_1 >> 32;
+ }
+
+ ulong x_2 = x[2];
+ ulong zz_3 = zz[3];
+ ulong zz_4 = zz[4];
+ {
+ zz_2 += x_2 * x_0;
+ w = (uint)zz_2;
+ zz[2] = (w << 1) | c;
+ c = w >> 31;
+ zz_3 += (zz_2 >> 32) + x_2 * x_1;
+ zz_4 += zz_3 >> 32;
+ zz_3 &= M;
+ }
+
+ ulong x_3 = x[3];
+ ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M;
+ {
+ zz_3 += x_3 * x_0;
+ w = (uint)zz_3;
+ zz[3] = (w << 1) | c;
+ c = w >> 31;
+ zz_4 += (zz_3 >> 32) + x_3 * x_1;
+ zz_5 += (zz_4 >> 32) + x_3 * x_2;
+ zz_6 += zz_5 >> 32;
+ }
+
+ w = (uint)zz_4;
+ zz[4] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_5;
+ zz[5] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_6;
+ zz[6] = (w << 1) | c;
+ c = w >> 31;
+ w = zz[7] + (uint)(zz_6 >> 32);
+ zz[7] = (w << 1) | c;
+ }
+
+ public static void Square(uint[] x, int xOff, uint[] zz, int zzOff)
+ {
+ ulong x_0 = x[xOff + 0];
+ ulong zz_1;
+
+ uint c = 0, w;
+ {
+ int i = 3, j = 8;
+ do
+ {
+ ulong xVal = x[xOff + i--];
+ ulong p = xVal * xVal;
+ zz[zzOff + --j] = (c << 31) | (uint)(p >> 33);
+ zz[zzOff + --j] = (uint)(p >> 1);
+ c = (uint)p;
+ }
+ while (i > 0);
+
+ {
+ ulong p = x_0 * x_0;
+ zz_1 = (ulong)(c << 31) | (p >> 33);
+ zz[zzOff + 0] = (uint)p;
+ c = (uint)(p >> 32) & 1;
+ }
+ }
+
+ ulong x_1 = x[xOff + 1];
+ ulong zz_2 = zz[zzOff + 2];
+
+ {
+ zz_1 += x_1 * x_0;
+ w = (uint)zz_1;
+ zz[zzOff + 1] = (w << 1) | c;
+ c = w >> 31;
+ zz_2 += zz_1 >> 32;
+ }
+
+ ulong x_2 = x[xOff + 2];
+ ulong zz_3 = zz[zzOff + 3];
+ ulong zz_4 = zz[zzOff + 4];
+ {
+ zz_2 += x_2 * x_0;
+ w = (uint)zz_2;
+ zz[zzOff + 2] = (w << 1) | c;
+ c = w >> 31;
+ zz_3 += (zz_2 >> 32) + x_2 * x_1;
+ zz_4 += zz_3 >> 32;
+ zz_3 &= M;
+ }
+
+ ulong x_3 = x[xOff + 3];
+ ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M;
+ {
+ zz_3 += x_3 * x_0;
+ w = (uint)zz_3;
+ zz[zzOff + 3] = (w << 1) | c;
+ c = w >> 31;
+ zz_4 += (zz_3 >> 32) + x_3 * x_1;
+ zz_5 += (zz_4 >> 32) + x_3 * x_2;
+ zz_6 += zz_5 >> 32;
+ }
+
+ w = (uint)zz_4;
+ zz[zzOff + 4] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_5;
+ zz[zzOff + 5] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_6;
+ zz[zzOff + 6] = (w << 1) | c;
+ c = w >> 31;
+ w = zz[zzOff + 7] + (uint)(zz_6 >> 32);
+ zz[zzOff + 7] = (w << 1) | c;
+ }
+
+ public static int Sub(uint[] x, uint[] y, uint[] z)
+ {
+ long c = 0;
+ c += (long)x[0] - y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)x[1] - y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)x[2] - y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)x[3] - y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int Sub(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ long c = 0;
+ c += (long)x[xOff + 0] - y[yOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 1] - y[yOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 2] - y[yOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 3] - y[yOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubBothFrom(uint[] x, uint[] y, uint[] z)
+ {
+ long c = 0;
+ c += (long)z[0] - x[0] - y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)z[1] - x[1] - y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)z[2] - x[2] - y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)z[3] - x[3] - y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubFrom(uint[] x, uint[] z)
+ {
+ long c = 0;
+ c += (long)z[0] - x[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)z[1] - x[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)z[2] - x[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)z[3] - x[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubFrom(uint[] x, int xOff, uint[] z, int zOff)
+ {
+ long c = 0;
+ c += (long)z[zOff + 0] - x[xOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 1] - x[xOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 2] - x[xOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 3] - x[xOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static BigInteger ToBigInteger(uint[] x)
+ {
+ byte[] bs = new byte[16];
+ for (int i = 0; i < 4; ++i)
+ {
+ uint x_i = x[i];
+ if (x_i != 0)
+ {
+ Pack.UInt32_To_BE(x_i, bs, (3 - i) << 2);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+
+ public static BigInteger ToBigInteger64(ulong[] x)
+ {
+ byte[] bs = new byte[16];
+ for (int i = 0; i < 2; ++i)
+ {
+ ulong x_i = x[i];
+ if (x_i != 0UL)
+ {
+ Pack.UInt64_To_BE(x_i, bs, (1 - i) << 3);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+
+ public static void Zero(uint[] z)
+ {
+ z[0] = 0;
+ z[1] = 0;
+ z[2] = 0;
+ z[3] = 0;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/raw/Nat160.cs b/bc-sharp-crypto/src/math/raw/Nat160.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1fd00e57675059cf4458b15c26bf26c94307a460
--- /dev/null
+++ b/bc-sharp-crypto/src/math/raw/Nat160.cs
@@ -0,0 +1,874 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Nat160
+ {
+ private const ulong M = 0xFFFFFFFFUL;
+
+ public static uint Add(uint[] x, uint[] y, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[4] + y[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddBothTo(uint[] x, uint[] y, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + y[0] + z[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + y[1] + z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + y[2] + z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + y[3] + z[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[4] + y[4] + z[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddTo(uint[] x, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + z[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + z[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[4] + z[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddTo(uint[] x, int xOff, uint[] z, int zOff, uint cIn)
+ {
+ ulong c = cIn;
+ c += (ulong)x[xOff + 0] + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 1] + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 2] + z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 3] + z[zOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 4] + z[zOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 5] + z[zOff + 5];
+ return (uint)c;
+ }
+
+ public static uint AddToEachOther(uint[] u, int uOff, uint[] v, int vOff)
+ {
+ ulong c = 0;
+ c += (ulong)u[uOff + 0] + v[vOff + 0];
+ u[uOff + 0] = (uint)c;
+ v[vOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 1] + v[vOff + 1];
+ u[uOff + 1] = (uint)c;
+ v[vOff + 1] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 2] + v[vOff + 2];
+ u[uOff + 2] = (uint)c;
+ v[vOff + 2] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 3] + v[vOff + 3];
+ u[uOff + 3] = (uint)c;
+ v[vOff + 3] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 4] + v[vOff + 4];
+ u[uOff + 4] = (uint)c;
+ v[vOff + 4] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static void Copy(uint[] x, uint[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ z[4] = x[4];
+ }
+
+ public static uint[] Create()
+ {
+ return new uint[5];
+ }
+
+ public static uint[] CreateExt()
+ {
+ return new uint[10];
+ }
+
+ public static bool Diff(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ bool pos = Gte(x, xOff, y, yOff);
+ if (pos)
+ {
+ Sub(x, xOff, y, yOff, z, zOff);
+ }
+ else
+ {
+ Sub(y, yOff, x, xOff, z, zOff);
+ }
+ return pos;
+ }
+
+ public static bool Eq(uint[] x, uint[] y)
+ {
+ for (int i = 4; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ return false;
+ }
+ return true;
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > 160)
+ throw new ArgumentException();
+
+ uint[] z = Create();
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (uint)x.IntValue;
+ x = x.ShiftRight(32);
+ }
+ return z;
+ }
+
+ public static uint GetBit(uint[] x, int bit)
+ {
+ if (bit == 0)
+ {
+ return x[0] & 1;
+ }
+ int w = bit >> 5;
+ if (w < 0 || w >= 5)
+ {
+ return 0;
+ }
+ int b = bit & 31;
+ return (x[w] >> b) & 1;
+ }
+
+ public static bool Gte(uint[] x, uint[] y)
+ {
+ for (int i = 4; i >= 0; --i)
+ {
+ uint x_i = x[i], y_i = y[i];
+ if (x_i < y_i)
+ return false;
+ if (x_i > y_i)
+ return true;
+ }
+ return true;
+ }
+
+ public static bool Gte(uint[] x, int xOff, uint[] y, int yOff)
+ {
+ for (int i = 4; i >= 0; --i)
+ {
+ uint x_i = x[xOff + i], y_i = y[yOff + i];
+ if (x_i < y_i)
+ return false;
+ if (x_i > y_i)
+ return true;
+ }
+ return true;
+ }
+
+ public static bool IsOne(uint[] x)
+ {
+ if (x[0] != 1)
+ {
+ return false;
+ }
+ for (int i = 1; i < 5; ++i)
+ {
+ if (x[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsZero(uint[] x)
+ {
+ for (int i = 0; i < 5; ++i)
+ {
+ if (x[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static void Mul(uint[] x, uint[] y, uint[] zz)
+ {
+ ulong y_0 = y[0];
+ ulong y_1 = y[1];
+ ulong y_2 = y[2];
+ ulong y_3 = y[3];
+ ulong y_4 = y[4];
+
+ {
+ ulong c = 0, x_0 = x[0];
+ c += x_0 * y_0;
+ zz[0] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_1;
+ zz[1] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_2;
+ zz[2] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_3;
+ zz[3] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_4;
+ zz[4] = (uint)c;
+ c >>= 32;
+ zz[5] = (uint)c;
+ }
+
+ for (int i = 1; i < 5; ++i)
+ {
+ ulong c = 0, x_i = x[i];
+ c += x_i * y_0 + zz[i + 0];
+ zz[i + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[i + 1];
+ zz[i + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[i + 2];
+ zz[i + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[i + 3];
+ zz[i + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[i + 4];
+ zz[i + 4] = (uint)c;
+ c >>= 32;
+ zz[i + 5] = (uint)c;
+ }
+ }
+
+ public static void Mul(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+ {
+ ulong y_0 = y[yOff + 0];
+ ulong y_1 = y[yOff + 1];
+ ulong y_2 = y[yOff + 2];
+ ulong y_3 = y[yOff + 3];
+ ulong y_4 = y[yOff + 4];
+
+ {
+ ulong c = 0, x_0 = x[xOff + 0];
+ c += x_0 * y_0;
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_1;
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_2;
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_3;
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_4;
+ zz[zzOff + 4] = (uint)c;
+ c >>= 32;
+ zz[zzOff + 5] = (uint)c;
+ }
+
+ for (int i = 1; i < 5; ++i)
+ {
+ ++zzOff;
+ ulong c = 0, x_i = x[xOff + i];
+ c += x_i * y_0 + zz[zzOff + 0];
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[zzOff + 1];
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[zzOff + 2];
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[zzOff + 3];
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[zzOff + 4];
+ zz[zzOff + 4] = (uint)c;
+ c >>= 32;
+ zz[zzOff + 5] = (uint)c;
+ }
+ }
+
+ public static uint MulAddTo(uint[] x, uint[] y, uint[] zz)
+ {
+ ulong y_0 = y[0];
+ ulong y_1 = y[1];
+ ulong y_2 = y[2];
+ ulong y_3 = y[3];
+ ulong y_4 = y[4];
+
+ ulong zc = 0;
+ for (int i = 0; i < 5; ++i)
+ {
+ ulong c = 0, x_i = x[i];
+ c += x_i * y_0 + zz[i + 0];
+ zz[i + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[i + 1];
+ zz[i + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[i + 2];
+ zz[i + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[i + 3];
+ zz[i + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[i + 4];
+ zz[i + 4] = (uint)c;
+ c >>= 32;
+ c += zc + zz[i + 5];
+ zz[i + 5] = (uint)c;
+ zc = c >> 32;
+ }
+ return (uint)zc;
+ }
+
+ public static uint MulAddTo(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+ {
+ ulong y_0 = y[yOff + 0];
+ ulong y_1 = y[yOff + 1];
+ ulong y_2 = y[yOff + 2];
+ ulong y_3 = y[yOff + 3];
+ ulong y_4 = y[yOff + 4];
+
+ ulong zc = 0;
+ for (int i = 0; i < 5; ++i)
+ {
+ ulong c = 0, x_i = x[xOff + i];
+ c += x_i * y_0 + zz[zzOff + 0];
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[zzOff + 1];
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[zzOff + 2];
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[zzOff + 3];
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[zzOff + 4];
+ zz[zzOff + 4] = (uint)c;
+ c >>= 32;
+ c += zc + zz[zzOff + 5];
+ zz[zzOff + 5] = (uint)c;
+ zc = c >> 32;
+ ++zzOff;
+ }
+ return (uint)zc;
+ }
+
+ public static ulong Mul33Add(uint w, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ Debug.Assert(w >> 31 == 0);
+
+ ulong c = 0, wVal = w;
+ ulong x0 = x[xOff + 0];
+ c += wVal * x0 + y[yOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ ulong x1 = x[xOff + 1];
+ c += wVal * x1 + x0 + y[yOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ ulong x2 = x[xOff + 2];
+ c += wVal * x2 + x1 + y[yOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ ulong x3 = x[xOff + 3];
+ c += wVal * x3 + x2 + y[yOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ ulong x4 = x[xOff + 4];
+ c += wVal * x4 + x3 + y[yOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ c += x4;
+ return c;
+ }
+
+ public static uint MulWordAddExt(uint x, uint[] yy, int yyOff, uint[] zz, int zzOff)
+ {
+ Debug.Assert(yyOff <= 5);
+ Debug.Assert(zzOff <= 5);
+
+ ulong c = 0, xVal = x;
+ c += xVal * yy[yyOff + 0] + zz[zzOff + 0];
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += xVal * yy[yyOff + 1] + zz[zzOff + 1];
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += xVal * yy[yyOff + 2] + zz[zzOff + 2];
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += xVal * yy[yyOff + 3] + zz[zzOff + 3];
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += xVal * yy[yyOff + 4] + zz[zzOff + 4];
+ zz[zzOff + 4] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint Mul33DWordAdd(uint x, ulong y, uint[] z, int zOff)
+ {
+ Debug.Assert(x >> 31 == 0);
+ Debug.Assert(zOff <= 1);
+ ulong c = 0, xVal = x;
+ ulong y00 = y & M;
+ c += xVal * y00 + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ ulong y01 = y >> 32;
+ c += xVal * y01 + y00 + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += y01 + z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(5, z, zOff, 4);
+ }
+
+ public static uint Mul33WordAdd(uint x, uint y, uint[] z, int zOff)
+ {
+ Debug.Assert(x >> 31 == 0);
+ Debug.Assert(zOff <= 2);
+ ulong c = 0, yVal = y;
+ c += yVal * x + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += yVal + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(5, z, zOff, 3);
+ }
+
+ public static uint MulWordDwordAdd(uint x, ulong y, uint[] z, int zOff)
+ {
+ Debug.Assert(zOff <= 2);
+ ulong c = 0, xVal = x;
+ c += xVal * y + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += xVal * (y >> 32) + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(5, z, zOff, 3);
+ }
+
+ public static uint MulWordsAdd(uint x, uint y, uint[] z, int zOff)
+ {
+ Debug.Assert(zOff <= 3);
+
+ ulong c = 0, xVal = x, yVal = y;
+ c += yVal * xVal + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(5, z, zOff, 2);
+ }
+
+ public static uint MulWord(uint x, uint[] y, uint[] z, int zOff)
+ {
+ ulong c = 0, xVal = x;
+ int i = 0;
+ do
+ {
+ c += xVal * y[i];
+ z[zOff + i] = (uint)c;
+ c >>= 32;
+ }
+ while (++i < 5);
+ return (uint)c;
+ }
+
+ public static void Square(uint[] x, uint[] zz)
+ {
+ ulong x_0 = x[0];
+ ulong zz_1;
+
+ uint c = 0, w;
+ {
+ int i = 4, j = 10;
+ do
+ {
+ ulong xVal = x[i--];
+ ulong p = xVal * xVal;
+ zz[--j] = (c << 31) | (uint)(p >> 33);
+ zz[--j] = (uint)(p >> 1);
+ c = (uint)p;
+ }
+ while (i > 0);
+
+ {
+ ulong p = x_0 * x_0;
+ zz_1 = (ulong)(c << 31) | (p >> 33);
+ zz[0] = (uint)p;
+ c = (uint)(p >> 32) & 1;
+ }
+ }
+
+ ulong x_1 = x[1];
+ ulong zz_2 = zz[2];
+
+ {
+ zz_1 += x_1 * x_0;
+ w = (uint)zz_1;
+ zz[1] = (w << 1) | c;
+ c = w >> 31;
+ zz_2 += zz_1 >> 32;
+ }
+
+ ulong x_2 = x[2];
+ ulong zz_3 = zz[3];
+ ulong zz_4 = zz[4];
+ {
+ zz_2 += x_2 * x_0;
+ w = (uint)zz_2;
+ zz[2] = (w << 1) | c;
+ c = w >> 31;
+ zz_3 += (zz_2 >> 32) + x_2 * x_1;
+ zz_4 += zz_3 >> 32;
+ zz_3 &= M;
+ }
+
+ ulong x_3 = x[3];
+ ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M;
+ {
+ zz_3 += x_3 * x_0;
+ w = (uint)zz_3;
+ zz[3] = (w << 1) | c;
+ c = w >> 31;
+ zz_4 += (zz_3 >> 32) + x_3 * x_1;
+ zz_5 += (zz_4 >> 32) + x_3 * x_2;
+ zz_4 &= M;
+ zz_6 += zz_5 >> 32;
+ zz_5 &= M;
+ }
+
+ ulong x_4 = x[4];
+ ulong zz_7 = zz[7] + (zz_6 >> 32); zz_6 &= M;
+ ulong zz_8 = zz[8] + (zz_7 >> 32); zz_7 &= M;
+ {
+ zz_4 += x_4 * x_0;
+ w = (uint)zz_4;
+ zz[4] = (w << 1) | c;
+ c = w >> 31;
+ zz_5 += (zz_4 >> 32) + x_4 * x_1;
+ zz_6 += (zz_5 >> 32) + x_4 * x_2;
+ zz_7 += (zz_6 >> 32) + x_4 * x_3;
+ zz_8 += zz_7 >> 32;
+ }
+
+ w = (uint)zz_5;
+ zz[5] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_6;
+ zz[6] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_7;
+ zz[7] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_8;
+ zz[8] = (w << 1) | c;
+ c = w >> 31;
+ w = zz[9] + (uint)(zz_8 >> 32);
+ zz[9] = (w << 1) | c;
+ }
+
+ public static void Square(uint[] x, int xOff, uint[] zz, int zzOff)
+ {
+ ulong x_0 = x[xOff + 0];
+ ulong zz_1;
+
+ uint c = 0, w;
+ {
+ int i = 4, j = 10;
+ do
+ {
+ ulong xVal = x[xOff + i--];
+ ulong p = xVal * xVal;
+ zz[zzOff + --j] = (c << 31) | (uint)(p >> 33);
+ zz[zzOff + --j] = (uint)(p >> 1);
+ c = (uint)p;
+ }
+ while (i > 0);
+
+ {
+ ulong p = x_0 * x_0;
+ zz_1 = (ulong)(c << 31) | (p >> 33);
+ zz[zzOff + 0] = (uint)p;
+ c = (uint)(p >> 32) & 1;
+ }
+ }
+
+ ulong x_1 = x[xOff + 1];
+ ulong zz_2 = zz[zzOff + 2];
+
+ {
+ zz_1 += x_1 * x_0;
+ w = (uint)zz_1;
+ zz[zzOff + 1] = (w << 1) | c;
+ c = w >> 31;
+ zz_2 += zz_1 >> 32;
+ }
+
+ ulong x_2 = x[xOff + 2];
+ ulong zz_3 = zz[zzOff + 3];
+ ulong zz_4 = zz[zzOff + 4];
+ {
+ zz_2 += x_2 * x_0;
+ w = (uint)zz_2;
+ zz[zzOff + 2] = (w << 1) | c;
+ c = w >> 31;
+ zz_3 += (zz_2 >> 32) + x_2 * x_1;
+ zz_4 += zz_3 >> 32;
+ zz_3 &= M;
+ }
+
+ ulong x_3 = x[xOff + 3];
+ ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M;
+ {
+ zz_3 += x_3 * x_0;
+ w = (uint)zz_3;
+ zz[zzOff + 3] = (w << 1) | c;
+ c = w >> 31;
+ zz_4 += (zz_3 >> 32) + x_3 * x_1;
+ zz_5 += (zz_4 >> 32) + x_3 * x_2;
+ zz_4 &= M;
+ zz_6 += zz_5 >> 32;
+ zz_5 &= M;
+ }
+
+ ulong x_4 = x[xOff + 4];
+ ulong zz_7 = zz[zzOff + 7] + (zz_6 >> 32); zz_6 &= M;
+ ulong zz_8 = zz[zzOff + 8] + (zz_7 >> 32); zz_7 &= M;
+ {
+ zz_4 += x_4 * x_0;
+ w = (uint)zz_4;
+ zz[zzOff + 4] = (w << 1) | c;
+ c = w >> 31;
+ zz_5 += (zz_4 >> 32) + x_4 * x_1;
+ zz_6 += (zz_5 >> 32) + x_4 * x_2;
+ zz_7 += (zz_6 >> 32) + x_4 * x_3;
+ zz_8 += zz_7 >> 32;
+ }
+
+ w = (uint)zz_5;
+ zz[zzOff + 5] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_6;
+ zz[zzOff + 6] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_7;
+ zz[zzOff + 7] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_8;
+ zz[zzOff + 8] = (w << 1) | c;
+ c = w >> 31;
+ w = zz[zzOff + 9] + (uint)(zz_8 >> 32);
+ zz[zzOff + 9] = (w << 1) | c;
+ }
+
+ public static int Sub(uint[] x, uint[] y, uint[] z)
+ {
+ long c = 0;
+ c += (long)x[0] - y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)x[1] - y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)x[2] - y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)x[3] - y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (long)x[4] - y[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int Sub(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ long c = 0;
+ c += (long)x[xOff + 0] - y[yOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 1] - y[yOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 2] - y[yOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 3] - y[yOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 4] - y[yOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubBothFrom(uint[] x, uint[] y, uint[] z)
+ {
+ long c = 0;
+ c += (long)z[0] - x[0] - y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)z[1] - x[1] - y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)z[2] - x[2] - y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)z[3] - x[3] - y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (long)z[4] - x[4] - y[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubFrom(uint[] x, uint[] z)
+ {
+ long c = 0;
+ c += (long)z[0] - x[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)z[1] - x[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)z[2] - x[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)z[3] - x[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (long)z[4] - x[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubFrom(uint[] x, int xOff, uint[] z, int zOff)
+ {
+ long c = 0;
+ c += (long)z[zOff + 0] - x[xOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 1] - x[xOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 2] - x[xOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 3] - x[xOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 4] - x[xOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static BigInteger ToBigInteger(uint[] x)
+ {
+ byte[] bs = new byte[20];
+ for (int i = 0; i < 5; ++i)
+ {
+ uint x_i = x[i];
+ if (x_i != 0)
+ {
+ Pack.UInt32_To_BE(x_i, bs, (4 - i) << 2);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+
+ public static void Zero(uint[] z)
+ {
+ z[0] = 0;
+ z[1] = 0;
+ z[2] = 0;
+ z[3] = 0;
+ z[4] = 0;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/raw/Nat192.cs b/bc-sharp-crypto/src/math/raw/Nat192.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3099bafabbb10db25b366df069fe1abfcde30126
--- /dev/null
+++ b/bc-sharp-crypto/src/math/raw/Nat192.cs
@@ -0,0 +1,1048 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Nat192
+ {
+ private const ulong M = 0xFFFFFFFFUL;
+
+ public static uint Add(uint[] x, uint[] y, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[4] + y[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[5] + y[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddBothTo(uint[] x, uint[] y, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + y[0] + z[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + y[1] + z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + y[2] + z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + y[3] + z[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[4] + y[4] + z[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[5] + y[5] + z[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddTo(uint[] x, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + z[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + z[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[4] + z[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[5] + z[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddTo(uint[] x, int xOff, uint[] z, int zOff, uint cIn)
+ {
+ ulong c = cIn;
+ c += (ulong)x[xOff + 0] + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 1] + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 2] + z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 3] + z[zOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 4] + z[zOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 5] + z[zOff + 5];
+ z[zOff + 5] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddToEachOther(uint[] u, int uOff, uint[] v, int vOff)
+ {
+ ulong c = 0;
+ c += (ulong)u[uOff + 0] + v[vOff + 0];
+ u[uOff + 0] = (uint)c;
+ v[vOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 1] + v[vOff + 1];
+ u[uOff + 1] = (uint)c;
+ v[vOff + 1] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 2] + v[vOff + 2];
+ u[uOff + 2] = (uint)c;
+ v[vOff + 2] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 3] + v[vOff + 3];
+ u[uOff + 3] = (uint)c;
+ v[vOff + 3] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 4] + v[vOff + 4];
+ u[uOff + 4] = (uint)c;
+ v[vOff + 4] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 5] + v[vOff + 5];
+ u[uOff + 5] = (uint)c;
+ v[vOff + 5] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static void Copy(uint[] x, uint[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ z[4] = x[4];
+ z[5] = x[5];
+ }
+
+ public static void Copy64(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ z[2] = x[2];
+ }
+
+ public static uint[] Create()
+ {
+ return new uint[6];
+ }
+
+ public static ulong[] Create64()
+ {
+ return new ulong[3];
+ }
+
+ public static uint[] CreateExt()
+ {
+ return new uint[12];
+ }
+
+ public static ulong[] CreateExt64()
+ {
+ return new ulong[6];
+ }
+
+ public static bool Diff(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ bool pos = Gte(x, xOff, y, yOff);
+ if (pos)
+ {
+ Sub(x, xOff, y, yOff, z, zOff);
+ }
+ else
+ {
+ Sub(y, yOff, x, xOff, z, zOff);
+ }
+ return pos;
+ }
+
+ public static bool Eq(uint[] x, uint[] y)
+ {
+ for (int i = 5; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ return false;
+ }
+ return true;
+ }
+
+ public static bool Eq64(ulong[] x, ulong[] y)
+ {
+ for (int i = 2; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > 192)
+ throw new ArgumentException();
+
+ uint[] z = Create();
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (uint)x.IntValue;
+ x = x.ShiftRight(32);
+ }
+ return z;
+ }
+
+ public static ulong[] FromBigInteger64(BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > 192)
+ throw new ArgumentException();
+
+ ulong[] z = Create64();
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (ulong)x.LongValue;
+ x = x.ShiftRight(64);
+ }
+ return z;
+ }
+
+ public static uint GetBit(uint[] x, int bit)
+ {
+ if (bit == 0)
+ {
+ return x[0] & 1;
+ }
+ int w = bit >> 5;
+ if (w < 0 || w >= 6)
+ {
+ return 0;
+ }
+ int b = bit & 31;
+ return (x[w] >> b) & 1;
+ }
+
+ public static bool Gte(uint[] x, uint[] y)
+ {
+ for (int i = 5; i >= 0; --i)
+ {
+ uint x_i = x[i], y_i = y[i];
+ if (x_i < y_i)
+ return false;
+ if (x_i > y_i)
+ return true;
+ }
+ return true;
+ }
+
+ public static bool Gte(uint[] x, int xOff, uint[] y, int yOff)
+ {
+ for (int i = 5; i >= 0; --i)
+ {
+ uint x_i = x[xOff + i], y_i = y[yOff + i];
+ if (x_i < y_i)
+ return false;
+ if (x_i > y_i)
+ return true;
+ }
+ return true;
+ }
+
+ public static bool IsOne(uint[] x)
+ {
+ if (x[0] != 1)
+ {
+ return false;
+ }
+ for (int i = 1; i < 6; ++i)
+ {
+ if (x[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsOne64(ulong[] x)
+ {
+ if (x[0] != 1UL)
+ {
+ return false;
+ }
+ for (int i = 1; i < 3; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsZero(uint[] x)
+ {
+ for (int i = 0; i < 6; ++i)
+ {
+ if (x[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsZero64(ulong[] x)
+ {
+ for (int i = 0; i < 3; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static void Mul(uint[] x, uint[] y, uint[] zz)
+ {
+ ulong y_0 = y[0];
+ ulong y_1 = y[1];
+ ulong y_2 = y[2];
+ ulong y_3 = y[3];
+ ulong y_4 = y[4];
+ ulong y_5 = y[5];
+
+ {
+ ulong c = 0, x_0 = x[0];
+ c += x_0 * y_0;
+ zz[0] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_1;
+ zz[1] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_2;
+ zz[2] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_3;
+ zz[3] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_4;
+ zz[4] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_5;
+ zz[5] = (uint)c;
+ c >>= 32;
+ zz[6] = (uint)c;
+ }
+
+ for (int i = 1; i < 6; ++i)
+ {
+ ulong c = 0, x_i = x[i];
+ c += x_i * y_0 + zz[i + 0];
+ zz[i + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[i + 1];
+ zz[i + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[i + 2];
+ zz[i + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[i + 3];
+ zz[i + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[i + 4];
+ zz[i + 4] = (uint)c;
+ c >>= 32;
+ c += x_i * y_5 + zz[i + 5];
+ zz[i + 5] = (uint)c;
+ c >>= 32;
+ zz[i + 6] = (uint)c;
+ }
+ }
+
+ public static void Mul(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+ {
+ ulong y_0 = y[yOff + 0];
+ ulong y_1 = y[yOff + 1];
+ ulong y_2 = y[yOff + 2];
+ ulong y_3 = y[yOff + 3];
+ ulong y_4 = y[yOff + 4];
+ ulong y_5 = y[yOff + 5];
+
+ {
+ ulong c = 0, x_0 = x[xOff + 0];
+ c += x_0 * y_0;
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_1;
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_2;
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_3;
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_4;
+ zz[zzOff + 4] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_5;
+ zz[zzOff + 5] = (uint)c;
+ c >>= 32;
+ zz[zzOff + 6] = (uint)c;
+ }
+
+ for (int i = 1; i < 6; ++i)
+ {
+ ++zzOff;
+ ulong c = 0, x_i = x[xOff + i];
+ c += x_i * y_0 + zz[zzOff + 0];
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[zzOff + 1];
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[zzOff + 2];
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[zzOff + 3];
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[zzOff + 4];
+ zz[zzOff + 4] = (uint)c;
+ c >>= 32;
+ c += x_i * y_5 + zz[zzOff + 5];
+ zz[zzOff + 5] = (uint)c;
+ c >>= 32;
+ zz[zzOff + 6] = (uint)c;
+ }
+ }
+
+ public static uint MulAddTo(uint[] x, uint[] y, uint[] zz)
+ {
+ ulong y_0 = y[0];
+ ulong y_1 = y[1];
+ ulong y_2 = y[2];
+ ulong y_3 = y[3];
+ ulong y_4 = y[4];
+ ulong y_5 = y[5];
+
+ ulong zc = 0;
+ for (int i = 0; i < 6; ++i)
+ {
+ ulong c = 0, x_i = x[i];
+ c += x_i * y_0 + zz[i + 0];
+ zz[i + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[i + 1];
+ zz[i + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[i + 2];
+ zz[i + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[i + 3];
+ zz[i + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[i + 4];
+ zz[i + 4] = (uint)c;
+ c >>= 32;
+ c += x_i * y_5 + zz[i + 5];
+ zz[i + 5] = (uint)c;
+ c >>= 32;
+ c += zc + zz[i + 6];
+ zz[i + 6] = (uint)c;
+ zc = c >> 32;
+ }
+ return (uint)zc;
+ }
+
+ public static uint MulAddTo(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+ {
+ ulong y_0 = y[yOff + 0];
+ ulong y_1 = y[yOff + 1];
+ ulong y_2 = y[yOff + 2];
+ ulong y_3 = y[yOff + 3];
+ ulong y_4 = y[yOff + 4];
+ ulong y_5 = y[yOff + 5];
+
+ ulong zc = 0;
+ for (int i = 0; i < 6; ++i)
+ {
+ ulong c = 0, x_i = x[xOff + i];
+ c += x_i * y_0 + zz[zzOff + 0];
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[zzOff + 1];
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[zzOff + 2];
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[zzOff + 3];
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[zzOff + 4];
+ zz[zzOff + 4] = (uint)c;
+ c >>= 32;
+ c += x_i * y_5 + zz[zzOff + 5];
+ zz[zzOff + 5] = (uint)c;
+ c >>= 32;
+ c += zc + zz[zzOff + 6];
+ zz[zzOff + 6] = (uint)c;
+ zc = c >> 32;
+ ++zzOff;
+ }
+ return (uint)zc;
+ }
+
+ public static ulong Mul33Add(uint w, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ Debug.Assert(w >> 31 == 0);
+
+ ulong c = 0, wVal = w;
+ ulong x0 = x[xOff + 0];
+ c += wVal * x0 + y[yOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ ulong x1 = x[xOff + 1];
+ c += wVal * x1 + x0 + y[yOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ ulong x2 = x[xOff + 2];
+ c += wVal * x2 + x1 + y[yOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ ulong x3 = x[xOff + 3];
+ c += wVal * x3 + x2 + y[yOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ ulong x4 = x[xOff + 4];
+ c += wVal * x4 + x3 + y[yOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ ulong x5 = x[xOff + 5];
+ c += wVal * x5 + x4 + y[yOff + 5];
+ z[zOff + 5] = (uint)c;
+ c >>= 32;
+ c += x5;
+ return c;
+ }
+
+ public static uint MulWordAddExt(uint x, uint[] yy, int yyOff, uint[] zz, int zzOff)
+ {
+ Debug.Assert(yyOff <= 6);
+ Debug.Assert(zzOff <= 6);
+ ulong c = 0, xVal = x;
+ c += xVal * yy[yyOff + 0] + zz[zzOff + 0];
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += xVal * yy[yyOff + 1] + zz[zzOff + 1];
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += xVal * yy[yyOff + 2] + zz[zzOff + 2];
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += xVal * yy[yyOff + 3] + zz[zzOff + 3];
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += xVal * yy[yyOff + 4] + zz[zzOff + 4];
+ zz[zzOff + 4] = (uint)c;
+ c >>= 32;
+ c += xVal * yy[yyOff + 5] + zz[zzOff + 5];
+ zz[zzOff + 5] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint Mul33DWordAdd(uint x, ulong y, uint[] z, int zOff)
+ {
+ Debug.Assert(x >> 31 == 0);
+ Debug.Assert(zOff <= 2);
+ ulong c = 0, xVal = x;
+ ulong y00 = y & M;
+ c += xVal * y00 + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ ulong y01 = y >> 32;
+ c += xVal * y01 + y00 + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += y01 + z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(6, z, zOff, 4);
+ }
+
+ public static uint Mul33WordAdd(uint x, uint y, uint[] z, int zOff)
+ {
+ Debug.Assert(x >> 31 == 0);
+ Debug.Assert(zOff <=3);
+ ulong c = 0, yVal = y;
+ c += yVal * x + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += yVal + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(6, z, zOff, 3);
+ }
+
+ public static uint MulWordDwordAdd(uint x, ulong y, uint[] z, int zOff)
+ {
+ Debug.Assert(zOff <= 3);
+ ulong c = 0, xVal = x;
+ c += xVal * y + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += xVal * (y >> 32) + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(6, z, zOff, 3);
+ }
+
+ public static uint MulWord(uint x, uint[] y, uint[] z, int zOff)
+ {
+ ulong c = 0, xVal = x;
+ int i = 0;
+ do
+ {
+ c += xVal * y[i];
+ z[zOff + i] = (uint)c;
+ c >>= 32;
+ }
+ while (++i < 6);
+ return (uint)c;
+ }
+
+ public static void Square(uint[] x, uint[] zz)
+ {
+ ulong x_0 = x[0];
+ ulong zz_1;
+
+ uint c = 0, w;
+ {
+ int i = 5, j = 12;
+ do
+ {
+ ulong xVal = x[i--];
+ ulong p = xVal * xVal;
+ zz[--j] = (c << 31) | (uint)(p >> 33);
+ zz[--j] = (uint)(p >> 1);
+ c = (uint)p;
+ }
+ while (i > 0);
+
+ {
+ ulong p = x_0 * x_0;
+ zz_1 = (ulong)(c << 31) | (p >> 33);
+ zz[0] = (uint)p;
+ c = (uint)(p >> 32) & 1;
+ }
+ }
+
+ ulong x_1 = x[1];
+ ulong zz_2 = zz[2];
+
+ {
+ zz_1 += x_1 * x_0;
+ w = (uint)zz_1;
+ zz[1] = (w << 1) | c;
+ c = w >> 31;
+ zz_2 += zz_1 >> 32;
+ }
+
+ ulong x_2 = x[2];
+ ulong zz_3 = zz[3];
+ ulong zz_4 = zz[4];
+ {
+ zz_2 += x_2 * x_0;
+ w = (uint)zz_2;
+ zz[2] = (w << 1) | c;
+ c = w >> 31;
+ zz_3 += (zz_2 >> 32) + x_2 * x_1;
+ zz_4 += zz_3 >> 32;
+ zz_3 &= M;
+ }
+
+ ulong x_3 = x[3];
+ ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M;
+ {
+ zz_3 += x_3 * x_0;
+ w = (uint)zz_3;
+ zz[3] = (w << 1) | c;
+ c = w >> 31;
+ zz_4 += (zz_3 >> 32) + x_3 * x_1;
+ zz_5 += (zz_4 >> 32) + x_3 * x_2;
+ zz_4 &= M;
+ zz_6 += zz_5 >> 32;
+ zz_5 &= M;
+ }
+
+ ulong x_4 = x[4];
+ ulong zz_7 = zz[7] + (zz_6 >> 32); zz_6 &= M;
+ ulong zz_8 = zz[8] + (zz_7 >> 32); zz_7 &= M;
+ {
+ zz_4 += x_4 * x_0;
+ w = (uint)zz_4;
+ zz[4] = (w << 1) | c;
+ c = w >> 31;
+ zz_5 += (zz_4 >> 32) + x_4 * x_1;
+ zz_6 += (zz_5 >> 32) + x_4 * x_2;
+ zz_5 &= M;
+ zz_7 += (zz_6 >> 32) + x_4 * x_3;
+ zz_6 &= M;
+ zz_8 += zz_7 >> 32;
+ zz_7 &= M;
+ }
+
+ ulong x_5 = x[5];
+ ulong zz_9 = zz[9] + (zz_8 >> 32); zz_8 &= M;
+ ulong zz_10 = zz[10] + (zz_9 >> 32); zz_9 &= M;
+ {
+ zz_5 += x_5 * x_0;
+ w = (uint)zz_5;
+ zz[5] = (w << 1) | c;
+ c = w >> 31;
+ zz_6 += (zz_5 >> 32) + x_5 * x_1;
+ zz_7 += (zz_6 >> 32) + x_5 * x_2;
+ zz_8 += (zz_7 >> 32) + x_5 * x_3;
+ zz_9 += (zz_8 >> 32) + x_5 * x_4;
+ zz_10 += zz_9 >> 32;
+ }
+
+ w = (uint)zz_6;
+ zz[6] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_7;
+ zz[7] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_8;
+ zz[8] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_9;
+ zz[9] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_10;
+ zz[10] = (w << 1) | c;
+ c = w >> 31;
+ w = zz[11] + (uint)(zz_10 >> 32);
+ zz[11] = (w << 1) | c;
+ }
+
+ public static void Square(uint[] x, int xOff, uint[] zz, int zzOff)
+ {
+ ulong x_0 = x[xOff + 0];
+ ulong zz_1;
+
+ uint c = 0, w;
+ {
+ int i = 5, j = 12;
+ do
+ {
+ ulong xVal = x[xOff + i--];
+ ulong p = xVal * xVal;
+ zz[zzOff + --j] = (c << 31) | (uint)(p >> 33);
+ zz[zzOff + --j] = (uint)(p >> 1);
+ c = (uint)p;
+ }
+ while (i > 0);
+
+ {
+ ulong p = x_0 * x_0;
+ zz_1 = (ulong)(c << 31) | (p >> 33);
+ zz[zzOff + 0] = (uint)p;
+ c = (uint)(p >> 32) & 1;
+ }
+ }
+
+ ulong x_1 = x[xOff + 1];
+ ulong zz_2 = zz[zzOff + 2];
+
+ {
+ zz_1 += x_1 * x_0;
+ w = (uint)zz_1;
+ zz[zzOff + 1] = (w << 1) | c;
+ c = w >> 31;
+ zz_2 += zz_1 >> 32;
+ }
+
+ ulong x_2 = x[xOff + 2];
+ ulong zz_3 = zz[zzOff + 3];
+ ulong zz_4 = zz[zzOff + 4];
+ {
+ zz_2 += x_2 * x_0;
+ w = (uint)zz_2;
+ zz[zzOff + 2] = (w << 1) | c;
+ c = w >> 31;
+ zz_3 += (zz_2 >> 32) + x_2 * x_1;
+ zz_4 += zz_3 >> 32;
+ zz_3 &= M;
+ }
+
+ ulong x_3 = x[xOff + 3];
+ ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M;
+ {
+ zz_3 += x_3 * x_0;
+ w = (uint)zz_3;
+ zz[zzOff + 3] = (w << 1) | c;
+ c = w >> 31;
+ zz_4 += (zz_3 >> 32) + x_3 * x_1;
+ zz_5 += (zz_4 >> 32) + x_3 * x_2;
+ zz_4 &= M;
+ zz_6 += zz_5 >> 32;
+ zz_5 &= M;
+ }
+
+ ulong x_4 = x[xOff + 4];
+ ulong zz_7 = zz[zzOff + 7] + (zz_6 >> 32); zz_6 &= M;
+ ulong zz_8 = zz[zzOff + 8] + (zz_7 >> 32); zz_7 &= M;
+ {
+ zz_4 += x_4 * x_0;
+ w = (uint)zz_4;
+ zz[zzOff + 4] = (w << 1) | c;
+ c = w >> 31;
+ zz_5 += (zz_4 >> 32) + x_4 * x_1;
+ zz_6 += (zz_5 >> 32) + x_4 * x_2;
+ zz_5 &= M;
+ zz_7 += (zz_6 >> 32) + x_4 * x_3;
+ zz_6 &= M;
+ zz_8 += zz_7 >> 32;
+ zz_7 &= M;
+ }
+
+ ulong x_5 = x[xOff + 5];
+ ulong zz_9 = zz[zzOff + 9] + (zz_8 >> 32); zz_8 &= M;
+ ulong zz_10 = zz[zzOff + 10] + (zz_9 >> 32); zz_9 &= M;
+ {
+ zz_5 += x_5 * x_0;
+ w = (uint)zz_5;
+ zz[zzOff + 5] = (w << 1) | c;
+ c = w >> 31;
+ zz_6 += (zz_5 >> 32) + x_5 * x_1;
+ zz_7 += (zz_6 >> 32) + x_5 * x_2;
+ zz_8 += (zz_7 >> 32) + x_5 * x_3;
+ zz_9 += (zz_8 >> 32) + x_5 * x_4;
+ zz_10 += zz_9 >> 32;
+ }
+
+ w = (uint)zz_6;
+ zz[zzOff + 6] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_7;
+ zz[zzOff + 7] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_8;
+ zz[zzOff + 8] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_9;
+ zz[zzOff + 9] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_10;
+ zz[zzOff + 10] = (w << 1) | c;
+ c = w >> 31;
+ w = zz[zzOff + 11] + (uint)(zz_10 >> 32);
+ zz[zzOff + 11] = (w << 1) | c;
+ }
+
+ public static int Sub(uint[] x, uint[] y, uint[] z)
+ {
+ long c = 0;
+ c += (long)x[0] - y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)x[1] - y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)x[2] - y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)x[3] - y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (long)x[4] - y[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (long)x[5] - y[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int Sub(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ long c = 0;
+ c += (long)x[xOff + 0] - y[yOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 1] - y[yOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 2] - y[yOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 3] - y[yOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 4] - y[yOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 5] - y[yOff + 5];
+ z[zOff + 5] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubBothFrom(uint[] x, uint[] y, uint[] z)
+ {
+ long c = 0;
+ c += (long)z[0] - x[0] - y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)z[1] - x[1] - y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)z[2] - x[2] - y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)z[3] - x[3] - y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (long)z[4] - x[4] - y[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (long)z[5] - x[5] - y[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubFrom(uint[] x, uint[] z)
+ {
+ long c = 0;
+ c += (long)z[0] - x[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)z[1] - x[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)z[2] - x[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)z[3] - x[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (long)z[4] - x[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (long)z[5] - x[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubFrom(uint[] x, int xOff, uint[] z, int zOff)
+ {
+ long c = 0;
+ c += (long)z[zOff + 0] - x[xOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 1] - x[xOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 2] - x[xOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 3] - x[xOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 4] - x[xOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 5] - x[xOff + 5];
+ z[zOff + 5] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static BigInteger ToBigInteger(uint[] x)
+ {
+ byte[] bs = new byte[24];
+ for (int i = 0; i < 6; ++i)
+ {
+ uint x_i = x[i];
+ if (x_i != 0)
+ {
+ Pack.UInt32_To_BE(x_i, bs, (5 - i) << 2);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+
+ public static BigInteger ToBigInteger64(ulong[] x)
+ {
+ byte[] bs = new byte[24];
+ for (int i = 0; i < 3; ++i)
+ {
+ ulong x_i = x[i];
+ if (x_i != 0L)
+ {
+ Pack.UInt64_To_BE(x_i, bs, (2 - i) << 3);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+
+ public static void Zero(uint[] z)
+ {
+ z[0] = 0;
+ z[1] = 0;
+ z[2] = 0;
+ z[3] = 0;
+ z[4] = 0;
+ z[5] = 0;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/raw/Nat224.cs b/bc-sharp-crypto/src/math/raw/Nat224.cs
new file mode 100644
index 0000000000000000000000000000000000000000..978caf26571b31c8b0466f621bfbca2cf623606b
--- /dev/null
+++ b/bc-sharp-crypto/src/math/raw/Nat224.cs
@@ -0,0 +1,1176 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Nat224
+ {
+ private const ulong M = 0xFFFFFFFFUL;
+
+ public static uint Add(uint[] x, uint[] y, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[4] + y[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[5] + y[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[6] + y[6];
+ z[6] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint Add(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ ulong c = 0;
+ c += (ulong)x[xOff + 0] + y[yOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 1] + y[yOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 2] + y[yOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 3] + y[yOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 4] + y[yOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 5] + y[yOff + 5];
+ z[zOff + 5] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 6] + y[yOff + 6];
+ z[zOff + 6] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddBothTo(uint[] x, uint[] y, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + y[0] + z[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + y[1] + z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + y[2] + z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + y[3] + z[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[4] + y[4] + z[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[5] + y[5] + z[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[6] + y[6] + z[6];
+ z[6] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddBothTo(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ ulong c = 0;
+ c += (ulong)x[xOff + 0] + y[yOff + 0] + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 1] + y[yOff + 1] + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 2] + y[yOff + 2] + z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 3] + y[yOff + 3] + z[zOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 4] + y[yOff + 4] + z[zOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 5] + y[yOff + 5] + z[zOff + 5];
+ z[zOff + 5] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 6] + y[yOff + 6] + z[zOff + 6];
+ z[zOff + 6] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddTo(uint[] x, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + z[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + z[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[4] + z[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[5] + z[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[6] + z[6];
+ z[6] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddTo(uint[] x, int xOff, uint[] z, int zOff, uint cIn)
+ {
+ ulong c = cIn;
+ c += (ulong)x[xOff + 0] + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 1] + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 2] + z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 3] + z[zOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 4] + z[zOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 5] + z[zOff + 5];
+ z[zOff + 5] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 6] + z[zOff + 6];
+ z[zOff + 6] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddToEachOther(uint[] u, int uOff, uint[] v, int vOff)
+ {
+ ulong c = 0;
+ c += (ulong)u[uOff + 0] + v[vOff + 0];
+ u[uOff + 0] = (uint)c;
+ v[vOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 1] + v[vOff + 1];
+ u[uOff + 1] = (uint)c;
+ v[vOff + 1] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 2] + v[vOff + 2];
+ u[uOff + 2] = (uint)c;
+ v[vOff + 2] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 3] + v[vOff + 3];
+ u[uOff + 3] = (uint)c;
+ v[vOff + 3] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 4] + v[vOff + 4];
+ u[uOff + 4] = (uint)c;
+ v[vOff + 4] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 5] + v[vOff + 5];
+ u[uOff + 5] = (uint)c;
+ v[vOff + 5] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 6] + v[vOff + 6];
+ u[uOff + 6] = (uint)c;
+ v[vOff + 6] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static void Copy(uint[] x, uint[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ z[4] = x[4];
+ z[5] = x[5];
+ z[6] = x[6];
+ }
+
+ public static uint[] Create()
+ {
+ return new uint[7];
+ }
+
+ public static uint[] CreateExt()
+ {
+ return new uint[14];
+ }
+
+ public static bool Diff(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ bool pos = Gte(x, xOff, y, yOff);
+ if (pos)
+ {
+ Sub(x, xOff, y, yOff, z, zOff);
+ }
+ else
+ {
+ Sub(y, yOff, x, xOff, z, zOff);
+ }
+ return pos;
+ }
+
+ public static bool Eq(uint[] x, uint[] y)
+ {
+ for (int i = 6; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ return false;
+ }
+ return true;
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > 224)
+ throw new ArgumentException();
+
+ uint[] z = Create();
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (uint)x.IntValue;
+ x = x.ShiftRight(32);
+ }
+ return z;
+ }
+
+ public static uint GetBit(uint[] x, int bit)
+ {
+ if (bit == 0)
+ {
+ return x[0] & 1;
+ }
+ int w = bit >> 5;
+ if (w < 0 || w >= 7)
+ {
+ return 0;
+ }
+ int b = bit & 31;
+ return (x[w] >> b) & 1;
+ }
+
+ public static bool Gte(uint[] x, uint[] y)
+ {
+ for (int i = 6; i >= 0; --i)
+ {
+ uint x_i = x[i], y_i = y[i];
+ if (x_i < y_i)
+ return false;
+ if (x_i > y_i)
+ return true;
+ }
+ return true;
+ }
+
+ public static bool Gte(uint[] x, int xOff, uint[] y, int yOff)
+ {
+ for (int i = 6; i >= 0; --i)
+ {
+ uint x_i = x[xOff + i], y_i = y[yOff + i];
+ if (x_i < y_i)
+ return false;
+ if (x_i > y_i)
+ return true;
+ }
+ return true;
+ }
+
+ public static bool IsOne(uint[] x)
+ {
+ if (x[0] != 1)
+ {
+ return false;
+ }
+ for (int i = 1; i < 7; ++i)
+ {
+ if (x[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsZero(uint[] x)
+ {
+ for (int i = 0; i < 7; ++i)
+ {
+ if (x[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static void Mul(uint[] x, uint[] y, uint[] zz)
+ {
+ ulong y_0 = y[0];
+ ulong y_1 = y[1];
+ ulong y_2 = y[2];
+ ulong y_3 = y[3];
+ ulong y_4 = y[4];
+ ulong y_5 = y[5];
+ ulong y_6 = y[6];
+
+ {
+ ulong c = 0, x_0 = x[0];
+ c += x_0 * y_0;
+ zz[0] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_1;
+ zz[1] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_2;
+ zz[2] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_3;
+ zz[3] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_4;
+ zz[4] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_5;
+ zz[5] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_6;
+ zz[6] = (uint)c;
+ c >>= 32;
+ zz[7] = (uint)c;
+ }
+
+ for (int i = 1; i < 7; ++i)
+ {
+ ulong c = 0, x_i = x[i];
+ c += x_i * y_0 + zz[i + 0];
+ zz[i + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[i + 1];
+ zz[i + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[i + 2];
+ zz[i + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[i + 3];
+ zz[i + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[i + 4];
+ zz[i + 4] = (uint)c;
+ c >>= 32;
+ c += x_i * y_5 + zz[i + 5];
+ zz[i + 5] = (uint)c;
+ c >>= 32;
+ c += x_i * y_6 + zz[i + 6];
+ zz[i + 6] = (uint)c;
+ c >>= 32;
+ zz[i + 7] = (uint)c;
+ }
+ }
+
+ public static void Mul(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+ {
+ ulong y_0 = y[yOff + 0];
+ ulong y_1 = y[yOff + 1];
+ ulong y_2 = y[yOff + 2];
+ ulong y_3 = y[yOff + 3];
+ ulong y_4 = y[yOff + 4];
+ ulong y_5 = y[yOff + 5];
+ ulong y_6 = y[yOff + 6];
+
+ {
+ ulong c = 0, x_0 = x[xOff + 0];
+ c += x_0 * y_0;
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_1;
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_2;
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_3;
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_4;
+ zz[zzOff + 4] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_5;
+ zz[zzOff + 5] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_6;
+ zz[zzOff + 6] = (uint)c;
+ c >>= 32;
+ zz[zzOff + 7] = (uint)c;
+ }
+
+ for (int i = 1; i < 7; ++i)
+ {
+ ++zzOff;
+ ulong c = 0, x_i = x[xOff + i];
+ c += x_i * y_0 + zz[zzOff + 0];
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[zzOff + 1];
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[zzOff + 2];
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[zzOff + 3];
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[zzOff + 4];
+ zz[zzOff + 4] = (uint)c;
+ c >>= 32;
+ c += x_i * y_5 + zz[zzOff + 5];
+ zz[zzOff + 5] = (uint)c;
+ c >>= 32;
+ c += x_i * y_6 + zz[zzOff + 6];
+ zz[zzOff + 6] = (uint)c;
+ c >>= 32;
+ zz[zzOff + 7] = (uint)c;
+ }
+ }
+
+ public static uint MulAddTo(uint[] x, uint[] y, uint[] zz)
+ {
+ ulong y_0 = y[0];
+ ulong y_1 = y[1];
+ ulong y_2 = y[2];
+ ulong y_3 = y[3];
+ ulong y_4 = y[4];
+ ulong y_5 = y[5];
+ ulong y_6 = y[6];
+
+ ulong zc = 0;
+ for (int i = 0; i < 7; ++i)
+ {
+ ulong c = 0, x_i = x[i];
+ c += x_i * y_0 + zz[i + 0];
+ zz[i + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[i + 1];
+ zz[i + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[i + 2];
+ zz[i + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[i + 3];
+ zz[i + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[i + 4];
+ zz[i + 4] = (uint)c;
+ c >>= 32;
+ c += x_i * y_5 + zz[i + 5];
+ zz[i + 5] = (uint)c;
+ c >>= 32;
+ c += x_i * y_6 + zz[i + 6];
+ zz[i + 6] = (uint)c;
+ c >>= 32;
+ c += zc + zz[i + 7];
+ zz[i + 7] = (uint)c;
+ zc = c >> 32;
+ }
+ return (uint)zc;
+ }
+
+ public static uint MulAddTo(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+ {
+ ulong y_0 = y[yOff + 0];
+ ulong y_1 = y[yOff + 1];
+ ulong y_2 = y[yOff + 2];
+ ulong y_3 = y[yOff + 3];
+ ulong y_4 = y[yOff + 4];
+ ulong y_5 = y[yOff + 5];
+ ulong y_6 = y[yOff + 6];
+
+ ulong zc = 0;
+ for (int i = 0; i < 7; ++i)
+ {
+ ulong c = 0, x_i = x[xOff + i];
+ c += x_i * y_0 + zz[zzOff + 0];
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[zzOff + 1];
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[zzOff + 2];
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[zzOff + 3];
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[zzOff + 4];
+ zz[zzOff + 4] = (uint)c;
+ c >>= 32;
+ c += x_i * y_5 + zz[zzOff + 5];
+ zz[zzOff + 5] = (uint)c;
+ c >>= 32;
+ c += x_i * y_6 + zz[zzOff + 6];
+ zz[zzOff + 6] = (uint)c;
+ c >>= 32;
+ c += zc + zz[zzOff + 7];
+ zz[zzOff + 7] = (uint)c;
+ zc = c >> 32;
+ ++zzOff;
+ }
+ return (uint)zc;
+ }
+
+ public static ulong Mul33Add(uint w, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ Debug.Assert(w >> 31 == 0);
+
+ ulong c = 0, wVal = w;
+ ulong x0 = x[xOff + 0];
+ c += wVal * x0 + y[yOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ ulong x1 = x[xOff + 1];
+ c += wVal * x1 + x0 + y[yOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ ulong x2 = x[xOff + 2];
+ c += wVal * x2 + x1 + y[yOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ ulong x3 = x[xOff + 3];
+ c += wVal * x3 + x2 + y[yOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ ulong x4 = x[xOff + 4];
+ c += wVal * x4 + x3 + y[yOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ ulong x5 = x[xOff + 5];
+ c += wVal * x5 + x4 + y[yOff + 5];
+ z[zOff + 5] = (uint)c;
+ c >>= 32;
+ ulong x6 = x[xOff + 6];
+ c += wVal * x6 + x5 + y[yOff + 6];
+ z[zOff + 6] = (uint)c;
+ c >>= 32;
+ c += x6;
+ return c;
+ }
+
+ public static uint MulByWord(uint x, uint[] z)
+ {
+ ulong c = 0, xVal = x;
+ c += xVal * (ulong)z[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[6];
+ z[6] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint MulByWordAddTo(uint x, uint[] y, uint[] z)
+ {
+ ulong c = 0, xVal = x;
+ c += xVal * (ulong)z[0] + y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[1] + y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[2] + y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[3] + y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[4] + y[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[5] + y[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[6] + y[6];
+ z[6] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint MulWordAddTo(uint x, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ ulong c = 0, xVal = x;
+ c += xVal * y[yOff + 0] + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += xVal * y[yOff + 1] + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += xVal * y[yOff + 2] + z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += xVal * y[yOff + 3] + z[zOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += xVal * y[yOff + 4] + z[zOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ c += xVal * y[yOff + 5] + z[zOff + 5];
+ z[zOff + 5] = (uint)c;
+ c >>= 32;
+ c += xVal * y[yOff + 6] + z[zOff + 6];
+ z[zOff + 6] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint Mul33DWordAdd(uint x, ulong y, uint[] z, int zOff)
+ {
+ Debug.Assert(x >> 31 == 0);
+ Debug.Assert(zOff <= 3);
+ ulong c = 0, xVal = x;
+ ulong y00 = y & M;
+ c += xVal * y00 + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ ulong y01 = y >> 32;
+ c += xVal * y01 + y00 + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += y01 + z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(7, z, zOff, 4);
+ }
+
+ public static uint Mul33WordAdd(uint x, uint y, uint[] z, int zOff)
+ {
+ Debug.Assert(x >> 31 == 0);
+ Debug.Assert(zOff <= 4);
+ ulong c = 0, yVal = y;
+ c += yVal * x + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += yVal + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(7, z, zOff, 3);
+ }
+
+ public static uint MulWordDwordAdd(uint x, ulong y, uint[] z, int zOff)
+ {
+ Debug.Assert(zOff <= 4);
+ ulong c = 0, xVal = x;
+ c += xVal * y + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += xVal * (y >> 32) + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(7, z, zOff, 3);
+ }
+
+ public static uint MulWord(uint x, uint[] y, uint[] z, int zOff)
+ {
+ ulong c = 0, xVal = x;
+ int i = 0;
+ do
+ {
+ c += xVal * y[i];
+ z[zOff + i] = (uint)c;
+ c >>= 32;
+ }
+ while (++i < 7);
+ return (uint)c;
+ }
+
+ public static void Square(uint[] x, uint[] zz)
+ {
+ ulong x_0 = x[0];
+ ulong zz_1;
+
+ uint c = 0, w;
+ {
+ int i = 6, j = 14;
+ do
+ {
+ ulong xVal = x[i--];
+ ulong p = xVal * xVal;
+ zz[--j] = (c << 31) | (uint)(p >> 33);
+ zz[--j] = (uint)(p >> 1);
+ c = (uint)p;
+ }
+ while (i > 0);
+
+ {
+ ulong p = x_0 * x_0;
+ zz_1 = (ulong)(c << 31) | (p >> 33);
+ zz[0] = (uint)p;
+ c = (uint)(p >> 32) & 1;
+ }
+ }
+
+ ulong x_1 = x[1];
+ ulong zz_2 = zz[2];
+
+ {
+ zz_1 += x_1 * x_0;
+ w = (uint)zz_1;
+ zz[1] = (w << 1) | c;
+ c = w >> 31;
+ zz_2 += zz_1 >> 32;
+ }
+
+ ulong x_2 = x[2];
+ ulong zz_3 = zz[3];
+ ulong zz_4 = zz[4];
+ {
+ zz_2 += x_2 * x_0;
+ w = (uint)zz_2;
+ zz[2] = (w << 1) | c;
+ c = w >> 31;
+ zz_3 += (zz_2 >> 32) + x_2 * x_1;
+ zz_4 += zz_3 >> 32;
+ zz_3 &= M;
+ }
+
+ ulong x_3 = x[3];
+ ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M;
+ {
+ zz_3 += x_3 * x_0;
+ w = (uint)zz_3;
+ zz[3] = (w << 1) | c;
+ c = w >> 31;
+ zz_4 += (zz_3 >> 32) + x_3 * x_1;
+ zz_5 += (zz_4 >> 32) + x_3 * x_2;
+ zz_4 &= M;
+ zz_6 += zz_5 >> 32;
+ zz_5 &= M;
+ }
+
+ ulong x_4 = x[4];
+ ulong zz_7 = zz[7] + (zz_6 >> 32); zz_6 &= M;
+ ulong zz_8 = zz[8] + (zz_7 >> 32); zz_7 &= M;
+ {
+ zz_4 += x_4 * x_0;
+ w = (uint)zz_4;
+ zz[4] = (w << 1) | c;
+ c = w >> 31;
+ zz_5 += (zz_4 >> 32) + x_4 * x_1;
+ zz_6 += (zz_5 >> 32) + x_4 * x_2;
+ zz_5 &= M;
+ zz_7 += (zz_6 >> 32) + x_4 * x_3;
+ zz_6 &= M;
+ zz_8 += zz_7 >> 32;
+ zz_7 &= M;
+ }
+
+ ulong x_5 = x[5];
+ ulong zz_9 = zz[9] + (zz_8 >> 32); zz_8 &= M;
+ ulong zz_10 = zz[10] + (zz_9 >> 32); zz_9 &= M;
+ {
+ zz_5 += x_5 * x_0;
+ w = (uint)zz_5;
+ zz[5] = (w << 1) | c;
+ c = w >> 31;
+ zz_6 += (zz_5 >> 32) + x_5 * x_1;
+ zz_7 += (zz_6 >> 32) + x_5 * x_2;
+ zz_6 &= M;
+ zz_8 += (zz_7 >> 32) + x_5 * x_3;
+ zz_7 &= M;
+ zz_9 += (zz_8 >> 32) + x_5 * x_4;
+ zz_8 &= M;
+ zz_10 += zz_9 >> 32;
+ zz_9 &= M;
+ }
+
+ ulong x_6 = x[6];
+ ulong zz_11 = zz[11] + (zz_10 >> 32); zz_10 &= M;
+ ulong zz_12 = zz[12] + (zz_11 >> 32); zz_11 &= M;
+ {
+ zz_6 += x_6 * x_0;
+ w = (uint)zz_6;
+ zz[6] = (w << 1) | c;
+ c = w >> 31;
+ zz_7 += (zz_6 >> 32) + x_6 * x_1;
+ zz_8 += (zz_7 >> 32) + x_6 * x_2;
+ zz_9 += (zz_8 >> 32) + x_6 * x_3;
+ zz_10 += (zz_9 >> 32) + x_6 * x_4;
+ zz_11 += (zz_10 >> 32) + x_6 * x_5;
+ zz_12 += zz_11 >> 32;
+ }
+
+ w = (uint)zz_7;
+ zz[7] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_8;
+ zz[8] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_9;
+ zz[9] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_10;
+ zz[10] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_11;
+ zz[11] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_12;
+ zz[12] = (w << 1) | c;
+ c = w >> 31;
+ w = zz[13] + (uint)(zz_12 >> 32);
+ zz[13] = (w << 1) | c;
+ }
+
+ public static void Square(uint[] x, int xOff, uint[] zz, int zzOff)
+ {
+ ulong x_0 = x[xOff + 0];
+ ulong zz_1;
+
+ uint c = 0, w;
+ {
+ int i = 6, j = 14;
+ do
+ {
+ ulong xVal = x[xOff + i--];
+ ulong p = xVal * xVal;
+ zz[zzOff + --j] = (c << 31) | (uint)(p >> 33);
+ zz[zzOff + --j] = (uint)(p >> 1);
+ c = (uint)p;
+ }
+ while (i > 0);
+
+ {
+ ulong p = x_0 * x_0;
+ zz_1 = (ulong)(c << 31) | (p >> 33);
+ zz[zzOff + 0] = (uint)p;
+ c = (uint)(p >> 32) & 1;
+ }
+ }
+
+ ulong x_1 = x[xOff + 1];
+ ulong zz_2 = zz[zzOff + 2];
+
+ {
+ zz_1 += x_1 * x_0;
+ w = (uint)zz_1;
+ zz[zzOff + 1] = (w << 1) | c;
+ c = w >> 31;
+ zz_2 += zz_1 >> 32;
+ }
+
+ ulong x_2 = x[xOff + 2];
+ ulong zz_3 = zz[zzOff + 3];
+ ulong zz_4 = zz[zzOff + 4];
+ {
+ zz_2 += x_2 * x_0;
+ w = (uint)zz_2;
+ zz[zzOff + 2] = (w << 1) | c;
+ c = w >> 31;
+ zz_3 += (zz_2 >> 32) + x_2 * x_1;
+ zz_4 += zz_3 >> 32;
+ zz_3 &= M;
+ }
+
+ ulong x_3 = x[xOff + 3];
+ ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M;
+ {
+ zz_3 += x_3 * x_0;
+ w = (uint)zz_3;
+ zz[zzOff + 3] = (w << 1) | c;
+ c = w >> 31;
+ zz_4 += (zz_3 >> 32) + x_3 * x_1;
+ zz_5 += (zz_4 >> 32) + x_3 * x_2;
+ zz_4 &= M;
+ zz_6 += zz_5 >> 32;
+ zz_5 &= M;
+ }
+
+ ulong x_4 = x[xOff + 4];
+ ulong zz_7 = zz[zzOff + 7] + (zz_6 >> 32); zz_6 &= M;
+ ulong zz_8 = zz[zzOff + 8] + (zz_7 >> 32); zz_7 &= M;
+ {
+ zz_4 += x_4 * x_0;
+ w = (uint)zz_4;
+ zz[zzOff + 4] = (w << 1) | c;
+ c = w >> 31;
+ zz_5 += (zz_4 >> 32) + x_4 * x_1;
+ zz_6 += (zz_5 >> 32) + x_4 * x_2;
+ zz_5 &= M;
+ zz_7 += (zz_6 >> 32) + x_4 * x_3;
+ zz_6 &= M;
+ zz_8 += zz_7 >> 32;
+ zz_7 &= M;
+ }
+
+ ulong x_5 = x[xOff + 5];
+ ulong zz_9 = zz[zzOff + 9] + (zz_8 >> 32); zz_8 &= M;
+ ulong zz_10 = zz[zzOff + 10] + (zz_9 >> 32); zz_9 &= M;
+ {
+ zz_5 += x_5 * x_0;
+ w = (uint)zz_5;
+ zz[zzOff + 5] = (w << 1) | c;
+ c = w >> 31;
+ zz_6 += (zz_5 >> 32) + x_5 * x_1;
+ zz_7 += (zz_6 >> 32) + x_5 * x_2;
+ zz_6 &= M;
+ zz_8 += (zz_7 >> 32) + x_5 * x_3;
+ zz_7 &= M;
+ zz_9 += (zz_8 >> 32) + x_5 * x_4;
+ zz_8 &= M;
+ zz_10 += zz_9 >> 32;
+ zz_9 &= M;
+ }
+
+ ulong x_6 = x[xOff + 6];
+ ulong zz_11 = zz[zzOff + 11] + (zz_10 >> 32); zz_10 &= M;
+ ulong zz_12 = zz[zzOff + 12] + (zz_11 >> 32); zz_11 &= M;
+ {
+ zz_6 += x_6 * x_0;
+ w = (uint)zz_6;
+ zz[zzOff + 6] = (w << 1) | c;
+ c = w >> 31;
+ zz_7 += (zz_6 >> 32) + x_6 * x_1;
+ zz_8 += (zz_7 >> 32) + x_6 * x_2;
+ zz_9 += (zz_8 >> 32) + x_6 * x_3;
+ zz_10 += (zz_9 >> 32) + x_6 * x_4;
+ zz_11 += (zz_10 >> 32) + x_6 * x_5;
+ zz_12 += zz_11 >> 32;
+ }
+
+ w = (uint)zz_7;
+ zz[zzOff + 7] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_8;
+ zz[zzOff + 8] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_9;
+ zz[zzOff + 9] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_10;
+ zz[zzOff + 10] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_11;
+ zz[zzOff + 11] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_12;
+ zz[zzOff + 12] = (w << 1) | c;
+ c = w >> 31;
+ w = zz[zzOff + 13] + (uint)(zz_12 >> 32);
+ zz[zzOff + 13] = (w << 1) | c;
+ }
+
+ public static int Sub(uint[] x, uint[] y, uint[] z)
+ {
+ long c = 0;
+ c += (long)x[0] - y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)x[1] - y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)x[2] - y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)x[3] - y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (long)x[4] - y[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (long)x[5] - y[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ c += (long)x[6] - y[6];
+ z[6] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int Sub(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ long c = 0;
+ c += (long)x[xOff + 0] - y[yOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 1] - y[yOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 2] - y[yOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 3] - y[yOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 4] - y[yOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 5] - y[yOff + 5];
+ z[zOff + 5] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 6] - y[yOff + 6];
+ z[zOff + 6] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubBothFrom(uint[] x, uint[] y, uint[] z)
+ {
+ long c = 0;
+ c += (long)z[0] - x[0] - y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)z[1] - x[1] - y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)z[2] - x[2] - y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)z[3] - x[3] - y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (long)z[4] - x[4] - y[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (long)z[5] - x[5] - y[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ c += (long)z[6] - x[6] - y[6];
+ z[6] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubFrom(uint[] x, uint[] z)
+ {
+ long c = 0;
+ c += (long)z[0] - x[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)z[1] - x[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)z[2] - x[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)z[3] - x[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (long)z[4] - x[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (long)z[5] - x[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ c += (long)z[6] - x[6];
+ z[6] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubFrom(uint[] x, int xOff, uint[] z, int zOff)
+ {
+ long c = 0;
+ c += (long)z[zOff + 0] - x[xOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 1] - x[xOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 2] - x[xOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 3] - x[xOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 4] - x[xOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 5] - x[xOff + 5];
+ z[zOff + 5] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 6] - x[xOff + 6];
+ z[zOff + 6] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static BigInteger ToBigInteger(uint[] x)
+ {
+ byte[] bs = new byte[28];
+ for (int i = 0; i < 7; ++i)
+ {
+ uint x_i = x[i];
+ if (x_i != 0)
+ {
+ Pack.UInt32_To_BE(x_i, bs, (6 - i) << 2);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+
+ public static void Zero(uint[] z)
+ {
+ z[0] = 0;
+ z[1] = 0;
+ z[2] = 0;
+ z[3] = 0;
+ z[4] = 0;
+ z[5] = 0;
+ z[6] = 0;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/raw/Nat256.cs b/bc-sharp-crypto/src/math/raw/Nat256.cs
new file mode 100644
index 0000000000000000000000000000000000000000..09c751a5a7d75c8eda37f6fd305e442603b75f31
--- /dev/null
+++ b/bc-sharp-crypto/src/math/raw/Nat256.cs
@@ -0,0 +1,1387 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Nat256
+ {
+ private const ulong M = 0xFFFFFFFFUL;
+
+ public static uint Add(uint[] x, uint[] y, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[4] + y[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[5] + y[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[6] + y[6];
+ z[6] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[7] + y[7];
+ z[7] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint Add(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ ulong c = 0;
+ c += (ulong)x[xOff + 0] + y[yOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 1] + y[yOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 2] + y[yOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 3] + y[yOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 4] + y[yOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 5] + y[yOff + 5];
+ z[zOff + 5] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 6] + y[yOff + 6];
+ z[zOff + 6] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 7] + y[yOff + 7];
+ z[zOff + 7] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddBothTo(uint[] x, uint[] y, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + y[0] + z[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + y[1] + z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + y[2] + z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + y[3] + z[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[4] + y[4] + z[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[5] + y[5] + z[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[6] + y[6] + z[6];
+ z[6] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[7] + y[7] + z[7];
+ z[7] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddBothTo(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ ulong c = 0;
+ c += (ulong)x[xOff + 0] + y[yOff + 0] + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 1] + y[yOff + 1] + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 2] + y[yOff + 2] + z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 3] + y[yOff + 3] + z[zOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 4] + y[yOff + 4] + z[zOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 5] + y[yOff + 5] + z[zOff + 5];
+ z[zOff + 5] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 6] + y[yOff + 6] + z[zOff + 6];
+ z[zOff + 6] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 7] + y[yOff + 7] + z[zOff + 7];
+ z[zOff + 7] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddTo(uint[] x, uint[] z)
+ {
+ ulong c = 0;
+ c += (ulong)x[0] + z[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[1] + z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[2] + z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[3] + z[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[4] + z[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[5] + z[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[6] + z[6];
+ z[6] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[7] + z[7];
+ z[7] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddTo(uint[] x, int xOff, uint[] z, int zOff, uint cIn)
+ {
+ ulong c = cIn;
+ c += (ulong)x[xOff + 0] + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 1] + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 2] + z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 3] + z[zOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 4] + z[zOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 5] + z[zOff + 5];
+ z[zOff + 5] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 6] + z[zOff + 6];
+ z[zOff + 6] = (uint)c;
+ c >>= 32;
+ c += (ulong)x[xOff + 7] + z[zOff + 7];
+ z[zOff + 7] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint AddToEachOther(uint[] u, int uOff, uint[] v, int vOff)
+ {
+ ulong c = 0;
+ c += (ulong)u[uOff + 0] + v[vOff + 0];
+ u[uOff + 0] = (uint)c;
+ v[vOff + 0] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 1] + v[vOff + 1];
+ u[uOff + 1] = (uint)c;
+ v[vOff + 1] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 2] + v[vOff + 2];
+ u[uOff + 2] = (uint)c;
+ v[vOff + 2] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 3] + v[vOff + 3];
+ u[uOff + 3] = (uint)c;
+ v[vOff + 3] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 4] + v[vOff + 4];
+ u[uOff + 4] = (uint)c;
+ v[vOff + 4] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 5] + v[vOff + 5];
+ u[uOff + 5] = (uint)c;
+ v[vOff + 5] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 6] + v[vOff + 6];
+ u[uOff + 6] = (uint)c;
+ v[vOff + 6] = (uint)c;
+ c >>= 32;
+ c += (ulong)u[uOff + 7] + v[vOff + 7];
+ u[uOff + 7] = (uint)c;
+ v[vOff + 7] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static void Copy(uint[] x, uint[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ z[4] = x[4];
+ z[5] = x[5];
+ z[6] = x[6];
+ z[7] = x[7];
+ }
+
+ public static void Copy64(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ }
+
+ public static uint[] Create()
+ {
+ return new uint[8];
+ }
+
+ public static ulong[] Create64()
+ {
+ return new ulong[4];
+ }
+
+ public static uint[] CreateExt()
+ {
+ return new uint[16];
+ }
+
+ public static ulong[] CreateExt64()
+ {
+ return new ulong[8];
+ }
+
+ public static bool Diff(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ bool pos = Gte(x, xOff, y, yOff);
+ if (pos)
+ {
+ Sub(x, xOff, y, yOff, z, zOff);
+ }
+ else
+ {
+ Sub(y, yOff, x, xOff, z, zOff);
+ }
+ return pos;
+ }
+
+ public static bool Eq(uint[] x, uint[] y)
+ {
+ for (int i = 7; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ return false;
+ }
+ return true;
+ }
+
+ public static bool Eq64(ulong[] x, ulong[] y)
+ {
+ for (int i = 3; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static uint[] FromBigInteger(BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > 256)
+ throw new ArgumentException();
+
+ uint[] z = Create();
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (uint)x.IntValue;
+ x = x.ShiftRight(32);
+ }
+ return z;
+ }
+
+ public static ulong[] FromBigInteger64(BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > 256)
+ throw new ArgumentException();
+
+ ulong[] z = Create64();
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (ulong)x.LongValue;
+ x = x.ShiftRight(64);
+ }
+ return z;
+ }
+
+ public static uint GetBit(uint[] x, int bit)
+ {
+ if (bit == 0)
+ {
+ return x[0] & 1;
+ }
+ if ((bit & 255) != bit)
+ {
+ return 0;
+ }
+ int w = bit >> 5;
+ int b = bit & 31;
+ return (x[w] >> b) & 1;
+ }
+
+ public static bool Gte(uint[] x, uint[] y)
+ {
+ for (int i = 7; i >= 0; --i)
+ {
+ uint x_i = x[i], y_i = y[i];
+ if (x_i < y_i)
+ return false;
+ if (x_i > y_i)
+ return true;
+ }
+ return true;
+ }
+
+ public static bool Gte(uint[] x, int xOff, uint[] y, int yOff)
+ {
+ for (int i = 7; i >= 0; --i)
+ {
+ uint x_i = x[xOff + i], y_i = y[yOff + i];
+ if (x_i < y_i)
+ return false;
+ if (x_i > y_i)
+ return true;
+ }
+ return true;
+ }
+
+ public static bool IsOne(uint[] x)
+ {
+ if (x[0] != 1)
+ {
+ return false;
+ }
+ for (int i = 1; i < 8; ++i)
+ {
+ if (x[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsOne64(ulong[] x)
+ {
+ if (x[0] != 1UL)
+ {
+ return false;
+ }
+ for (int i = 1; i < 4; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsZero(uint[] x)
+ {
+ for (int i = 0; i < 8; ++i)
+ {
+ if (x[i] != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsZero64(ulong[] x)
+ {
+ for (int i = 0; i < 4; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static void Mul(uint[] x, uint[] y, uint[] zz)
+ {
+ ulong y_0 = y[0];
+ ulong y_1 = y[1];
+ ulong y_2 = y[2];
+ ulong y_3 = y[3];
+ ulong y_4 = y[4];
+ ulong y_5 = y[5];
+ ulong y_6 = y[6];
+ ulong y_7 = y[7];
+
+ {
+ ulong c = 0, x_0 = x[0];
+ c += x_0 * y_0;
+ zz[0] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_1;
+ zz[1] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_2;
+ zz[2] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_3;
+ zz[3] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_4;
+ zz[4] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_5;
+ zz[5] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_6;
+ zz[6] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_7;
+ zz[7] = (uint)c;
+ c >>= 32;
+ zz[8] = (uint)c;
+ }
+
+ for (int i = 1; i < 8; ++i)
+ {
+ ulong c = 0, x_i = x[i];
+ c += x_i * y_0 + zz[i + 0];
+ zz[i + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[i + 1];
+ zz[i + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[i + 2];
+ zz[i + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[i + 3];
+ zz[i + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[i + 4];
+ zz[i + 4] = (uint)c;
+ c >>= 32;
+ c += x_i * y_5 + zz[i + 5];
+ zz[i + 5] = (uint)c;
+ c >>= 32;
+ c += x_i * y_6 + zz[i + 6];
+ zz[i + 6] = (uint)c;
+ c >>= 32;
+ c += x_i * y_7 + zz[i + 7];
+ zz[i + 7] = (uint)c;
+ c >>= 32;
+ zz[i + 8] = (uint)c;
+ }
+ }
+
+ public static void Mul(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+ {
+ ulong y_0 = y[yOff + 0];
+ ulong y_1 = y[yOff + 1];
+ ulong y_2 = y[yOff + 2];
+ ulong y_3 = y[yOff + 3];
+ ulong y_4 = y[yOff + 4];
+ ulong y_5 = y[yOff + 5];
+ ulong y_6 = y[yOff + 6];
+ ulong y_7 = y[yOff + 7];
+
+ {
+ ulong c = 0, x_0 = x[xOff + 0];
+ c += x_0 * y_0;
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_1;
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_2;
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_3;
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_4;
+ zz[zzOff + 4] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_5;
+ zz[zzOff + 5] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_6;
+ zz[zzOff + 6] = (uint)c;
+ c >>= 32;
+ c += x_0 * y_7;
+ zz[zzOff + 7] = (uint)c;
+ c >>= 32;
+ zz[zzOff + 8] = (uint)c;
+ }
+
+ for (int i = 1; i < 8; ++i)
+ {
+ ++zzOff;
+ ulong c = 0, x_i = x[xOff + i];
+ c += x_i * y_0 + zz[zzOff + 0];
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[zzOff + 1];
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[zzOff + 2];
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[zzOff + 3];
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[zzOff + 4];
+ zz[zzOff + 4] = (uint)c;
+ c >>= 32;
+ c += x_i * y_5 + zz[zzOff + 5];
+ zz[zzOff + 5] = (uint)c;
+ c >>= 32;
+ c += x_i * y_6 + zz[zzOff + 6];
+ zz[zzOff + 6] = (uint)c;
+ c >>= 32;
+ c += x_i * y_7 + zz[zzOff + 7];
+ zz[zzOff + 7] = (uint)c;
+ c >>= 32;
+ zz[zzOff + 8] = (uint)c;
+ }
+ }
+
+ public static uint MulAddTo(uint[] x, uint[] y, uint[] zz)
+ {
+ ulong y_0 = y[0];
+ ulong y_1 = y[1];
+ ulong y_2 = y[2];
+ ulong y_3 = y[3];
+ ulong y_4 = y[4];
+ ulong y_5 = y[5];
+ ulong y_6 = y[6];
+ ulong y_7 = y[7];
+
+ ulong zc = 0;
+ for (int i = 0; i < 8; ++i)
+ {
+ ulong c = 0, x_i = x[i];
+ c += x_i * y_0 + zz[i + 0];
+ zz[i + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[i + 1];
+ zz[i + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[i + 2];
+ zz[i + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[i + 3];
+ zz[i + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[i + 4];
+ zz[i + 4] = (uint)c;
+ c >>= 32;
+ c += x_i * y_5 + zz[i + 5];
+ zz[i + 5] = (uint)c;
+ c >>= 32;
+ c += x_i * y_6 + zz[i + 6];
+ zz[i + 6] = (uint)c;
+ c >>= 32;
+ c += x_i * y_7 + zz[i + 7];
+ zz[i + 7] = (uint)c;
+ c >>= 32;
+ c += zc + zz[i + 8];
+ zz[i + 8] = (uint)c;
+ zc = c >> 32;
+ }
+ return (uint)zc;
+ }
+
+ public static uint MulAddTo(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+ {
+ ulong y_0 = y[yOff + 0];
+ ulong y_1 = y[yOff + 1];
+ ulong y_2 = y[yOff + 2];
+ ulong y_3 = y[yOff + 3];
+ ulong y_4 = y[yOff + 4];
+ ulong y_5 = y[yOff + 5];
+ ulong y_6 = y[yOff + 6];
+ ulong y_7 = y[yOff + 7];
+
+ ulong zc = 0;
+ for (int i = 0; i < 8; ++i)
+ {
+ ulong c = 0, x_i = x[xOff + i];
+ c += x_i * y_0 + zz[zzOff + 0];
+ zz[zzOff + 0] = (uint)c;
+ c >>= 32;
+ c += x_i * y_1 + zz[zzOff + 1];
+ zz[zzOff + 1] = (uint)c;
+ c >>= 32;
+ c += x_i * y_2 + zz[zzOff + 2];
+ zz[zzOff + 2] = (uint)c;
+ c >>= 32;
+ c += x_i * y_3 + zz[zzOff + 3];
+ zz[zzOff + 3] = (uint)c;
+ c >>= 32;
+ c += x_i * y_4 + zz[zzOff + 4];
+ zz[zzOff + 4] = (uint)c;
+ c >>= 32;
+ c += x_i * y_5 + zz[zzOff + 5];
+ zz[zzOff + 5] = (uint)c;
+ c >>= 32;
+ c += x_i * y_6 + zz[zzOff + 6];
+ zz[zzOff + 6] = (uint)c;
+ c >>= 32;
+ c += x_i * y_7 + zz[zzOff + 7];
+ zz[zzOff + 7] = (uint)c;
+ c >>= 32;
+ c += zc + zz[zzOff + 8];
+ zz[zzOff + 8] = (uint)c;
+ zc = c >> 32;
+ ++zzOff;
+ }
+ return (uint)zc;
+ }
+
+ public static ulong Mul33Add(uint w, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ Debug.Assert(w >> 31 == 0);
+
+ ulong c = 0, wVal = w;
+ ulong x0 = x[xOff + 0];
+ c += wVal * x0 + y[yOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ ulong x1 = x[xOff + 1];
+ c += wVal * x1 + x0 + y[yOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ ulong x2 = x[xOff + 2];
+ c += wVal * x2 + x1 + y[yOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ ulong x3 = x[xOff + 3];
+ c += wVal * x3 + x2 + y[yOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ ulong x4 = x[xOff + 4];
+ c += wVal * x4 + x3 + y[yOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ ulong x5 = x[xOff + 5];
+ c += wVal * x5 + x4 + y[yOff + 5];
+ z[zOff + 5] = (uint)c;
+ c >>= 32;
+ ulong x6 = x[xOff + 6];
+ c += wVal * x6 + x5 + y[yOff + 6];
+ z[zOff + 6] = (uint)c;
+ c >>= 32;
+ ulong x7 = x[xOff + 7];
+ c += wVal * x7 + x6 + y[yOff + 7];
+ z[zOff + 7] = (uint)c;
+ c >>= 32;
+ c += x7;
+ return c;
+ }
+
+ public static uint MulByWord(uint x, uint[] z)
+ {
+ ulong c = 0, xVal = x;
+ c += xVal * (ulong)z[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[6];
+ z[6] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[7];
+ z[7] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint MulByWordAddTo(uint x, uint[] y, uint[] z)
+ {
+ ulong c = 0, xVal = x;
+ c += xVal * (ulong)z[0] + y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[1] + y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[2] + y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[3] + y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[4] + y[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[5] + y[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[6] + y[6];
+ z[6] = (uint)c;
+ c >>= 32;
+ c += xVal * (ulong)z[7] + y[7];
+ z[7] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint MulWordAddTo(uint x, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ ulong c = 0, xVal = x;
+ c += xVal * y[yOff + 0] + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += xVal * y[yOff + 1] + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += xVal * y[yOff + 2] + z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += xVal * y[yOff + 3] + z[zOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += xVal * y[yOff + 4] + z[zOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ c += xVal * y[yOff + 5] + z[zOff + 5];
+ z[zOff + 5] = (uint)c;
+ c >>= 32;
+ c += xVal * y[yOff + 6] + z[zOff + 6];
+ z[zOff + 6] = (uint)c;
+ c >>= 32;
+ c += xVal * y[yOff + 7] + z[zOff + 7];
+ z[zOff + 7] = (uint)c;
+ c >>= 32;
+ return (uint)c;
+ }
+
+ public static uint Mul33DWordAdd(uint x, ulong y, uint[] z, int zOff)
+ {
+ Debug.Assert(x >> 31 == 0);
+ Debug.Assert(zOff <= 4);
+ ulong c = 0, xVal = x;
+ ulong y00 = y & M;
+ c += xVal * y00 + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ ulong y01 = y >> 32;
+ c += xVal * y01 + y00 + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += y01 + z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(8, z, zOff, 4);
+ }
+
+ public static uint Mul33WordAdd(uint x, uint y, uint[] z, int zOff)
+ {
+ Debug.Assert(x >> 31 == 0);
+ Debug.Assert(zOff <= 5);
+ ulong c = 0, yVal = y;
+ c += yVal * x + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += yVal + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(8, z, zOff, 3);
+ }
+
+ public static uint MulWordDwordAdd(uint x, ulong y, uint[] z, int zOff)
+ {
+ Debug.Assert(zOff <= 5);
+ ulong c = 0, xVal = x;
+ c += xVal * y + z[zOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += xVal * (y >> 32) + z[zOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += z[zOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ return c == 0 ? 0 : Nat.IncAt(8, z, zOff, 3);
+ }
+
+ public static uint MulWord(uint x, uint[] y, uint[] z, int zOff)
+ {
+ ulong c = 0, xVal = x;
+ int i = 0;
+ do
+ {
+ c += xVal * y[i];
+ z[zOff + i] = (uint)c;
+ c >>= 32;
+ }
+ while (++i < 8);
+ return (uint)c;
+ }
+
+ public static void Square(uint[] x, uint[] zz)
+ {
+ ulong x_0 = x[0];
+ ulong zz_1;
+
+ uint c = 0, w;
+ {
+ int i = 7, j = 16;
+ do
+ {
+ ulong xVal = x[i--];
+ ulong p = xVal * xVal;
+ zz[--j] = (c << 31) | (uint)(p >> 33);
+ zz[--j] = (uint)(p >> 1);
+ c = (uint)p;
+ }
+ while (i > 0);
+
+ {
+ ulong p = x_0 * x_0;
+ zz_1 = (ulong)(c << 31) | (p >> 33);
+ zz[0] = (uint)p;
+ c = (uint)(p >> 32) & 1;
+ }
+ }
+
+ ulong x_1 = x[1];
+ ulong zz_2 = zz[2];
+
+ {
+ zz_1 += x_1 * x_0;
+ w = (uint)zz_1;
+ zz[1] = (w << 1) | c;
+ c = w >> 31;
+ zz_2 += zz_1 >> 32;
+ }
+
+ ulong x_2 = x[2];
+ ulong zz_3 = zz[3];
+ ulong zz_4 = zz[4];
+ {
+ zz_2 += x_2 * x_0;
+ w = (uint)zz_2;
+ zz[2] = (w << 1) | c;
+ c = w >> 31;
+ zz_3 += (zz_2 >> 32) + x_2 * x_1;
+ zz_4 += zz_3 >> 32;
+ zz_3 &= M;
+ }
+
+ ulong x_3 = x[3];
+ ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M;
+ {
+ zz_3 += x_3 * x_0;
+ w = (uint)zz_3;
+ zz[3] = (w << 1) | c;
+ c = w >> 31;
+ zz_4 += (zz_3 >> 32) + x_3 * x_1;
+ zz_5 += (zz_4 >> 32) + x_3 * x_2;
+ zz_4 &= M;
+ zz_6 += zz_5 >> 32;
+ zz_5 &= M;
+ }
+
+ ulong x_4 = x[4];
+ ulong zz_7 = zz[7] + (zz_6 >> 32); zz_6 &= M;
+ ulong zz_8 = zz[8] + (zz_7 >> 32); zz_7 &= M;
+ {
+ zz_4 += x_4 * x_0;
+ w = (uint)zz_4;
+ zz[4] = (w << 1) | c;
+ c = w >> 31;
+ zz_5 += (zz_4 >> 32) + x_4 * x_1;
+ zz_6 += (zz_5 >> 32) + x_4 * x_2;
+ zz_5 &= M;
+ zz_7 += (zz_6 >> 32) + x_4 * x_3;
+ zz_6 &= M;
+ zz_8 += zz_7 >> 32;
+ zz_7 &= M;
+ }
+
+ ulong x_5 = x[5];
+ ulong zz_9 = zz[9] + (zz_8 >> 32); zz_8 &= M;
+ ulong zz_10 = zz[10] + (zz_9 >> 32); zz_9 &= M;
+ {
+ zz_5 += x_5 * x_0;
+ w = (uint)zz_5;
+ zz[5] = (w << 1) | c;
+ c = w >> 31;
+ zz_6 += (zz_5 >> 32) + x_5 * x_1;
+ zz_7 += (zz_6 >> 32) + x_5 * x_2;
+ zz_6 &= M;
+ zz_8 += (zz_7 >> 32) + x_5 * x_3;
+ zz_7 &= M;
+ zz_9 += (zz_8 >> 32) + x_5 * x_4;
+ zz_8 &= M;
+ zz_10 += zz_9 >> 32;
+ zz_9 &= M;
+ }
+
+ ulong x_6 = x[6];
+ ulong zz_11 = zz[11] + (zz_10 >> 32); zz_10 &= M;
+ ulong zz_12 = zz[12] + (zz_11 >> 32); zz_11 &= M;
+ {
+ zz_6 += x_6 * x_0;
+ w = (uint)zz_6;
+ zz[6] = (w << 1) | c;
+ c = w >> 31;
+ zz_7 += (zz_6 >> 32) + x_6 * x_1;
+ zz_8 += (zz_7 >> 32) + x_6 * x_2;
+ zz_7 &= M;
+ zz_9 += (zz_8 >> 32) + x_6 * x_3;
+ zz_8 &= M;
+ zz_10 += (zz_9 >> 32) + x_6 * x_4;
+ zz_9 &= M;
+ zz_11 += (zz_10 >> 32) + x_6 * x_5;
+ zz_10 &= M;
+ zz_12 += zz_11 >> 32;
+ zz_11 &= M;
+ }
+
+ ulong x_7 = x[7];
+ ulong zz_13 = zz[13] + (zz_12 >> 32); zz_12 &= M;
+ ulong zz_14 = zz[14] + (zz_13 >> 32); zz_13 &= M;
+ {
+ zz_7 += x_7 * x_0;
+ w = (uint)zz_7;
+ zz[7] = (w << 1) | c;
+ c = w >> 31;
+ zz_8 += (zz_7 >> 32) + x_7 * x_1;
+ zz_9 += (zz_8 >> 32) + x_7 * x_2;
+ zz_10 += (zz_9 >> 32) + x_7 * x_3;
+ zz_11 += (zz_10 >> 32) + x_7 * x_4;
+ zz_12 += (zz_11 >> 32) + x_7 * x_5;
+ zz_13 += (zz_12 >> 32) + x_7 * x_6;
+ zz_14 += zz_13 >> 32;
+ }
+
+ w = (uint)zz_8;
+ zz[8] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_9;
+ zz[9] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_10;
+ zz[10] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_11;
+ zz[11] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_12;
+ zz[12] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_13;
+ zz[13] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_14;
+ zz[14] = (w << 1) | c;
+ c = w >> 31;
+ w = zz[15] + (uint)(zz_14 >> 32);
+ zz[15] = (w << 1) | c;
+ }
+
+ public static void Square(uint[] x, int xOff, uint[] zz, int zzOff)
+ {
+ ulong x_0 = x[xOff + 0];
+ ulong zz_1;
+
+ uint c = 0, w;
+ {
+ int i = 7, j = 16;
+ do
+ {
+ ulong xVal = x[xOff + i--];
+ ulong p = xVal * xVal;
+ zz[zzOff + --j] = (c << 31) | (uint)(p >> 33);
+ zz[zzOff + --j] = (uint)(p >> 1);
+ c = (uint)p;
+ }
+ while (i > 0);
+
+ {
+ ulong p = x_0 * x_0;
+ zz_1 = (ulong)(c << 31) | (p >> 33);
+ zz[zzOff + 0] = (uint)p;
+ c = (uint)(p >> 32) & 1;
+ }
+ }
+
+ ulong x_1 = x[xOff + 1];
+ ulong zz_2 = zz[zzOff + 2];
+
+ {
+ zz_1 += x_1 * x_0;
+ w = (uint)zz_1;
+ zz[zzOff + 1] = (w << 1) | c;
+ c = w >> 31;
+ zz_2 += zz_1 >> 32;
+ }
+
+ ulong x_2 = x[xOff + 2];
+ ulong zz_3 = zz[zzOff + 3];
+ ulong zz_4 = zz[zzOff + 4];
+ {
+ zz_2 += x_2 * x_0;
+ w = (uint)zz_2;
+ zz[zzOff + 2] = (w << 1) | c;
+ c = w >> 31;
+ zz_3 += (zz_2 >> 32) + x_2 * x_1;
+ zz_4 += zz_3 >> 32;
+ zz_3 &= M;
+ }
+
+ ulong x_3 = x[xOff + 3];
+ ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M;
+ ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M;
+ {
+ zz_3 += x_3 * x_0;
+ w = (uint)zz_3;
+ zz[zzOff + 3] = (w << 1) | c;
+ c = w >> 31;
+ zz_4 += (zz_3 >> 32) + x_3 * x_1;
+ zz_5 += (zz_4 >> 32) + x_3 * x_2;
+ zz_4 &= M;
+ zz_6 += zz_5 >> 32;
+ zz_5 &= M;
+ }
+
+ ulong x_4 = x[xOff + 4];
+ ulong zz_7 = zz[zzOff + 7] + (zz_6 >> 32); zz_6 &= M;
+ ulong zz_8 = zz[zzOff + 8] + (zz_7 >> 32); zz_7 &= M;
+ {
+ zz_4 += x_4 * x_0;
+ w = (uint)zz_4;
+ zz[zzOff + 4] = (w << 1) | c;
+ c = w >> 31;
+ zz_5 += (zz_4 >> 32) + x_4 * x_1;
+ zz_6 += (zz_5 >> 32) + x_4 * x_2;
+ zz_5 &= M;
+ zz_7 += (zz_6 >> 32) + x_4 * x_3;
+ zz_6 &= M;
+ zz_8 += zz_7 >> 32;
+ zz_7 &= M;
+ }
+
+ ulong x_5 = x[xOff + 5];
+ ulong zz_9 = zz[zzOff + 9] + (zz_8 >> 32); zz_8 &= M;
+ ulong zz_10 = zz[zzOff + 10] + (zz_9 >> 32); zz_9 &= M;
+ {
+ zz_5 += x_5 * x_0;
+ w = (uint)zz_5;
+ zz[zzOff + 5] = (w << 1) | c;
+ c = w >> 31;
+ zz_6 += (zz_5 >> 32) + x_5 * x_1;
+ zz_7 += (zz_6 >> 32) + x_5 * x_2;
+ zz_6 &= M;
+ zz_8 += (zz_7 >> 32) + x_5 * x_3;
+ zz_7 &= M;
+ zz_9 += (zz_8 >> 32) + x_5 * x_4;
+ zz_8 &= M;
+ zz_10 += zz_9 >> 32;
+ zz_9 &= M;
+ }
+
+ ulong x_6 = x[xOff + 6];
+ ulong zz_11 = zz[zzOff + 11] + (zz_10 >> 32); zz_10 &= M;
+ ulong zz_12 = zz[zzOff + 12] + (zz_11 >> 32); zz_11 &= M;
+ {
+ zz_6 += x_6 * x_0;
+ w = (uint)zz_6;
+ zz[zzOff + 6] = (w << 1) | c;
+ c = w >> 31;
+ zz_7 += (zz_6 >> 32) + x_6 * x_1;
+ zz_8 += (zz_7 >> 32) + x_6 * x_2;
+ zz_7 &= M;
+ zz_9 += (zz_8 >> 32) + x_6 * x_3;
+ zz_8 &= M;
+ zz_10 += (zz_9 >> 32) + x_6 * x_4;
+ zz_9 &= M;
+ zz_11 += (zz_10 >> 32) + x_6 * x_5;
+ zz_10 &= M;
+ zz_12 += zz_11 >> 32;
+ zz_11 &= M;
+ }
+
+ ulong x_7 = x[xOff + 7];
+ ulong zz_13 = zz[zzOff + 13] + (zz_12 >> 32); zz_12 &= M;
+ ulong zz_14 = zz[zzOff + 14] + (zz_13 >> 32); zz_13 &= M;
+ {
+ zz_7 += x_7 * x_0;
+ w = (uint)zz_7;
+ zz[zzOff + 7] = (w << 1) | c;
+ c = w >> 31;
+ zz_8 += (zz_7 >> 32) + x_7 * x_1;
+ zz_9 += (zz_8 >> 32) + x_7 * x_2;
+ zz_10 += (zz_9 >> 32) + x_7 * x_3;
+ zz_11 += (zz_10 >> 32) + x_7 * x_4;
+ zz_12 += (zz_11 >> 32) + x_7 * x_5;
+ zz_13 += (zz_12 >> 32) + x_7 * x_6;
+ zz_14 += zz_13 >> 32;
+ }
+
+ w = (uint)zz_8;
+ zz[zzOff + 8] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_9;
+ zz[zzOff + 9] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_10;
+ zz[zzOff + 10] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_11;
+ zz[zzOff + 11] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_12;
+ zz[zzOff + 12] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_13;
+ zz[zzOff + 13] = (w << 1) | c;
+ c = w >> 31;
+ w = (uint)zz_14;
+ zz[zzOff + 14] = (w << 1) | c;
+ c = w >> 31;
+ w = zz[zzOff + 15] + (uint)(zz_14 >> 32);
+ zz[zzOff + 15] = (w << 1) | c;
+ }
+
+ public static int Sub(uint[] x, uint[] y, uint[] z)
+ {
+ long c = 0;
+ c += (long)x[0] - y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)x[1] - y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)x[2] - y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)x[3] - y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (long)x[4] - y[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (long)x[5] - y[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ c += (long)x[6] - y[6];
+ z[6] = (uint)c;
+ c >>= 32;
+ c += (long)x[7] - y[7];
+ z[7] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int Sub(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+ {
+ long c = 0;
+ c += (long)x[xOff + 0] - y[yOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 1] - y[yOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 2] - y[yOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 3] - y[yOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 4] - y[yOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 5] - y[yOff + 5];
+ z[zOff + 5] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 6] - y[yOff + 6];
+ z[zOff + 6] = (uint)c;
+ c >>= 32;
+ c += (long)x[xOff + 7] - y[yOff + 7];
+ z[zOff + 7] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubBothFrom(uint[] x, uint[] y, uint[] z)
+ {
+ long c = 0;
+ c += (long)z[0] - x[0] - y[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)z[1] - x[1] - y[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)z[2] - x[2] - y[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)z[3] - x[3] - y[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (long)z[4] - x[4] - y[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (long)z[5] - x[5] - y[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ c += (long)z[6] - x[6] - y[6];
+ z[6] = (uint)c;
+ c >>= 32;
+ c += (long)z[7] - x[7] - y[7];
+ z[7] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubFrom(uint[] x, uint[] z)
+ {
+ long c = 0;
+ c += (long)z[0] - x[0];
+ z[0] = (uint)c;
+ c >>= 32;
+ c += (long)z[1] - x[1];
+ z[1] = (uint)c;
+ c >>= 32;
+ c += (long)z[2] - x[2];
+ z[2] = (uint)c;
+ c >>= 32;
+ c += (long)z[3] - x[3];
+ z[3] = (uint)c;
+ c >>= 32;
+ c += (long)z[4] - x[4];
+ z[4] = (uint)c;
+ c >>= 32;
+ c += (long)z[5] - x[5];
+ z[5] = (uint)c;
+ c >>= 32;
+ c += (long)z[6] - x[6];
+ z[6] = (uint)c;
+ c >>= 32;
+ c += (long)z[7] - x[7];
+ z[7] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static int SubFrom(uint[] x, int xOff, uint[] z, int zOff)
+ {
+ long c = 0;
+ c += (long)z[zOff + 0] - x[xOff + 0];
+ z[zOff + 0] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 1] - x[xOff + 1];
+ z[zOff + 1] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 2] - x[xOff + 2];
+ z[zOff + 2] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 3] - x[xOff + 3];
+ z[zOff + 3] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 4] - x[xOff + 4];
+ z[zOff + 4] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 5] - x[xOff + 5];
+ z[zOff + 5] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 6] - x[xOff + 6];
+ z[zOff + 6] = (uint)c;
+ c >>= 32;
+ c += (long)z[zOff + 7] - x[xOff + 7];
+ z[zOff + 7] = (uint)c;
+ c >>= 32;
+ return (int)c;
+ }
+
+ public static BigInteger ToBigInteger(uint[] x)
+ {
+ byte[] bs = new byte[32];
+ for (int i = 0; i < 8; ++i)
+ {
+ uint x_i = x[i];
+ if (x_i != 0)
+ {
+ Pack.UInt32_To_BE(x_i, bs, (7 - i) << 2);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+
+ public static BigInteger ToBigInteger64(ulong[] x)
+ {
+ byte[] bs = new byte[32];
+ for (int i = 0; i < 4; ++i)
+ {
+ ulong x_i = x[i];
+ if (x_i != 0L)
+ {
+ Pack.UInt64_To_BE(x_i, bs, (3 - i) << 3);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+
+ public static void Zero(uint[] z)
+ {
+ z[0] = 0;
+ z[1] = 0;
+ z[2] = 0;
+ z[3] = 0;
+ z[4] = 0;
+ z[5] = 0;
+ z[6] = 0;
+ z[7] = 0;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/raw/Nat320.cs b/bc-sharp-crypto/src/math/raw/Nat320.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c7daa71e26756ff9e7dccc90819ffb69949b8aaa
--- /dev/null
+++ b/bc-sharp-crypto/src/math/raw/Nat320.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Nat320
+ {
+ public static void Copy64(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ z[4] = x[4];
+ }
+
+ public static ulong[] Create64()
+ {
+ return new ulong[5];
+ }
+
+ public static ulong[] CreateExt64()
+ {
+ return new ulong[10];
+ }
+
+ public static bool Eq64(ulong[] x, ulong[] y)
+ {
+ for (int i = 4; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static ulong[] FromBigInteger64(BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > 320)
+ throw new ArgumentException();
+
+ ulong[] z = Create64();
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (ulong)x.LongValue;
+ x = x.ShiftRight(64);
+ }
+ return z;
+ }
+
+ public static bool IsOne64(ulong[] x)
+ {
+ if (x[0] != 1UL)
+ {
+ return false;
+ }
+ for (int i = 1; i < 5; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsZero64(ulong[] x)
+ {
+ for (int i = 0; i < 5; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static BigInteger ToBigInteger64(ulong[] x)
+ {
+ byte[] bs = new byte[40];
+ for (int i = 0; i < 5; ++i)
+ {
+ ulong x_i = x[i];
+ if (x_i != 0L)
+ {
+ Pack.UInt64_To_BE(x_i, bs, (4 - i) << 3);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/raw/Nat384.cs b/bc-sharp-crypto/src/math/raw/Nat384.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ed1c47e8c1f0fc3c81e2cc531b351896a47722ca
--- /dev/null
+++ b/bc-sharp-crypto/src/math/raw/Nat384.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Diagnostics;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Nat384
+ {
+ public static void Mul(uint[] x, uint[] y, uint[] zz)
+ {
+ Nat192.Mul(x, y, zz);
+ Nat192.Mul(x, 6, y, 6, zz, 12);
+
+ uint c18 = Nat192.AddToEachOther(zz, 6, zz, 12);
+ uint c12 = c18 + Nat192.AddTo(zz, 0, zz, 6, 0);
+ c18 += Nat192.AddTo(zz, 18, zz, 12, c12);
+
+ uint[] dx = Nat192.Create(), dy = Nat192.Create();
+ bool neg = Nat192.Diff(x, 6, x, 0, dx, 0) != Nat192.Diff(y, 6, y, 0, dy, 0);
+
+ uint[] tt = Nat192.CreateExt();
+ Nat192.Mul(dx, dy, tt);
+
+ c18 += neg ? Nat.AddTo(12, tt, 0, zz, 6) : (uint)Nat.SubFrom(12, tt, 0, zz, 6);
+ Nat.AddWordAt(24, c18, zz, 18);
+ }
+
+ public static void Square(uint[] x, uint[] zz)
+ {
+ Nat192.Square(x, zz);
+ Nat192.Square(x, 6, zz, 12);
+
+ uint c18 = Nat192.AddToEachOther(zz, 6, zz, 12);
+ uint c12 = c18 + Nat192.AddTo(zz, 0, zz, 6, 0);
+ c18 += Nat192.AddTo(zz, 18, zz, 12, c12);
+
+ uint[] dx = Nat192.Create();
+ Nat192.Diff(x, 6, x, 0, dx, 0);
+
+ uint[] m = Nat192.CreateExt();
+ Nat192.Square(dx, m);
+
+ c18 += (uint)Nat.SubFrom(12, m, 0, zz, 6);
+ Nat.AddWordAt(24, c18, zz, 18);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/raw/Nat448.cs b/bc-sharp-crypto/src/math/raw/Nat448.cs
new file mode 100644
index 0000000000000000000000000000000000000000..52a253f1b5b05bfcc1aeff9b132b077203ab0a73
--- /dev/null
+++ b/bc-sharp-crypto/src/math/raw/Nat448.cs
@@ -0,0 +1,100 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Nat448
+ {
+ public static void Copy64(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ z[4] = x[4];
+ z[5] = x[5];
+ z[6] = x[6];
+ }
+
+ public static ulong[] Create64()
+ {
+ return new ulong[7];
+ }
+
+ public static ulong[] CreateExt64()
+ {
+ return new ulong[14];
+ }
+
+ public static bool Eq64(ulong[] x, ulong[] y)
+ {
+ for (int i = 6; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static ulong[] FromBigInteger64(BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > 448)
+ throw new ArgumentException();
+
+ ulong[] z = Create64();
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (ulong)x.LongValue;
+ x = x.ShiftRight(64);
+ }
+ return z;
+ }
+
+ public static bool IsOne64(ulong[] x)
+ {
+ if (x[0] != 1UL)
+ {
+ return false;
+ }
+ for (int i = 1; i < 7; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsZero64(ulong[] x)
+ {
+ for (int i = 0; i < 7; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static BigInteger ToBigInteger64(ulong[] x)
+ {
+ byte[] bs = new byte[56];
+ for (int i = 0; i < 7; ++i)
+ {
+ ulong x_i = x[i];
+ if (x_i != 0L)
+ {
+ Pack.UInt64_To_BE(x_i, bs, (6 - i) << 3);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/raw/Nat512.cs b/bc-sharp-crypto/src/math/raw/Nat512.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a9ef2b3b637458ac69e6154af7f83b5ba7d1b637
--- /dev/null
+++ b/bc-sharp-crypto/src/math/raw/Nat512.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Diagnostics;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Nat512
+ {
+ public static void Mul(uint[] x, uint[] y, uint[] zz)
+ {
+ Nat256.Mul(x, y, zz);
+ Nat256.Mul(x, 8, y, 8, zz, 16);
+
+ uint c24 = Nat256.AddToEachOther(zz, 8, zz, 16);
+ uint c16 = c24 + Nat256.AddTo(zz, 0, zz, 8, 0);
+ c24 += Nat256.AddTo(zz, 24, zz, 16, c16);
+
+ uint[] dx = Nat256.Create(), dy = Nat256.Create();
+ bool neg = Nat256.Diff(x, 8, x, 0, dx, 0) != Nat256.Diff(y, 8, y, 0, dy, 0);
+
+ uint[] tt = Nat256.CreateExt();
+ Nat256.Mul(dx, dy, tt);
+
+ c24 += neg ? Nat.AddTo(16, tt, 0, zz, 8) : (uint)Nat.SubFrom(16, tt, 0, zz, 8);
+ Nat.AddWordAt(32, c24, zz, 24);
+ }
+
+ public static void Square(uint[] x, uint[] zz)
+ {
+ Nat256.Square(x, zz);
+ Nat256.Square(x, 8, zz, 16);
+
+ uint c24 = Nat256.AddToEachOther(zz, 8, zz, 16);
+ uint c16 = c24 + Nat256.AddTo(zz, 0, zz, 8, 0);
+ c24 += Nat256.AddTo(zz, 24, zz, 16, c16);
+
+ uint[] dx = Nat256.Create();
+ Nat256.Diff(x, 8, x, 0, dx, 0);
+
+ uint[] m = Nat256.CreateExt();
+ Nat256.Square(dx, m);
+
+ c24 += (uint)Nat.SubFrom(16, m, 0, zz, 8);
+ Nat.AddWordAt(32, c24, zz, 24);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/math/raw/Nat576.cs b/bc-sharp-crypto/src/math/raw/Nat576.cs
new file mode 100644
index 0000000000000000000000000000000000000000..813fb86bed7556372040decf7cfabde6353bbf15
--- /dev/null
+++ b/bc-sharp-crypto/src/math/raw/Nat576.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.Raw
+{
+ internal abstract class Nat576
+ {
+ public static void Copy64(ulong[] x, ulong[] z)
+ {
+ z[0] = x[0];
+ z[1] = x[1];
+ z[2] = x[2];
+ z[3] = x[3];
+ z[4] = x[4];
+ z[5] = x[5];
+ z[6] = x[6];
+ z[7] = x[7];
+ z[8] = x[8];
+ }
+
+ public static ulong[] Create64()
+ {
+ return new ulong[9];
+ }
+
+ public static ulong[] CreateExt64()
+ {
+ return new ulong[18];
+ }
+
+ public static bool Eq64(ulong[] x, ulong[] y)
+ {
+ for (int i = 8; i >= 0; --i)
+ {
+ if (x[i] != y[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static ulong[] FromBigInteger64(BigInteger x)
+ {
+ if (x.SignValue < 0 || x.BitLength > 576)
+ throw new ArgumentException();
+
+ ulong[] z = Create64();
+ int i = 0;
+ while (x.SignValue != 0)
+ {
+ z[i++] = (ulong)x.LongValue;
+ x = x.ShiftRight(64);
+ }
+ return z;
+ }
+
+ public static bool IsOne64(ulong[] x)
+ {
+ if (x[0] != 1UL)
+ {
+ return false;
+ }
+ for (int i = 1; i < 9; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static bool IsZero64(ulong[] x)
+ {
+ for (int i = 0; i < 9; ++i)
+ {
+ if (x[i] != 0UL)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static BigInteger ToBigInteger64(ulong[] x)
+ {
+ byte[] bs = new byte[72];
+ for (int i = 0; i < 9; ++i)
+ {
+ ulong x_i = x[i];
+ if (x_i != 0L)
+ {
+ Pack.UInt64_To_BE(x_i, bs, (8 - i) << 3);
+ }
+ }
+ return new BigInteger(1, bs);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/ocsp/BasicOCSPResp.cs b/bc-sharp-crypto/src/ocsp/BasicOCSPResp.cs
new file mode 100644
index 0000000000000000000000000000000000000000..63ab8921ede3252766566022924310141c057b17
--- /dev/null
+++ b/bc-sharp-crypto/src/ocsp/BasicOCSPResp.cs
@@ -0,0 +1,220 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ ///
+ ///
+ /// BasicOcspResponse ::= SEQUENCE {
+ /// tbsResponseData ResponseData,
+ /// signatureAlgorithm AlgorithmIdentifier,
+ /// signature BIT STRING,
+ /// certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL
+ /// }
+ ///
+ ///
+ public class BasicOcspResp
+ : X509ExtensionBase
+ {
+ private readonly BasicOcspResponse resp;
+ private readonly ResponseData data;
+// private readonly X509Certificate[] chain;
+
+ public BasicOcspResp(
+ BasicOcspResponse resp)
+ {
+ this.resp = resp;
+ this.data = resp.TbsResponseData;
+ }
+
+ /// The DER encoding of the tbsResponseData field.
+ /// In the event of an encoding error.
+ public byte[] GetTbsResponseData()
+ {
+ try
+ {
+ return data.GetDerEncoded();
+ }
+ catch (IOException e)
+ {
+ throw new OcspException("problem encoding tbsResponseData", e);
+ }
+ }
+
+ public int Version
+ {
+ get { return data.Version.Value.IntValue + 1; }
+ }
+
+ public RespID ResponderId
+ {
+ get { return new RespID(data.ResponderID); }
+ }
+
+ public DateTime ProducedAt
+ {
+ get { return data.ProducedAt.ToDateTime(); }
+ }
+
+ public SingleResp[] Responses
+ {
+ get
+ {
+ Asn1Sequence s = data.Responses;
+ SingleResp[] rs = new SingleResp[s.Count];
+
+ for (int i = 0; i != rs.Length; i++)
+ {
+ rs[i] = new SingleResp(SingleResponse.GetInstance(s[i]));
+ }
+
+ return rs;
+ }
+ }
+
+ public X509Extensions ResponseExtensions
+ {
+ get { return data.ResponseExtensions; }
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return ResponseExtensions;
+ }
+
+ public string SignatureAlgName
+ {
+ get { return OcspUtilities.GetAlgorithmName(resp.SignatureAlgorithm.Algorithm); }
+ }
+
+ public string SignatureAlgOid
+ {
+ get { return resp.SignatureAlgorithm.Algorithm.Id; }
+ }
+
+ [Obsolete("RespData class is no longer required as all functionality is available on this class")]
+ public RespData GetResponseData()
+ {
+ return new RespData(data);
+ }
+
+ public byte[] GetSignature()
+ {
+ return resp.GetSignatureOctets();
+ }
+
+ private IList GetCertList()
+ {
+ // load the certificates and revocation lists if we have any
+
+ IList certs = Platform.CreateArrayList();
+ Asn1Sequence s = resp.Certs;
+
+ if (s != null)
+ {
+ foreach (Asn1Encodable ae in s)
+ {
+ try
+ {
+ certs.Add(new X509CertificateParser().ReadCertificate(ae.GetEncoded()));
+ }
+ catch (IOException ex)
+ {
+ throw new OcspException("can't re-encode certificate!", ex);
+ }
+ catch (CertificateException ex)
+ {
+ throw new OcspException("can't re-encode certificate!", ex);
+ }
+ }
+ }
+
+ return certs;
+ }
+
+ public X509Certificate[] GetCerts()
+ {
+ IList certs = GetCertList();
+ X509Certificate[] result = new X509Certificate[certs.Count];
+ for (int i = 0; i < certs.Count; ++i)
+ {
+ result[i] = (X509Certificate)certs[i];
+ }
+ return result;
+ }
+
+ /// The certificates, if any, associated with the response.
+ /// In the event of an encoding error.
+ public IX509Store GetCertificates(
+ string type)
+ {
+ try
+ {
+ return X509StoreFactory.Create(
+ "Certificate/" + type,
+ new X509CollectionStoreParameters(this.GetCertList()));
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("can't setup the CertStore", e);
+ }
+ }
+
+ ///
+ /// Verify the signature against the tbsResponseData object we contain.
+ ///
+ public bool Verify(
+ AsymmetricKeyParameter publicKey)
+ {
+ try
+ {
+ ISigner signature = SignerUtilities.GetSigner(this.SignatureAlgName);
+ signature.Init(false, publicKey);
+ byte[] bs = data.GetDerEncoded();
+ signature.BlockUpdate(bs, 0, bs.Length);
+
+ return signature.VerifySignature(this.GetSignature());
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("exception processing sig: " + e, e);
+ }
+ }
+
+ /// The ASN.1 encoded representation of this object.
+ public byte[] GetEncoded()
+ {
+ return resp.GetEncoded();
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ BasicOcspResp other = obj as BasicOcspResp;
+
+ if (other == null)
+ return false;
+
+ return resp.Equals(other.resp);
+ }
+
+ public override int GetHashCode()
+ {
+ return resp.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/ocsp/BasicOCSPRespGenerator.cs b/bc-sharp-crypto/src/ocsp/BasicOCSPRespGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0dd4e0a097e7eeca86b3df103f44d7fe21a69525
--- /dev/null
+++ b/bc-sharp-crypto/src/ocsp/BasicOCSPRespGenerator.cs
@@ -0,0 +1,313 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.Crypto.Operators;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ /**
+ * Generator for basic OCSP response objects.
+ */
+ public class BasicOcspRespGenerator
+ {
+ private readonly IList list = Platform.CreateArrayList();
+
+ private X509Extensions responseExtensions;
+ private RespID responderID;
+
+ private class ResponseObject
+ {
+ internal CertificateID certId;
+ internal CertStatus certStatus;
+ internal DerGeneralizedTime thisUpdate;
+ internal DerGeneralizedTime nextUpdate;
+ internal X509Extensions extensions;
+
+ public ResponseObject(
+ CertificateID certId,
+ CertificateStatus certStatus,
+ DateTime thisUpdate,
+ X509Extensions extensions)
+ : this(certId, certStatus, new DerGeneralizedTime(thisUpdate), null, extensions)
+ {
+ }
+
+ public ResponseObject(
+ CertificateID certId,
+ CertificateStatus certStatus,
+ DateTime thisUpdate,
+ DateTime nextUpdate,
+ X509Extensions extensions)
+ : this(certId, certStatus, new DerGeneralizedTime(thisUpdate), new DerGeneralizedTime(nextUpdate), extensions)
+ {
+ }
+
+ private ResponseObject(
+ CertificateID certId,
+ CertificateStatus certStatus,
+ DerGeneralizedTime thisUpdate,
+ DerGeneralizedTime nextUpdate,
+ X509Extensions extensions)
+ {
+ this.certId = certId;
+
+ if (certStatus == null)
+ {
+ this.certStatus = new CertStatus();
+ }
+ else if (certStatus is UnknownStatus)
+ {
+ this.certStatus = new CertStatus(2, DerNull.Instance);
+ }
+ else
+ {
+ RevokedStatus rs = (RevokedStatus) certStatus;
+ CrlReason revocationReason = rs.HasRevocationReason
+ ? new CrlReason(rs.RevocationReason)
+ : null;
+
+ this.certStatus = new CertStatus(
+ new RevokedInfo(new DerGeneralizedTime(rs.RevocationTime), revocationReason));
+ }
+
+ this.thisUpdate = thisUpdate;
+ this.nextUpdate = nextUpdate;
+
+ this.extensions = extensions;
+ }
+
+ public SingleResponse ToResponse()
+ {
+ return new SingleResponse(certId.ToAsn1Object(), certStatus, thisUpdate, nextUpdate, extensions);
+ }
+ }
+
+ /**
+ * basic constructor
+ */
+ public BasicOcspRespGenerator(
+ RespID responderID)
+ {
+ this.responderID = responderID;
+ }
+
+ /**
+ * construct with the responderID to be the SHA-1 keyHash of the passed in public key.
+ */
+ public BasicOcspRespGenerator(
+ AsymmetricKeyParameter publicKey)
+ {
+ this.responderID = new RespID(publicKey);
+ }
+
+ /**
+ * Add a response for a particular Certificate ID.
+ *
+ * @param certID certificate ID details
+ * @param certStatus status of the certificate - null if okay
+ */
+ public void AddResponse(
+ CertificateID certID,
+ CertificateStatus certStatus)
+ {
+ list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, null));
+ }
+
+ /**
+ * Add a response for a particular Certificate ID.
+ *
+ * @param certID certificate ID details
+ * @param certStatus status of the certificate - null if okay
+ * @param singleExtensions optional extensions
+ */
+ public void AddResponse(
+ CertificateID certID,
+ CertificateStatus certStatus,
+ X509Extensions singleExtensions)
+ {
+ list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, singleExtensions));
+ }
+
+ /**
+ * Add a response for a particular Certificate ID.
+ *
+ * @param certID certificate ID details
+ * @param nextUpdate date when next update should be requested
+ * @param certStatus status of the certificate - null if okay
+ * @param singleExtensions optional extensions
+ */
+ public void AddResponse(
+ CertificateID certID,
+ CertificateStatus certStatus,
+ DateTime nextUpdate,
+ X509Extensions singleExtensions)
+ {
+ list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, nextUpdate, singleExtensions));
+ }
+
+ /**
+ * Add a response for a particular Certificate ID.
+ *
+ * @param certID certificate ID details
+ * @param thisUpdate date this response was valid on
+ * @param nextUpdate date when next update should be requested
+ * @param certStatus status of the certificate - null if okay
+ * @param singleExtensions optional extensions
+ */
+ public void AddResponse(
+ CertificateID certID,
+ CertificateStatus certStatus,
+ DateTime thisUpdate,
+ DateTime nextUpdate,
+ X509Extensions singleExtensions)
+ {
+ list.Add(new ResponseObject(certID, certStatus, thisUpdate, nextUpdate, singleExtensions));
+ }
+
+ /**
+ * Set the extensions for the response.
+ *
+ * @param responseExtensions the extension object to carry.
+ */
+ public void SetResponseExtensions(
+ X509Extensions responseExtensions)
+ {
+ this.responseExtensions = responseExtensions;
+ }
+
+ private BasicOcspResp GenerateResponse(
+ ISignatureFactory signatureCalculator,
+ X509Certificate[] chain,
+ DateTime producedAt)
+ {
+ AlgorithmIdentifier signingAlgID = (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails;
+ DerObjectIdentifier signingAlgorithm = signingAlgID.Algorithm;
+
+ Asn1EncodableVector responses = new Asn1EncodableVector();
+
+ foreach (ResponseObject respObj in list)
+ {
+ try
+ {
+ responses.Add(respObj.ToResponse());
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("exception creating Request", e);
+ }
+ }
+
+ ResponseData tbsResp = new ResponseData(responderID.ToAsn1Object(), new DerGeneralizedTime(producedAt), new DerSequence(responses), responseExtensions);
+ DerBitString bitSig = null;
+
+ try
+ {
+ IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator();
+
+ byte[] encoded = tbsResp.GetDerEncoded();
+
+ streamCalculator.Stream.Write(encoded, 0, encoded.Length);
+
+ Platform.Dispose(streamCalculator.Stream);
+
+ bitSig = new DerBitString(((IBlockResult)streamCalculator.GetResult()).Collect());
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("exception processing TBSRequest: " + e, e);
+ }
+
+ AlgorithmIdentifier sigAlgId = OcspUtilities.GetSigAlgID(signingAlgorithm);
+
+ DerSequence chainSeq = null;
+ if (chain != null && chain.Length > 0)
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+ try
+ {
+ for (int i = 0; i != chain.Length; i++)
+ {
+ v.Add(
+ X509CertificateStructure.GetInstance(
+ Asn1Object.FromByteArray(chain[i].GetEncoded())));
+ }
+ }
+ catch (IOException e)
+ {
+ throw new OcspException("error processing certs", e);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new OcspException("error encoding certs", e);
+ }
+
+ chainSeq = new DerSequence(v);
+ }
+
+ return new BasicOcspResp(new BasicOcspResponse(tbsResp, sigAlgId, bitSig, chainSeq));
+ }
+
+ public BasicOcspResp Generate(
+ string signingAlgorithm,
+ AsymmetricKeyParameter privateKey,
+ X509Certificate[] chain,
+ DateTime thisUpdate)
+ {
+ return Generate(signingAlgorithm, privateKey, chain, thisUpdate, null);
+ }
+
+ public BasicOcspResp Generate(
+ string signingAlgorithm,
+ AsymmetricKeyParameter privateKey,
+ X509Certificate[] chain,
+ DateTime producedAt,
+ SecureRandom random)
+ {
+ if (signingAlgorithm == null)
+ {
+ throw new ArgumentException("no signing algorithm specified");
+ }
+
+ return GenerateResponse(new Asn1SignatureFactory(signingAlgorithm, privateKey, random), chain, producedAt);
+ }
+
+ ///
+ /// Generate the signed response using the passed in signature calculator.
+ ///
+ /// Implementation of signing calculator factory.
+ /// The certificate chain associated with the response signer.
+ /// "produced at" date.
+ ///
+ public BasicOcspResp Generate(
+ ISignatureFactory signatureCalculatorFactory,
+ X509Certificate[] chain,
+ DateTime producedAt)
+ {
+ if (signatureCalculatorFactory == null)
+ {
+ throw new ArgumentException("no signature calculator specified");
+ }
+
+ return GenerateResponse(signatureCalculatorFactory, chain, producedAt);
+ }
+
+ /**
+ * Return an IEnumerable of the signature names supported by the generator.
+ *
+ * @return an IEnumerable containing recognised names.
+ */
+ public IEnumerable SignatureAlgNames
+ {
+ get { return OcspUtilities.AlgNames; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/ocsp/CertificateID.cs b/bc-sharp-crypto/src/ocsp/CertificateID.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ec902d5c386074019e994d5e72582fdfb6c7897e
--- /dev/null
+++ b/bc-sharp-crypto/src/ocsp/CertificateID.cs
@@ -0,0 +1,141 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ public class CertificateID
+ {
+ public const string HashSha1 = "1.3.14.3.2.26";
+
+ private readonly CertID id;
+
+ public CertificateID(
+ CertID id)
+ {
+ if (id == null)
+ throw new ArgumentNullException("id");
+
+ this.id = id;
+ }
+
+ /**
+ * create from an issuer certificate and the serial number of the
+ * certificate it signed.
+ * @exception OcspException if any problems occur creating the id fields.
+ */
+ public CertificateID(
+ string hashAlgorithm,
+ X509Certificate issuerCert,
+ BigInteger serialNumber)
+ {
+ AlgorithmIdentifier hashAlg = new AlgorithmIdentifier(
+ new DerObjectIdentifier(hashAlgorithm), DerNull.Instance);
+
+ this.id = CreateCertID(hashAlg, issuerCert, new DerInteger(serialNumber));
+ }
+
+ public string HashAlgOid
+ {
+ get { return id.HashAlgorithm.Algorithm.Id; }
+ }
+
+ public byte[] GetIssuerNameHash()
+ {
+ return id.IssuerNameHash.GetOctets();
+ }
+
+ public byte[] GetIssuerKeyHash()
+ {
+ return id.IssuerKeyHash.GetOctets();
+ }
+
+ /**
+ * return the serial number for the certificate associated
+ * with this request.
+ */
+ public BigInteger SerialNumber
+ {
+ get { return id.SerialNumber.Value; }
+ }
+
+ public bool MatchesIssuer(
+ X509Certificate issuerCert)
+ {
+ return CreateCertID(id.HashAlgorithm, issuerCert, id.SerialNumber).Equals(id);
+ }
+
+ public CertID ToAsn1Object()
+ {
+ return id;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ CertificateID other = obj as CertificateID;
+
+ if (other == null)
+ return false;
+
+ return id.ToAsn1Object().Equals(other.id.ToAsn1Object());
+ }
+
+ public override int GetHashCode()
+ {
+ return id.ToAsn1Object().GetHashCode();
+ }
+
+
+ /**
+ * Create a new CertificateID for a new serial number derived from a previous one
+ * calculated for the same CA certificate.
+ *
+ * @param original the previously calculated CertificateID for the CA.
+ * @param newSerialNumber the serial number for the new certificate of interest.
+ *
+ * @return a new CertificateID for newSerialNumber
+ */
+ public static CertificateID DeriveCertificateID(CertificateID original, BigInteger newSerialNumber)
+ {
+ return new CertificateID(new CertID(original.id.HashAlgorithm, original.id.IssuerNameHash,
+ original.id.IssuerKeyHash, new DerInteger(newSerialNumber)));
+ }
+
+ private static CertID CreateCertID(
+ AlgorithmIdentifier hashAlg,
+ X509Certificate issuerCert,
+ DerInteger serialNumber)
+ {
+ try
+ {
+ String hashAlgorithm = hashAlg.Algorithm.Id;
+
+ X509Name issuerName = PrincipalUtilities.GetSubjectX509Principal(issuerCert);
+ byte[] issuerNameHash = DigestUtilities.CalculateDigest(
+ hashAlgorithm, issuerName.GetEncoded());
+
+ AsymmetricKeyParameter issuerKey = issuerCert.GetPublicKey();
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(issuerKey);
+ byte[] issuerKeyHash = DigestUtilities.CalculateDigest(
+ hashAlgorithm, info.PublicKeyData.GetBytes());
+
+ return new CertID(hashAlg, new DerOctetString(issuerNameHash),
+ new DerOctetString(issuerKeyHash), serialNumber);
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("problem creating ID: " + e, e);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/ocsp/CertificateStatus.cs b/bc-sharp-crypto/src/ocsp/CertificateStatus.cs
new file mode 100644
index 0000000000000000000000000000000000000000..edfcc2582a80bd4c8f1566e3bd27b6bd4a74e140
--- /dev/null
+++ b/bc-sharp-crypto/src/ocsp/CertificateStatus.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ public abstract class CertificateStatus
+ {
+ public static readonly CertificateStatus Good = null;
+ }
+}
diff --git a/bc-sharp-crypto/src/ocsp/OCSPException.cs b/bc-sharp-crypto/src/ocsp/OCSPException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d7b14ddc7f6b5e3bfe414d942ec0d2f18233d0a1
--- /dev/null
+++ b/bc-sharp-crypto/src/ocsp/OCSPException.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Org.BouncyCastle.Ocsp
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class OcspException
+ : Exception
+ {
+ public OcspException()
+ {
+ }
+
+ public OcspException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public OcspException(
+ string message,
+ Exception e)
+ : base(message, e)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/ocsp/OCSPReq.cs b/bc-sharp-crypto/src/ocsp/OCSPReq.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0cd95c6d6465486a9a984aa0ab00df37e6d12475
--- /dev/null
+++ b/bc-sharp-crypto/src/ocsp/OCSPReq.cs
@@ -0,0 +1,268 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ /**
+ *
+ * OcspRequest ::= SEQUENCE {
+ * tbsRequest TBSRequest,
+ * optionalSignature [0] EXPLICIT Signature OPTIONAL }
+ *
+ * TBSRequest ::= SEQUENCE {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * requestorName [1] EXPLICIT GeneralName OPTIONAL,
+ * requestList SEQUENCE OF Request,
+ * requestExtensions [2] EXPLICIT Extensions OPTIONAL }
+ *
+ * Signature ::= SEQUENCE {
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL}
+ *
+ * Version ::= INTEGER { v1(0) }
+ *
+ * Request ::= SEQUENCE {
+ * reqCert CertID,
+ * singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL }
+ *
+ * CertID ::= SEQUENCE {
+ * hashAlgorithm AlgorithmIdentifier,
+ * issuerNameHash OCTET STRING, -- Hash of Issuer's DN
+ * issuerKeyHash OCTET STRING, -- Hash of Issuers public key
+ * serialNumber CertificateSerialNumber }
+ *
+ */
+ public class OcspReq
+ : X509ExtensionBase
+ {
+ private OcspRequest req;
+
+ public OcspReq(
+ OcspRequest req)
+ {
+ this.req = req;
+ }
+
+ public OcspReq(
+ byte[] req)
+ : this(new Asn1InputStream(req))
+ {
+ }
+
+ public OcspReq(
+ Stream inStr)
+ : this(new Asn1InputStream(inStr))
+ {
+ }
+
+ private OcspReq(
+ Asn1InputStream aIn)
+ {
+ try
+ {
+ this.req = OcspRequest.GetInstance(aIn.ReadObject());
+ }
+ catch (ArgumentException e)
+ {
+ throw new IOException("malformed request: " + e.Message);
+ }
+ catch (InvalidCastException e)
+ {
+ throw new IOException("malformed request: " + e.Message);
+ }
+ }
+
+ /**
+ * Return the DER encoding of the tbsRequest field.
+ * @return DER encoding of tbsRequest
+ * @throws OcspException in the event of an encoding error.
+ */
+ public byte[] GetTbsRequest()
+ {
+ try
+ {
+ return req.TbsRequest.GetEncoded();
+ }
+ catch (IOException e)
+ {
+ throw new OcspException("problem encoding tbsRequest", e);
+ }
+ }
+
+ public int Version
+ {
+ get { return req.TbsRequest.Version.Value.IntValue + 1; }
+ }
+
+ public GeneralName RequestorName
+ {
+ get { return GeneralName.GetInstance(req.TbsRequest.RequestorName); }
+ }
+
+ public Req[] GetRequestList()
+ {
+ Asn1Sequence seq = req.TbsRequest.RequestList;
+ Req[] requests = new Req[seq.Count];
+
+ for (int i = 0; i != requests.Length; i++)
+ {
+ requests[i] = new Req(Request.GetInstance(seq[i]));
+ }
+
+ return requests;
+ }
+
+ public X509Extensions RequestExtensions
+ {
+ get { return X509Extensions.GetInstance(req.TbsRequest.RequestExtensions); }
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return RequestExtensions;
+ }
+
+ /**
+ * return the object identifier representing the signature algorithm
+ */
+ public string SignatureAlgOid
+ {
+ get
+ {
+ if (!this.IsSigned)
+ return null;
+
+ return req.OptionalSignature.SignatureAlgorithm.Algorithm.Id;
+ }
+ }
+
+ public byte[] GetSignature()
+ {
+ if (!this.IsSigned)
+ return null;
+
+ return req.OptionalSignature.GetSignatureOctets();
+ }
+
+ private IList GetCertList()
+ {
+ // load the certificates if we have any
+
+ IList certs = Platform.CreateArrayList();
+ Asn1Sequence s = req.OptionalSignature.Certs;
+
+ if (s != null)
+ {
+ foreach (Asn1Encodable ae in s)
+ {
+ try
+ {
+ certs.Add(new X509CertificateParser().ReadCertificate(ae.GetEncoded()));
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("can't re-encode certificate!", e);
+ }
+ }
+ }
+
+ return certs;
+ }
+
+ public X509Certificate[] GetCerts()
+ {
+ if (!this.IsSigned)
+ return null;
+
+ IList certs = this.GetCertList();
+ X509Certificate[] result = new X509Certificate[certs.Count];
+ for (int i = 0; i < certs.Count; ++i)
+ {
+ result[i] = (X509Certificate)certs[i];
+ }
+ return result;
+ }
+
+ /**
+ * If the request is signed return a possibly empty CertStore containing the certificates in the
+ * request. If the request is not signed the method returns null.
+ *
+ * @return null if not signed, a CertStore otherwise
+ * @throws OcspException
+ */
+ public IX509Store GetCertificates(
+ string type)
+ {
+ if (!this.IsSigned)
+ return null;
+
+ try
+ {
+ return X509StoreFactory.Create(
+ "Certificate/" + type,
+ new X509CollectionStoreParameters(this.GetCertList()));
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("can't setup the CertStore", e);
+ }
+ }
+
+ /**
+ * Return whether or not this request is signed.
+ *
+ * @return true if signed false otherwise.
+ */
+ public bool IsSigned
+ {
+ get { return req.OptionalSignature != null; }
+ }
+
+ /**
+ * Verify the signature against the TBSRequest object we contain.
+ */
+ public bool Verify(
+ AsymmetricKeyParameter publicKey)
+ {
+ if (!this.IsSigned)
+ throw new OcspException("attempt to Verify signature on unsigned object");
+
+ try
+ {
+ ISigner signature = SignerUtilities.GetSigner(this.SignatureAlgOid);
+
+ signature.Init(false, publicKey);
+
+ byte[] encoded = req.TbsRequest.GetEncoded();
+
+ signature.BlockUpdate(encoded, 0, encoded.Length);
+
+ return signature.VerifySignature(this.GetSignature());
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("exception processing sig: " + e, e);
+ }
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] GetEncoded()
+ {
+ return req.GetEncoded();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/ocsp/OCSPReqGenerator.cs b/bc-sharp-crypto/src/ocsp/OCSPReqGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8032a4598e62e0d3eb2d41c84fe66a8adceebb04
--- /dev/null
+++ b/bc-sharp-crypto/src/ocsp/OCSPReqGenerator.cs
@@ -0,0 +1,243 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ public class OcspReqGenerator
+ {
+ private IList list = Platform.CreateArrayList();
+ private GeneralName requestorName = null;
+ private X509Extensions requestExtensions = null;
+
+ private class RequestObject
+ {
+ internal CertificateID certId;
+ internal X509Extensions extensions;
+
+ public RequestObject(
+ CertificateID certId,
+ X509Extensions extensions)
+ {
+ this.certId = certId;
+ this.extensions = extensions;
+ }
+
+ public Request ToRequest()
+ {
+ return new Request(certId.ToAsn1Object(), extensions);
+ }
+ }
+
+ /**
+ * Add a request for the given CertificateID.
+ *
+ * @param certId certificate ID of interest
+ */
+ public void AddRequest(
+ CertificateID certId)
+ {
+ list.Add(new RequestObject(certId, null));
+ }
+
+ /**
+ * Add a request with extensions
+ *
+ * @param certId certificate ID of interest
+ * @param singleRequestExtensions the extensions to attach to the request
+ */
+ public void AddRequest(
+ CertificateID certId,
+ X509Extensions singleRequestExtensions)
+ {
+ list.Add(new RequestObject(certId, singleRequestExtensions));
+ }
+
+ /**
+ * Set the requestor name to the passed in X509Principal
+ *
+ * @param requestorName a X509Principal representing the requestor name.
+ */
+ public void SetRequestorName(
+ X509Name requestorName)
+ {
+ try
+ {
+ this.requestorName = new GeneralName(GeneralName.DirectoryName, requestorName);
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("cannot encode principal", e);
+ }
+ }
+
+ public void SetRequestorName(
+ GeneralName requestorName)
+ {
+ this.requestorName = requestorName;
+ }
+
+ public void SetRequestExtensions(
+ X509Extensions requestExtensions)
+ {
+ this.requestExtensions = requestExtensions;
+ }
+
+ private OcspReq GenerateRequest(
+ DerObjectIdentifier signingAlgorithm,
+ AsymmetricKeyParameter privateKey,
+ X509Certificate[] chain,
+ SecureRandom random)
+ {
+ Asn1EncodableVector requests = new Asn1EncodableVector();
+
+ foreach (RequestObject reqObj in list)
+ {
+ try
+ {
+ requests.Add(reqObj.ToRequest());
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("exception creating Request", e);
+ }
+ }
+
+ TbsRequest tbsReq = new TbsRequest(requestorName, new DerSequence(requests), requestExtensions);
+
+ ISigner sig = null;
+ Signature signature = null;
+
+ if (signingAlgorithm != null)
+ {
+ if (requestorName == null)
+ {
+ throw new OcspException("requestorName must be specified if request is signed.");
+ }
+
+ try
+ {
+ sig = SignerUtilities.GetSigner(signingAlgorithm.Id);
+ if (random != null)
+ {
+ sig.Init(true, new ParametersWithRandom(privateKey, random));
+ }
+ else
+ {
+ sig.Init(true, privateKey);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("exception creating signature: " + e, e);
+ }
+
+ DerBitString bitSig = null;
+
+ try
+ {
+ byte[] encoded = tbsReq.GetEncoded();
+ sig.BlockUpdate(encoded, 0, encoded.Length);
+
+ bitSig = new DerBitString(sig.GenerateSignature());
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("exception processing TBSRequest: " + e, e);
+ }
+
+ AlgorithmIdentifier sigAlgId = new AlgorithmIdentifier(signingAlgorithm, DerNull.Instance);
+
+ if (chain != null && chain.Length > 0)
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+ try
+ {
+ for (int i = 0; i != chain.Length; i++)
+ {
+ v.Add(
+ X509CertificateStructure.GetInstance(
+ Asn1Object.FromByteArray(chain[i].GetEncoded())));
+ }
+ }
+ catch (IOException e)
+ {
+ throw new OcspException("error processing certs", e);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new OcspException("error encoding certs", e);
+ }
+
+ signature = new Signature(sigAlgId, bitSig, new DerSequence(v));
+ }
+ else
+ {
+ signature = new Signature(sigAlgId, bitSig);
+ }
+ }
+
+ return new OcspReq(new OcspRequest(tbsReq, signature));
+ }
+
+ /**
+ * Generate an unsigned request
+ *
+ * @return the OcspReq
+ * @throws OcspException
+ */
+ public OcspReq Generate()
+ {
+ return GenerateRequest(null, null, null, null);
+ }
+
+ public OcspReq Generate(
+ string signingAlgorithm,
+ AsymmetricKeyParameter privateKey,
+ X509Certificate[] chain)
+ {
+ return Generate(signingAlgorithm, privateKey, chain, null);
+ }
+
+ public OcspReq Generate(
+ string signingAlgorithm,
+ AsymmetricKeyParameter privateKey,
+ X509Certificate[] chain,
+ SecureRandom random)
+ {
+ if (signingAlgorithm == null)
+ throw new ArgumentException("no signing algorithm specified");
+
+ try
+ {
+ DerObjectIdentifier oid = OcspUtilities.GetAlgorithmOid(signingAlgorithm);
+
+ return GenerateRequest(oid, privateKey, chain, random);
+ }
+ catch (ArgumentException)
+ {
+ throw new ArgumentException("unknown signing algorithm specified: " + signingAlgorithm);
+ }
+ }
+
+ /**
+ * Return an IEnumerable of the signature names supported by the generator.
+ *
+ * @return an IEnumerable containing recognised names.
+ */
+ public IEnumerable SignatureAlgNames
+ {
+ get { return OcspUtilities.AlgNames; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/ocsp/OCSPResp.cs b/bc-sharp-crypto/src/ocsp/OCSPResp.cs
new file mode 100644
index 0000000000000000000000000000000000000000..dc99c6a9a25eecf599d858d72039479e1966e202
--- /dev/null
+++ b/bc-sharp-crypto/src/ocsp/OCSPResp.cs
@@ -0,0 +1,100 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ public class OcspResp
+ {
+ private OcspResponse resp;
+
+ public OcspResp(
+ OcspResponse resp)
+ {
+ this.resp = resp;
+ }
+
+ public OcspResp(
+ byte[] resp)
+ : this(new Asn1InputStream(resp))
+ {
+ }
+
+ public OcspResp(
+ Stream inStr)
+ : this(new Asn1InputStream(inStr))
+ {
+ }
+
+ private OcspResp(
+ Asn1InputStream aIn)
+ {
+ try
+ {
+ this.resp = OcspResponse.GetInstance(aIn.ReadObject());
+ }
+ catch (Exception e)
+ {
+ throw new IOException("malformed response: " + e.Message, e);
+ }
+ }
+
+ public int Status
+ {
+ get { return this.resp.ResponseStatus.Value.IntValue; }
+ }
+
+ public object GetResponseObject()
+ {
+ ResponseBytes rb = this.resp.ResponseBytes;
+
+ if (rb == null)
+ return null;
+
+ if (rb.ResponseType.Equals(OcspObjectIdentifiers.PkixOcspBasic))
+ {
+ try
+ {
+ return new BasicOcspResp(
+ BasicOcspResponse.GetInstance(
+ Asn1Object.FromByteArray(rb.Response.GetOctets())));
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("problem decoding object: " + e, e);
+ }
+ }
+
+ return rb.Response;
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] GetEncoded()
+ {
+ return resp.GetEncoded();
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ OcspResp other = obj as OcspResp;
+
+ if (other == null)
+ return false;
+
+ return resp.Equals(other.resp);
+ }
+
+ public override int GetHashCode()
+ {
+ return resp.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/ocsp/OCSPRespGenerator.cs b/bc-sharp-crypto/src/ocsp/OCSPRespGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e0eb9ae90eeebf9fb0990ac0c1f513bc6195c5d9
--- /dev/null
+++ b/bc-sharp-crypto/src/ocsp/OCSPRespGenerator.cs
@@ -0,0 +1,54 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ /**
+ * base generator for an OCSP response - at the moment this only supports the
+ * generation of responses containing BasicOCSP responses.
+ */
+ public class OCSPRespGenerator
+ {
+ public const int Successful = 0; // Response has valid confirmations
+ public const int MalformedRequest = 1; // Illegal confirmation request
+ public const int InternalError = 2; // Internal error in issuer
+ public const int TryLater = 3; // Try again later
+ // (4) is not used
+ public const int SigRequired = 5; // Must sign the request
+ public const int Unauthorized = 6; // Request unauthorized
+
+ public OcspResp Generate(
+ int status,
+ object response)
+ {
+ if (response == null)
+ {
+ return new OcspResp(new OcspResponse(new OcspResponseStatus(status),null));
+ }
+ if (response is BasicOcspResp)
+ {
+ BasicOcspResp r = (BasicOcspResp)response;
+ Asn1OctetString octs;
+
+ try
+ {
+ octs = new DerOctetString(r.GetEncoded());
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("can't encode object.", e);
+ }
+
+ ResponseBytes rb = new ResponseBytes(
+ OcspObjectIdentifiers.PkixOcspBasic, octs);
+
+ return new OcspResp(new OcspResponse(
+ new OcspResponseStatus(status), rb));
+ }
+
+ throw new OcspException("unknown response object");
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/ocsp/OCSPRespStatus.cs b/bc-sharp-crypto/src/ocsp/OCSPRespStatus.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9c00c70359bedd3fa39bcb4c554c689bb516f3e2
--- /dev/null
+++ b/bc-sharp-crypto/src/ocsp/OCSPRespStatus.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ [Obsolete("Use version with correct spelling 'OcspRespStatus'")]
+ public abstract class OcscpRespStatus : OcspRespStatus
+ {
+ }
+
+ public abstract class OcspRespStatus
+ {
+ /**
+ * note 4 is not used.
+ */
+ public const int Successful = 0; // --Response has valid confirmations
+ public const int MalformedRequest = 1; // --Illegal confirmation request
+ public const int InternalError = 2; // --Internal error in issuer
+ public const int TryLater = 3; // --Try again later
+ public const int SigRequired = 5; // --Must sign the request
+ public const int Unauthorized = 6; // --Request unauthorized
+ }
+}
diff --git a/bc-sharp-crypto/src/ocsp/OCSPUtil.cs b/bc-sharp-crypto/src/ocsp/OCSPUtil.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cbc1e95f5d1fd9fa4db5a29eb0bc571842aa074d
--- /dev/null
+++ b/bc-sharp-crypto/src/ocsp/OCSPUtil.cs
@@ -0,0 +1,132 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ class OcspUtilities
+ {
+ private static readonly IDictionary algorithms = Platform.CreateHashtable();
+ private static readonly IDictionary oids = Platform.CreateHashtable();
+ private static readonly ISet noParams = new HashSet();
+
+ static OcspUtilities()
+ {
+ algorithms.Add("MD2WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+ algorithms.Add("MD2WITHRSA", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+ algorithms.Add("MD5WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+ algorithms.Add("MD5WITHRSA", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSA", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+ algorithms.Add("SHA224WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+ algorithms.Add("SHA224WITHRSA", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+ algorithms.Add("SHA256WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+ algorithms.Add("SHA256WITHRSA", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+ algorithms.Add("SHA384WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+ algorithms.Add("SHA384WITHRSA", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+ algorithms.Add("SHA512WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+ algorithms.Add("SHA512WITHRSA", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+ algorithms.Add("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+ algorithms.Add("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+ algorithms.Add("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+ algorithms.Add("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+ algorithms.Add("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+ algorithms.Add("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+ algorithms.Add("SHA1WITHDSA", X9ObjectIdentifiers.IdDsaWithSha1);
+ algorithms.Add("DSAWITHSHA1", X9ObjectIdentifiers.IdDsaWithSha1);
+ algorithms.Add("SHA224WITHDSA", NistObjectIdentifiers.DsaWithSha224);
+ algorithms.Add("SHA256WITHDSA", NistObjectIdentifiers.DsaWithSha256);
+ algorithms.Add("SHA1WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha1);
+ algorithms.Add("ECDSAWITHSHA1", X9ObjectIdentifiers.ECDsaWithSha1);
+ algorithms.Add("SHA224WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha224);
+ algorithms.Add("SHA256WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha256);
+ algorithms.Add("SHA384WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha384);
+ algorithms.Add("SHA512WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha512);
+ algorithms.Add("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ algorithms.Add("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+
+ oids.Add(PkcsObjectIdentifiers.MD2WithRsaEncryption, "MD2WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.MD5WithRsaEncryption, "MD5WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.Sha1WithRsaEncryption, "SHA1WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.Sha224WithRsaEncryption, "SHA224WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.Sha256WithRsaEncryption, "SHA256WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.Sha384WithRsaEncryption, "SHA384WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.Sha512WithRsaEncryption, "SHA512WITHRSA");
+ oids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160, "RIPEMD160WITHRSA");
+ oids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128, "RIPEMD128WITHRSA");
+ oids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256, "RIPEMD256WITHRSA");
+ oids.Add(X9ObjectIdentifiers.IdDsaWithSha1, "SHA1WITHDSA");
+ oids.Add(NistObjectIdentifiers.DsaWithSha224, "SHA224WITHDSA");
+ oids.Add(NistObjectIdentifiers.DsaWithSha256, "SHA256WITHDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha1, "SHA1WITHECDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha224, "SHA224WITHECDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha256, "SHA256WITHECDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha384, "SHA384WITHECDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha512, "SHA512WITHECDSA");
+ oids.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94, "GOST3411WITHGOST3410");
+
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha1);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha224);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha256);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha384);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha512);
+ noParams.Add(X9ObjectIdentifiers.IdDsaWithSha1);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha224);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha256);
+ }
+
+ internal static DerObjectIdentifier GetAlgorithmOid(
+ string algorithmName)
+ {
+ algorithmName = Platform.ToUpperInvariant(algorithmName);
+
+ if (algorithms.Contains(algorithmName))
+ {
+ return (DerObjectIdentifier)algorithms[algorithmName];
+ }
+
+ return new DerObjectIdentifier(algorithmName);
+ }
+
+
+ internal static string GetAlgorithmName(
+ DerObjectIdentifier oid)
+ {
+ if (oids.Contains(oid))
+ {
+ return (string)oids[oid];
+ }
+
+ return oid.Id;
+ }
+
+ internal static AlgorithmIdentifier GetSigAlgID(
+ DerObjectIdentifier sigOid)
+ {
+ if (noParams.Contains(sigOid))
+ {
+ return new AlgorithmIdentifier(sigOid);
+ }
+
+ return new AlgorithmIdentifier(sigOid, DerNull.Instance);
+ }
+
+ internal static IEnumerable AlgNames
+ {
+ get { return new EnumerableProxy(algorithms.Keys); }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/ocsp/Req.cs b/bc-sharp-crypto/src/ocsp/Req.cs
new file mode 100644
index 0000000000000000000000000000000000000000..68fd9f12a0ad51abb28b881cdd041cf16a9536d8
--- /dev/null
+++ b/bc-sharp-crypto/src/ocsp/Req.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ public class Req
+ : X509ExtensionBase
+ {
+ private Request req;
+
+ public Req(
+ Request req)
+ {
+ this.req = req;
+ }
+
+ public CertificateID GetCertID()
+ {
+ return new CertificateID(req.ReqCert);
+ }
+
+ public X509Extensions SingleRequestExtensions
+ {
+ get { return req.SingleRequestExtensions; }
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return SingleRequestExtensions;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/ocsp/RespData.cs b/bc-sharp-crypto/src/ocsp/RespData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..105726ca7e7617c0bdc7ad7a276ffe44634f2e67
--- /dev/null
+++ b/bc-sharp-crypto/src/ocsp/RespData.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ public class RespData
+ : X509ExtensionBase
+ {
+ internal readonly ResponseData data;
+
+ public RespData(
+ ResponseData data)
+ {
+ this.data = data;
+ }
+
+ public int Version
+ {
+ get { return data.Version.Value.IntValue + 1; }
+ }
+
+ public RespID GetResponderId()
+ {
+ return new RespID(data.ResponderID);
+ }
+
+ public DateTime ProducedAt
+ {
+ get { return data.ProducedAt.ToDateTime(); }
+ }
+
+ public SingleResp[] GetResponses()
+ {
+ Asn1Sequence s = data.Responses;
+ SingleResp[] rs = new SingleResp[s.Count];
+
+ for (int i = 0; i != rs.Length; i++)
+ {
+ rs[i] = new SingleResp(SingleResponse.GetInstance(s[i]));
+ }
+
+ return rs;
+ }
+
+ public X509Extensions ResponseExtensions
+ {
+ get { return data.ResponseExtensions; }
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return ResponseExtensions;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/ocsp/RespID.cs b/bc-sharp-crypto/src/ocsp/RespID.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3238b26da05d832451dee749965edc73d1ab12bf
--- /dev/null
+++ b/bc-sharp-crypto/src/ocsp/RespID.cs
@@ -0,0 +1,72 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ /**
+ * Carrier for a ResponderID.
+ */
+ public class RespID
+ {
+ internal readonly ResponderID id;
+
+ public RespID(
+ ResponderID id)
+ {
+ this.id = id;
+ }
+
+ public RespID(
+ X509Name name)
+ {
+ this.id = new ResponderID(name);
+ }
+
+ public RespID(
+ AsymmetricKeyParameter publicKey)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);
+
+ byte[] keyHash = DigestUtilities.CalculateDigest("SHA1", info.PublicKeyData.GetBytes());
+
+ this.id = new ResponderID(new DerOctetString(keyHash));
+ }
+ catch (Exception e)
+ {
+ throw new OcspException("problem creating ID: " + e, e);
+ }
+ }
+
+ public ResponderID ToAsn1Object()
+ {
+ return id;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ RespID other = obj as RespID;
+
+ if (other == null)
+ return false;
+
+ return id.Equals(other.id);
+ }
+
+ public override int GetHashCode()
+ {
+ return id.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/ocsp/RevokedStatus.cs b/bc-sharp-crypto/src/ocsp/RevokedStatus.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6e5ad1b2612159d8ccc8e56290f5367f05b39412
--- /dev/null
+++ b/bc-sharp-crypto/src/ocsp/RevokedStatus.cs
@@ -0,0 +1,58 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ /**
+ * wrapper for the RevokedInfo object
+ */
+ public class RevokedStatus
+ : CertificateStatus
+ {
+ internal readonly RevokedInfo info;
+
+ public RevokedStatus(
+ RevokedInfo info)
+ {
+ this.info = info;
+ }
+
+ public RevokedStatus(
+ DateTime revocationDate,
+ int reason)
+ {
+ this.info = new RevokedInfo(new DerGeneralizedTime(revocationDate), new CrlReason(reason));
+ }
+
+ public DateTime RevocationTime
+ {
+ get { return info.RevocationTime.ToDateTime(); }
+ }
+
+ public bool HasRevocationReason
+ {
+ get { return (info.RevocationReason != null); }
+ }
+
+ /**
+ * return the revocation reason. Note: this field is optional, test for it
+ * with hasRevocationReason() first.
+ * @exception InvalidOperationException if a reason is asked for and none is avaliable
+ */
+ public int RevocationReason
+ {
+ get
+ {
+ if (info.RevocationReason == null)
+ {
+ throw new InvalidOperationException("attempt to get a reason where none is available");
+ }
+
+ return info.RevocationReason.Value.IntValue;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/ocsp/SingleResp.cs b/bc-sharp-crypto/src/ocsp/SingleResp.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b8979c5380aec9b8969e35b711ec7a3f43e5f64d
--- /dev/null
+++ b/bc-sharp-crypto/src/ocsp/SingleResp.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ public class SingleResp
+ : X509ExtensionBase
+ {
+ internal readonly SingleResponse resp;
+
+ public SingleResp(
+ SingleResponse resp)
+ {
+ this.resp = resp;
+ }
+
+ public CertificateID GetCertID()
+ {
+ return new CertificateID(resp.CertId);
+ }
+
+ /**
+ * Return the status object for the response - null indicates good.
+ *
+ * @return the status object for the response, null if it is good.
+ */
+ public object GetCertStatus()
+ {
+ CertStatus s = resp.CertStatus;
+
+ if (s.TagNo == 0)
+ {
+ return null; // good
+ }
+
+ if (s.TagNo == 1)
+ {
+ return new RevokedStatus(RevokedInfo.GetInstance(s.Status));
+ }
+
+ return new UnknownStatus();
+ }
+
+ public DateTime ThisUpdate
+ {
+ get { return resp.ThisUpdate.ToDateTime(); }
+ }
+
+ /**
+ * return the NextUpdate value - note: this is an optional field so may
+ * be returned as null.
+ *
+ * @return nextUpdate, or null if not present.
+ */
+ public DateTimeObject NextUpdate
+ {
+ get
+ {
+ return resp.NextUpdate == null
+ ? null
+ : new DateTimeObject(resp.NextUpdate.ToDateTime());
+ }
+ }
+
+ public X509Extensions SingleExtensions
+ {
+ get { return resp.SingleExtensions; }
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return SingleExtensions;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/ocsp/UnknownStatus.cs b/bc-sharp-crypto/src/ocsp/UnknownStatus.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c0f7a3a64c690d58680e7a86e4f8efc079bef3c9
--- /dev/null
+++ b/bc-sharp-crypto/src/ocsp/UnknownStatus.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Ocsp
+{
+ /**
+ * wrapper for the UnknownInfo object
+ */
+ public class UnknownStatus
+ : CertificateStatus
+ {
+ public UnknownStatus()
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/IStreamGenerator.cs b/bc-sharp-crypto/src/openpgp/IStreamGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..379213a66cb9a10b7e93fad26a6fc21772fac28e
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/IStreamGenerator.cs
@@ -0,0 +1,7 @@
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ public interface IStreamGenerator
+ {
+ void Close();
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PGPKeyRing.cs b/bc-sharp-crypto/src/openpgp/PGPKeyRing.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6426f3f25c12db396cccbc740729cc440021e9ed
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PGPKeyRing.cs
@@ -0,0 +1,79 @@
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ public abstract class PgpKeyRing
+ : PgpObject
+ {
+ internal PgpKeyRing()
+ {
+ }
+
+ internal static TrustPacket ReadOptionalTrustPacket(
+ BcpgInputStream bcpgInput)
+ {
+ return (bcpgInput.NextPacketTag() == PacketTag.Trust)
+ ? (TrustPacket) bcpgInput.ReadPacket()
+ : null;
+ }
+
+ internal static IList ReadSignaturesAndTrust(
+ BcpgInputStream bcpgInput)
+ {
+ try
+ {
+ IList sigList = Platform.CreateArrayList();
+
+ while (bcpgInput.NextPacketTag() == PacketTag.Signature)
+ {
+ SignaturePacket signaturePacket = (SignaturePacket) bcpgInput.ReadPacket();
+ TrustPacket trustPacket = ReadOptionalTrustPacket(bcpgInput);
+
+ sigList.Add(new PgpSignature(signaturePacket, trustPacket));
+ }
+
+ return sigList;
+ }
+ catch (PgpException e)
+ {
+ throw new IOException("can't create signature object: " + e.Message, e);
+ }
+ }
+
+ internal static void ReadUserIDs(
+ BcpgInputStream bcpgInput,
+ out IList ids,
+ out IList idTrusts,
+ out IList idSigs)
+ {
+ ids = Platform.CreateArrayList();
+ idTrusts = Platform.CreateArrayList();
+ idSigs = Platform.CreateArrayList();
+
+ while (bcpgInput.NextPacketTag() == PacketTag.UserId
+ || bcpgInput.NextPacketTag() == PacketTag.UserAttribute)
+ {
+ Packet obj = bcpgInput.ReadPacket();
+ if (obj is UserIdPacket)
+ {
+ UserIdPacket id = (UserIdPacket)obj;
+ ids.Add(id.GetId());
+ }
+ else
+ {
+ UserAttributePacket user = (UserAttributePacket) obj;
+ ids.Add(new PgpUserAttributeSubpacketVector(user.GetSubpackets()));
+ }
+
+ idTrusts.Add(
+ ReadOptionalTrustPacket(bcpgInput));
+
+ idSigs.Add(
+ ReadSignaturesAndTrust(bcpgInput));
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PGPObject.cs b/bc-sharp-crypto/src/openpgp/PGPObject.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d38276cb693313db89cb6877a2e802f79e331cd5
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PGPObject.cs
@@ -0,0 +1,9 @@
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ public abstract class PgpObject
+ {
+ internal PgpObject()
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PGPUserAttributeSubpacketVectorGenerator.cs b/bc-sharp-crypto/src/openpgp/PGPUserAttributeSubpacketVectorGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9d56c8bc31bc4f709400e4ab7b2553e071dc327d
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PGPUserAttributeSubpacketVectorGenerator.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Bcpg.Attr;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ public class PgpUserAttributeSubpacketVectorGenerator
+ {
+ private IList list = Platform.CreateArrayList();
+
+ public virtual void SetImageAttribute(
+ ImageAttrib.Format imageType,
+ byte[] imageData)
+ {
+ if (imageData == null)
+ throw new ArgumentException("attempt to set null image", "imageData");
+
+ list.Add(new ImageAttrib(imageType, imageData));
+ }
+
+ public virtual PgpUserAttributeSubpacketVector Generate()
+ {
+ UserAttributeSubpacket[] a = new UserAttributeSubpacket[list.Count];
+ for (int i = 0; i < list.Count; ++i)
+ {
+ a[i] = (UserAttributeSubpacket)list[i];
+ }
+ return new PgpUserAttributeSubpacketVector(a);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpCompressedData.cs b/bc-sharp-crypto/src/openpgp/PgpCompressedData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e64a17c9c66899651dde5bd1e4c0a7e9d5d0644e
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpCompressedData.cs
@@ -0,0 +1,50 @@
+using System.IO;
+
+using Org.BouncyCastle.Apache.Bzip2;
+using Org.BouncyCastle.Utilities.Zlib;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Compressed data objects
+ public class PgpCompressedData
+ : PgpObject
+ {
+ private readonly CompressedDataPacket data;
+
+ public PgpCompressedData(
+ BcpgInputStream bcpgInput)
+ {
+ data = (CompressedDataPacket) bcpgInput.ReadPacket();
+ }
+
+ /// The algorithm used for compression
+ public CompressionAlgorithmTag Algorithm
+ {
+ get { return data.Algorithm; }
+ }
+
+ /// Get the raw input stream contained in the object.
+ public Stream GetInputStream()
+ {
+ return data.GetInputStream();
+ }
+
+ /// Return an uncompressed input stream which allows reading of the compressed data.
+ public Stream GetDataStream()
+ {
+ switch (Algorithm)
+ {
+ case CompressionAlgorithmTag.Uncompressed:
+ return GetInputStream();
+ case CompressionAlgorithmTag.Zip:
+ return new ZInputStream(GetInputStream(), true);
+ case CompressionAlgorithmTag.ZLib:
+ return new ZInputStream(GetInputStream());
+ case CompressionAlgorithmTag.BZip2:
+ return new CBZip2InputStream(GetInputStream());
+ default:
+ throw new PgpException("can't recognise compression algorithm: " + Algorithm);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpCompressedDataGenerator.cs b/bc-sharp-crypto/src/openpgp/PgpCompressedDataGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..51b64527909fe51069450cd6f19884b375970a11
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpCompressedDataGenerator.cs
@@ -0,0 +1,221 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Apache.Bzip2;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Zlib;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Class for producing compressed data packets.
+ public class PgpCompressedDataGenerator
+ : IStreamGenerator
+ {
+ private readonly CompressionAlgorithmTag algorithm;
+ private readonly int compression;
+
+ private Stream dOut;
+ private BcpgOutputStream pkOut;
+
+ public PgpCompressedDataGenerator(
+ CompressionAlgorithmTag algorithm)
+ : this(algorithm, JZlib.Z_DEFAULT_COMPRESSION)
+ {
+ }
+
+ public PgpCompressedDataGenerator(
+ CompressionAlgorithmTag algorithm,
+ int compression)
+ {
+ switch (algorithm)
+ {
+ case CompressionAlgorithmTag.Uncompressed:
+ case CompressionAlgorithmTag.Zip:
+ case CompressionAlgorithmTag.ZLib:
+ case CompressionAlgorithmTag.BZip2:
+ break;
+ default:
+ throw new ArgumentException("unknown compression algorithm", "algorithm");
+ }
+
+ if (compression != JZlib.Z_DEFAULT_COMPRESSION)
+ {
+ if ((compression < JZlib.Z_NO_COMPRESSION) || (compression > JZlib.Z_BEST_COMPRESSION))
+ {
+ throw new ArgumentException("unknown compression level: " + compression);
+ }
+ }
+
+ this.algorithm = algorithm;
+ this.compression = compression;
+ }
+
+ ///
+ ///
+ /// Return an output stream which will save the data being written to
+ /// the compressed object.
+ ///
+ ///
+ /// The stream created can be closed off by either calling Close()
+ /// on the stream or Close() on the generator. Closing the returned
+ /// stream does not close off the Stream parameter outStr .
+ ///
+ ///
+ /// Stream to be used for output.
+ /// A Stream for output of the compressed data.
+ ///
+ ///
+ ///
+ public Stream Open(
+ Stream outStr)
+ {
+ if (dOut != null)
+ throw new InvalidOperationException("generator already in open state");
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
+
+ this.pkOut = new BcpgOutputStream(outStr, PacketTag.CompressedData);
+
+ doOpen();
+
+ return new WrappedGeneratorStream(this, dOut);
+ }
+
+ ///
+ ///
+ /// Return an output stream which will compress the data as it is written to it.
+ /// The stream will be written out in chunks according to the size of the passed in buffer.
+ ///
+ ///
+ /// The stream created can be closed off by either calling Close()
+ /// on the stream or Close() on the generator. Closing the returned
+ /// stream does not close off the Stream parameter outStr .
+ ///
+ ///
+ /// Note : if the buffer is not a power of 2 in length only the largest power of 2
+ /// bytes worth of the buffer will be used.
+ ///
+ ///
+ /// Note : using this may break compatibility with RFC 1991 compliant tools.
+ /// Only recent OpenPGP implementations are capable of accepting these streams.
+ ///
+ ///
+ /// Stream to be used for output.
+ /// The buffer to use.
+ /// A Stream for output of the compressed data.
+ ///
+ ///
+ ///
+ ///
+ public Stream Open(
+ Stream outStr,
+ byte[] buffer)
+ {
+ if (dOut != null)
+ throw new InvalidOperationException("generator already in open state");
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
+ if (buffer == null)
+ throw new ArgumentNullException("buffer");
+
+ this.pkOut = new BcpgOutputStream(outStr, PacketTag.CompressedData, buffer);
+
+ doOpen();
+
+ return new WrappedGeneratorStream(this, dOut);
+ }
+
+ private void doOpen()
+ {
+ pkOut.WriteByte((byte) algorithm);
+
+ switch (algorithm)
+ {
+ case CompressionAlgorithmTag.Uncompressed:
+ dOut = pkOut;
+ break;
+ case CompressionAlgorithmTag.Zip:
+ dOut = new SafeZOutputStream(pkOut, compression, true);
+ break;
+ case CompressionAlgorithmTag.ZLib:
+ dOut = new SafeZOutputStream(pkOut, compression, false);
+ break;
+ case CompressionAlgorithmTag.BZip2:
+ dOut = new SafeCBZip2OutputStream(pkOut);
+ break;
+ default:
+ // Constructor should guard against this possibility
+ throw new InvalidOperationException();
+ }
+ }
+
+ /// Close the compressed object. summary>
+ public void Close()
+ {
+ if (dOut != null)
+ {
+ if (dOut != pkOut)
+ {
+ Platform.Dispose(dOut);
+ }
+ dOut = null;
+
+ pkOut.Finish();
+ pkOut.Flush();
+ pkOut = null;
+ }
+ }
+
+ private class SafeCBZip2OutputStream : CBZip2OutputStream
+ {
+ public SafeCBZip2OutputStream(Stream output)
+ : base(output)
+ {
+ }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Finish();
+ return;
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ Finish();
+ }
+#endif
+ }
+
+ private class SafeZOutputStream : ZOutputStream
+ {
+ public SafeZOutputStream(Stream output, int level, bool nowrap)
+ : base(output, level, nowrap)
+ {
+ }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Finish();
+ End();
+ return;
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ Finish();
+ End();
+ }
+#endif
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpDataValidationException.cs b/bc-sharp-crypto/src/openpgp/PgpDataValidationException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d06833c16bb5d97ba04e2de278c9cf8408dcbb88
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpDataValidationException.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// Thrown if the IV at the start of a data stream indicates the wrong key is being used.
+ ///
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class PgpDataValidationException
+ : PgpException
+ {
+ public PgpDataValidationException() : base() {}
+ public PgpDataValidationException(string message) : base(message) {}
+ public PgpDataValidationException(string message, Exception exception) : base(message, exception) {}
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpEncryptedData.cs b/bc-sharp-crypto/src/openpgp/PgpEncryptedData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..558e0b8a2c656c04c5244de6ab0baf6cb9092140
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpEncryptedData.cs
@@ -0,0 +1,151 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ public abstract class PgpEncryptedData
+ {
+ internal class TruncatedStream
+ : BaseInputStream
+ {
+ private const int LookAheadSize = 22;
+ private const int LookAheadBufSize = 512;
+ private const int LookAheadBufLimit = LookAheadBufSize - LookAheadSize;
+
+ private readonly Stream inStr;
+ private readonly byte[] lookAhead = new byte[LookAheadBufSize];
+ private int bufStart, bufEnd;
+
+ internal TruncatedStream(
+ Stream inStr)
+ {
+ int numRead = Streams.ReadFully(inStr, lookAhead, 0, lookAhead.Length);
+
+ if (numRead < LookAheadSize)
+ throw new EndOfStreamException();
+
+ this.inStr = inStr;
+ this.bufStart = 0;
+ this.bufEnd = numRead - LookAheadSize;
+ }
+
+ private int FillBuffer()
+ {
+ if (bufEnd < LookAheadBufLimit)
+ return 0;
+
+ Debug.Assert(bufStart == LookAheadBufLimit);
+ Debug.Assert(bufEnd == LookAheadBufLimit);
+
+ Array.Copy(lookAhead, LookAheadBufLimit, lookAhead, 0, LookAheadSize);
+ bufEnd = Streams.ReadFully(inStr, lookAhead, LookAheadSize, LookAheadBufLimit);
+ bufStart = 0;
+ return bufEnd;
+ }
+
+ public override int ReadByte()
+ {
+ if (bufStart < bufEnd)
+ return lookAhead[bufStart++];
+
+ if (FillBuffer() < 1)
+ return -1;
+
+ return lookAhead[bufStart++];
+ }
+
+ public override int Read(byte[] buf, int off, int len)
+ {
+ int avail = bufEnd - bufStart;
+
+ int pos = off;
+ while (len > avail)
+ {
+ Array.Copy(lookAhead, bufStart, buf, pos, avail);
+
+ bufStart += avail;
+ pos += avail;
+ len -= avail;
+
+ if ((avail = FillBuffer()) < 1)
+ return pos - off;
+ }
+
+ Array.Copy(lookAhead, bufStart, buf, pos, len);
+ bufStart += len;
+
+ return pos + len - off;
+ }
+
+ internal byte[] GetLookAhead()
+ {
+ byte[] temp = new byte[LookAheadSize];
+ Array.Copy(lookAhead, bufStart, temp, 0, LookAheadSize);
+ return temp;
+ }
+ }
+
+ internal InputStreamPacket encData;
+ internal Stream encStream;
+ internal TruncatedStream truncStream;
+
+ internal PgpEncryptedData(
+ InputStreamPacket encData)
+ {
+ this.encData = encData;
+ }
+
+ /// Return the raw input stream for the data stream.
+ public virtual Stream GetInputStream()
+ {
+ return encData.GetInputStream();
+ }
+
+ /// Return true if the message is integrity protected.
+ /// True, if there is a modification detection code namespace associated
+ /// with this stream.
+ public bool IsIntegrityProtected()
+ {
+ return encData is SymmetricEncIntegrityPacket;
+ }
+
+ /// Note: This can only be called after the message has been read.
+ /// True, if the message verifies, false otherwise
+ public bool Verify()
+ {
+ if (!IsIntegrityProtected())
+ throw new PgpException("data not integrity protected.");
+
+ DigestStream dIn = (DigestStream) encStream;
+
+ //
+ // make sure we are at the end.
+ //
+ while (encStream.ReadByte() >= 0)
+ {
+ // do nothing
+ }
+
+ //
+ // process the MDC packet
+ //
+ byte[] lookAhead = truncStream.GetLookAhead();
+
+ IDigest hash = dIn.ReadDigest();
+ hash.BlockUpdate(lookAhead, 0, 2);
+ byte[] digest = DigestUtilities.DoFinal(hash);
+
+ byte[] streamDigest = new byte[digest.Length];
+ Array.Copy(lookAhead, 2, streamDigest, 0, streamDigest.Length);
+
+ return Arrays.ConstantTimeAreEqual(digest, streamDigest);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpEncryptedDataGenerator.cs b/bc-sharp-crypto/src/openpgp/PgpEncryptedDataGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..014281b24cdd87fa9a20d74c0dce7fc9ad32474d
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpEncryptedDataGenerator.cs
@@ -0,0 +1,598 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Generator for encrypted objects.
+ public class PgpEncryptedDataGenerator
+ : IStreamGenerator
+ {
+ private BcpgOutputStream pOut;
+ private CipherStream cOut;
+ private IBufferedCipher c;
+ private bool withIntegrityPacket;
+ private bool oldFormat;
+ private DigestStream digestOut;
+
+ private abstract class EncMethod
+ : ContainedPacket
+ {
+ protected byte[] sessionInfo;
+ protected SymmetricKeyAlgorithmTag encAlgorithm;
+ protected KeyParameter key;
+
+ public abstract void AddSessionInfo(byte[] si, SecureRandom random);
+ }
+
+ private class PbeMethod
+ : EncMethod
+ {
+ private S2k s2k;
+
+ internal PbeMethod(
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ S2k s2k,
+ KeyParameter key)
+ {
+ this.encAlgorithm = encAlgorithm;
+ this.s2k = s2k;
+ this.key = key;
+ }
+
+ public KeyParameter GetKey()
+ {
+ return key;
+ }
+
+ public override void AddSessionInfo(
+ byte[] si,
+ SecureRandom random)
+ {
+ string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);
+ IBufferedCipher c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
+
+ byte[] iv = new byte[c.GetBlockSize()];
+ c.Init(true, new ParametersWithRandom(new ParametersWithIV(key, iv), random));
+
+ this.sessionInfo = c.DoFinal(si, 0, si.Length - 2);
+ }
+
+ public override void Encode(BcpgOutputStream pOut)
+ {
+ SymmetricKeyEncSessionPacket pk = new SymmetricKeyEncSessionPacket(
+ encAlgorithm, s2k, sessionInfo);
+
+ pOut.WritePacket(pk);
+ }
+ }
+
+ private class PubMethod
+ : EncMethod
+ {
+ internal PgpPublicKey pubKey;
+ internal byte[][] data;
+
+ internal PubMethod(PgpPublicKey pubKey)
+ {
+ this.pubKey = pubKey;
+ }
+
+ public override void AddSessionInfo(
+ byte[] sessionInfo,
+ SecureRandom random)
+ {
+ byte[] encryptedSessionInfo = EncryptSessionInfo(sessionInfo, random);
+
+ this.data = ProcessSessionInfo(encryptedSessionInfo);
+ }
+
+ private byte[] EncryptSessionInfo(byte[] sessionInfo, SecureRandom random)
+ {
+ if (pubKey.Algorithm != PublicKeyAlgorithmTag.ECDH)
+ {
+ IBufferedCipher c;
+ switch (pubKey.Algorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaEncrypt:
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ c = CipherUtilities.GetCipher("RSA//PKCS1Padding");
+ break;
+ case PublicKeyAlgorithmTag.ElGamalEncrypt:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ c = CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding");
+ break;
+ case PublicKeyAlgorithmTag.Dsa:
+ throw new PgpException("Can't use DSA for encryption.");
+ case PublicKeyAlgorithmTag.ECDsa:
+ throw new PgpException("Can't use ECDSA for encryption.");
+ default:
+ throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm);
+ }
+
+ AsymmetricKeyParameter akp = pubKey.GetKey();
+ c.Init(true, new ParametersWithRandom(akp, random));
+ return c.DoFinal(sessionInfo);
+ }
+
+ ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)pubKey.PublicKeyPacket.Key;
+
+ // Generate the ephemeral key pair
+ IAsymmetricCipherKeyPairGenerator gen = GeneratorUtilities.GetKeyPairGenerator("ECDH");
+ gen.Init(new ECKeyGenerationParameters(ecKey.CurveOid, random));
+
+ AsymmetricCipherKeyPair ephKp = gen.GenerateKeyPair();
+ ECPrivateKeyParameters ephPriv = (ECPrivateKeyParameters)ephKp.Private;
+ ECPublicKeyParameters ephPub = (ECPublicKeyParameters)ephKp.Public;
+
+ ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey.GetKey();
+ ECPoint S = pub.Q.Multiply(ephPriv.D).Normalize();
+
+ KeyParameter key = new KeyParameter(Rfc6637Utilities.CreateKey(pubKey.PublicKeyPacket, S));
+
+ IWrapper w = PgpUtilities.CreateWrapper(ecKey.SymmetricKeyAlgorithm);
+ w.Init(true, new ParametersWithRandom(key, random));
+
+ byte[] paddedSessionData = PgpPad.PadSessionData(sessionInfo);
+
+ byte[] C = w.Wrap(paddedSessionData, 0, paddedSessionData.Length);
+ byte[] VB = new MPInteger(new BigInteger(1, ephPub.Q.GetEncoded(false))).GetEncoded();
+
+ byte[] rv = new byte[VB.Length + 1 + C.Length];
+
+ Array.Copy(VB, 0, rv, 0, VB.Length);
+ rv[VB.Length] = (byte)C.Length;
+ Array.Copy(C, 0, rv, VB.Length + 1, C.Length);
+
+ return rv;
+ }
+
+ private byte[][] ProcessSessionInfo(byte[] encryptedSessionInfo)
+ {
+ byte[][] data;
+
+ switch (pubKey.Algorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaEncrypt:
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ data = new byte[][] { ConvertToEncodedMpi(encryptedSessionInfo) };
+ break;
+ case PublicKeyAlgorithmTag.ElGamalEncrypt:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ int halfLength = encryptedSessionInfo.Length / 2;
+ byte[] b1 = new byte[halfLength];
+ byte[] b2 = new byte[halfLength];
+
+ Array.Copy(encryptedSessionInfo, 0, b1, 0, halfLength);
+ Array.Copy(encryptedSessionInfo, halfLength, b2, 0, halfLength);
+
+ data = new byte[][] {
+ ConvertToEncodedMpi(b1),
+ ConvertToEncodedMpi(b2),
+ };
+ break;
+ case PublicKeyAlgorithmTag.ECDH:
+ data = new byte[][]{ encryptedSessionInfo };
+ break;
+ default:
+ throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm);
+ }
+
+ return data;
+ }
+
+ private byte[] ConvertToEncodedMpi(byte[] encryptedSessionInfo)
+ {
+ try
+ {
+ return new MPInteger(new BigInteger(1, encryptedSessionInfo)).GetEncoded();
+ }
+ catch (IOException e)
+ {
+ throw new PgpException("Invalid MPI encoding: " + e.Message, e);
+ }
+ }
+
+ public override void Encode(BcpgOutputStream pOut)
+ {
+ PublicKeyEncSessionPacket pk = new PublicKeyEncSessionPacket(pubKey.KeyId, pubKey.Algorithm, data);
+
+ pOut.WritePacket(pk);
+ }
+ }
+
+ private readonly IList methods = Platform.CreateArrayList();
+ private readonly SymmetricKeyAlgorithmTag defAlgorithm;
+ private readonly SecureRandom rand;
+
+ public PgpEncryptedDataGenerator(
+ SymmetricKeyAlgorithmTag encAlgorithm)
+ {
+ this.defAlgorithm = encAlgorithm;
+ this.rand = new SecureRandom();
+ }
+
+ public PgpEncryptedDataGenerator(
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ bool withIntegrityPacket)
+ {
+ this.defAlgorithm = encAlgorithm;
+ this.withIntegrityPacket = withIntegrityPacket;
+ this.rand = new SecureRandom();
+ }
+
+ /// Existing SecureRandom constructor.
+ /// The symmetric algorithm to use.
+ /// Source of randomness.
+ public PgpEncryptedDataGenerator(
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ SecureRandom rand)
+ {
+ this.defAlgorithm = encAlgorithm;
+ this.rand = rand;
+ }
+
+ /// Creates a cipher stream which will have an integrity packet associated with it.
+ public PgpEncryptedDataGenerator(
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ bool withIntegrityPacket,
+ SecureRandom rand)
+ {
+ this.defAlgorithm = encAlgorithm;
+ this.rand = rand;
+ this.withIntegrityPacket = withIntegrityPacket;
+ }
+
+ /// Base constructor.
+ /// The symmetric algorithm to use.
+ /// Source of randomness.
+ /// PGP 2.6.x compatibility required.
+ public PgpEncryptedDataGenerator(
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ SecureRandom rand,
+ bool oldFormat)
+ {
+ this.defAlgorithm = encAlgorithm;
+ this.rand = rand;
+ this.oldFormat = oldFormat;
+ }
+
+ ///
+ /// Add a PBE encryption method to the encrypted object using the default algorithm (S2K_SHA1).
+ ///
+ ///
+ /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+ /// the historical behaviour of the library (1.7 and earlier).
+ ///
+ [Obsolete("Use version that takes an explicit s2kDigest parameter")]
+ public void AddMethod(char[] passPhrase)
+ {
+ AddMethod(passPhrase, HashAlgorithmTag.Sha1);
+ }
+
+ /// Add a PBE encryption method to the encrypted object.
+ ///
+ /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+ /// the historical behaviour of the library (1.7 and earlier).
+ ///
+ public void AddMethod(char[] passPhrase, HashAlgorithmTag s2kDigest)
+ {
+ DoAddMethod(PgpUtilities.EncodePassPhrase(passPhrase, false), true, s2kDigest);
+ }
+
+ /// Add a PBE encryption method to the encrypted object.
+ ///
+ /// The passphrase is encoded to bytes using UTF8 (Encoding.UTF8.GetBytes).
+ ///
+ public void AddMethodUtf8(char[] passPhrase, HashAlgorithmTag s2kDigest)
+ {
+ DoAddMethod(PgpUtilities.EncodePassPhrase(passPhrase, true), true, s2kDigest);
+ }
+
+ /// Add a PBE encryption method to the encrypted object.
+ ///
+ /// Allows the caller to handle the encoding of the passphrase to bytes.
+ ///
+ public void AddMethodRaw(byte[] rawPassPhrase, HashAlgorithmTag s2kDigest)
+ {
+ DoAddMethod(rawPassPhrase, false, s2kDigest);
+ }
+
+ internal void DoAddMethod(byte[] rawPassPhrase, bool clearPassPhrase, HashAlgorithmTag s2kDigest)
+ {
+ S2k s2k = PgpUtilities.GenerateS2k(s2kDigest, 0x60, rand);
+
+ methods.Add(new PbeMethod(defAlgorithm, s2k, PgpUtilities.DoMakeKeyFromPassPhrase(defAlgorithm, s2k, rawPassPhrase, clearPassPhrase)));
+ }
+
+ /// Add a public key encrypted session key to the encrypted object.
+ public void AddMethod(
+ PgpPublicKey key)
+ {
+ if (!key.IsEncryptionKey)
+ {
+ throw new ArgumentException("passed in key not an encryption key!");
+ }
+
+ methods.Add(new PubMethod(key));
+ }
+
+ private void AddCheckSum(
+ byte[] sessionInfo)
+ {
+ Debug.Assert(sessionInfo != null);
+ Debug.Assert(sessionInfo.Length >= 3);
+
+ int check = 0;
+
+ for (int i = 1; i < sessionInfo.Length - 2; i++)
+ {
+ check += sessionInfo[i];
+ }
+
+ sessionInfo[sessionInfo.Length - 2] = (byte)(check >> 8);
+ sessionInfo[sessionInfo.Length - 1] = (byte)(check);
+ }
+
+ private byte[] CreateSessionInfo(
+ SymmetricKeyAlgorithmTag algorithm,
+ KeyParameter key)
+ {
+ byte[] keyBytes = key.GetKey();
+ byte[] sessionInfo = new byte[keyBytes.Length + 3];
+ sessionInfo[0] = (byte) algorithm;
+ keyBytes.CopyTo(sessionInfo, 1);
+ AddCheckSum(sessionInfo);
+ return sessionInfo;
+ }
+
+ ///
+ ///
+ /// If buffer is non null stream assumed to be partial, otherwise the length will be used
+ /// to output a fixed length packet.
+ ///
+ ///
+ /// The stream created can be closed off by either calling Close()
+ /// on the stream or Close() on the generator. Closing the returned
+ /// stream does not close off the Stream parameter outStr .
+ ///
+ ///
+ private Stream Open(
+ Stream outStr,
+ long length,
+ byte[] buffer)
+ {
+ if (cOut != null)
+ throw new InvalidOperationException("generator already in open state");
+ if (methods.Count == 0)
+ throw new InvalidOperationException("No encryption methods specified");
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
+
+ pOut = new BcpgOutputStream(outStr);
+
+ KeyParameter key;
+
+ if (methods.Count == 1)
+ {
+ if (methods[0] is PbeMethod)
+ {
+ PbeMethod m = (PbeMethod)methods[0];
+
+ key = m.GetKey();
+ }
+ else
+ {
+ key = PgpUtilities.MakeRandomKey(defAlgorithm, rand);
+
+ byte[] sessionInfo = CreateSessionInfo(defAlgorithm, key);
+ PubMethod m = (PubMethod)methods[0];
+
+ try
+ {
+ m.AddSessionInfo(sessionInfo, rand);
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("exception encrypting session key", e);
+ }
+ }
+
+ pOut.WritePacket((ContainedPacket)methods[0]);
+ }
+ else // multiple methods
+ {
+ key = PgpUtilities.MakeRandomKey(defAlgorithm, rand);
+ byte[] sessionInfo = CreateSessionInfo(defAlgorithm, key);
+
+ for (int i = 0; i != methods.Count; i++)
+ {
+ EncMethod m = (EncMethod)methods[i];
+
+ try
+ {
+ m.AddSessionInfo(sessionInfo, rand);
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("exception encrypting session key", e);
+ }
+
+ pOut.WritePacket(m);
+ }
+ }
+
+ string cName = PgpUtilities.GetSymmetricCipherName(defAlgorithm);
+ if (cName == null)
+ {
+ throw new PgpException("null cipher specified");
+ }
+
+ try
+ {
+ if (withIntegrityPacket)
+ {
+ cName += "/CFB/NoPadding";
+ }
+ else
+ {
+ cName += "/OpenPGPCFB/NoPadding";
+ }
+
+ c = CipherUtilities.GetCipher(cName);
+
+ // TODO Confirm the IV should be all zero bytes (not inLineIv - see below)
+ byte[] iv = new byte[c.GetBlockSize()];
+ c.Init(true, new ParametersWithRandom(new ParametersWithIV(key, iv), rand));
+
+ if (buffer == null)
+ {
+ //
+ // we have to Add block size + 2 for the Generated IV and + 1 + 22 if integrity protected
+ //
+ if (withIntegrityPacket)
+ {
+ pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricEncryptedIntegrityProtected, length + c.GetBlockSize() + 2 + 1 + 22);
+ pOut.WriteByte(1); // version number
+ }
+ else
+ {
+ pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricKeyEncrypted, length + c.GetBlockSize() + 2, oldFormat);
+ }
+ }
+ else
+ {
+ if (withIntegrityPacket)
+ {
+ pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricEncryptedIntegrityProtected, buffer);
+ pOut.WriteByte(1); // version number
+ }
+ else
+ {
+ pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricKeyEncrypted, buffer);
+ }
+ }
+
+ int blockSize = c.GetBlockSize();
+ byte[] inLineIv = new byte[blockSize + 2];
+ rand.NextBytes(inLineIv, 0, blockSize);
+ Array.Copy(inLineIv, inLineIv.Length - 4, inLineIv, inLineIv.Length - 2, 2);
+
+ Stream myOut = cOut = new CipherStream(pOut, null, c);
+
+ if (withIntegrityPacket)
+ {
+ string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1);
+ IDigest digest = DigestUtilities.GetDigest(digestName);
+ myOut = digestOut = new DigestStream(myOut, null, digest);
+ }
+
+ myOut.Write(inLineIv, 0, inLineIv.Length);
+
+ return new WrappedGeneratorStream(this, myOut);
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception creating cipher", e);
+ }
+ }
+
+ ///
+ ///
+ /// Return an output stream which will encrypt the data as it is written to it.
+ ///
+ ///
+ /// The stream created can be closed off by either calling Close()
+ /// on the stream or Close() on the generator. Closing the returned
+ /// stream does not close off the Stream parameter outStr .
+ ///
+ ///
+ public Stream Open(
+ Stream outStr,
+ long length)
+ {
+ return Open(outStr, length, null);
+ }
+
+ ///
+ ///
+ /// Return an output stream which will encrypt the data as it is written to it.
+ /// The stream will be written out in chunks according to the size of the passed in buffer.
+ ///
+ ///
+ /// The stream created can be closed off by either calling Close()
+ /// on the stream or Close() on the generator. Closing the returned
+ /// stream does not close off the Stream parameter outStr .
+ ///
+ ///
+ /// Note : if the buffer is not a power of 2 in length only the largest power of 2
+ /// bytes worth of the buffer will be used.
+ ///
+ ///
+ public Stream Open(
+ Stream outStr,
+ byte[] buffer)
+ {
+ return Open(outStr, 0, buffer);
+ }
+
+ ///
+ ///
+ /// Close off the encrypted object - this is equivalent to calling Close() on the stream
+ /// returned by the Open() method.
+ ///
+ ///
+ /// Note : This does not close the underlying output stream, only the stream on top of
+ /// it created by the Open() method.
+ ///
+ ///
+ public void Close()
+ {
+ if (cOut != null)
+ {
+ // TODO Should this all be under the try/catch block?
+ if (digestOut != null)
+ {
+ //
+ // hand code a mod detection packet
+ //
+ BcpgOutputStream bOut = new BcpgOutputStream(
+ digestOut, PacketTag.ModificationDetectionCode, 20);
+
+ bOut.Flush();
+ digestOut.Flush();
+
+ // TODO
+ byte[] dig = DigestUtilities.DoFinal(digestOut.WriteDigest());
+ cOut.Write(dig, 0, dig.Length);
+ }
+
+ cOut.Flush();
+
+ try
+ {
+ pOut.Write(c.DoFinal());
+ pOut.Finish();
+ }
+ catch (Exception e)
+ {
+ throw new IOException(e.Message, e);
+ }
+
+ cOut = null;
+ pOut = null;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpEncryptedDataList.cs b/bc-sharp-crypto/src/openpgp/PgpEncryptedDataList.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8dded7c054d390dc47b7af298c15263fe1550bf1
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpEncryptedDataList.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// A holder for a list of PGP encryption method packets.
+ public class PgpEncryptedDataList
+ : PgpObject
+ {
+ private IList list = Platform.CreateArrayList();
+ private InputStreamPacket data;
+
+ public PgpEncryptedDataList(
+ BcpgInputStream bcpgInput)
+ {
+ while (bcpgInput.NextPacketTag() == PacketTag.PublicKeyEncryptedSession
+ || bcpgInput.NextPacketTag() == PacketTag.SymmetricKeyEncryptedSessionKey)
+ {
+ list.Add(bcpgInput.ReadPacket());
+ }
+
+ data = (InputStreamPacket)bcpgInput.ReadPacket();
+
+ for (int i = 0; i != list.Count; i++)
+ {
+ if (list[i] is SymmetricKeyEncSessionPacket)
+ {
+ list[i] = new PgpPbeEncryptedData((SymmetricKeyEncSessionPacket) list[i], data);
+ }
+ else
+ {
+ list[i] = new PgpPublicKeyEncryptedData((PublicKeyEncSessionPacket) list[i], data);
+ }
+ }
+ }
+
+ public PgpEncryptedData this[int index]
+ {
+ get { return (PgpEncryptedData) list[index]; }
+ }
+
+ [Obsolete("Use 'object[index]' syntax instead")]
+ public object Get(int index)
+ {
+ return this[index];
+ }
+
+ [Obsolete("Use 'Count' property instead")]
+ public int Size
+ {
+ get { return list.Count; }
+ }
+
+ public int Count
+ {
+ get { return list.Count; }
+ }
+
+ public bool IsEmpty
+ {
+ get { return list.Count == 0; }
+ }
+
+ public IEnumerable GetEncryptedDataObjects()
+ {
+ return new EnumerableProxy(list);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpException.cs b/bc-sharp-crypto/src/openpgp/PgpException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..230dab86e2706e7e232f593cd9aef70729a9eb34
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpException.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Generic exception class for PGP encoding/decoding problems.
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class PgpException
+ : Exception
+ {
+ public PgpException() : base() {}
+ public PgpException(string message) : base(message) {}
+ public PgpException(string message, Exception exception) : base(message, exception) {}
+
+ [Obsolete("Use InnerException property")]
+ public Exception UnderlyingException
+ {
+ get { return InnerException; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpExperimental.cs b/bc-sharp-crypto/src/openpgp/PgpExperimental.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8518335a13ca93849bb37b7c9af14496231e094c
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpExperimental.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ public class PgpExperimental
+ : PgpObject
+ {
+ private readonly ExperimentalPacket p;
+
+ public PgpExperimental(
+ BcpgInputStream bcpgIn)
+ {
+ p = (ExperimentalPacket) bcpgIn.ReadPacket();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpKeyFlags.cs b/bc-sharp-crypto/src/openpgp/PgpKeyFlags.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ea180060609c6caa196c2731af71582678d9f8e6
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpKeyFlags.cs
@@ -0,0 +1,13 @@
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Key flag values for the KeyFlags subpacket.
+ public abstract class PgpKeyFlags
+ {
+ public const int CanCertify = 0x01; // This key may be used to certify other keys.
+ public const int CanSign = 0x02; // This key may be used to sign data.
+ public const int CanEncryptCommunications = 0x04; // This key may be used to encrypt communications.
+ public const int CanEncryptStorage = 0x08; // This key may be used to encrypt storage.
+ public const int MaybeSplit = 0x10; // The private component of this key may have been split by a secret-sharing mechanism.
+ public const int MaybeShared = 0x80; // The private component of this key may be in the possession of more than one person.
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpKeyPair.cs b/bc-sharp-crypto/src/openpgp/PgpKeyPair.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9cf78fa6fbfdd9332b7535dad9da17da2eddf106
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpKeyPair.cs
@@ -0,0 +1,67 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// General class to handle JCA key pairs and convert them into OpenPGP ones.
+ ///
+ /// A word for the unwary, the KeyId for an OpenPGP public key is calculated from
+ /// a hash that includes the time of creation, if you pass a different date to the
+ /// constructor below with the same public private key pair the KeyIs will not be the
+ /// same as for previous generations of the key, so ideally you only want to do
+ /// this once.
+ ///
+ ///
+ public class PgpKeyPair
+ {
+ private readonly PgpPublicKey pub;
+ private readonly PgpPrivateKey priv;
+
+ public PgpKeyPair(
+ PublicKeyAlgorithmTag algorithm,
+ AsymmetricCipherKeyPair keyPair,
+ DateTime time)
+ : this(algorithm, keyPair.Public, keyPair.Private, time)
+ {
+ }
+
+ public PgpKeyPair(
+ PublicKeyAlgorithmTag algorithm,
+ AsymmetricKeyParameter pubKey,
+ AsymmetricKeyParameter privKey,
+ DateTime time)
+ {
+ this.pub = new PgpPublicKey(algorithm, pubKey, time);
+ this.priv = new PgpPrivateKey(pub.KeyId, pub.PublicKeyPacket, privKey);
+ }
+
+ /// Create a key pair from a PgpPrivateKey and a PgpPublicKey.
+ /// The public key.
+ /// The private key.
+ public PgpKeyPair(
+ PgpPublicKey pub,
+ PgpPrivateKey priv)
+ {
+ this.pub = pub;
+ this.priv = priv;
+ }
+
+ /// The keyId associated with this key pair.
+ public long KeyId
+ {
+ get { return pub.KeyId; }
+ }
+
+ public PgpPublicKey PublicKey
+ {
+ get { return pub; }
+ }
+
+ public PgpPrivateKey PrivateKey
+ {
+ get { return priv; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpKeyRingGenerator.cs b/bc-sharp-crypto/src/openpgp/PgpKeyRingGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4f6a4b12f312cdec73357cb9086da7e7344777b3
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpKeyRingGenerator.cs
@@ -0,0 +1,402 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// Generator for a PGP master and subkey ring.
+ /// This class will generate both the secret and public key rings
+ ///
+ public class PgpKeyRingGenerator
+ {
+ private IList keys = Platform.CreateArrayList();
+ private string id;
+ private SymmetricKeyAlgorithmTag encAlgorithm;
+ private HashAlgorithmTag hashAlgorithm;
+ private int certificationLevel;
+ private byte[] rawPassPhrase;
+ private bool useSha1;
+ private PgpKeyPair masterKey;
+ private PgpSignatureSubpacketVector hashedPacketVector;
+ private PgpSignatureSubpacketVector unhashedPacketVector;
+ private SecureRandom rand;
+
+ ///
+ /// Create a new key ring generator using old style checksumming. It is recommended to use
+ /// SHA1 checksumming where possible.
+ ///
+ ///
+ /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+ /// the historical behaviour of the library (1.7 and earlier).
+ ///
+ /// The certification level for keys on this ring.
+ /// The master key pair.
+ /// The id to be associated with the ring.
+ /// The algorithm to be used to protect secret keys.
+ /// The passPhrase to be used to protect secret keys.
+ /// Packets to be included in the certification hash.
+ /// Packets to be attached unhashed to the certification.
+ /// input secured random.
+ [Obsolete("Use version taking an explicit 'useSha1' parameter instead")]
+ public PgpKeyRingGenerator(
+ int certificationLevel,
+ PgpKeyPair masterKey,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ char[] passPhrase,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(certificationLevel, masterKey, id, encAlgorithm, passPhrase, false, hashedPackets, unhashedPackets, rand)
+ {
+ }
+
+ ///
+ /// Create a new key ring generator.
+ ///
+ ///
+ /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+ /// the historical behaviour of the library (1.7 and earlier).
+ ///
+ /// The certification level for keys on this ring.
+ /// The master key pair.
+ /// The id to be associated with the ring.
+ /// The algorithm to be used to protect secret keys.
+ /// The passPhrase to be used to protect secret keys.
+ /// Checksum the secret keys with SHA1 rather than the older 16 bit checksum.
+ /// Packets to be included in the certification hash.
+ /// Packets to be attached unhashed to the certification.
+ /// input secured random.
+ public PgpKeyRingGenerator(
+ int certificationLevel,
+ PgpKeyPair masterKey,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ char[] passPhrase,
+ bool useSha1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(certificationLevel, masterKey, id, encAlgorithm, false, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
+ {
+ }
+
+ ///
+ /// Create a new key ring generator.
+ ///
+ /// The certification level for keys on this ring.
+ /// The master key pair.
+ /// The id to be associated with the ring.
+ /// The algorithm to be used to protect secret keys.
+ ///
+ /// If true, conversion of the passphrase to bytes uses Encoding.UTF8.GetBytes(), otherwise the conversion
+ /// is performed using Convert.ToByte(), which is the historical behaviour of the library (1.7 and earlier).
+ ///
+ /// The passPhrase to be used to protect secret keys.
+ /// Checksum the secret keys with SHA1 rather than the older 16 bit checksum.
+ /// Packets to be included in the certification hash.
+ /// Packets to be attached unhashed to the certification.
+ /// input secured random.
+ public PgpKeyRingGenerator(
+ int certificationLevel,
+ PgpKeyPair masterKey,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ bool utf8PassPhrase,
+ char[] passPhrase,
+ bool useSha1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(certificationLevel, masterKey, id, encAlgorithm,
+ PgpUtilities.EncodePassPhrase(passPhrase, utf8PassPhrase),
+ useSha1, hashedPackets, unhashedPackets, rand)
+ {
+ }
+
+ ///
+ /// Create a new key ring generator.
+ ///
+ /// The certification level for keys on this ring.
+ /// The master key pair.
+ /// The id to be associated with the ring.
+ /// The algorithm to be used to protect secret keys.
+ /// The passPhrase to be used to protect secret keys.
+ /// Checksum the secret keys with SHA1 rather than the older 16 bit checksum.
+ /// Packets to be included in the certification hash.
+ /// Packets to be attached unhashed to the certification.
+ /// input secured random.
+ public PgpKeyRingGenerator(
+ int certificationLevel,
+ PgpKeyPair masterKey,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ byte[] rawPassPhrase,
+ bool useSha1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ {
+ this.certificationLevel = certificationLevel;
+ this.masterKey = masterKey;
+ this.id = id;
+ this.encAlgorithm = encAlgorithm;
+ this.rawPassPhrase = rawPassPhrase;
+ this.useSha1 = useSha1;
+ this.hashedPacketVector = hashedPackets;
+ this.unhashedPacketVector = unhashedPackets;
+ this.rand = rand;
+
+ keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, rawPassPhrase, false, useSha1, hashedPackets, unhashedPackets, rand));
+ }
+
+ ///
+ /// Create a new key ring generator.
+ ///
+ ///
+ /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+ /// the historical behaviour of the library (1.7 and earlier).
+ ///
+ /// The certification level for keys on this ring.
+ /// The master key pair.
+ /// The id to be associated with the ring.
+ /// The algorithm to be used to protect secret keys.
+ /// The hash algorithm.
+ /// The passPhrase to be used to protect secret keys.
+ /// Checksum the secret keys with SHA1 rather than the older 16 bit checksum.
+ /// Packets to be included in the certification hash.
+ /// Packets to be attached unhashed to the certification.
+ /// input secured random.
+ public PgpKeyRingGenerator(
+ int certificationLevel,
+ PgpKeyPair masterKey,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ HashAlgorithmTag hashAlgorithm,
+ char[] passPhrase,
+ bool useSha1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(certificationLevel, masterKey, id, encAlgorithm, hashAlgorithm, false, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
+ {
+ }
+
+ ///
+ /// Create a new key ring generator.
+ ///
+ /// The certification level for keys on this ring.
+ /// The master key pair.
+ /// The id to be associated with the ring.
+ /// The algorithm to be used to protect secret keys.
+ /// The hash algorithm.
+ ///
+ /// If true, conversion of the passphrase to bytes uses Encoding.UTF8.GetBytes(), otherwise the conversion
+ /// is performed using Convert.ToByte(), which is the historical behaviour of the library (1.7 and earlier).
+ ///
+ /// The passPhrase to be used to protect secret keys.
+ /// Checksum the secret keys with SHA1 rather than the older 16 bit checksum.
+ /// Packets to be included in the certification hash.
+ /// Packets to be attached unhashed to the certification.
+ /// input secured random.
+ public PgpKeyRingGenerator(
+ int certificationLevel,
+ PgpKeyPair masterKey,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ HashAlgorithmTag hashAlgorithm,
+ bool utf8PassPhrase,
+ char[] passPhrase,
+ bool useSha1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(certificationLevel, masterKey, id, encAlgorithm, hashAlgorithm,
+ PgpUtilities.EncodePassPhrase(passPhrase, utf8PassPhrase),
+ useSha1, hashedPackets, unhashedPackets, rand)
+ {
+ }
+
+ ///
+ /// Create a new key ring generator.
+ ///
+ ///
+ /// Allows the caller to handle the encoding of the passphrase to bytes.
+ ///
+ /// The certification level for keys on this ring.
+ /// The master key pair.
+ /// The id to be associated with the ring.
+ /// The algorithm to be used to protect secret keys.
+ /// The hash algorithm.
+ /// The passPhrase to be used to protect secret keys.
+ /// Checksum the secret keys with SHA1 rather than the older 16 bit checksum.
+ /// Packets to be included in the certification hash.
+ /// Packets to be attached unhashed to the certification.
+ /// input secured random.
+ public PgpKeyRingGenerator(
+ int certificationLevel,
+ PgpKeyPair masterKey,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ HashAlgorithmTag hashAlgorithm,
+ byte[] rawPassPhrase,
+ bool useSha1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ {
+ this.certificationLevel = certificationLevel;
+ this.masterKey = masterKey;
+ this.id = id;
+ this.encAlgorithm = encAlgorithm;
+ this.rawPassPhrase = rawPassPhrase;
+ this.useSha1 = useSha1;
+ this.hashedPacketVector = hashedPackets;
+ this.unhashedPacketVector = unhashedPackets;
+ this.rand = rand;
+ this.hashAlgorithm = hashAlgorithm;
+
+ keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, hashAlgorithm, rawPassPhrase, false, useSha1, hashedPackets, unhashedPackets, rand));
+ }
+
+ /// Add a subkey to the key ring to be generated with default certification.
+ public void AddSubKey(
+ PgpKeyPair keyPair)
+ {
+ AddSubKey(keyPair, this.hashedPacketVector, this.unhashedPacketVector);
+ }
+
+
+ ///
+ /// Add a subkey to the key ring to be generated with default certification.
+ ///
+ /// The key pair.
+ /// The hash algorithm.
+ public void AddSubKey(PgpKeyPair keyPair, HashAlgorithmTag hashAlgorithm)
+ {
+ this.AddSubKey(keyPair, this.hashedPacketVector, this.unhashedPacketVector, hashAlgorithm);
+ }
+
+ ///
+ /// Add a subkey with specific hashed and unhashed packets associated with it and
+ /// default certification.
+ ///
+ /// Public/private key pair.
+ /// Hashed packet values to be included in certification.
+ /// Unhashed packets values to be included in certification.
+ ///
+ public void AddSubKey(
+ PgpKeyPair keyPair,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets)
+ {
+ try
+ {
+ PgpSignatureGenerator sGen = new PgpSignatureGenerator(
+ masterKey.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
+
+ //
+ // Generate the certification
+ //
+ sGen.InitSign(PgpSignature.SubkeyBinding, masterKey.PrivateKey);
+
+ sGen.SetHashedSubpackets(hashedPackets);
+ sGen.SetUnhashedSubpackets(unhashedPackets);
+
+ IList subSigs = Platform.CreateArrayList();
+
+ subSigs.Add(sGen.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey));
+
+ keys.Add(new PgpSecretKey(keyPair.PrivateKey, new PgpPublicKey(keyPair.PublicKey, null, subSigs), encAlgorithm,
+ rawPassPhrase, false, useSha1, rand, false));
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("exception adding subkey: ", e);
+ }
+ }
+
+ ///
+ /// Add a subkey with specific hashed and unhashed packets associated with it and
+ /// default certification.
+ ///
+ /// Public/private key pair.
+ /// Hashed packet values to be included in certification.
+ /// Unhashed packets values to be included in certification.
+ /// The hash algorithm.
+ /// exception adding subkey:
+ ///
+ public void AddSubKey(
+ PgpKeyPair keyPair,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ HashAlgorithmTag hashAlgorithm)
+ {
+ try
+ {
+ PgpSignatureGenerator sGen = new PgpSignatureGenerator(masterKey.PublicKey.Algorithm, hashAlgorithm);
+
+ //
+ // Generate the certification
+ //
+ sGen.InitSign(PgpSignature.SubkeyBinding, masterKey.PrivateKey);
+
+ sGen.SetHashedSubpackets(hashedPackets);
+ sGen.SetUnhashedSubpackets(unhashedPackets);
+
+ IList subSigs = Platform.CreateArrayList();
+ subSigs.Add(sGen.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey));
+
+ keys.Add(new PgpSecretKey(keyPair.PrivateKey, new PgpPublicKey(keyPair.PublicKey, null, subSigs), encAlgorithm,
+ rawPassPhrase, false, useSha1, rand, false));
+ }
+ catch (PgpException)
+ {
+ throw;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("exception adding subkey: ", e);
+ }
+ }
+
+
+ /// Return the secret key ring.
+ public PgpSecretKeyRing GenerateSecretKeyRing()
+ {
+ return new PgpSecretKeyRing(keys);
+ }
+
+ /// Return the public key ring that corresponds to the secret key ring.
+ public PgpPublicKeyRing GeneratePublicKeyRing()
+ {
+ IList pubKeys = Platform.CreateArrayList();
+
+ IEnumerator enumerator = keys.GetEnumerator();
+ enumerator.MoveNext();
+
+ PgpSecretKey pgpSecretKey = (PgpSecretKey) enumerator.Current;
+ pubKeys.Add(pgpSecretKey.PublicKey);
+
+ while (enumerator.MoveNext())
+ {
+ pgpSecretKey = (PgpSecretKey) enumerator.Current;
+
+ PgpPublicKey k = new PgpPublicKey(pgpSecretKey.PublicKey);
+ k.publicPk = new PublicSubkeyPacket(
+ k.Algorithm, k.CreationTime, k.publicPk.Key);
+
+ pubKeys.Add(k);
+ }
+
+ return new PgpPublicKeyRing(pubKeys);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpKeyValidationException.cs b/bc-sharp-crypto/src/openpgp/PgpKeyValidationException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..383ae57a285681a8aa4e181dfc8ed57a30de1147
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpKeyValidationException.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// Thrown if the key checksum is invalid.
+ ///
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class PgpKeyValidationException
+ : PgpException
+ {
+ public PgpKeyValidationException() : base() {}
+ public PgpKeyValidationException(string message) : base(message) {}
+ public PgpKeyValidationException(string message, Exception exception) : base(message, exception) {}
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpLiteralData.cs b/bc-sharp-crypto/src/openpgp/PgpLiteralData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..79bbc398450eb473460eac6b95b2dd099962744f
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpLiteralData.cs
@@ -0,0 +1,63 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Class for processing literal data objects.
+ public class PgpLiteralData
+ : PgpObject
+ {
+ public const char Binary = 'b';
+ public const char Text = 't';
+ public const char Utf8 = 'u';
+
+ /// The special name indicating a "for your eyes only" packet.
+ public const string Console = "_CONSOLE";
+
+ private LiteralDataPacket data;
+
+ public PgpLiteralData(
+ BcpgInputStream bcpgInput)
+ {
+ data = (LiteralDataPacket) bcpgInput.ReadPacket();
+ }
+
+ /// The format of the data stream - Binary or Text
+ public int Format
+ {
+ get { return data.Format; }
+ }
+
+ /// The file name that's associated with the data stream.
+ public string FileName
+ {
+ get { return data.FileName; }
+ }
+
+ /// Return the file name as an unintrepreted byte array.
+ public byte[] GetRawFileName()
+ {
+ return data.GetRawFileName();
+ }
+
+ /// The modification time for the file.
+ public DateTime ModificationTime
+ {
+ get { return DateTimeUtilities.UnixMsToDateTime(data.ModificationTime); }
+ }
+
+ /// The raw input stream for the data stream.
+ public Stream GetInputStream()
+ {
+ return data.GetInputStream();
+ }
+
+ /// The input stream representing the data stream.
+ public Stream GetDataStream()
+ {
+ return GetInputStream();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpLiteralDataGenerator.cs b/bc-sharp-crypto/src/openpgp/PgpLiteralDataGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7672659cabf6460c0f10e334593e2ceb0e1f3d8f
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpLiteralDataGenerator.cs
@@ -0,0 +1,182 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Class for producing literal data packets.
+ public class PgpLiteralDataGenerator
+ : IStreamGenerator
+ {
+ public const char Binary = PgpLiteralData.Binary;
+ public const char Text = PgpLiteralData.Text;
+ public const char Utf8 = PgpLiteralData.Utf8;
+
+ /// The special name indicating a "for your eyes only" packet.
+ public const string Console = PgpLiteralData.Console;
+
+ private BcpgOutputStream pkOut;
+ private bool oldFormat;
+
+ public PgpLiteralDataGenerator()
+ {
+ }
+
+ ///
+ /// Generates literal data objects in the old format.
+ /// This is important if you need compatibility with PGP 2.6.x.
+ ///
+ /// If true, uses old format.
+ public PgpLiteralDataGenerator(
+ bool oldFormat)
+ {
+ this.oldFormat = oldFormat;
+ }
+
+ private void WriteHeader(
+ BcpgOutputStream outStr,
+ char format,
+ byte[] encName,
+ long modificationTime)
+ {
+ outStr.Write(
+ (byte) format,
+ (byte) encName.Length);
+
+ outStr.Write(encName);
+
+ long modDate = modificationTime / 1000L;
+
+ outStr.Write(
+ (byte)(modDate >> 24),
+ (byte)(modDate >> 16),
+ (byte)(modDate >> 8),
+ (byte)modDate);
+ }
+
+ ///
+ ///
+ /// Open a literal data packet, returning a stream to store the data inside the packet.
+ ///
+ ///
+ /// The stream created can be closed off by either calling Close()
+ /// on the stream or Close() on the generator. Closing the returned
+ /// stream does not close off the Stream parameter outStr .
+ ///
+ ///
+ /// The stream we want the packet in.
+ /// The format we are using.
+ /// The name of the 'file'.
+ /// The length of the data we will write.
+ /// The time of last modification we want stored.
+ public Stream Open(
+ Stream outStr,
+ char format,
+ string name,
+ long length,
+ DateTime modificationTime)
+ {
+ if (pkOut != null)
+ throw new InvalidOperationException("generator already in open state");
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
+
+ // Do this first, since it might throw an exception
+ long unixMs = DateTimeUtilities.DateTimeToUnixMs(modificationTime);
+
+ byte[] encName = Strings.ToUtf8ByteArray(name);
+
+ pkOut = new BcpgOutputStream(outStr, PacketTag.LiteralData,
+ length + 2 + encName.Length + 4, oldFormat);
+
+ WriteHeader(pkOut, format, encName, unixMs);
+
+ return new WrappedGeneratorStream(this, pkOut);
+ }
+
+ ///
+ ///
+ /// Open a literal data packet, returning a stream to store the data inside the packet,
+ /// as an indefinite length stream. The stream is written out as a series of partial
+ /// packets with a chunk size determined by the size of the passed in buffer.
+ ///
+ ///
+ /// The stream created can be closed off by either calling Close()
+ /// on the stream or Close() on the generator. Closing the returned
+ /// stream does not close off the Stream parameter outStr .
+ ///
+ ///
+ /// Note : if the buffer is not a power of 2 in length only the largest power of 2
+ /// bytes worth of the buffer will be used.
+ ///
+ /// The stream we want the packet in.
+ /// The format we are using.
+ /// The name of the 'file'.
+ /// The time of last modification we want stored.
+ /// The buffer to use for collecting data to put into chunks.
+ public Stream Open(
+ Stream outStr,
+ char format,
+ string name,
+ DateTime modificationTime,
+ byte[] buffer)
+ {
+ if (pkOut != null)
+ throw new InvalidOperationException("generator already in open state");
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
+
+ // Do this first, since it might throw an exception
+ long unixMs = DateTimeUtilities.DateTimeToUnixMs(modificationTime);
+
+ byte[] encName = Strings.ToUtf8ByteArray(name);
+
+ pkOut = new BcpgOutputStream(outStr, PacketTag.LiteralData, buffer);
+
+ WriteHeader(pkOut, format, encName, unixMs);
+
+ return new WrappedGeneratorStream(this, pkOut);
+ }
+
+#if !PORTABLE || DOTNET
+ ///
+ ///
+ /// Open a literal data packet for the passed in FileInfo object, returning
+ /// an output stream for saving the file contents.
+ ///
+ ///
+ /// The stream created can be closed off by either calling Close()
+ /// on the stream or Close() on the generator. Closing the returned
+ /// stream does not close off the Stream parameter outStr .
+ ///
+ ///
+ /// The stream we want the packet in.
+ /// The format we are using.
+ /// The FileInfo object containg the packet details.
+ public Stream Open(
+ Stream outStr,
+ char format,
+ FileInfo file)
+ {
+ return Open(outStr, format, file.Name, file.Length, file.LastWriteTime);
+ }
+#endif
+
+ ///
+ /// Close the literal data packet - this is equivalent to calling Close()
+ /// on the stream returned by the Open() method.
+ ///
+ public void Close()
+ {
+ if (pkOut != null)
+ {
+ pkOut.Finish();
+ pkOut.Flush();
+ pkOut = null;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpMarker.cs b/bc-sharp-crypto/src/openpgp/PgpMarker.cs
new file mode 100644
index 0000000000000000000000000000000000000000..733e4e959fb529da47f60f468c758877f1c34d83
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpMarker.cs
@@ -0,0 +1,18 @@
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// A PGP marker packet - in general these should be ignored other than where
+ /// the idea is to preserve the original input stream.
+ ///
+ public class PgpMarker
+ : PgpObject
+ {
+ private readonly MarkerPacket p;
+
+ public PgpMarker(
+ BcpgInputStream bcpgIn)
+ {
+ p = (MarkerPacket) bcpgIn.ReadPacket();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpObjectFactory.cs b/bc-sharp-crypto/src/openpgp/PgpObjectFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c5c6fcb685d3f1d7233474783c7f2db92b55f5eb
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpObjectFactory.cs
@@ -0,0 +1,143 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// General class for reading a PGP object stream.
+ ///
+ /// Note: if this class finds a PgpPublicKey or a PgpSecretKey it
+ /// will create a PgpPublicKeyRing, or a PgpSecretKeyRing for each
+ /// key found. If all you are trying to do is read a key ring file use
+ /// either PgpPublicKeyRingBundle or PgpSecretKeyRingBundle.
+ ///
+ public class PgpObjectFactory
+ {
+ private readonly BcpgInputStream bcpgIn;
+
+ public PgpObjectFactory(
+ Stream inputStream)
+ {
+ this.bcpgIn = BcpgInputStream.Wrap(inputStream);
+ }
+
+ public PgpObjectFactory(
+ byte[] bytes)
+ : this(new MemoryStream(bytes, false))
+ {
+ }
+
+ /// Return the next object in the stream, or null if the end is reached.
+ /// On a parse error
+ public PgpObject NextPgpObject()
+ {
+ PacketTag tag = bcpgIn.NextPacketTag();
+
+ if ((int) tag == -1) return null;
+
+ switch (tag)
+ {
+ case PacketTag.Signature:
+ {
+ IList l = Platform.CreateArrayList();
+
+ while (bcpgIn.NextPacketTag() == PacketTag.Signature)
+ {
+ try
+ {
+ l.Add(new PgpSignature(bcpgIn));
+ }
+ catch (PgpException e)
+ {
+ throw new IOException("can't create signature object: " + e);
+ }
+ }
+
+ PgpSignature[] sigs = new PgpSignature[l.Count];
+ for (int i = 0; i < l.Count; ++i)
+ {
+ sigs[i] = (PgpSignature)l[i];
+ }
+ return new PgpSignatureList(sigs);
+ }
+ case PacketTag.SecretKey:
+ try
+ {
+ return new PgpSecretKeyRing(bcpgIn);
+ }
+ catch (PgpException e)
+ {
+ throw new IOException("can't create secret key object: " + e);
+ }
+ case PacketTag.PublicKey:
+ return new PgpPublicKeyRing(bcpgIn);
+ // TODO Make PgpPublicKey a PgpObject or return a PgpPublicKeyRing
+// case PacketTag.PublicSubkey:
+// return PgpPublicKeyRing.ReadSubkey(bcpgIn);
+ case PacketTag.CompressedData:
+ return new PgpCompressedData(bcpgIn);
+ case PacketTag.LiteralData:
+ return new PgpLiteralData(bcpgIn);
+ case PacketTag.PublicKeyEncryptedSession:
+ case PacketTag.SymmetricKeyEncryptedSessionKey:
+ return new PgpEncryptedDataList(bcpgIn);
+ case PacketTag.OnePassSignature:
+ {
+ IList l = Platform.CreateArrayList();
+
+ while (bcpgIn.NextPacketTag() == PacketTag.OnePassSignature)
+ {
+ try
+ {
+ l.Add(new PgpOnePassSignature(bcpgIn));
+ }
+ catch (PgpException e)
+ {
+ throw new IOException("can't create one pass signature object: " + e);
+ }
+ }
+
+ PgpOnePassSignature[] sigs = new PgpOnePassSignature[l.Count];
+ for (int i = 0; i < l.Count; ++i)
+ {
+ sigs[i] = (PgpOnePassSignature)l[i];
+ }
+ return new PgpOnePassSignatureList(sigs);
+ }
+ case PacketTag.Marker:
+ return new PgpMarker(bcpgIn);
+ case PacketTag.Experimental1:
+ case PacketTag.Experimental2:
+ case PacketTag.Experimental3:
+ case PacketTag.Experimental4:
+ return new PgpExperimental(bcpgIn);
+ }
+
+ throw new IOException("unknown object in stream " + bcpgIn.NextPacketTag());
+ }
+
+ [Obsolete("Use NextPgpObject() instead")]
+ public object NextObject()
+ {
+ return NextPgpObject();
+ }
+
+ ///
+ /// Return all available objects in a list.
+ ///
+ /// An IList containing all objects from this factory, in order.
+ public IList AllPgpObjects()
+ {
+ IList result = Platform.CreateArrayList();
+ PgpObject pgpObject;
+ while ((pgpObject = NextPgpObject()) != null)
+ {
+ result.Add(pgpObject);
+ }
+ return result;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpOnePassSignature.cs b/bc-sharp-crypto/src/openpgp/PgpOnePassSignature.cs
new file mode 100644
index 0000000000000000000000000000000000000000..68fc5994d5daa4cfe113b5cae12ec3a49b59dd24
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpOnePassSignature.cs
@@ -0,0 +1,179 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// A one pass signature object.
+ public class PgpOnePassSignature
+ {
+ private OnePassSignaturePacket sigPack;
+ private int signatureType;
+ private ISigner sig;
+ private byte lastb;
+
+ internal PgpOnePassSignature(
+ BcpgInputStream bcpgInput)
+ : this((OnePassSignaturePacket) bcpgInput.ReadPacket())
+ {
+ }
+
+ internal PgpOnePassSignature(
+ OnePassSignaturePacket sigPack)
+ {
+ this.sigPack = sigPack;
+ this.signatureType = sigPack.SignatureType;
+ }
+
+ /// Initialise the signature object for verification.
+ public void InitVerify(
+ PgpPublicKey pubKey)
+ {
+ lastb = 0;
+
+ try
+ {
+ sig = SignerUtilities.GetSigner(
+ PgpUtilities.GetSignatureName(sigPack.KeyAlgorithm, sigPack.HashAlgorithm));
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("can't set up signature object.", e);
+ }
+
+ try
+ {
+ sig.Init(false, pubKey.GetKey());
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new PgpException("invalid key.", e);
+ }
+ }
+
+ public void Update(
+ byte b)
+ {
+ if (signatureType == PgpSignature.CanonicalTextDocument)
+ {
+ doCanonicalUpdateByte(b);
+ }
+ else
+ {
+ sig.Update(b);
+ }
+ }
+
+ private void doCanonicalUpdateByte(
+ byte b)
+ {
+ if (b == '\r')
+ {
+ doUpdateCRLF();
+ }
+ else if (b == '\n')
+ {
+ if (lastb != '\r')
+ {
+ doUpdateCRLF();
+ }
+ }
+ else
+ {
+ sig.Update(b);
+ }
+
+ lastb = b;
+ }
+
+ private void doUpdateCRLF()
+ {
+ sig.Update((byte)'\r');
+ sig.Update((byte)'\n');
+ }
+
+ public void Update(
+ byte[] bytes)
+ {
+ if (signatureType == PgpSignature.CanonicalTextDocument)
+ {
+ for (int i = 0; i != bytes.Length; i++)
+ {
+ doCanonicalUpdateByte(bytes[i]);
+ }
+ }
+ else
+ {
+ sig.BlockUpdate(bytes, 0, bytes.Length);
+ }
+ }
+
+ public void Update(
+ byte[] bytes,
+ int off,
+ int length)
+ {
+ if (signatureType == PgpSignature.CanonicalTextDocument)
+ {
+ int finish = off + length;
+
+ for (int i = off; i != finish; i++)
+ {
+ doCanonicalUpdateByte(bytes[i]);
+ }
+ }
+ else
+ {
+ sig.BlockUpdate(bytes, off, length);
+ }
+ }
+
+ /// Verify the calculated signature against the passed in PgpSignature.
+ public bool Verify(
+ PgpSignature pgpSig)
+ {
+ byte[] trailer = pgpSig.GetSignatureTrailer();
+
+ sig.BlockUpdate(trailer, 0, trailer.Length);
+
+ return sig.VerifySignature(pgpSig.GetSignature());
+ }
+
+ public long KeyId
+ {
+ get { return sigPack.KeyId; }
+ }
+
+ public int SignatureType
+ {
+ get { return sigPack.SignatureType; }
+ }
+
+ public HashAlgorithmTag HashAlgorithm
+ {
+ get { return sigPack.HashAlgorithm; }
+ }
+
+ public PublicKeyAlgorithmTag KeyAlgorithm
+ {
+ get { return sigPack.KeyAlgorithm; }
+ }
+
+ public byte[] GetEncoded()
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ Encode(bOut);
+
+ return bOut.ToArray();
+ }
+
+ public void Encode(
+ Stream outStr)
+ {
+ BcpgOutputStream.Wrap(outStr).WritePacket(sigPack);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpOnePassSignatureList.cs b/bc-sharp-crypto/src/openpgp/PgpOnePassSignatureList.cs
new file mode 100644
index 0000000000000000000000000000000000000000..37c4288e353570c01bfa6d7a528d8d23b9e9d6cf
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpOnePassSignatureList.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Holder for a list of PgpOnePassSignature objects.
+ public class PgpOnePassSignatureList
+ : PgpObject
+ {
+ private readonly PgpOnePassSignature[] sigs;
+
+ public PgpOnePassSignatureList(
+ PgpOnePassSignature[] sigs)
+ {
+ this.sigs = (PgpOnePassSignature[]) sigs.Clone();
+ }
+
+ public PgpOnePassSignatureList(
+ PgpOnePassSignature sig)
+ {
+ this.sigs = new PgpOnePassSignature[]{ sig };
+ }
+
+ public PgpOnePassSignature this[int index]
+ {
+ get { return sigs[index]; }
+ }
+
+ [Obsolete("Use 'object[index]' syntax instead")]
+ public PgpOnePassSignature Get(
+ int index)
+ {
+ return this[index];
+ }
+
+ [Obsolete("Use 'Count' property instead")]
+ public int Size
+ {
+ get { return sigs.Length; }
+ }
+
+ public int Count
+ {
+ get { return sigs.Length; }
+ }
+
+ public bool IsEmpty
+ {
+ get { return (sigs.Length == 0); }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpPad.cs b/bc-sharp-crypto/src/openpgp/PgpPad.cs
new file mode 100644
index 0000000000000000000000000000000000000000..48f7f2f44dcb15e696d353487ff904b9a5d94e2c
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpPad.cs
@@ -0,0 +1,45 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Padding functions.
+ public sealed class PgpPad
+ {
+ private PgpPad()
+ {
+ }
+
+ public static byte[] PadSessionData(byte[] sessionInfo)
+ {
+ byte[] result = new byte[40];
+
+ Array.Copy(sessionInfo, 0, result, 0, sessionInfo.Length);
+
+ byte padValue = (byte)(result.Length - sessionInfo.Length);
+
+ for (int i = sessionInfo.Length; i != result.Length; i++)
+ {
+ result[i] = padValue;
+ }
+
+ return result;
+ }
+
+ public static byte[] UnpadSessionData(byte[] encoded)
+ {
+ byte padValue = encoded[encoded.Length - 1];
+
+ for (int i = encoded.Length - padValue; i != encoded.Length; i++)
+ {
+ if (encoded[i] != padValue)
+ throw new PgpException("bad padding found in session data");
+ }
+
+ byte[] taggedKey = new byte[encoded.Length - padValue];
+
+ Array.Copy(encoded, 0, taggedKey, 0, taggedKey.Length);
+
+ return taggedKey;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpPbeEncryptedData.cs b/bc-sharp-crypto/src/openpgp/PgpPbeEncryptedData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f43f2f51241cfc7bdd0e14010f3f4452328b5c97
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpPbeEncryptedData.cs
@@ -0,0 +1,160 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// A password based encryption object.
+ public class PgpPbeEncryptedData
+ : PgpEncryptedData
+ {
+ private readonly SymmetricKeyEncSessionPacket keyData;
+
+ internal PgpPbeEncryptedData(
+ SymmetricKeyEncSessionPacket keyData,
+ InputStreamPacket encData)
+ : base(encData)
+ {
+ this.keyData = keyData;
+ }
+
+ /// Return the raw input stream for the data stream.
+ public override Stream GetInputStream()
+ {
+ return encData.GetInputStream();
+ }
+
+ /// Return the decrypted input stream, using the passed in passphrase.
+ ///
+ /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+ /// the historical behaviour of the library (1.7 and earlier).
+ ///
+ public Stream GetDataStream(char[] passPhrase)
+ {
+ return DoGetDataStream(PgpUtilities.EncodePassPhrase(passPhrase, false), true);
+ }
+
+ /// Return the decrypted input stream, using the passed in passphrase.
+ ///
+ /// The passphrase is encoded to bytes using UTF8 (Encoding.UTF8.GetBytes).
+ ///
+ public Stream GetDataStreamUtf8(char[] passPhrase)
+ {
+ return DoGetDataStream(PgpUtilities.EncodePassPhrase(passPhrase, true), true);
+ }
+
+ /// Return the decrypted input stream, using the passed in passphrase.
+ ///
+ /// Allows the caller to handle the encoding of the passphrase to bytes.
+ ///
+ public Stream GetDataStreamRaw(byte[] rawPassPhrase)
+ {
+ return DoGetDataStream(rawPassPhrase, false);
+ }
+
+ internal Stream DoGetDataStream(byte[] rawPassPhrase, bool clearPassPhrase)
+ {
+ try
+ {
+ SymmetricKeyAlgorithmTag keyAlgorithm = keyData.EncAlgorithm;
+
+ KeyParameter key = PgpUtilities.DoMakeKeyFromPassPhrase(
+ keyAlgorithm, keyData.S2k, rawPassPhrase, clearPassPhrase);
+
+ byte[] secKeyData = keyData.GetSecKeyData();
+ if (secKeyData != null && secKeyData.Length > 0)
+ {
+ IBufferedCipher keyCipher = CipherUtilities.GetCipher(
+ PgpUtilities.GetSymmetricCipherName(keyAlgorithm) + "/CFB/NoPadding");
+
+ keyCipher.Init(false,
+ new ParametersWithIV(key, new byte[keyCipher.GetBlockSize()]));
+
+ byte[] keyBytes = keyCipher.DoFinal(secKeyData);
+
+ keyAlgorithm = (SymmetricKeyAlgorithmTag) keyBytes[0];
+
+ key = ParameterUtilities.CreateKeyParameter(
+ PgpUtilities.GetSymmetricCipherName(keyAlgorithm),
+ keyBytes, 1, keyBytes.Length - 1);
+ }
+
+
+ IBufferedCipher c = CreateStreamCipher(keyAlgorithm);
+
+ byte[] iv = new byte[c.GetBlockSize()];
+
+ c.Init(false, new ParametersWithIV(key, iv));
+
+ encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), c, null));
+
+ if (encData is SymmetricEncIntegrityPacket)
+ {
+ truncStream = new TruncatedStream(encStream);
+
+ string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1);
+ IDigest digest = DigestUtilities.GetDigest(digestName);
+
+ encStream = new DigestStream(truncStream, digest, null);
+ }
+
+ if (Streams.ReadFully(encStream, iv, 0, iv.Length) < iv.Length)
+ throw new EndOfStreamException("unexpected end of stream.");
+
+ int v1 = encStream.ReadByte();
+ int v2 = encStream.ReadByte();
+
+ if (v1 < 0 || v2 < 0)
+ throw new EndOfStreamException("unexpected end of stream.");
+
+
+ // Note: the oracle attack on the "quick check" bytes is not deemed
+ // a security risk for PBE (see PgpPublicKeyEncryptedData)
+
+ bool repeatCheckPassed =
+ iv[iv.Length - 2] == (byte)v1
+ && iv[iv.Length - 1] == (byte)v2;
+
+ // Note: some versions of PGP appear to produce 0 for the extra
+ // bytes rather than repeating the two previous bytes
+ bool zeroesCheckPassed =
+ v1 == 0
+ && v2 == 0;
+
+ if (!repeatCheckPassed && !zeroesCheckPassed)
+ {
+ throw new PgpDataValidationException("quick check failed.");
+ }
+
+
+ return encStream;
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception creating cipher", e);
+ }
+ }
+
+ private IBufferedCipher CreateStreamCipher(
+ SymmetricKeyAlgorithmTag keyAlgorithm)
+ {
+ string mode = (encData is SymmetricEncIntegrityPacket)
+ ? "CFB"
+ : "OpenPGPCFB";
+
+ string cName = PgpUtilities.GetSymmetricCipherName(keyAlgorithm)
+ + "/" + mode + "/NoPadding";
+
+ return CipherUtilities.GetCipher(cName);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpPrivateKey.cs b/bc-sharp-crypto/src/openpgp/PgpPrivateKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..61487a5b25d9dff939657a37ddc5049da8f183c7
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpPrivateKey.cs
@@ -0,0 +1,51 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// General class to contain a private key for use with other OpenPGP objects.
+ public class PgpPrivateKey
+ {
+ private readonly long keyID;
+ private readonly PublicKeyPacket publicKeyPacket;
+ private readonly AsymmetricKeyParameter privateKey;
+
+ ///
+ /// Create a PgpPrivateKey from a keyID, the associated public data packet, and a regular private key.
+ ///
+ /// ID of the corresponding public key.
+ /// the public key data packet to be associated with this private key.
+ /// the private key data packet to be associated with this private key.
+ public PgpPrivateKey(
+ long keyID,
+ PublicKeyPacket publicKeyPacket,
+ AsymmetricKeyParameter privateKey)
+ {
+ if (!privateKey.IsPrivate)
+ throw new ArgumentException("Expected a private key", "privateKey");
+
+ this.keyID = keyID;
+ this.publicKeyPacket = publicKeyPacket;
+ this.privateKey = privateKey;
+ }
+
+ /// The keyId associated with the contained private key.
+ public long KeyId
+ {
+ get { return keyID; }
+ }
+
+ /// The public key packet associated with this private key, if available.
+ public PublicKeyPacket PublicKeyPacket
+ {
+ get { return publicKeyPacket; }
+ }
+
+ /// The contained private key.
+ public AsymmetricKeyParameter Key
+ {
+ get { return privateKey; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpPublicKey.cs b/bc-sharp-crypto/src/openpgp/PgpPublicKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fc125e8c88a6dc0c845fcfd99cb8916758a7e2ff
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpPublicKey.cs
@@ -0,0 +1,980 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// General class to handle a PGP public key object.
+ public class PgpPublicKey
+ {
+ public static byte[] CalculateFingerprint(PublicKeyPacket publicPk)
+ {
+ IBcpgKey key = publicPk.Key;
+ IDigest digest;
+
+ if (publicPk.Version <= 3)
+ {
+ RsaPublicBcpgKey rK = (RsaPublicBcpgKey)key;
+
+ try
+ {
+ digest = DigestUtilities.GetDigest("MD5");
+ UpdateDigest(digest, rK.Modulus);
+ UpdateDigest(digest, rK.PublicExponent);
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("can't encode key components: " + e.Message, e);
+ }
+ }
+ else
+ {
+ try
+ {
+ byte[] kBytes = publicPk.GetEncodedContents();
+
+ digest = DigestUtilities.GetDigest("SHA1");
+
+ digest.Update(0x99);
+ digest.Update((byte)(kBytes.Length >> 8));
+ digest.Update((byte)kBytes.Length);
+ digest.BlockUpdate(kBytes, 0, kBytes.Length);
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("can't encode key components: " + e.Message, e);
+ }
+ }
+
+ return DigestUtilities.DoFinal(digest);
+ }
+
+ private static void UpdateDigest(IDigest d, BigInteger b)
+ {
+ byte[] bytes = b.ToByteArrayUnsigned();
+ d.BlockUpdate(bytes, 0, bytes.Length);
+ }
+
+ private static readonly int[] MasterKeyCertificationTypes = new int[]
+ {
+ PgpSignature.PositiveCertification,
+ PgpSignature.CasualCertification,
+ PgpSignature.NoCertification,
+ PgpSignature.DefaultCertification
+ };
+
+ private long keyId;
+ private byte[] fingerprint;
+ private int keyStrength;
+
+ internal PublicKeyPacket publicPk;
+ internal TrustPacket trustPk;
+ internal IList keySigs = Platform.CreateArrayList();
+ internal IList ids = Platform.CreateArrayList();
+ internal IList idTrusts = Platform.CreateArrayList();
+ internal IList idSigs = Platform.CreateArrayList();
+ internal IList subSigs;
+
+ private void Init()
+ {
+ IBcpgKey key = publicPk.Key;
+
+ this.fingerprint = CalculateFingerprint(publicPk);
+
+ if (publicPk.Version <= 3)
+ {
+ RsaPublicBcpgKey rK = (RsaPublicBcpgKey) key;
+
+ this.keyId = rK.Modulus.LongValue;
+ this.keyStrength = rK.Modulus.BitLength;
+ }
+ else
+ {
+ this.keyId = (long)(((ulong)fingerprint[fingerprint.Length - 8] << 56)
+ | ((ulong)fingerprint[fingerprint.Length - 7] << 48)
+ | ((ulong)fingerprint[fingerprint.Length - 6] << 40)
+ | ((ulong)fingerprint[fingerprint.Length - 5] << 32)
+ | ((ulong)fingerprint[fingerprint.Length - 4] << 24)
+ | ((ulong)fingerprint[fingerprint.Length - 3] << 16)
+ | ((ulong)fingerprint[fingerprint.Length - 2] << 8)
+ | (ulong)fingerprint[fingerprint.Length - 1]);
+
+ if (key is RsaPublicBcpgKey)
+ {
+ this.keyStrength = ((RsaPublicBcpgKey)key).Modulus.BitLength;
+ }
+ else if (key is DsaPublicBcpgKey)
+ {
+ this.keyStrength = ((DsaPublicBcpgKey)key).P.BitLength;
+ }
+ else if (key is ElGamalPublicBcpgKey)
+ {
+ this.keyStrength = ((ElGamalPublicBcpgKey)key).P.BitLength;
+ }
+ else if (key is ECPublicBcpgKey)
+ {
+ this.keyStrength = ECKeyPairGenerator.FindECCurveByOid(((ECPublicBcpgKey)key).CurveOid).Curve.FieldSize;
+ }
+ }
+ }
+
+ ///
+ /// Create a PgpPublicKey from the passed in lightweight one.
+ ///
+ ///
+ /// Note: the time passed in affects the value of the key's keyId, so you probably only want
+ /// to do this once for a lightweight key, or make sure you keep track of the time you used.
+ ///
+ /// Asymmetric algorithm type representing the public key.
+ /// Actual public key to associate.
+ /// Date of creation.
+ /// If pubKey is not public.
+ /// On key creation problem.
+ public PgpPublicKey(
+ PublicKeyAlgorithmTag algorithm,
+ AsymmetricKeyParameter pubKey,
+ DateTime time)
+ {
+ if (pubKey.IsPrivate)
+ throw new ArgumentException("Expected a public key", "pubKey");
+
+ IBcpgKey bcpgKey;
+ if (pubKey is RsaKeyParameters)
+ {
+ RsaKeyParameters rK = (RsaKeyParameters) pubKey;
+
+ bcpgKey = new RsaPublicBcpgKey(rK.Modulus, rK.Exponent);
+ }
+ else if (pubKey is DsaPublicKeyParameters)
+ {
+ DsaPublicKeyParameters dK = (DsaPublicKeyParameters) pubKey;
+ DsaParameters dP = dK.Parameters;
+
+ bcpgKey = new DsaPublicBcpgKey(dP.P, dP.Q, dP.G, dK.Y);
+ }
+ else if (pubKey is ECPublicKeyParameters)
+ {
+ ECPublicKeyParameters ecK = (ECPublicKeyParameters)pubKey;
+
+ if (algorithm == PublicKeyAlgorithmTag.ECDH)
+ {
+ bcpgKey = new ECDHPublicBcpgKey(ecK.PublicKeyParamSet, ecK.Q, HashAlgorithmTag.Sha256, SymmetricKeyAlgorithmTag.Aes128);
+ }
+ else if (algorithm == PublicKeyAlgorithmTag.ECDsa)
+ {
+ bcpgKey = new ECDsaPublicBcpgKey(ecK.PublicKeyParamSet, ecK.Q);
+ }
+ else
+ {
+ throw new PgpException("unknown EC algorithm");
+ }
+ }
+ else if (pubKey is ElGamalPublicKeyParameters)
+ {
+ ElGamalPublicKeyParameters eK = (ElGamalPublicKeyParameters) pubKey;
+ ElGamalParameters eS = eK.Parameters;
+
+ bcpgKey = new ElGamalPublicBcpgKey(eS.P, eS.G, eK.Y);
+ }
+ else
+ {
+ throw new PgpException("unknown key class");
+ }
+
+ this.publicPk = new PublicKeyPacket(algorithm, time, bcpgKey);
+ this.ids = Platform.CreateArrayList();
+ this.idSigs = Platform.CreateArrayList();
+
+ try
+ {
+ Init();
+ }
+ catch (IOException e)
+ {
+ throw new PgpException("exception calculating keyId", e);
+ }
+ }
+
+ public PgpPublicKey(PublicKeyPacket publicPk)
+ : this(publicPk, Platform.CreateArrayList(), Platform.CreateArrayList())
+ {
+ }
+
+ /// Constructor for a sub-key.
+ internal PgpPublicKey(
+ PublicKeyPacket publicPk,
+ TrustPacket trustPk,
+ IList sigs)
+ {
+ this.publicPk = publicPk;
+ this.trustPk = trustPk;
+ this.subSigs = sigs;
+
+ Init();
+ }
+
+ internal PgpPublicKey(
+ PgpPublicKey key,
+ TrustPacket trust,
+ IList subSigs)
+ {
+ this.publicPk = key.publicPk;
+ this.trustPk = trust;
+ this.subSigs = subSigs;
+
+ this.fingerprint = key.fingerprint;
+ this.keyId = key.keyId;
+ this.keyStrength = key.keyStrength;
+ }
+
+ /// Copy constructor.
+ /// The public key to copy.
+ internal PgpPublicKey(
+ PgpPublicKey pubKey)
+ {
+ this.publicPk = pubKey.publicPk;
+
+ this.keySigs = Platform.CreateArrayList(pubKey.keySigs);
+ this.ids = Platform.CreateArrayList(pubKey.ids);
+ this.idTrusts = Platform.CreateArrayList(pubKey.idTrusts);
+ this.idSigs = Platform.CreateArrayList(pubKey.idSigs.Count);
+ for (int i = 0; i != pubKey.idSigs.Count; i++)
+ {
+ this.idSigs.Add(Platform.CreateArrayList((IList)pubKey.idSigs[i]));
+ }
+
+ if (pubKey.subSigs != null)
+ {
+ this.subSigs = Platform.CreateArrayList(pubKey.subSigs.Count);
+ for (int i = 0; i != pubKey.subSigs.Count; i++)
+ {
+ this.subSigs.Add(pubKey.subSigs[i]);
+ }
+ }
+
+ this.fingerprint = pubKey.fingerprint;
+ this.keyId = pubKey.keyId;
+ this.keyStrength = pubKey.keyStrength;
+ }
+
+ internal PgpPublicKey(
+ PublicKeyPacket publicPk,
+ TrustPacket trustPk,
+ IList keySigs,
+ IList ids,
+ IList idTrusts,
+ IList idSigs)
+ {
+ this.publicPk = publicPk;
+ this.trustPk = trustPk;
+ this.keySigs = keySigs;
+ this.ids = ids;
+ this.idTrusts = idTrusts;
+ this.idSigs = idSigs;
+
+ Init();
+ }
+
+ internal PgpPublicKey(
+ PublicKeyPacket publicPk,
+ IList ids,
+ IList idSigs)
+ {
+ this.publicPk = publicPk;
+ this.ids = ids;
+ this.idSigs = idSigs;
+ Init();
+ }
+
+ /// The version of this key.
+ public int Version
+ {
+ get { return publicPk.Version; }
+ }
+
+ /// The creation time of this key.
+ public DateTime CreationTime
+ {
+ get { return publicPk.GetTime(); }
+ }
+
+ /// The number of valid days from creation time - zero means no expiry.
+ /// WARNING: This method will return 1 for keys with version > 3 that expire in less than 1 day
+ [Obsolete("Use 'GetValidSeconds' instead")]
+ public int ValidDays
+ {
+ get
+ {
+ if (publicPk.Version <= 3)
+ {
+ return publicPk.ValidDays;
+ }
+
+ long expSecs = GetValidSeconds();
+ if (expSecs <= 0)
+ return 0;
+
+ int days = (int)(expSecs / (24 * 60 * 60));
+ return System.Math.Max(1, days);
+ }
+ }
+
+ /// Return the trust data associated with the public key, if present.
+ /// A byte array with trust data, null otherwise.
+ public byte[] GetTrustData()
+ {
+ if (trustPk == null)
+ {
+ return null;
+ }
+
+ return Arrays.Clone(trustPk.GetLevelAndTrustAmount());
+ }
+
+ /// The number of valid seconds from creation time - zero means no expiry.
+ public long GetValidSeconds()
+ {
+ if (publicPk.Version <= 3)
+ {
+ return (long)publicPk.ValidDays * (24 * 60 * 60);
+ }
+
+ if (IsMasterKey)
+ {
+ for (int i = 0; i != MasterKeyCertificationTypes.Length; i++)
+ {
+ long seconds = GetExpirationTimeFromSig(true, MasterKeyCertificationTypes[i]);
+ if (seconds >= 0)
+ {
+ return seconds;
+ }
+ }
+ }
+ else
+ {
+ long seconds = GetExpirationTimeFromSig(false, PgpSignature.SubkeyBinding);
+ if (seconds >= 0)
+ {
+ return seconds;
+ }
+ }
+
+ return 0;
+ }
+
+ private long GetExpirationTimeFromSig(bool selfSigned, int signatureType)
+ {
+ long expiryTime = -1;
+ long lastDate = -1;
+
+ foreach (PgpSignature sig in GetSignaturesOfType(signatureType))
+ {
+ if (selfSigned && sig.KeyId != this.KeyId)
+ continue;
+
+ PgpSignatureSubpacketVector hashed = sig.GetHashedSubPackets();
+ if (hashed == null)
+ continue;
+
+ long current = hashed.GetKeyExpirationTime();
+
+ if (sig.KeyId == this.KeyId)
+ {
+ if (sig.CreationTime.Ticks > lastDate)
+ {
+ lastDate = sig.CreationTime.Ticks;
+ expiryTime = current;
+ }
+ }
+ else if (current == 0 || current > expiryTime)
+ {
+ expiryTime = current;
+ }
+ }
+
+ return expiryTime;
+ }
+
+ /// The keyId associated with the public key.
+ public long KeyId
+ {
+ get { return keyId; }
+ }
+
+ /// The fingerprint of the key
+ public byte[] GetFingerprint()
+ {
+ return (byte[]) fingerprint.Clone();
+ }
+
+ ///
+ /// Check if this key has an algorithm type that makes it suitable to use for encryption.
+ ///
+ ///
+ /// Note: with version 4 keys KeyFlags subpackets should also be considered when present for
+ /// determining the preferred use of the key.
+ ///
+ ///
+ /// true if this key algorithm is suitable for encryption.
+ ///
+ public bool IsEncryptionKey
+ {
+ get
+ {
+ switch (publicPk.Algorithm)
+ {
+ case PublicKeyAlgorithmTag.ECDH:
+ case PublicKeyAlgorithmTag.ElGamalEncrypt:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ case PublicKeyAlgorithmTag.RsaEncrypt:
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ return true;
+ default:
+ return false;
+ }
+ }
+ }
+
+ /// True, if this is a master key.
+ public bool IsMasterKey
+ {
+ get { return subSigs == null; }
+ }
+
+ /// The algorithm code associated with the public key.
+ public PublicKeyAlgorithmTag Algorithm
+ {
+ get { return publicPk.Algorithm; }
+ }
+
+ /// The strength of the key in bits.
+ public int BitStrength
+ {
+ get { return keyStrength; }
+ }
+
+ /// The public key contained in the object.
+ /// A lightweight public key.
+ /// If the key algorithm is not recognised.
+ public AsymmetricKeyParameter GetKey()
+ {
+ try
+ {
+ switch (publicPk.Algorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaEncrypt:
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ case PublicKeyAlgorithmTag.RsaSign:
+ RsaPublicBcpgKey rsaK = (RsaPublicBcpgKey)publicPk.Key;
+ return new RsaKeyParameters(false, rsaK.Modulus, rsaK.PublicExponent);
+ case PublicKeyAlgorithmTag.Dsa:
+ DsaPublicBcpgKey dsaK = (DsaPublicBcpgKey)publicPk.Key;
+ return new DsaPublicKeyParameters(dsaK.Y, new DsaParameters(dsaK.P, dsaK.Q, dsaK.G));
+ case PublicKeyAlgorithmTag.ECDsa:
+ return GetECKey("ECDSA");
+ case PublicKeyAlgorithmTag.ECDH:
+ return GetECKey("ECDH");
+ case PublicKeyAlgorithmTag.ElGamalEncrypt:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ ElGamalPublicBcpgKey elK = (ElGamalPublicBcpgKey)publicPk.Key;
+ return new ElGamalPublicKeyParameters(elK.Y, new ElGamalParameters(elK.P, elK.G));
+ default:
+ throw new PgpException("unknown public key algorithm encountered");
+ }
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("exception constructing public key", e);
+ }
+ }
+
+ private ECPublicKeyParameters GetECKey(string algorithm)
+ {
+ ECPublicBcpgKey ecK = (ECPublicBcpgKey)publicPk.Key;
+ X9ECParameters x9 = ECKeyPairGenerator.FindECCurveByOid(ecK.CurveOid);
+ ECPoint q = x9.Curve.DecodePoint(BigIntegers.AsUnsignedByteArray(ecK.EncodedPoint));
+ return new ECPublicKeyParameters(algorithm, q, ecK.CurveOid);
+ }
+
+ /// Allows enumeration of any user IDs associated with the key.
+ /// An IEnumerable of string objects.
+ public IEnumerable GetUserIds()
+ {
+ IList temp = Platform.CreateArrayList();
+
+ foreach (object o in ids)
+ {
+ if (o is string)
+ {
+ temp.Add(o);
+ }
+ }
+
+ return new EnumerableProxy(temp);
+ }
+
+ /// Allows enumeration of any user attribute vectors associated with the key.
+ /// An IEnumerable of PgpUserAttributeSubpacketVector objects.
+ public IEnumerable GetUserAttributes()
+ {
+ IList temp = Platform.CreateArrayList();
+
+ foreach (object o in ids)
+ {
+ if (o is PgpUserAttributeSubpacketVector)
+ {
+ temp.Add(o);
+ }
+ }
+
+ return new EnumerableProxy(temp);
+ }
+
+ /// Allows enumeration of any signatures associated with the passed in id.
+ /// The ID to be matched.
+ /// An IEnumerable of PgpSignature objects.
+ public IEnumerable GetSignaturesForId(
+ string id)
+ {
+ if (id == null)
+ throw new ArgumentNullException("id");
+
+ for (int i = 0; i != ids.Count; i++)
+ {
+ if (id.Equals(ids[i]))
+ {
+ return new EnumerableProxy((IList)idSigs[i]);
+ }
+ }
+
+ return null;
+ }
+
+ /// Allows enumeration of signatures associated with the passed in user attributes.
+ /// The vector of user attributes to be matched.
+ /// An IEnumerable of PgpSignature objects.
+ public IEnumerable GetSignaturesForUserAttribute(
+ PgpUserAttributeSubpacketVector userAttributes)
+ {
+ for (int i = 0; i != ids.Count; i++)
+ {
+ if (userAttributes.Equals(ids[i]))
+ {
+ return new EnumerableProxy((IList) idSigs[i]);
+ }
+ }
+
+ return null;
+ }
+
+ /// Allows enumeration of signatures of the passed in type that are on this key.
+ /// The type of the signature to be returned.
+ /// An IEnumerable of PgpSignature objects.
+ public IEnumerable GetSignaturesOfType(
+ int signatureType)
+ {
+ IList temp = Platform.CreateArrayList();
+
+ foreach (PgpSignature sig in GetSignatures())
+ {
+ if (sig.SignatureType == signatureType)
+ {
+ temp.Add(sig);
+ }
+ }
+
+ return new EnumerableProxy(temp);
+ }
+
+ /// Allows enumeration of all signatures/certifications associated with this key.
+ /// An IEnumerable with all signatures/certifications.
+ public IEnumerable GetSignatures()
+ {
+ IList sigs = subSigs;
+ if (sigs == null)
+ {
+ sigs = Platform.CreateArrayList(keySigs);
+
+ foreach (ICollection extraSigs in idSigs)
+ {
+ CollectionUtilities.AddRange(sigs, extraSigs);
+ }
+ }
+
+ return new EnumerableProxy(sigs);
+ }
+
+ /**
+ * Return all signatures/certifications directly associated with this key (ie, not to a user id).
+ *
+ * @return an iterator (possibly empty) with all signatures/certifications.
+ */
+ public IEnumerable GetKeySignatures()
+ {
+ IList sigs = subSigs;
+ if (sigs == null)
+ {
+ sigs = Platform.CreateArrayList(keySigs);
+ }
+ return new EnumerableProxy(sigs);
+ }
+
+ public PublicKeyPacket PublicKeyPacket
+ {
+ get { return publicPk; }
+ }
+
+ public byte[] GetEncoded()
+ {
+ MemoryStream bOut = new MemoryStream();
+ Encode(bOut);
+ return bOut.ToArray();
+ }
+
+ public void Encode(
+ Stream outStr)
+ {
+ BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
+
+ bcpgOut.WritePacket(publicPk);
+ if (trustPk != null)
+ {
+ bcpgOut.WritePacket(trustPk);
+ }
+
+ if (subSigs == null) // not a sub-key
+ {
+ foreach (PgpSignature keySig in keySigs)
+ {
+ keySig.Encode(bcpgOut);
+ }
+
+ for (int i = 0; i != ids.Count; i++)
+ {
+ if (ids[i] is string)
+ {
+ string id = (string) ids[i];
+
+ bcpgOut.WritePacket(new UserIdPacket(id));
+ }
+ else
+ {
+ PgpUserAttributeSubpacketVector v = (PgpUserAttributeSubpacketVector)ids[i];
+ bcpgOut.WritePacket(new UserAttributePacket(v.ToSubpacketArray()));
+ }
+
+ if (idTrusts[i] != null)
+ {
+ bcpgOut.WritePacket((ContainedPacket)idTrusts[i]);
+ }
+
+ foreach (PgpSignature sig in (IList) idSigs[i])
+ {
+ sig.Encode(bcpgOut);
+ }
+ }
+ }
+ else
+ {
+ foreach (PgpSignature subSig in subSigs)
+ {
+ subSig.Encode(bcpgOut);
+ }
+ }
+ }
+
+ /// Check whether this (sub)key has a revocation signature on it.
+ /// True, if this (sub)key has been revoked.
+ public bool IsRevoked()
+ {
+ int ns = 0;
+ bool revoked = false;
+ if (IsMasterKey) // Master key
+ {
+ while (!revoked && (ns < keySigs.Count))
+ {
+ if (((PgpSignature)keySigs[ns++]).SignatureType == PgpSignature.KeyRevocation)
+ {
+ revoked = true;
+ }
+ }
+ }
+ else // Sub-key
+ {
+ while (!revoked && (ns < subSigs.Count))
+ {
+ if (((PgpSignature)subSigs[ns++]).SignatureType == PgpSignature.SubkeyRevocation)
+ {
+ revoked = true;
+ }
+ }
+ }
+ return revoked;
+ }
+
+ /// Add a certification for an id to the given public key.
+ /// The key the certification is to be added to.
+ /// The ID the certification is associated with.
+ /// The new certification.
+ /// The re-certified key.
+ public static PgpPublicKey AddCertification(
+ PgpPublicKey key,
+ string id,
+ PgpSignature certification)
+ {
+ return AddCert(key, id, certification);
+ }
+
+ /// Add a certification for the given UserAttributeSubpackets to the given public key.
+ /// The key the certification is to be added to.
+ /// The attributes the certification is associated with.
+ /// The new certification.
+ /// The re-certified key.
+ public static PgpPublicKey AddCertification(
+ PgpPublicKey key,
+ PgpUserAttributeSubpacketVector userAttributes,
+ PgpSignature certification)
+ {
+ return AddCert(key, userAttributes, certification);
+ }
+
+ private static PgpPublicKey AddCert(
+ PgpPublicKey key,
+ object id,
+ PgpSignature certification)
+ {
+ PgpPublicKey returnKey = new PgpPublicKey(key);
+ IList sigList = null;
+
+ for (int i = 0; i != returnKey.ids.Count; i++)
+ {
+ if (id.Equals(returnKey.ids[i]))
+ {
+ sigList = (IList) returnKey.idSigs[i];
+ }
+ }
+
+ if (sigList != null)
+ {
+ sigList.Add(certification);
+ }
+ else
+ {
+ sigList = Platform.CreateArrayList();
+ sigList.Add(certification);
+ returnKey.ids.Add(id);
+ returnKey.idTrusts.Add(null);
+ returnKey.idSigs.Add(sigList);
+ }
+
+ return returnKey;
+ }
+
+ ///
+ /// Remove any certifications associated with a user attribute subpacket on a key.
+ ///
+ /// The key the certifications are to be removed from.
+ /// The attributes to be removed.
+ ///
+ /// The re-certified key, or null if the user attribute subpacket was not found on the key.
+ ///
+ public static PgpPublicKey RemoveCertification(
+ PgpPublicKey key,
+ PgpUserAttributeSubpacketVector userAttributes)
+ {
+ return RemoveCert(key, userAttributes);
+ }
+
+ /// Remove any certifications associated with a given ID on a key.
+ /// The key the certifications are to be removed from.
+ /// The ID that is to be removed.
+ /// The re-certified key, or null if the ID was not found on the key.
+ public static PgpPublicKey RemoveCertification(
+ PgpPublicKey key,
+ string id)
+ {
+ return RemoveCert(key, id);
+ }
+
+ private static PgpPublicKey RemoveCert(
+ PgpPublicKey key,
+ object id)
+ {
+ PgpPublicKey returnKey = new PgpPublicKey(key);
+ bool found = false;
+
+ for (int i = 0; i < returnKey.ids.Count; i++)
+ {
+ if (id.Equals(returnKey.ids[i]))
+ {
+ found = true;
+ returnKey.ids.RemoveAt(i);
+ returnKey.idTrusts.RemoveAt(i);
+ returnKey.idSigs.RemoveAt(i);
+ }
+ }
+
+ return found ? returnKey : null;
+ }
+
+ /// Remove a certification associated with a given ID on a key.
+ /// The key the certifications are to be removed from.
+ /// The ID that the certfication is to be removed from.
+ /// The certfication to be removed.
+ /// The re-certified key, or null if the certification was not found.
+ public static PgpPublicKey RemoveCertification(
+ PgpPublicKey key,
+ string id,
+ PgpSignature certification)
+ {
+ return RemoveCert(key, id, certification);
+ }
+
+ /// Remove a certification associated with a given user attributes on a key.
+ /// The key the certifications are to be removed from.
+ /// The user attributes that the certfication is to be removed from.
+ /// The certification to be removed.
+ /// The re-certified key, or null if the certification was not found.
+ public static PgpPublicKey RemoveCertification(
+ PgpPublicKey key,
+ PgpUserAttributeSubpacketVector userAttributes,
+ PgpSignature certification)
+ {
+ return RemoveCert(key, userAttributes, certification);
+ }
+
+ private static PgpPublicKey RemoveCert(
+ PgpPublicKey key,
+ object id,
+ PgpSignature certification)
+ {
+ PgpPublicKey returnKey = new PgpPublicKey(key);
+ bool found = false;
+
+ for (int i = 0; i < returnKey.ids.Count; i++)
+ {
+ if (id.Equals(returnKey.ids[i]))
+ {
+ IList certs = (IList) returnKey.idSigs[i];
+ found = certs.Contains(certification);
+
+ if (found)
+ {
+ certs.Remove(certification);
+ }
+ }
+ }
+
+ return found ? returnKey : null;
+ }
+
+ /// Add a revocation or some other key certification to a key.
+ /// The key the revocation is to be added to.
+ /// The key signature to be added.
+ /// The new changed public key object.
+ public static PgpPublicKey AddCertification(
+ PgpPublicKey key,
+ PgpSignature certification)
+ {
+ if (key.IsMasterKey)
+ {
+ if (certification.SignatureType == PgpSignature.SubkeyRevocation)
+ {
+ throw new ArgumentException("signature type incorrect for master key revocation.");
+ }
+ }
+ else
+ {
+ if (certification.SignatureType == PgpSignature.KeyRevocation)
+ {
+ throw new ArgumentException("signature type incorrect for sub-key revocation.");
+ }
+ }
+
+ PgpPublicKey returnKey = new PgpPublicKey(key);
+
+ if (returnKey.subSigs != null)
+ {
+ returnKey.subSigs.Add(certification);
+ }
+ else
+ {
+ returnKey.keySigs.Add(certification);
+ }
+
+ return returnKey;
+ }
+
+ /// Remove a certification from the key.
+ /// The key the certifications are to be removed from.
+ /// The certfication to be removed.
+ /// The modified key, null if the certification was not found.
+ public static PgpPublicKey RemoveCertification(
+ PgpPublicKey key,
+ PgpSignature certification)
+ {
+ PgpPublicKey returnKey = new PgpPublicKey(key);
+ IList sigs = returnKey.subSigs != null
+ ? returnKey.subSigs
+ : returnKey.keySigs;
+
+// bool found = sigs.Remove(certification);
+ int pos = sigs.IndexOf(certification);
+ bool found = pos >= 0;
+
+ if (found)
+ {
+ sigs.RemoveAt(pos);
+ }
+ else
+ {
+ foreach (String id in key.GetUserIds())
+ {
+ foreach (object sig in key.GetSignaturesForId(id))
+ {
+ // TODO Is this the right type of equality test?
+ if (certification == sig)
+ {
+ found = true;
+ returnKey = PgpPublicKey.RemoveCertification(returnKey, id, certification);
+ }
+ }
+ }
+
+ if (!found)
+ {
+ foreach (PgpUserAttributeSubpacketVector id in key.GetUserAttributes())
+ {
+ foreach (object sig in key.GetSignaturesForUserAttribute(id))
+ {
+ // TODO Is this the right type of equality test?
+ if (certification == sig)
+ {
+ found = true;
+ returnKey = PgpPublicKey.RemoveCertification(returnKey, id, certification);
+ }
+ }
+ }
+ }
+ }
+
+ return returnKey;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpPublicKeyEncryptedData.cs b/bc-sharp-crypto/src/openpgp/PgpPublicKeyEncryptedData.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c2a351182d09e0e8ce05889ae66ee45d892c337f
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpPublicKeyEncryptedData.cs
@@ -0,0 +1,272 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// A public key encrypted data object.
+ public class PgpPublicKeyEncryptedData
+ : PgpEncryptedData
+ {
+ private PublicKeyEncSessionPacket keyData;
+
+ internal PgpPublicKeyEncryptedData(
+ PublicKeyEncSessionPacket keyData,
+ InputStreamPacket encData)
+ : base(encData)
+ {
+ this.keyData = keyData;
+ }
+
+ private static IBufferedCipher GetKeyCipher(
+ PublicKeyAlgorithmTag algorithm)
+ {
+ try
+ {
+ switch (algorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaEncrypt:
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ return CipherUtilities.GetCipher("RSA//PKCS1Padding");
+ case PublicKeyAlgorithmTag.ElGamalEncrypt:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ return CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding");
+ default:
+ throw new PgpException("unknown asymmetric algorithm: " + algorithm);
+ }
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception creating cipher", e);
+ }
+ }
+
+ private bool ConfirmCheckSum(
+ byte[] sessionInfo)
+ {
+ int check = 0;
+
+ for (int i = 1; i != sessionInfo.Length - 2; i++)
+ {
+ check += sessionInfo[i] & 0xff;
+ }
+
+ return (sessionInfo[sessionInfo.Length - 2] == (byte)(check >> 8))
+ && (sessionInfo[sessionInfo.Length - 1] == (byte)(check));
+ }
+
+ /// The key ID for the key used to encrypt the data.
+ public long KeyId
+ {
+ get { return keyData.KeyId; }
+ }
+
+ ///
+ /// Return the algorithm code for the symmetric algorithm used to encrypt the data.
+ ///
+ public SymmetricKeyAlgorithmTag GetSymmetricAlgorithm(
+ PgpPrivateKey privKey)
+ {
+ byte[] sessionData = RecoverSessionData(privKey);
+
+ return (SymmetricKeyAlgorithmTag)sessionData[0];
+ }
+
+ /// Return the decrypted data stream for the packet.
+ public Stream GetDataStream(
+ PgpPrivateKey privKey)
+ {
+ byte[] sessionData = RecoverSessionData(privKey);
+
+ if (!ConfirmCheckSum(sessionData))
+ throw new PgpKeyValidationException("key checksum failed");
+
+ SymmetricKeyAlgorithmTag symmAlg = (SymmetricKeyAlgorithmTag)sessionData[0];
+ if (symmAlg == SymmetricKeyAlgorithmTag.Null)
+ return encData.GetInputStream();
+
+ IBufferedCipher cipher;
+ string cipherName = PgpUtilities.GetSymmetricCipherName(symmAlg);
+ string cName = cipherName;
+
+ try
+ {
+ if (encData is SymmetricEncIntegrityPacket)
+ {
+ cName += "/CFB/NoPadding";
+ }
+ else
+ {
+ cName += "/OpenPGPCFB/NoPadding";
+ }
+
+ cipher = CipherUtilities.GetCipher(cName);
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("exception creating cipher", e);
+ }
+
+ try
+ {
+ KeyParameter key = ParameterUtilities.CreateKeyParameter(
+ cipherName, sessionData, 1, sessionData.Length - 3);
+
+ byte[] iv = new byte[cipher.GetBlockSize()];
+
+ cipher.Init(false, new ParametersWithIV(key, iv));
+
+ encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), cipher, null));
+
+ if (encData is SymmetricEncIntegrityPacket)
+ {
+ truncStream = new TruncatedStream(encStream);
+
+ string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1);
+ IDigest digest = DigestUtilities.GetDigest(digestName);
+
+ encStream = new DigestStream(truncStream, digest, null);
+ }
+
+ if (Streams.ReadFully(encStream, iv, 0, iv.Length) < iv.Length)
+ throw new EndOfStreamException("unexpected end of stream.");
+
+ int v1 = encStream.ReadByte();
+ int v2 = encStream.ReadByte();
+
+ if (v1 < 0 || v2 < 0)
+ throw new EndOfStreamException("unexpected end of stream.");
+
+ // Note: the oracle attack on the "quick check" bytes is deemed
+ // a security risk for typical public key encryption usages,
+ // therefore we do not perform the check.
+
+// bool repeatCheckPassed =
+// iv[iv.Length - 2] == (byte)v1
+// && iv[iv.Length - 1] == (byte)v2;
+//
+// // Note: some versions of PGP appear to produce 0 for the extra
+// // bytes rather than repeating the two previous bytes
+// bool zeroesCheckPassed =
+// v1 == 0
+// && v2 == 0;
+//
+// if (!repeatCheckPassed && !zeroesCheckPassed)
+// {
+// throw new PgpDataValidationException("quick check failed.");
+// }
+
+ return encStream;
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception starting decryption", e);
+ }
+ }
+
+ private byte[] RecoverSessionData(PgpPrivateKey privKey)
+ {
+ byte[][] secKeyData = keyData.GetEncSessionKey();
+
+ if (keyData.Algorithm == PublicKeyAlgorithmTag.ECDH)
+ {
+ ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)privKey.PublicKeyPacket.Key;
+ X9ECParameters x9Params = ECKeyPairGenerator.FindECCurveByOid(ecKey.CurveOid);
+
+ byte[] enc = secKeyData[0];
+
+ int pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8;
+ byte[] pEnc = new byte[pLen];
+
+ Array.Copy(enc, 2, pEnc, 0, pLen);
+
+ byte[] keyEnc = new byte[enc[pLen + 2]];
+
+ Array.Copy(enc, 2 + pLen + 1, keyEnc, 0, keyEnc.Length);
+
+ ECPoint publicPoint = x9Params.Curve.DecodePoint(pEnc);
+
+ ECPrivateKeyParameters privKeyParams = (ECPrivateKeyParameters)privKey.Key;
+ ECPoint S = publicPoint.Multiply(privKeyParams.D).Normalize();
+
+ KeyParameter key = new KeyParameter(Rfc6637Utilities.CreateKey(privKey.PublicKeyPacket, S));
+
+ IWrapper w = PgpUtilities.CreateWrapper(ecKey.SymmetricKeyAlgorithm);
+ w.Init(false, key);
+
+ return PgpPad.UnpadSessionData(w.Unwrap(keyEnc, 0, keyEnc.Length));
+ }
+
+ IBufferedCipher cipher = GetKeyCipher(keyData.Algorithm);
+
+ try
+ {
+ cipher.Init(false, privKey.Key);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new PgpException("error setting asymmetric cipher", e);
+ }
+
+ if (keyData.Algorithm == PublicKeyAlgorithmTag.RsaEncrypt
+ || keyData.Algorithm == PublicKeyAlgorithmTag.RsaGeneral)
+ {
+ byte[] bi = secKeyData[0];
+
+ cipher.ProcessBytes(bi, 2, bi.Length - 2);
+ }
+ else
+ {
+ ElGamalPrivateKeyParameters k = (ElGamalPrivateKeyParameters)privKey.Key;
+ int size = (k.Parameters.P.BitLength + 7) / 8;
+
+ ProcessEncodedMpi(cipher, size, secKeyData[0]);
+ ProcessEncodedMpi(cipher, size, secKeyData[1]);
+ }
+
+ try
+ {
+ return cipher.DoFinal();
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("exception decrypting secret key", e);
+ }
+ }
+
+ private static void ProcessEncodedMpi(IBufferedCipher cipher, int size, byte[] mpiEnc)
+ {
+ if (mpiEnc.Length - 2 > size) // leading Zero? Shouldn't happen but...
+ {
+ cipher.ProcessBytes(mpiEnc, 3, mpiEnc.Length - 3);
+ }
+ else
+ {
+ byte[] tmp = new byte[size];
+ Array.Copy(mpiEnc, 2, tmp, tmp.Length - (mpiEnc.Length - 2), mpiEnc.Length - 2);
+ cipher.ProcessBytes(tmp, 0, tmp.Length);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpPublicKeyRing.cs b/bc-sharp-crypto/src/openpgp/PgpPublicKeyRing.cs
new file mode 100644
index 0000000000000000000000000000000000000000..92464d64f3760e14c7165a9f7d3d2ca6baa7d4b9
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpPublicKeyRing.cs
@@ -0,0 +1,200 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// Class to hold a single master public key and its subkeys.
+ ///
+ /// Often PGP keyring files consist of multiple master keys, if you are trying to process
+ /// or construct one of these you should use the PgpPublicKeyRingBundle class.
+ ///
+ ///
+ public class PgpPublicKeyRing
+ : PgpKeyRing
+ {
+ private readonly IList keys;
+
+ public PgpPublicKeyRing(
+ byte[] encoding)
+ : this(new MemoryStream(encoding, false))
+ {
+ }
+
+ internal PgpPublicKeyRing(
+ IList pubKeys)
+ {
+ this.keys = pubKeys;
+ }
+
+ public PgpPublicKeyRing(
+ Stream inputStream)
+ {
+ this.keys = Platform.CreateArrayList();
+
+ BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream);
+
+ PacketTag initialTag = bcpgInput.NextPacketTag();
+ if (initialTag != PacketTag.PublicKey && initialTag != PacketTag.PublicSubkey)
+ {
+ throw new IOException("public key ring doesn't start with public key tag: "
+ + "tag 0x" + ((int)initialTag).ToString("X"));
+ }
+
+ PublicKeyPacket pubPk = (PublicKeyPacket) bcpgInput.ReadPacket();
+ TrustPacket trustPk = ReadOptionalTrustPacket(bcpgInput);
+
+ // direct signatures and revocations
+ IList keySigs = ReadSignaturesAndTrust(bcpgInput);
+
+ IList ids, idTrusts, idSigs;
+ ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs);
+
+ keys.Add(new PgpPublicKey(pubPk, trustPk, keySigs, ids, idTrusts, idSigs));
+
+
+ // Read subkeys
+ while (bcpgInput.NextPacketTag() == PacketTag.PublicSubkey)
+ {
+ keys.Add(ReadSubkey(bcpgInput));
+ }
+ }
+
+ /// Return the first public key in the ring.
+ public virtual PgpPublicKey GetPublicKey()
+ {
+ return (PgpPublicKey) keys[0];
+ }
+
+ /// Return the public key referred to by the passed in key ID if it is present.
+ public virtual PgpPublicKey GetPublicKey(
+ long keyId)
+ {
+ foreach (PgpPublicKey k in keys)
+ {
+ if (keyId == k.KeyId)
+ {
+ return k;
+ }
+ }
+
+ return null;
+ }
+
+ /// Allows enumeration of all the public keys.
+ /// An IEnumerable of PgpPublicKey objects.
+ public virtual IEnumerable GetPublicKeys()
+ {
+ return new EnumerableProxy(keys);
+ }
+
+ public virtual byte[] GetEncoded()
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ Encode(bOut);
+
+ return bOut.ToArray();
+ }
+
+ public virtual void Encode(
+ Stream outStr)
+ {
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
+
+ foreach (PgpPublicKey k in keys)
+ {
+ k.Encode(outStr);
+ }
+ }
+
+ ///
+ /// Returns a new key ring with the public key passed in either added or
+ /// replacing an existing one.
+ ///
+ /// The public key ring to be modified.
+ /// The public key to be inserted.
+ /// A new PgpPublicKeyRing
+ public static PgpPublicKeyRing InsertPublicKey(
+ PgpPublicKeyRing pubRing,
+ PgpPublicKey pubKey)
+ {
+ IList keys = Platform.CreateArrayList(pubRing.keys);
+ bool found = false;
+ bool masterFound = false;
+
+ for (int i = 0; i != keys.Count; i++)
+ {
+ PgpPublicKey key = (PgpPublicKey) keys[i];
+
+ if (key.KeyId == pubKey.KeyId)
+ {
+ found = true;
+ keys[i] = pubKey;
+ }
+ if (key.IsMasterKey)
+ {
+ masterFound = true;
+ }
+ }
+
+ if (!found)
+ {
+ if (pubKey.IsMasterKey)
+ {
+ if (masterFound)
+ throw new ArgumentException("cannot add a master key to a ring that already has one");
+
+ keys.Insert(0, pubKey);
+ }
+ else
+ {
+ keys.Add(pubKey);
+ }
+ }
+
+ return new PgpPublicKeyRing(keys);
+ }
+
+ /// Returns a new key ring with the public key passed in removed from the key ring.
+ /// The public key ring to be modified.
+ /// The public key to be removed.
+ /// A new PgpPublicKeyRing , or null if pubKey is not found.
+ public static PgpPublicKeyRing RemovePublicKey(
+ PgpPublicKeyRing pubRing,
+ PgpPublicKey pubKey)
+ {
+ IList keys = Platform.CreateArrayList(pubRing.keys);
+ bool found = false;
+
+ for (int i = 0; i < keys.Count; i++)
+ {
+ PgpPublicKey key = (PgpPublicKey) keys[i];
+
+ if (key.KeyId == pubKey.KeyId)
+ {
+ found = true;
+ keys.RemoveAt(i);
+ }
+ }
+
+ return found ? new PgpPublicKeyRing(keys) : null;
+ }
+
+ internal static PgpPublicKey ReadSubkey(BcpgInputStream bcpgInput)
+ {
+ PublicKeyPacket pk = (PublicKeyPacket) bcpgInput.ReadPacket();
+ TrustPacket kTrust = ReadOptionalTrustPacket(bcpgInput);
+
+ // PGP 8 actually leaves out the signature.
+ IList sigList = ReadSignaturesAndTrust(bcpgInput);
+
+ return new PgpPublicKey(pk, kTrust, sigList);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpPublicKeyRingBundle.cs b/bc-sharp-crypto/src/openpgp/PgpPublicKeyRingBundle.cs
new file mode 100644
index 0000000000000000000000000000000000000000..91113e904fb6c9a99e017e9e5dccbc390267aa43
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpPublicKeyRingBundle.cs
@@ -0,0 +1,279 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// Often a PGP key ring file is made up of a succession of master/sub-key key rings.
+ /// If you want to read an entire public key file in one hit this is the class for you.
+ ///
+ public class PgpPublicKeyRingBundle
+ {
+ private readonly IDictionary pubRings;
+ private readonly IList order;
+
+ private PgpPublicKeyRingBundle(
+ IDictionary pubRings,
+ IList order)
+ {
+ this.pubRings = pubRings;
+ this.order = order;
+ }
+
+ public PgpPublicKeyRingBundle(
+ byte[] encoding)
+ : this(new MemoryStream(encoding, false))
+ {
+ }
+
+ /// Build a PgpPublicKeyRingBundle from the passed in input stream.
+ /// Input stream containing data.
+ /// If a problem parsing the stream occurs.
+ /// If an object is encountered which isn't a PgpPublicKeyRing.
+ public PgpPublicKeyRingBundle(
+ Stream inputStream)
+ : this(new PgpObjectFactory(inputStream).AllPgpObjects())
+ {
+ }
+
+ public PgpPublicKeyRingBundle(
+ IEnumerable e)
+ {
+ this.pubRings = Platform.CreateHashtable();
+ this.order = Platform.CreateArrayList();
+
+ foreach (object obj in e)
+ {
+ PgpPublicKeyRing pgpPub = obj as PgpPublicKeyRing;
+
+ if (pgpPub == null)
+ {
+ throw new PgpException(Platform.GetTypeName(obj) + " found where PgpPublicKeyRing expected");
+ }
+
+ long key = pgpPub.GetPublicKey().KeyId;
+ pubRings.Add(key, pgpPub);
+ order.Add(key);
+ }
+ }
+
+ [Obsolete("Use 'Count' property instead")]
+ public int Size
+ {
+ get { return order.Count; }
+ }
+
+ /// Return the number of key rings in this collection.
+ public int Count
+ {
+ get { return order.Count; }
+ }
+
+ /// Allow enumeration of the public key rings making up this collection.
+ public IEnumerable GetKeyRings()
+ {
+ return new EnumerableProxy(pubRings.Values);
+ }
+
+ /// Allow enumeration of the key rings associated with the passed in userId.
+ /// The user ID to be matched.
+ /// An IEnumerable of key rings which matched (possibly none).
+ public IEnumerable GetKeyRings(
+ string userId)
+ {
+ return GetKeyRings(userId, false, false);
+ }
+
+ /// Allow enumeration of the key rings associated with the passed in userId.
+ /// The user ID to be matched.
+ /// If true, userId need only be a substring of an actual ID string to match.
+ /// An IEnumerable of key rings which matched (possibly none).
+ public IEnumerable GetKeyRings(
+ string userId,
+ bool matchPartial)
+ {
+ return GetKeyRings(userId, matchPartial, false);
+ }
+
+ /// Allow enumeration of the key rings associated with the passed in userId.
+ /// The user ID to be matched.
+ /// If true, userId need only be a substring of an actual ID string to match.
+ /// If true, case is ignored in user ID comparisons.
+ /// An IEnumerable of key rings which matched (possibly none).
+ public IEnumerable GetKeyRings(
+ string userId,
+ bool matchPartial,
+ bool ignoreCase)
+ {
+ IList rings = Platform.CreateArrayList();
+
+ if (ignoreCase)
+ {
+ userId = Platform.ToUpperInvariant(userId);
+ }
+
+ foreach (PgpPublicKeyRing pubRing in GetKeyRings())
+ {
+ foreach (string nextUserID in pubRing.GetPublicKey().GetUserIds())
+ {
+ string next = nextUserID;
+ if (ignoreCase)
+ {
+ next = Platform.ToUpperInvariant(next);
+ }
+
+ if (matchPartial)
+ {
+ if (Platform.IndexOf(next, userId) > -1)
+ {
+ rings.Add(pubRing);
+ }
+ }
+ else
+ {
+ if (next.Equals(userId))
+ {
+ rings.Add(pubRing);
+ }
+ }
+ }
+ }
+
+ return new EnumerableProxy(rings);
+ }
+
+ /// Return the PGP public key associated with the given key id.
+ /// The ID of the public key to return.
+ public PgpPublicKey GetPublicKey(
+ long keyId)
+ {
+ foreach (PgpPublicKeyRing pubRing in GetKeyRings())
+ {
+ PgpPublicKey pub = pubRing.GetPublicKey(keyId);
+
+ if (pub != null)
+ {
+ return pub;
+ }
+ }
+
+ return null;
+ }
+
+ /// Return the public key ring which contains the key referred to by keyId
+ /// key ID to match against
+ public PgpPublicKeyRing GetPublicKeyRing(
+ long keyId)
+ {
+ if (pubRings.Contains(keyId))
+ {
+ return (PgpPublicKeyRing)pubRings[keyId];
+ }
+
+ foreach (PgpPublicKeyRing pubRing in GetKeyRings())
+ {
+ PgpPublicKey pub = pubRing.GetPublicKey(keyId);
+
+ if (pub != null)
+ {
+ return pubRing;
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Return true if a key matching the passed in key ID is present, false otherwise.
+ ///
+ /// key ID to look for.
+ public bool Contains(
+ long keyID)
+ {
+ return GetPublicKey(keyID) != null;
+ }
+
+ public byte[] GetEncoded()
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ Encode(bOut);
+
+ return bOut.ToArray();
+ }
+
+ public void Encode(
+ Stream outStr)
+ {
+ BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
+
+ foreach (long key in order)
+ {
+ PgpPublicKeyRing sec = (PgpPublicKeyRing) pubRings[key];
+
+ sec.Encode(bcpgOut);
+ }
+ }
+
+ ///
+ /// Return a new bundle containing the contents of the passed in bundle and
+ /// the passed in public key ring.
+ ///
+ /// The PgpPublicKeyRingBundle the key ring is to be added to.
+ /// The key ring to be added.
+ /// A new PgpPublicKeyRingBundle merging the current one with the passed in key ring.
+ /// If the keyId for the passed in key ring is already present.
+ public static PgpPublicKeyRingBundle AddPublicKeyRing(
+ PgpPublicKeyRingBundle bundle,
+ PgpPublicKeyRing publicKeyRing)
+ {
+ long key = publicKeyRing.GetPublicKey().KeyId;
+
+ if (bundle.pubRings.Contains(key))
+ {
+ throw new ArgumentException("Bundle already contains a key with a keyId for the passed in ring.");
+ }
+
+ IDictionary newPubRings = Platform.CreateHashtable(bundle.pubRings);
+ IList newOrder = Platform.CreateArrayList(bundle.order);
+
+ newPubRings[key] = publicKeyRing;
+
+ newOrder.Add(key);
+
+ return new PgpPublicKeyRingBundle(newPubRings, newOrder);
+ }
+
+ ///
+ /// Return a new bundle containing the contents of the passed in bundle with
+ /// the passed in public key ring removed.
+ ///
+ /// The PgpPublicKeyRingBundle the key ring is to be removed from.
+ /// The key ring to be removed.
+ /// A new PgpPublicKeyRingBundle not containing the passed in key ring.
+ /// If the keyId for the passed in key ring is not present.
+ public static PgpPublicKeyRingBundle RemovePublicKeyRing(
+ PgpPublicKeyRingBundle bundle,
+ PgpPublicKeyRing publicKeyRing)
+ {
+ long key = publicKeyRing.GetPublicKey().KeyId;
+
+ if (!bundle.pubRings.Contains(key))
+ {
+ throw new ArgumentException("Bundle does not contain a key with a keyId for the passed in ring.");
+ }
+
+ IDictionary newPubRings = Platform.CreateHashtable(bundle.pubRings);
+ IList newOrder = Platform.CreateArrayList(bundle.order);
+
+ newPubRings.Remove(key);
+ newOrder.Remove(key);
+
+ return new PgpPublicKeyRingBundle(newPubRings, newOrder);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpSecretKey.cs b/bc-sharp-crypto/src/openpgp/PgpSecretKey.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b3986073dd2a3c95d9e9e8809fc50ffa4e2549d2
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpSecretKey.cs
@@ -0,0 +1,1295 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// General class to handle a PGP secret key object.
+ public class PgpSecretKey
+ {
+ private readonly SecretKeyPacket secret;
+ private readonly PgpPublicKey pub;
+
+ internal PgpSecretKey(
+ SecretKeyPacket secret,
+ PgpPublicKey pub)
+ {
+ this.secret = secret;
+ this.pub = pub;
+ }
+
+ internal PgpSecretKey(
+ PgpPrivateKey privKey,
+ PgpPublicKey pubKey,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ byte[] rawPassPhrase,
+ bool clearPassPhrase,
+ bool useSha1,
+ SecureRandom rand,
+ bool isMasterKey)
+ {
+ BcpgObject secKey;
+
+ this.pub = pubKey;
+
+ switch (pubKey.Algorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaEncrypt:
+ case PublicKeyAlgorithmTag.RsaSign:
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ RsaPrivateCrtKeyParameters rsK = (RsaPrivateCrtKeyParameters) privKey.Key;
+ secKey = new RsaSecretBcpgKey(rsK.Exponent, rsK.P, rsK.Q);
+ break;
+ case PublicKeyAlgorithmTag.Dsa:
+ DsaPrivateKeyParameters dsK = (DsaPrivateKeyParameters) privKey.Key;
+ secKey = new DsaSecretBcpgKey(dsK.X);
+ break;
+ case PublicKeyAlgorithmTag.ECDH:
+ case PublicKeyAlgorithmTag.ECDsa:
+ ECPrivateKeyParameters ecK = (ECPrivateKeyParameters)privKey.Key;
+ secKey = new ECSecretBcpgKey(ecK.D);
+ break;
+ case PublicKeyAlgorithmTag.ElGamalEncrypt:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ ElGamalPrivateKeyParameters esK = (ElGamalPrivateKeyParameters) privKey.Key;
+ secKey = new ElGamalSecretBcpgKey(esK.X);
+ break;
+ default:
+ throw new PgpException("unknown key class");
+ }
+
+ try
+ {
+ MemoryStream bOut = new MemoryStream();
+ BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+ pOut.WriteObject(secKey);
+
+ byte[] keyData = bOut.ToArray();
+ byte[] checksumData = Checksum(useSha1, keyData, keyData.Length);
+
+ keyData = Arrays.Concatenate(keyData, checksumData);
+
+ if (encAlgorithm == SymmetricKeyAlgorithmTag.Null)
+ {
+ if (isMasterKey)
+ {
+ this.secret = new SecretKeyPacket(pub.publicPk, encAlgorithm, null, null, keyData);
+ }
+ else
+ {
+ this.secret = new SecretSubkeyPacket(pub.publicPk, encAlgorithm, null, null, keyData);
+ }
+ }
+ else
+ {
+ S2k s2k;
+ byte[] iv;
+
+ byte[] encData;
+ if (pub.Version >= 4)
+ {
+ encData = EncryptKeyDataV4(keyData, encAlgorithm, HashAlgorithmTag.Sha1, rawPassPhrase, clearPassPhrase, rand, out s2k, out iv);
+ }
+ else
+ {
+ encData = EncryptKeyDataV3(keyData, encAlgorithm, rawPassPhrase, clearPassPhrase, rand, out s2k, out iv);
+ }
+
+ int s2kUsage = useSha1
+ ? SecretKeyPacket.UsageSha1
+ : SecretKeyPacket.UsageChecksum;
+
+ if (isMasterKey)
+ {
+ this.secret = new SecretKeyPacket(pub.publicPk, encAlgorithm, s2kUsage, s2k, iv, encData);
+ }
+ else
+ {
+ this.secret = new SecretSubkeyPacket(pub.publicPk, encAlgorithm, s2kUsage, s2k, iv, encData);
+ }
+ }
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception encrypting key", e);
+ }
+ }
+
+ ///
+ /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+ /// the historical behaviour of the library (1.7 and earlier).
+ ///
+ [Obsolete("Use the constructor taking an explicit 'useSha1' parameter instead")]
+ public PgpSecretKey(
+ int certificationLevel,
+ PgpKeyPair keyPair,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ char[] passPhrase,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(certificationLevel, keyPair, id, encAlgorithm, passPhrase, false, hashedPackets, unhashedPackets, rand)
+ {
+ }
+
+ ///
+ /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+ /// the historical behaviour of the library (1.7 and earlier).
+ ///
+ public PgpSecretKey(
+ int certificationLevel,
+ PgpKeyPair keyPair,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ char[] passPhrase,
+ bool useSha1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(certificationLevel, keyPair, id, encAlgorithm, false, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
+ {
+ }
+
+ ///
+ /// If utf8PassPhrase is true, conversion of the passphrase to bytes uses Encoding.UTF8.GetBytes(), otherwise the conversion
+ /// is performed using Convert.ToByte(), which is the historical behaviour of the library (1.7 and earlier).
+ ///
+ public PgpSecretKey(
+ int certificationLevel,
+ PgpKeyPair keyPair,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ bool utf8PassPhrase,
+ char[] passPhrase,
+ bool useSha1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(certificationLevel, keyPair, id, encAlgorithm,
+ PgpUtilities.EncodePassPhrase(passPhrase, utf8PassPhrase), true,
+ useSha1, hashedPackets, unhashedPackets, rand)
+ {
+ }
+
+ ///
+ /// Allows the caller to handle the encoding of the passphrase to bytes.
+ ///
+ public PgpSecretKey(
+ int certificationLevel,
+ PgpKeyPair keyPair,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ byte[] rawPassPhrase,
+ bool useSha1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(certificationLevel, keyPair, id, encAlgorithm, rawPassPhrase, false, useSha1, hashedPackets, unhashedPackets, rand)
+ {
+ }
+
+ internal PgpSecretKey(
+ int certificationLevel,
+ PgpKeyPair keyPair,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ byte[] rawPassPhrase,
+ bool clearPassPhrase,
+ bool useSha1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(keyPair.PrivateKey, CertifiedPublicKey(certificationLevel, keyPair, id, hashedPackets, unhashedPackets),
+ encAlgorithm, rawPassPhrase, clearPassPhrase, useSha1, rand, true)
+ {
+ }
+
+ ///
+ /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+ /// the historical behaviour of the library (1.7 and earlier).
+ ///
+ public PgpSecretKey(
+ int certificationLevel,
+ PgpKeyPair keyPair,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ HashAlgorithmTag hashAlgorithm,
+ char[] passPhrase,
+ bool useSha1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(certificationLevel, keyPair, id, encAlgorithm, hashAlgorithm, false, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
+ {
+ }
+
+ ///
+ /// If utf8PassPhrase is true, conversion of the passphrase to bytes uses Encoding.UTF8.GetBytes(), otherwise the conversion
+ /// is performed using Convert.ToByte(), which is the historical behaviour of the library (1.7 and earlier).
+ ///
+ public PgpSecretKey(
+ int certificationLevel,
+ PgpKeyPair keyPair,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ HashAlgorithmTag hashAlgorithm,
+ bool utf8PassPhrase,
+ char[] passPhrase,
+ bool useSha1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(certificationLevel, keyPair, id, encAlgorithm, hashAlgorithm,
+ PgpUtilities.EncodePassPhrase(passPhrase, utf8PassPhrase), true,
+ useSha1, hashedPackets, unhashedPackets, rand)
+ {
+ }
+
+ ///
+ /// Allows the caller to handle the encoding of the passphrase to bytes.
+ ///
+ public PgpSecretKey(
+ int certificationLevel,
+ PgpKeyPair keyPair,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ HashAlgorithmTag hashAlgorithm,
+ byte[] rawPassPhrase,
+ bool useSha1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(certificationLevel, keyPair, id, encAlgorithm, hashAlgorithm, rawPassPhrase, false, useSha1, hashedPackets, unhashedPackets, rand)
+ {
+ }
+
+ internal PgpSecretKey(
+ int certificationLevel,
+ PgpKeyPair keyPair,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ HashAlgorithmTag hashAlgorithm,
+ byte[] rawPassPhrase,
+ bool clearPassPhrase,
+ bool useSha1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(keyPair.PrivateKey, CertifiedPublicKey(certificationLevel, keyPair, id, hashedPackets, unhashedPackets, hashAlgorithm),
+ encAlgorithm, rawPassPhrase, clearPassPhrase, useSha1, rand, true)
+ {
+ }
+
+ private static PgpPublicKey CertifiedPublicKey(
+ int certificationLevel,
+ PgpKeyPair keyPair,
+ string id,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets)
+ {
+ PgpSignatureGenerator sGen;
+ try
+ {
+ sGen = new PgpSignatureGenerator(keyPair.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Creating signature generator: " + e.Message, e);
+ }
+
+ //
+ // Generate the certification
+ //
+ sGen.InitSign(certificationLevel, keyPair.PrivateKey);
+
+ sGen.SetHashedSubpackets(hashedPackets);
+ sGen.SetUnhashedSubpackets(unhashedPackets);
+
+ try
+ {
+ PgpSignature certification = sGen.GenerateCertification(id, keyPair.PublicKey);
+ return PgpPublicKey.AddCertification(keyPair.PublicKey, id, certification);
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception doing certification: " + e.Message, e);
+ }
+ }
+
+
+ private static PgpPublicKey CertifiedPublicKey(
+ int certificationLevel,
+ PgpKeyPair keyPair,
+ string id,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ HashAlgorithmTag hashAlgorithm)
+ {
+ PgpSignatureGenerator sGen;
+ try
+ {
+ sGen = new PgpSignatureGenerator(keyPair.PublicKey.Algorithm, hashAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Creating signature generator: " + e.Message, e);
+ }
+
+ //
+ // Generate the certification
+ //
+ sGen.InitSign(certificationLevel, keyPair.PrivateKey);
+
+ sGen.SetHashedSubpackets(hashedPackets);
+ sGen.SetUnhashedSubpackets(unhashedPackets);
+
+ try
+ {
+ PgpSignature certification = sGen.GenerateCertification(id, keyPair.PublicKey);
+ return PgpPublicKey.AddCertification(keyPair.PublicKey, id, certification);
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception doing certification: " + e.Message, e);
+ }
+ }
+
+ public PgpSecretKey(
+ int certificationLevel,
+ PublicKeyAlgorithmTag algorithm,
+ AsymmetricKeyParameter pubKey,
+ AsymmetricKeyParameter privKey,
+ DateTime time,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ char[] passPhrase,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(certificationLevel,
+ new PgpKeyPair(algorithm, pubKey, privKey, time),
+ id, encAlgorithm, passPhrase, false, hashedPackets, unhashedPackets, rand)
+ {
+ }
+
+ public PgpSecretKey(
+ int certificationLevel,
+ PublicKeyAlgorithmTag algorithm,
+ AsymmetricKeyParameter pubKey,
+ AsymmetricKeyParameter privKey,
+ DateTime time,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ char[] passPhrase,
+ bool useSha1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(certificationLevel, new PgpKeyPair(algorithm, pubKey, privKey, time), id, encAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
+ {
+ }
+
+ ///
+ /// Check if this key has an algorithm type that makes it suitable to use for signing.
+ ///
+ ///
+ /// Note: with version 4 keys KeyFlags subpackets should also be considered when present for
+ /// determining the preferred use of the key.
+ ///
+ ///
+ /// true if this key algorithm is suitable for use with signing.
+ ///
+ public bool IsSigningKey
+ {
+ get
+ {
+ switch (pub.Algorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ case PublicKeyAlgorithmTag.RsaSign:
+ case PublicKeyAlgorithmTag.Dsa:
+ case PublicKeyAlgorithmTag.ECDsa:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ return true;
+ default:
+ return false;
+ }
+ }
+ }
+
+ /// True, if this is a master key.
+ public bool IsMasterKey
+ {
+ get { return pub.IsMasterKey; }
+ }
+
+ /// Detect if the Secret Key's Private Key is empty or not
+ public bool IsPrivateKeyEmpty
+ {
+ get
+ {
+ byte[] secKeyData = secret.GetSecretKeyData();
+
+ return secKeyData == null || secKeyData.Length < 1;
+ }
+ }
+
+ /// The algorithm the key is encrypted with.
+ public SymmetricKeyAlgorithmTag KeyEncryptionAlgorithm
+ {
+ get { return secret.EncAlgorithm; }
+ }
+
+ /// The key ID of the public key associated with this key.
+ public long KeyId
+ {
+ get { return pub.KeyId; }
+ }
+
+ /// Return the S2K usage associated with this key.
+ public int S2kUsage
+ {
+ get { return secret.S2kUsage; }
+ }
+
+ /// Return the S2K used to process this key.
+ public S2k S2k
+ {
+ get { return secret.S2k; }
+ }
+
+ /// The public key associated with this key.
+ public PgpPublicKey PublicKey
+ {
+ get { return pub; }
+ }
+
+ /// Allows enumeration of any user IDs associated with the key.
+ /// An IEnumerable of string objects.
+ public IEnumerable UserIds
+ {
+ get { return pub.GetUserIds(); }
+ }
+
+ /// Allows enumeration of any user attribute vectors associated with the key.
+ /// An IEnumerable of string objects.
+ public IEnumerable UserAttributes
+ {
+ get { return pub.GetUserAttributes(); }
+ }
+
+ private byte[] ExtractKeyData(byte[] rawPassPhrase, bool clearPassPhrase)
+ {
+ SymmetricKeyAlgorithmTag encAlgorithm = secret.EncAlgorithm;
+ byte[] encData = secret.GetSecretKeyData();
+
+ if (encAlgorithm == SymmetricKeyAlgorithmTag.Null)
+ // TODO Check checksum here?
+ return encData;
+
+ // TODO Factor this block out as 'decryptData'
+ try
+ {
+ KeyParameter key = PgpUtilities.DoMakeKeyFromPassPhrase(secret.EncAlgorithm, secret.S2k, rawPassPhrase, clearPassPhrase);
+ byte[] iv = secret.GetIV();
+ byte[] data;
+
+ if (secret.PublicKeyPacket.Version >= 4)
+ {
+ data = RecoverKeyData(encAlgorithm, "/CFB/NoPadding", key, iv, encData, 0, encData.Length);
+
+ bool useSha1 = secret.S2kUsage == SecretKeyPacket.UsageSha1;
+ byte[] check = Checksum(useSha1, data, (useSha1) ? data.Length - 20 : data.Length - 2);
+
+ for (int i = 0; i != check.Length; i++)
+ {
+ if (check[i] != data[data.Length - check.Length + i])
+ {
+ throw new PgpException("Checksum mismatch at " + i + " of " + check.Length);
+ }
+ }
+ }
+ else // version 2 or 3, RSA only.
+ {
+ data = new byte[encData.Length];
+
+ iv = Arrays.Clone(iv);
+
+ //
+ // read in the four numbers
+ //
+ int pos = 0;
+
+ for (int i = 0; i != 4; i++)
+ {
+ int encLen = (((encData[pos] << 8) | (encData[pos + 1] & 0xff)) + 7) / 8;
+
+ data[pos] = encData[pos];
+ data[pos + 1] = encData[pos + 1];
+ pos += 2;
+
+ byte[] tmp = RecoverKeyData(encAlgorithm, "/CFB/NoPadding", key, iv, encData, pos, encLen);
+ Array.Copy(tmp, 0, data, pos, encLen);
+ pos += encLen;
+
+ if (i != 3)
+ {
+ Array.Copy(encData, pos - iv.Length, iv, 0, iv.Length);
+ }
+ }
+
+ //
+ // verify and copy checksum
+ //
+
+ data[pos] = encData[pos];
+ data[pos + 1] = encData[pos + 1];
+
+ int cs = ((encData[pos] << 8) & 0xff00) | (encData[pos + 1] & 0xff);
+ int calcCs = 0;
+ for (int j = 0; j < pos; j++)
+ {
+ calcCs += data[j] & 0xff;
+ }
+
+ calcCs &= 0xffff;
+ if (calcCs != cs)
+ {
+ throw new PgpException("Checksum mismatch: passphrase wrong, expected "
+ + cs.ToString("X")
+ + " found " + calcCs.ToString("X"));
+ }
+ }
+
+ return data;
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception decrypting key", e);
+ }
+ }
+
+ private static byte[] RecoverKeyData(SymmetricKeyAlgorithmTag encAlgorithm, string modeAndPadding,
+ KeyParameter key, byte[] iv, byte[] keyData, int keyOff, int keyLen)
+ {
+ IBufferedCipher c;
+ try
+ {
+ string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);
+ c = CipherUtilities.GetCipher(cName + modeAndPadding);
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception creating cipher", e);
+ }
+
+ c.Init(false, new ParametersWithIV(key, iv));
+
+ return c.DoFinal(keyData, keyOff, keyLen);
+ }
+
+ /// Extract a PgpPrivateKey from this secret key's encrypted contents.
+ ///
+ /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+ /// the historical behaviour of the library (1.7 and earlier).
+ ///
+ public PgpPrivateKey ExtractPrivateKey(char[] passPhrase)
+ {
+ return DoExtractPrivateKey(PgpUtilities.EncodePassPhrase(passPhrase, false), true);
+ }
+
+ /// Extract a PgpPrivateKey from this secret key's encrypted contents.
+ ///
+ /// The passphrase is encoded to bytes using UTF8 (Encoding.UTF8.GetBytes).
+ ///
+ public PgpPrivateKey ExtractPrivateKeyUtf8(char[] passPhrase)
+ {
+ return DoExtractPrivateKey(PgpUtilities.EncodePassPhrase(passPhrase, true), true);
+ }
+
+ /// Extract a PgpPrivateKey from this secret key's encrypted contents.
+ ///
+ /// Allows the caller to handle the encoding of the passphrase to bytes.
+ ///
+ public PgpPrivateKey ExtractPrivateKeyRaw(byte[] rawPassPhrase)
+ {
+ return DoExtractPrivateKey(rawPassPhrase, false);
+ }
+
+ internal PgpPrivateKey DoExtractPrivateKey(byte[] rawPassPhrase, bool clearPassPhrase)
+ {
+ if (IsPrivateKeyEmpty)
+ return null;
+
+ PublicKeyPacket pubPk = secret.PublicKeyPacket;
+ try
+ {
+ byte[] data = ExtractKeyData(rawPassPhrase, clearPassPhrase);
+ BcpgInputStream bcpgIn = BcpgInputStream.Wrap(new MemoryStream(data, false));
+ AsymmetricKeyParameter privateKey;
+ switch (pubPk.Algorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaEncrypt:
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ case PublicKeyAlgorithmTag.RsaSign:
+ RsaPublicBcpgKey rsaPub = (RsaPublicBcpgKey)pubPk.Key;
+ RsaSecretBcpgKey rsaPriv = new RsaSecretBcpgKey(bcpgIn);
+ RsaPrivateCrtKeyParameters rsaPrivSpec = new RsaPrivateCrtKeyParameters(
+ rsaPriv.Modulus,
+ rsaPub.PublicExponent,
+ rsaPriv.PrivateExponent,
+ rsaPriv.PrimeP,
+ rsaPriv.PrimeQ,
+ rsaPriv.PrimeExponentP,
+ rsaPriv.PrimeExponentQ,
+ rsaPriv.CrtCoefficient);
+ privateKey = rsaPrivSpec;
+ break;
+ case PublicKeyAlgorithmTag.Dsa:
+ DsaPublicBcpgKey dsaPub = (DsaPublicBcpgKey)pubPk.Key;
+ DsaSecretBcpgKey dsaPriv = new DsaSecretBcpgKey(bcpgIn);
+ DsaParameters dsaParams = new DsaParameters(dsaPub.P, dsaPub.Q, dsaPub.G);
+ privateKey = new DsaPrivateKeyParameters(dsaPriv.X, dsaParams);
+ break;
+ case PublicKeyAlgorithmTag.ECDH:
+ privateKey = GetECKey("ECDH", bcpgIn);
+ break;
+ case PublicKeyAlgorithmTag.ECDsa:
+ privateKey = GetECKey("ECDSA", bcpgIn);
+ break;
+ case PublicKeyAlgorithmTag.ElGamalEncrypt:
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ ElGamalPublicBcpgKey elPub = (ElGamalPublicBcpgKey)pubPk.Key;
+ ElGamalSecretBcpgKey elPriv = new ElGamalSecretBcpgKey(bcpgIn);
+ ElGamalParameters elParams = new ElGamalParameters(elPub.P, elPub.G);
+ privateKey = new ElGamalPrivateKeyParameters(elPriv.X, elParams);
+ break;
+ default:
+ throw new PgpException("unknown public key algorithm encountered");
+ }
+
+ return new PgpPrivateKey(KeyId, pubPk, privateKey);
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception constructing key", e);
+ }
+ }
+
+ private ECPrivateKeyParameters GetECKey(string algorithm, BcpgInputStream bcpgIn)
+ {
+ ECPublicBcpgKey ecdsaPub = (ECPublicBcpgKey)secret.PublicKeyPacket.Key;
+ ECSecretBcpgKey ecdsaPriv = new ECSecretBcpgKey(bcpgIn);
+ return new ECPrivateKeyParameters(algorithm, ecdsaPriv.X, ecdsaPub.CurveOid);
+ }
+
+ private static byte[] Checksum(
+ bool useSha1,
+ byte[] bytes,
+ int length)
+ {
+ if (useSha1)
+ {
+ try
+ {
+ IDigest dig = DigestUtilities.GetDigest("SHA1");
+ dig.BlockUpdate(bytes, 0, length);
+ return DigestUtilities.DoFinal(dig);
+ }
+ //catch (NoSuchAlgorithmException e)
+ catch (Exception e)
+ {
+ throw new PgpException("Can't find SHA-1", e);
+ }
+ }
+ else
+ {
+ int Checksum = 0;
+ for (int i = 0; i != length; i++)
+ {
+ Checksum += bytes[i];
+ }
+
+ return new byte[] { (byte)(Checksum >> 8), (byte)Checksum };
+ }
+ }
+
+ public byte[] GetEncoded()
+ {
+ MemoryStream bOut = new MemoryStream();
+ Encode(bOut);
+ return bOut.ToArray();
+ }
+
+ public void Encode(
+ Stream outStr)
+ {
+ BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
+
+ bcpgOut.WritePacket(secret);
+ if (pub.trustPk != null)
+ {
+ bcpgOut.WritePacket(pub.trustPk);
+ }
+
+ if (pub.subSigs == null) // is not a sub key
+ {
+ foreach (PgpSignature keySig in pub.keySigs)
+ {
+ keySig.Encode(bcpgOut);
+ }
+
+ for (int i = 0; i != pub.ids.Count; i++)
+ {
+ object pubID = pub.ids[i];
+ if (pubID is string)
+ {
+ string id = (string) pubID;
+ bcpgOut.WritePacket(new UserIdPacket(id));
+ }
+ else
+ {
+ PgpUserAttributeSubpacketVector v = (PgpUserAttributeSubpacketVector) pubID;
+ bcpgOut.WritePacket(new UserAttributePacket(v.ToSubpacketArray()));
+ }
+
+ if (pub.idTrusts[i] != null)
+ {
+ bcpgOut.WritePacket((ContainedPacket)pub.idTrusts[i]);
+ }
+
+ foreach (PgpSignature sig in (IList) pub.idSigs[i])
+ {
+ sig.Encode(bcpgOut);
+ }
+ }
+ }
+ else
+ {
+ foreach (PgpSignature subSig in pub.subSigs)
+ {
+ subSig.Encode(bcpgOut);
+ }
+ }
+
+ // TODO Check that this is right/necessary
+ //bcpgOut.Finish();
+ }
+
+ ///
+ /// Return a copy of the passed in secret key, encrypted using a new password
+ /// and the passed in algorithm.
+ ///
+ ///
+ /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+ /// the historical behaviour of the library (1.7 and earlier).
+ ///
+ /// The PgpSecretKey to be copied.
+ /// The current password for the key.
+ /// The new password for the key.
+ /// The algorithm to be used for the encryption.
+ /// Source of randomness.
+ public static PgpSecretKey CopyWithNewPassword(
+ PgpSecretKey key,
+ char[] oldPassPhrase,
+ char[] newPassPhrase,
+ SymmetricKeyAlgorithmTag newEncAlgorithm,
+ SecureRandom rand)
+ {
+ return DoCopyWithNewPassword(key, PgpUtilities.EncodePassPhrase(oldPassPhrase, false),
+ PgpUtilities.EncodePassPhrase(newPassPhrase, false), true, newEncAlgorithm, rand);
+ }
+
+ ///
+ /// Return a copy of the passed in secret key, encrypted using a new password
+ /// and the passed in algorithm.
+ ///
+ ///
+ /// The passphrase is encoded to bytes using UTF8 (Encoding.UTF8.GetBytes).
+ ///
+ /// The PgpSecretKey to be copied.
+ /// The current password for the key.
+ /// The new password for the key.
+ /// The algorithm to be used for the encryption.
+ /// Source of randomness.
+ public static PgpSecretKey CopyWithNewPasswordUtf8(
+ PgpSecretKey key,
+ char[] oldPassPhrase,
+ char[] newPassPhrase,
+ SymmetricKeyAlgorithmTag newEncAlgorithm,
+ SecureRandom rand)
+ {
+ return DoCopyWithNewPassword(key, PgpUtilities.EncodePassPhrase(oldPassPhrase, true),
+ PgpUtilities.EncodePassPhrase(newPassPhrase, true), true, newEncAlgorithm, rand);
+ }
+
+ ///
+ /// Return a copy of the passed in secret key, encrypted using a new password
+ /// and the passed in algorithm.
+ ///
+ ///
+ /// Allows the caller to handle the encoding of the passphrase to bytes.
+ ///
+ /// The PgpSecretKey to be copied.
+ /// The current password for the key.
+ /// The new password for the key.
+ /// The algorithm to be used for the encryption.
+ /// Source of randomness.
+ public static PgpSecretKey CopyWithNewPasswordRaw(
+ PgpSecretKey key,
+ byte[] rawOldPassPhrase,
+ byte[] rawNewPassPhrase,
+ SymmetricKeyAlgorithmTag newEncAlgorithm,
+ SecureRandom rand)
+ {
+ return DoCopyWithNewPassword(key, rawOldPassPhrase, rawNewPassPhrase, false, newEncAlgorithm, rand);
+ }
+
+ internal static PgpSecretKey DoCopyWithNewPassword(
+ PgpSecretKey key,
+ byte[] rawOldPassPhrase,
+ byte[] rawNewPassPhrase,
+ bool clearPassPhrase,
+ SymmetricKeyAlgorithmTag newEncAlgorithm,
+ SecureRandom rand)
+ {
+ if (key.IsPrivateKeyEmpty)
+ throw new PgpException("no private key in this SecretKey - public key present only.");
+
+ byte[] rawKeyData = key.ExtractKeyData(rawOldPassPhrase, clearPassPhrase);
+ int s2kUsage = key.secret.S2kUsage;
+ byte[] iv = null;
+ S2k s2k = null;
+ byte[] keyData;
+ PublicKeyPacket pubKeyPacket = key.secret.PublicKeyPacket;
+
+ if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null)
+ {
+ s2kUsage = SecretKeyPacket.UsageNone;
+ if (key.secret.S2kUsage == SecretKeyPacket.UsageSha1) // SHA-1 hash, need to rewrite Checksum
+ {
+ keyData = new byte[rawKeyData.Length - 18];
+
+ Array.Copy(rawKeyData, 0, keyData, 0, keyData.Length - 2);
+
+ byte[] check = Checksum(false, keyData, keyData.Length - 2);
+
+ keyData[keyData.Length - 2] = check[0];
+ keyData[keyData.Length - 1] = check[1];
+ }
+ else
+ {
+ keyData = rawKeyData;
+ }
+ }
+ else
+ {
+ if (s2kUsage == SecretKeyPacket.UsageNone)
+ {
+ s2kUsage = SecretKeyPacket.UsageChecksum;
+ }
+
+ try
+ {
+ if (pubKeyPacket.Version >= 4)
+ {
+ keyData = EncryptKeyDataV4(rawKeyData, newEncAlgorithm, HashAlgorithmTag.Sha1, rawNewPassPhrase, clearPassPhrase, rand, out s2k, out iv);
+ }
+ else
+ {
+ keyData = EncryptKeyDataV3(rawKeyData, newEncAlgorithm, rawNewPassPhrase, clearPassPhrase, rand, out s2k, out iv);
+ }
+ }
+ catch (PgpException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception encrypting key", e);
+ }
+ }
+
+ SecretKeyPacket secret;
+ if (key.secret is SecretSubkeyPacket)
+ {
+ secret = new SecretSubkeyPacket(pubKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData);
+ }
+ else
+ {
+ secret = new SecretKeyPacket(pubKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData);
+ }
+
+ return new PgpSecretKey(secret, key.pub);
+ }
+
+ /// Replace the passed the public key on the passed in secret key.
+ /// Secret key to change.
+ /// New public key.
+ /// A new secret key.
+ /// If KeyId's do not match.
+ public static PgpSecretKey ReplacePublicKey(
+ PgpSecretKey secretKey,
+ PgpPublicKey publicKey)
+ {
+ if (publicKey.KeyId != secretKey.KeyId)
+ throw new ArgumentException("KeyId's do not match");
+
+ return new PgpSecretKey(secretKey.secret, publicKey);
+ }
+
+ private static byte[] EncryptKeyDataV3(
+ byte[] rawKeyData,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ byte[] rawPassPhrase,
+ bool clearPassPhrase,
+ SecureRandom random,
+ out S2k s2k,
+ out byte[] iv)
+ {
+ // Version 2 or 3 - RSA Keys only
+
+ s2k = null;
+ iv = null;
+
+ KeyParameter encKey = PgpUtilities.DoMakeKeyFromPassPhrase(encAlgorithm, s2k, rawPassPhrase, clearPassPhrase);
+
+ byte[] keyData = new byte[rawKeyData.Length];
+
+ //
+ // process 4 numbers
+ //
+ int pos = 0;
+ for (int i = 0; i != 4; i++)
+ {
+ int encLen = (((rawKeyData[pos] << 8) | (rawKeyData[pos + 1] & 0xff)) + 7) / 8;
+
+ keyData[pos] = rawKeyData[pos];
+ keyData[pos + 1] = rawKeyData[pos + 1];
+
+ byte[] tmp;
+ if (i == 0)
+ {
+ tmp = EncryptData(encAlgorithm, encKey, rawKeyData, pos + 2, encLen, random, ref iv);
+ }
+ else
+ {
+ byte[] tmpIv = Arrays.CopyOfRange(keyData, pos - iv.Length, pos);
+
+ tmp = EncryptData(encAlgorithm, encKey, rawKeyData, pos + 2, encLen, random, ref tmpIv);
+ }
+
+ Array.Copy(tmp, 0, keyData, pos + 2, tmp.Length);
+ pos += 2 + encLen;
+ }
+
+ //
+ // copy in checksum.
+ //
+ keyData[pos] = rawKeyData[pos];
+ keyData[pos + 1] = rawKeyData[pos + 1];
+
+ return keyData;
+ }
+
+ private static byte[] EncryptKeyDataV4(
+ byte[] rawKeyData,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ HashAlgorithmTag hashAlgorithm,
+ byte[] rawPassPhrase,
+ bool clearPassPhrase,
+ SecureRandom random,
+ out S2k s2k,
+ out byte[] iv)
+ {
+ s2k = PgpUtilities.GenerateS2k(hashAlgorithm, 0x60, random);
+
+ KeyParameter key = PgpUtilities.DoMakeKeyFromPassPhrase(encAlgorithm, s2k, rawPassPhrase, clearPassPhrase);
+
+ iv = null;
+ return EncryptData(encAlgorithm, key, rawKeyData, 0, rawKeyData.Length, random, ref iv);
+ }
+
+ private static byte[] EncryptData(
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ KeyParameter key,
+ byte[] data,
+ int dataOff,
+ int dataLen,
+ SecureRandom random,
+ ref byte[] iv)
+ {
+ IBufferedCipher c;
+ try
+ {
+ string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);
+ c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception creating cipher", e);
+ }
+
+ if (iv == null)
+ {
+ iv = PgpUtilities.GenerateIV(c.GetBlockSize(), random);
+ }
+
+ c.Init(true, new ParametersWithRandom(new ParametersWithIV(key, iv), random));
+
+ return c.DoFinal(data, dataOff, dataLen);
+ }
+
+ ///
+ /// Parse a secret key from one of the GPG S expression keys associating it with the passed in public key.
+ ///
+ ///
+ /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+ /// the historical behaviour of the library (1.7 and earlier).
+ ///
+ public static PgpSecretKey ParseSecretKeyFromSExpr(Stream inputStream, char[] passPhrase, PgpPublicKey pubKey)
+ {
+ return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, false), true, pubKey);
+ }
+
+ ///
+ /// Parse a secret key from one of the GPG S expression keys associating it with the passed in public key.
+ ///
+ ///
+ /// The passphrase is encoded to bytes using UTF8 (Encoding.UTF8.GetBytes).
+ ///
+ public static PgpSecretKey ParseSecretKeyFromSExprUtf8(Stream inputStream, char[] passPhrase, PgpPublicKey pubKey)
+ {
+ return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, true), true, pubKey);
+ }
+
+ ///
+ /// Parse a secret key from one of the GPG S expression keys associating it with the passed in public key.
+ ///
+ ///
+ /// Allows the caller to handle the encoding of the passphrase to bytes.
+ ///
+ public static PgpSecretKey ParseSecretKeyFromSExprRaw(Stream inputStream, byte[] rawPassPhrase, PgpPublicKey pubKey)
+ {
+ return DoParseSecretKeyFromSExpr(inputStream, rawPassPhrase, false, pubKey);
+ }
+
+ internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase, PgpPublicKey pubKey)
+ {
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ string type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+ if (type.Equals("protected-private-key"))
+ {
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ string curveName;
+
+ string keyType = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+ if (keyType.Equals("ecc"))
+ {
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ string curveID = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+ curveName = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+
+ SXprUtilities.SkipCloseParenthesis(inputStream);
+ }
+ else
+ {
+ throw new PgpException("no curve details found");
+ }
+
+ byte[] qVal;
+
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+ if (type.Equals("q"))
+ {
+ qVal = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
+ }
+ else
+ {
+ throw new PgpException("no q value found");
+ }
+
+ SXprUtilities.SkipCloseParenthesis(inputStream);
+
+ byte[] dValue = GetDValue(inputStream, rawPassPhrase, clearPassPhrase, curveName);
+ // TODO: check SHA-1 hash.
+
+ return new PgpSecretKey(new SecretKeyPacket(pubKey.PublicKeyPacket, SymmetricKeyAlgorithmTag.Null, null, null,
+ new ECSecretBcpgKey(new BigInteger(1, dValue)).GetEncoded()), pubKey);
+ }
+
+ throw new PgpException("unknown key type found");
+ }
+
+ ///
+ /// Parse a secret key from one of the GPG S expression keys.
+ ///
+ ///
+ /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+ /// the historical behaviour of the library (1.7 and earlier).
+ ///
+ public static PgpSecretKey ParseSecretKeyFromSExpr(Stream inputStream, char[] passPhrase)
+ {
+ return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, false), true);
+ }
+
+ ///
+ /// Parse a secret key from one of the GPG S expression keys.
+ ///
+ ///
+ /// The passphrase is encoded to bytes using UTF8 (Encoding.UTF8.GetBytes).
+ ///
+ public static PgpSecretKey ParseSecretKeyFromSExprUtf8(Stream inputStream, char[] passPhrase)
+ {
+ return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, true), true);
+ }
+
+ ///
+ /// Parse a secret key from one of the GPG S expression keys.
+ ///
+ ///
+ /// Allows the caller to handle the encoding of the passphrase to bytes.
+ ///
+ public static PgpSecretKey ParseSecretKeyFromSExprRaw(Stream inputStream, byte[] rawPassPhrase)
+ {
+ return DoParseSecretKeyFromSExpr(inputStream, rawPassPhrase, false);
+ }
+
+ ///
+ /// Parse a secret key from one of the GPG S expression keys.
+ ///
+ internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase)
+ {
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ string type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+ if (type.Equals("protected-private-key"))
+ {
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ string curveName;
+
+ string keyType = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+ if (keyType.Equals("ecc"))
+ {
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ string curveID = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+ curveName = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+
+ if (Platform.StartsWith(curveName, "NIST "))
+ {
+ curveName = curveName.Substring("NIST ".Length);
+ }
+
+ SXprUtilities.SkipCloseParenthesis(inputStream);
+ }
+ else
+ {
+ throw new PgpException("no curve details found");
+ }
+
+ byte[] qVal;
+
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+ if (type.Equals("q"))
+ {
+ qVal = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
+ }
+ else
+ {
+ throw new PgpException("no q value found");
+ }
+
+ PublicKeyPacket pubPacket = new PublicKeyPacket(PublicKeyAlgorithmTag.ECDsa, DateTime.UtcNow,
+ new ECDsaPublicBcpgKey(ECNamedCurveTable.GetOid(curveName), new BigInteger(1, qVal)));
+
+ SXprUtilities.SkipCloseParenthesis(inputStream);
+
+ byte[] dValue = GetDValue(inputStream, rawPassPhrase, clearPassPhrase, curveName);
+ // TODO: check SHA-1 hash.
+
+ return new PgpSecretKey(new SecretKeyPacket(pubPacket, SymmetricKeyAlgorithmTag.Null, null, null,
+ new ECSecretBcpgKey(new BigInteger(1, dValue)).GetEncoded()), new PgpPublicKey(pubPacket));
+ }
+
+ throw new PgpException("unknown key type found");
+ }
+
+ private static byte[] GetDValue(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase, string curveName)
+ {
+ string type;
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ string protection;
+ S2k s2k;
+ byte[] iv;
+ byte[] secKeyData;
+
+ type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+ if (type.Equals("protected"))
+ {
+ protection = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+
+ SXprUtilities.SkipOpenParenthesis(inputStream);
+
+ s2k = SXprUtilities.ParseS2k(inputStream);
+
+ iv = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
+
+ SXprUtilities.SkipCloseParenthesis(inputStream);
+
+ secKeyData = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
+ }
+ else
+ {
+ throw new PgpException("protected block not found");
+ }
+
+ // TODO: recognise other algorithms
+ KeyParameter key = PgpUtilities.DoMakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag.Aes128, s2k, rawPassPhrase, clearPassPhrase);
+
+ byte[] data = RecoverKeyData(SymmetricKeyAlgorithmTag.Aes128, "/CBC/NoPadding", key, iv, secKeyData, 0, secKeyData.Length);
+
+ //
+ // parse the secret key S-expr
+ //
+ Stream keyIn = new MemoryStream(data, false);
+
+ SXprUtilities.SkipOpenParenthesis(keyIn);
+ SXprUtilities.SkipOpenParenthesis(keyIn);
+ SXprUtilities.SkipOpenParenthesis(keyIn);
+ String name = SXprUtilities.ReadString(keyIn, keyIn.ReadByte());
+ return SXprUtilities.ReadBytes(keyIn, keyIn.ReadByte());
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpSecretKeyRing.cs b/bc-sharp-crypto/src/openpgp/PgpSecretKeyRing.cs
new file mode 100644
index 0000000000000000000000000000000000000000..70cd7217c548ed42d638a86258ea1a0826ae0f74
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpSecretKeyRing.cs
@@ -0,0 +1,308 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// Class to hold a single master secret key and its subkeys.
+ ///
+ /// Often PGP keyring files consist of multiple master keys, if you are trying to process
+ /// or construct one of these you should use the PgpSecretKeyRingBundle class.
+ ///
+ ///
+ public class PgpSecretKeyRing
+ : PgpKeyRing
+ {
+ private readonly IList keys;
+ private readonly IList extraPubKeys;
+
+ internal PgpSecretKeyRing(
+ IList keys)
+ : this(keys, Platform.CreateArrayList())
+ {
+ }
+
+ private PgpSecretKeyRing(
+ IList keys,
+ IList extraPubKeys)
+ {
+ this.keys = keys;
+ this.extraPubKeys = extraPubKeys;
+ }
+
+ public PgpSecretKeyRing(
+ byte[] encoding)
+ : this(new MemoryStream(encoding))
+ {
+ }
+
+ public PgpSecretKeyRing(
+ Stream inputStream)
+ {
+ this.keys = Platform.CreateArrayList();
+ this.extraPubKeys = Platform.CreateArrayList();
+
+ BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream);
+
+ PacketTag initialTag = bcpgInput.NextPacketTag();
+ if (initialTag != PacketTag.SecretKey && initialTag != PacketTag.SecretSubkey)
+ {
+ throw new IOException("secret key ring doesn't start with secret key tag: "
+ + "tag 0x" + ((int)initialTag).ToString("X"));
+ }
+
+ SecretKeyPacket secret = (SecretKeyPacket) bcpgInput.ReadPacket();
+
+ //
+ // ignore GPG comment packets if found.
+ //
+ while (bcpgInput.NextPacketTag() == PacketTag.Experimental2)
+ {
+ bcpgInput.ReadPacket();
+ }
+
+ TrustPacket trust = ReadOptionalTrustPacket(bcpgInput);
+
+ // revocation and direct signatures
+ IList keySigs = ReadSignaturesAndTrust(bcpgInput);
+
+ IList ids, idTrusts, idSigs;
+ ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs);
+
+ keys.Add(new PgpSecretKey(secret, new PgpPublicKey(secret.PublicKeyPacket, trust, keySigs, ids, idTrusts, idSigs)));
+
+
+ // Read subkeys
+ while (bcpgInput.NextPacketTag() == PacketTag.SecretSubkey
+ || bcpgInput.NextPacketTag() == PacketTag.PublicSubkey)
+ {
+ if (bcpgInput.NextPacketTag() == PacketTag.SecretSubkey)
+ {
+ SecretSubkeyPacket sub = (SecretSubkeyPacket) bcpgInput.ReadPacket();
+
+ //
+ // ignore GPG comment packets if found.
+ //
+ while (bcpgInput.NextPacketTag() == PacketTag.Experimental2)
+ {
+ bcpgInput.ReadPacket();
+ }
+
+ TrustPacket subTrust = ReadOptionalTrustPacket(bcpgInput);
+ IList sigList = ReadSignaturesAndTrust(bcpgInput);
+
+ keys.Add(new PgpSecretKey(sub, new PgpPublicKey(sub.PublicKeyPacket, subTrust, sigList)));
+ }
+ else
+ {
+ PublicSubkeyPacket sub = (PublicSubkeyPacket) bcpgInput.ReadPacket();
+
+ TrustPacket subTrust = ReadOptionalTrustPacket(bcpgInput);
+ IList sigList = ReadSignaturesAndTrust(bcpgInput);
+
+ extraPubKeys.Add(new PgpPublicKey(sub, subTrust, sigList));
+ }
+ }
+ }
+
+ /// Return the public key for the master key.
+ public PgpPublicKey GetPublicKey()
+ {
+ return ((PgpSecretKey) keys[0]).PublicKey;
+ }
+
+ /// Return the master private key.
+ public PgpSecretKey GetSecretKey()
+ {
+ return (PgpSecretKey) keys[0];
+ }
+
+ /// Allows enumeration of the secret keys.
+ /// An IEnumerable of PgpSecretKey objects.
+ public IEnumerable GetSecretKeys()
+ {
+ return new EnumerableProxy(keys);
+ }
+
+ public PgpSecretKey GetSecretKey(
+ long keyId)
+ {
+ foreach (PgpSecretKey k in keys)
+ {
+ if (keyId == k.KeyId)
+ {
+ return k;
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Return an iterator of the public keys in the secret key ring that
+ /// have no matching private key. At the moment only personal certificate data
+ /// appears in this fashion.
+ ///
+ /// An IEnumerable of unattached, or extra, public keys.
+ public IEnumerable GetExtraPublicKeys()
+ {
+ return new EnumerableProxy(extraPubKeys);
+ }
+
+ public byte[] GetEncoded()
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ Encode(bOut);
+
+ return bOut.ToArray();
+ }
+
+ public void Encode(
+ Stream outStr)
+ {
+ if (outStr == null)
+ throw new ArgumentNullException("outStr");
+
+ foreach (PgpSecretKey key in keys)
+ {
+ key.Encode(outStr);
+ }
+ foreach (PgpPublicKey extraPubKey in extraPubKeys)
+ {
+ extraPubKey.Encode(outStr);
+ }
+ }
+
+ ///
+ /// Replace the public key set on the secret ring with the corresponding key off the public ring.
+ ///
+ /// Secret ring to be changed.
+ /// Public ring containing the new public key set.
+ public static PgpSecretKeyRing ReplacePublicKeys(
+ PgpSecretKeyRing secretRing,
+ PgpPublicKeyRing publicRing)
+ {
+ IList newList = Platform.CreateArrayList(secretRing.keys.Count);
+
+ foreach (PgpSecretKey sk in secretRing.keys)
+ {
+ PgpPublicKey pk = publicRing.GetPublicKey(sk.KeyId);
+
+ newList.Add(PgpSecretKey.ReplacePublicKey(sk, pk));
+ }
+
+ return new PgpSecretKeyRing(newList);
+ }
+
+ ///
+ /// Return a copy of the passed in secret key ring, with the master key and sub keys encrypted
+ /// using a new password and the passed in algorithm.
+ ///
+ /// The PgpSecretKeyRing to be copied.
+ /// The current password for key.
+ /// The new password for the key.
+ /// The algorithm to be used for the encryption.
+ /// Source of randomness.
+ public static PgpSecretKeyRing CopyWithNewPassword(
+ PgpSecretKeyRing ring,
+ char[] oldPassPhrase,
+ char[] newPassPhrase,
+ SymmetricKeyAlgorithmTag newEncAlgorithm,
+ SecureRandom rand)
+ {
+ IList newKeys = Platform.CreateArrayList(ring.keys.Count);
+ foreach (PgpSecretKey secretKey in ring.GetSecretKeys())
+ {
+ if (secretKey.IsPrivateKeyEmpty)
+ {
+ newKeys.Add(secretKey);
+ }
+ else
+ {
+ newKeys.Add(PgpSecretKey.CopyWithNewPassword(secretKey, oldPassPhrase, newPassPhrase, newEncAlgorithm, rand));
+ }
+ }
+
+ return new PgpSecretKeyRing(newKeys, ring.extraPubKeys);
+ }
+
+ ///
+ /// Returns a new key ring with the secret key passed in either added or
+ /// replacing an existing one with the same key ID.
+ ///
+ /// The secret key ring to be modified.
+ /// The secret key to be inserted.
+ /// A new PgpSecretKeyRing
+ public static PgpSecretKeyRing InsertSecretKey(
+ PgpSecretKeyRing secRing,
+ PgpSecretKey secKey)
+ {
+ IList keys = Platform.CreateArrayList(secRing.keys);
+ bool found = false;
+ bool masterFound = false;
+
+ for (int i = 0; i != keys.Count; i++)
+ {
+ PgpSecretKey key = (PgpSecretKey) keys[i];
+
+ if (key.KeyId == secKey.KeyId)
+ {
+ found = true;
+ keys[i] = secKey;
+ }
+ if (key.IsMasterKey)
+ {
+ masterFound = true;
+ }
+ }
+
+ if (!found)
+ {
+ if (secKey.IsMasterKey)
+ {
+ if (masterFound)
+ throw new ArgumentException("cannot add a master key to a ring that already has one");
+
+ keys.Insert(0, secKey);
+ }
+ else
+ {
+ keys.Add(secKey);
+ }
+ }
+
+ return new PgpSecretKeyRing(keys, secRing.extraPubKeys);
+ }
+
+ /// Returns a new key ring with the secret key passed in removed from the key ring.
+ /// The secret key ring to be modified.
+ /// The secret key to be removed.
+ /// A new PgpSecretKeyRing , or null if secKey is not found.
+ public static PgpSecretKeyRing RemoveSecretKey(
+ PgpSecretKeyRing secRing,
+ PgpSecretKey secKey)
+ {
+ IList keys = Platform.CreateArrayList(secRing.keys);
+ bool found = false;
+
+ for (int i = 0; i < keys.Count; i++)
+ {
+ PgpSecretKey key = (PgpSecretKey)keys[i];
+
+ if (key.KeyId == secKey.KeyId)
+ {
+ found = true;
+ keys.RemoveAt(i);
+ }
+ }
+
+ return found ? new PgpSecretKeyRing(keys, secRing.extraPubKeys) : null;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpSecretKeyRingBundle.cs b/bc-sharp-crypto/src/openpgp/PgpSecretKeyRingBundle.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c9f4d395953027741cd8300b2777a8236670da6b
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpSecretKeyRingBundle.cs
@@ -0,0 +1,280 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ ///
+ /// Often a PGP key ring file is made up of a succession of master/sub-key key rings.
+ /// If you want to read an entire secret key file in one hit this is the class for you.
+ ///
+ public class PgpSecretKeyRingBundle
+ {
+ private readonly IDictionary secretRings;
+ private readonly IList order;
+
+ private PgpSecretKeyRingBundle(
+ IDictionary secretRings,
+ IList order)
+ {
+ this.secretRings = secretRings;
+ this.order = order;
+ }
+
+ public PgpSecretKeyRingBundle(
+ byte[] encoding)
+ : this(new MemoryStream(encoding, false))
+ {
+ }
+
+ /// Build a PgpSecretKeyRingBundle from the passed in input stream.
+ /// Input stream containing data.
+ /// If a problem parsing the stream occurs.
+ /// If an object is encountered which isn't a PgpSecretKeyRing.
+ public PgpSecretKeyRingBundle(
+ Stream inputStream)
+ : this(new PgpObjectFactory(inputStream).AllPgpObjects())
+ {
+ }
+
+ public PgpSecretKeyRingBundle(
+ IEnumerable e)
+ {
+ this.secretRings = Platform.CreateHashtable();
+ this.order = Platform.CreateArrayList();
+
+ foreach (object obj in e)
+ {
+ PgpSecretKeyRing pgpSecret = obj as PgpSecretKeyRing;
+
+ if (pgpSecret == null)
+ {
+ throw new PgpException(Platform.GetTypeName(obj) + " found where PgpSecretKeyRing expected");
+ }
+
+ long key = pgpSecret.GetPublicKey().KeyId;
+ secretRings.Add(key, pgpSecret);
+ order.Add(key);
+ }
+ }
+
+ [Obsolete("Use 'Count' property instead")]
+ public int Size
+ {
+ get { return order.Count; }
+ }
+
+ /// Return the number of rings in this collection.
+ public int Count
+ {
+ get { return order.Count; }
+ }
+
+ /// Allow enumeration of the secret key rings making up this collection.
+ public IEnumerable GetKeyRings()
+ {
+ return new EnumerableProxy(secretRings.Values);
+ }
+
+ /// Allow enumeration of the key rings associated with the passed in userId.
+ /// The user ID to be matched.
+ /// An IEnumerable of key rings which matched (possibly none).
+ public IEnumerable GetKeyRings(
+ string userId)
+ {
+ return GetKeyRings(userId, false, false);
+ }
+
+ /// Allow enumeration of the key rings associated with the passed in userId.
+ /// The user ID to be matched.
+ /// If true, userId need only be a substring of an actual ID string to match.
+ /// An IEnumerable of key rings which matched (possibly none).
+ public IEnumerable GetKeyRings(
+ string userId,
+ bool matchPartial)
+ {
+ return GetKeyRings(userId, matchPartial, false);
+ }
+
+ /// Allow enumeration of the key rings associated with the passed in userId.
+ /// The user ID to be matched.
+ /// If true, userId need only be a substring of an actual ID string to match.
+ /// If true, case is ignored in user ID comparisons.
+ /// An IEnumerable of key rings which matched (possibly none).
+ public IEnumerable GetKeyRings(
+ string userId,
+ bool matchPartial,
+ bool ignoreCase)
+ {
+ IList rings = Platform.CreateArrayList();
+
+ if (ignoreCase)
+ {
+ userId = Platform.ToUpperInvariant(userId);
+ }
+
+ foreach (PgpSecretKeyRing secRing in GetKeyRings())
+ {
+ foreach (string nextUserID in secRing.GetSecretKey().UserIds)
+ {
+ string next = nextUserID;
+ if (ignoreCase)
+ {
+ next = Platform.ToUpperInvariant(next);
+ }
+
+ if (matchPartial)
+ {
+ if (Platform.IndexOf(next, userId) > -1)
+ {
+ rings.Add(secRing);
+ }
+ }
+ else
+ {
+ if (next.Equals(userId))
+ {
+ rings.Add(secRing);
+ }
+ }
+ }
+ }
+
+ return new EnumerableProxy(rings);
+ }
+
+ /// Return the PGP secret key associated with the given key id.
+ /// The ID of the secret key to return.
+ public PgpSecretKey GetSecretKey(
+ long keyId)
+ {
+ foreach (PgpSecretKeyRing secRing in GetKeyRings())
+ {
+ PgpSecretKey sec = secRing.GetSecretKey(keyId);
+
+ if (sec != null)
+ {
+ return sec;
+ }
+ }
+
+ return null;
+ }
+
+ /// Return the secret key ring which contains the key referred to by keyId
+ /// The ID of the secret key
+ public PgpSecretKeyRing GetSecretKeyRing(
+ long keyId)
+ {
+ long id = keyId;
+
+ if (secretRings.Contains(id))
+ {
+ return (PgpSecretKeyRing) secretRings[id];
+ }
+
+ foreach (PgpSecretKeyRing secretRing in GetKeyRings())
+ {
+ PgpSecretKey secret = secretRing.GetSecretKey(keyId);
+
+ if (secret != null)
+ {
+ return secretRing;
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Return true if a key matching the passed in key ID is present, false otherwise.
+ ///
+ /// key ID to look for.
+ public bool Contains(
+ long keyID)
+ {
+ return GetSecretKey(keyID) != null;
+ }
+
+ public byte[] GetEncoded()
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ Encode(bOut);
+
+ return bOut.ToArray();
+ }
+
+ public void Encode(
+ Stream outStr)
+ {
+ BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
+
+ foreach (long key in order)
+ {
+ PgpSecretKeyRing pub = (PgpSecretKeyRing) secretRings[key];
+
+ pub.Encode(bcpgOut);
+ }
+ }
+
+ ///
+ /// Return a new bundle containing the contents of the passed in bundle and
+ /// the passed in secret key ring.
+ ///
+ /// The PgpSecretKeyRingBundle the key ring is to be added to.
+ /// The key ring to be added.
+ /// A new PgpSecretKeyRingBundle merging the current one with the passed in key ring.
+ /// If the keyId for the passed in key ring is already present.
+ public static PgpSecretKeyRingBundle AddSecretKeyRing(
+ PgpSecretKeyRingBundle bundle,
+ PgpSecretKeyRing secretKeyRing)
+ {
+ long key = secretKeyRing.GetPublicKey().KeyId;
+
+ if (bundle.secretRings.Contains(key))
+ {
+ throw new ArgumentException("Collection already contains a key with a keyId for the passed in ring.");
+ }
+
+ IDictionary newSecretRings = Platform.CreateHashtable(bundle.secretRings);
+ IList newOrder = Platform.CreateArrayList(bundle.order);
+
+ newSecretRings[key] = secretKeyRing;
+ newOrder.Add(key);
+
+ return new PgpSecretKeyRingBundle(newSecretRings, newOrder);
+ }
+
+ ///
+ /// Return a new bundle containing the contents of the passed in bundle with
+ /// the passed in secret key ring removed.
+ ///
+ /// The PgpSecretKeyRingBundle the key ring is to be removed from.
+ /// The key ring to be removed.
+ /// A new PgpSecretKeyRingBundle not containing the passed in key ring.
+ /// If the keyId for the passed in key ring is not present.
+ public static PgpSecretKeyRingBundle RemoveSecretKeyRing(
+ PgpSecretKeyRingBundle bundle,
+ PgpSecretKeyRing secretKeyRing)
+ {
+ long key = secretKeyRing.GetPublicKey().KeyId;
+
+ if (!bundle.secretRings.Contains(key))
+ {
+ throw new ArgumentException("Collection does not contain a key with a keyId for the passed in ring.");
+ }
+
+ IDictionary newSecretRings = Platform.CreateHashtable(bundle.secretRings);
+ IList newOrder = Platform.CreateArrayList(bundle.order);
+
+ newSecretRings.Remove(key);
+ newOrder.Remove(key);
+
+ return new PgpSecretKeyRingBundle(newSecretRings, newOrder);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpSignature.cs b/bc-sharp-crypto/src/openpgp/PgpSignature.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c8c541befc1e32f9e50a16569aac0d36cb452584
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpSignature.cs
@@ -0,0 +1,447 @@
+using System;
+using System.IO;
+using Org.BouncyCastle.Asn1;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// A PGP signature object.
+ public class PgpSignature
+ {
+ public const int BinaryDocument = 0x00;
+ public const int CanonicalTextDocument = 0x01;
+ public const int StandAlone = 0x02;
+
+ public const int DefaultCertification = 0x10;
+ public const int NoCertification = 0x11;
+ public const int CasualCertification = 0x12;
+ public const int PositiveCertification = 0x13;
+
+ public const int SubkeyBinding = 0x18;
+ public const int PrimaryKeyBinding = 0x19;
+ public const int DirectKey = 0x1f;
+ public const int KeyRevocation = 0x20;
+ public const int SubkeyRevocation = 0x28;
+ public const int CertificationRevocation = 0x30;
+ public const int Timestamp = 0x40;
+
+ private readonly SignaturePacket sigPck;
+ private readonly int signatureType;
+ private readonly TrustPacket trustPck;
+
+ private ISigner sig;
+ private byte lastb; // Initial value anything but '\r'
+
+ internal PgpSignature(
+ BcpgInputStream bcpgInput)
+ : this((SignaturePacket)bcpgInput.ReadPacket())
+ {
+ }
+
+ internal PgpSignature(
+ SignaturePacket sigPacket)
+ : this(sigPacket, null)
+ {
+ }
+
+ internal PgpSignature(
+ SignaturePacket sigPacket,
+ TrustPacket trustPacket)
+ {
+ if (sigPacket == null)
+ throw new ArgumentNullException("sigPacket");
+
+ this.sigPck = sigPacket;
+ this.signatureType = sigPck.SignatureType;
+ this.trustPck = trustPacket;
+ }
+
+ private void GetSig()
+ {
+ this.sig = SignerUtilities.GetSigner(
+ PgpUtilities.GetSignatureName(sigPck.KeyAlgorithm, sigPck.HashAlgorithm));
+ }
+
+ /// The OpenPGP version number for this signature.
+ public int Version
+ {
+ get { return sigPck.Version; }
+ }
+
+ /// The key algorithm associated with this signature.
+ public PublicKeyAlgorithmTag KeyAlgorithm
+ {
+ get { return sigPck.KeyAlgorithm; }
+ }
+
+ /// The hash algorithm associated with this signature.
+ public HashAlgorithmTag HashAlgorithm
+ {
+ get { return sigPck.HashAlgorithm; }
+ }
+
+ /// Return true if this signature represents a certification.
+ public bool IsCertification()
+ {
+ return IsCertification(SignatureType);
+ }
+
+ public void InitVerify(
+ PgpPublicKey pubKey)
+ {
+ lastb = 0;
+ if (sig == null)
+ {
+ GetSig();
+ }
+ try
+ {
+ sig.Init(false, pubKey.GetKey());
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new PgpException("invalid key.", e);
+ }
+ }
+
+ public void Update(
+ byte b)
+ {
+ if (signatureType == CanonicalTextDocument)
+ {
+ doCanonicalUpdateByte(b);
+ }
+ else
+ {
+ sig.Update(b);
+ }
+ }
+
+ private void doCanonicalUpdateByte(
+ byte b)
+ {
+ if (b == '\r')
+ {
+ doUpdateCRLF();
+ }
+ else if (b == '\n')
+ {
+ if (lastb != '\r')
+ {
+ doUpdateCRLF();
+ }
+ }
+ else
+ {
+ sig.Update(b);
+ }
+
+ lastb = b;
+ }
+
+ private void doUpdateCRLF()
+ {
+ sig.Update((byte)'\r');
+ sig.Update((byte)'\n');
+ }
+
+ public void Update(
+ params byte[] bytes)
+ {
+ Update(bytes, 0, bytes.Length);
+ }
+
+ public void Update(
+ byte[] bytes,
+ int off,
+ int length)
+ {
+ if (signatureType == CanonicalTextDocument)
+ {
+ int finish = off + length;
+
+ for (int i = off; i != finish; i++)
+ {
+ doCanonicalUpdateByte(bytes[i]);
+ }
+ }
+ else
+ {
+ sig.BlockUpdate(bytes, off, length);
+ }
+ }
+
+ public bool Verify()
+ {
+ byte[] trailer = GetSignatureTrailer();
+ sig.BlockUpdate(trailer, 0, trailer.Length);
+
+ return sig.VerifySignature(GetSignature());
+ }
+
+ private void UpdateWithIdData(
+ int header,
+ byte[] idBytes)
+ {
+ this.Update(
+ (byte) header,
+ (byte)(idBytes.Length >> 24),
+ (byte)(idBytes.Length >> 16),
+ (byte)(idBytes.Length >> 8),
+ (byte)(idBytes.Length));
+ this.Update(idBytes);
+ }
+
+ private void UpdateWithPublicKey(
+ PgpPublicKey key)
+ {
+ byte[] keyBytes = GetEncodedPublicKey(key);
+
+ this.Update(
+ (byte) 0x99,
+ (byte)(keyBytes.Length >> 8),
+ (byte)(keyBytes.Length));
+ this.Update(keyBytes);
+ }
+
+ ///
+ /// Verify the signature as certifying the passed in public key as associated
+ /// with the passed in user attributes.
+ ///
+ /// User attributes the key was stored under.
+ /// The key to be verified.
+ /// True, if the signature matches, false otherwise.
+ public bool VerifyCertification(
+ PgpUserAttributeSubpacketVector userAttributes,
+ PgpPublicKey key)
+ {
+ UpdateWithPublicKey(key);
+
+ //
+ // hash in the userAttributes
+ //
+ try
+ {
+ MemoryStream bOut = new MemoryStream();
+ foreach (UserAttributeSubpacket packet in userAttributes.ToSubpacketArray())
+ {
+ packet.Encode(bOut);
+ }
+ UpdateWithIdData(0xd1, bOut.ToArray());
+ }
+ catch (IOException e)
+ {
+ throw new PgpException("cannot encode subpacket array", e);
+ }
+
+ this.Update(sigPck.GetSignatureTrailer());
+
+ return sig.VerifySignature(this.GetSignature());
+ }
+
+ ///
+ /// Verify the signature as certifying the passed in public key as associated
+ /// with the passed in ID.
+ ///
+ /// ID the key was stored under.
+ /// The key to be verified.
+ /// True, if the signature matches, false otherwise.
+ public bool VerifyCertification(
+ string id,
+ PgpPublicKey key)
+ {
+ UpdateWithPublicKey(key);
+
+ //
+ // hash in the id
+ //
+ UpdateWithIdData(0xb4, Strings.ToUtf8ByteArray(id));
+
+ Update(sigPck.GetSignatureTrailer());
+
+ return sig.VerifySignature(GetSignature());
+ }
+
+ /// Verify a certification for the passed in key against the passed in master key.
+ /// The key we are verifying against.
+ /// The key we are verifying.
+ /// True, if the certification is valid, false otherwise.
+ public bool VerifyCertification(
+ PgpPublicKey masterKey,
+ PgpPublicKey pubKey)
+ {
+ UpdateWithPublicKey(masterKey);
+ UpdateWithPublicKey(pubKey);
+
+ Update(sigPck.GetSignatureTrailer());
+
+ return sig.VerifySignature(GetSignature());
+ }
+
+ /// Verify a key certification, such as revocation, for the passed in key.
+ /// The key we are checking.
+ /// True, if the certification is valid, false otherwise.
+ public bool VerifyCertification(
+ PgpPublicKey pubKey)
+ {
+ if (SignatureType != KeyRevocation
+ && SignatureType != SubkeyRevocation)
+ {
+ throw new InvalidOperationException("signature is not a key signature");
+ }
+
+ UpdateWithPublicKey(pubKey);
+
+ Update(sigPck.GetSignatureTrailer());
+
+ return sig.VerifySignature(GetSignature());
+ }
+
+ public int SignatureType
+ {
+ get { return sigPck.SignatureType; }
+ }
+
+ /// The ID of the key that created the signature.
+ public long KeyId
+ {
+ get { return sigPck.KeyId; }
+ }
+
+ [Obsolete("Use 'CreationTime' property instead")]
+ public DateTime GetCreationTime()
+ {
+ return CreationTime;
+ }
+
+ /// The creation time of this signature.
+ public DateTime CreationTime
+ {
+ get { return DateTimeUtilities.UnixMsToDateTime(sigPck.CreationTime); }
+ }
+
+ public byte[] GetSignatureTrailer()
+ {
+ return sigPck.GetSignatureTrailer();
+ }
+
+ ///
+ /// Return true if the signature has either hashed or unhashed subpackets.
+ ///
+ public bool HasSubpackets
+ {
+ get
+ {
+ return sigPck.GetHashedSubPackets() != null
+ || sigPck.GetUnhashedSubPackets() != null;
+ }
+ }
+
+ public PgpSignatureSubpacketVector GetHashedSubPackets()
+ {
+ return createSubpacketVector(sigPck.GetHashedSubPackets());
+ }
+
+ public PgpSignatureSubpacketVector GetUnhashedSubPackets()
+ {
+ return createSubpacketVector(sigPck.GetUnhashedSubPackets());
+ }
+
+ private PgpSignatureSubpacketVector createSubpacketVector(SignatureSubpacket[] pcks)
+ {
+ return pcks == null ? null : new PgpSignatureSubpacketVector(pcks);
+ }
+
+ public byte[] GetSignature()
+ {
+ MPInteger[] sigValues = sigPck.GetSignature();
+ byte[] signature;
+
+ if (sigValues != null)
+ {
+ if (sigValues.Length == 1) // an RSA signature
+ {
+ signature = sigValues[0].Value.ToByteArrayUnsigned();
+ }
+ else
+ {
+ try
+ {
+ signature = new DerSequence(
+ new DerInteger(sigValues[0].Value),
+ new DerInteger(sigValues[1].Value)).GetEncoded();
+ }
+ catch (IOException e)
+ {
+ throw new PgpException("exception encoding DSA sig.", e);
+ }
+ }
+ }
+ else
+ {
+ signature = sigPck.GetSignatureBytes();
+ }
+
+ return signature;
+ }
+
+ // TODO Handle the encoding stuff by subclassing BcpgObject?
+ public byte[] GetEncoded()
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ Encode(bOut);
+
+ return bOut.ToArray();
+ }
+
+ public void Encode(
+ Stream outStream)
+ {
+ BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStream);
+
+ bcpgOut.WritePacket(sigPck);
+
+ if (trustPck != null)
+ {
+ bcpgOut.WritePacket(trustPck);
+ }
+ }
+
+ private byte[] GetEncodedPublicKey(
+ PgpPublicKey pubKey)
+ {
+ try
+ {
+ return pubKey.publicPk.GetEncodedContents();
+ }
+ catch (IOException e)
+ {
+ throw new PgpException("exception preparing key.", e);
+ }
+ }
+
+ ///
+ /// Return true if the passed in signature type represents a certification, false if the signature type is not.
+ ///
+ ///
+ /// true if signatureType is a certification, false otherwise.
+ public static bool IsCertification(int signatureType)
+ {
+ switch (signatureType)
+ {
+ case DefaultCertification:
+ case NoCertification:
+ case CasualCertification:
+ case PositiveCertification:
+ return true;
+ default:
+ return false;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpSignatureGenerator.cs b/bc-sharp-crypto/src/openpgp/PgpSignatureGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c5309689fb3ac0de12b55e851d875e9249f8cd3d
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpSignatureGenerator.cs
@@ -0,0 +1,393 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Bcpg.Sig;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Generator for PGP signatures.
+ // TODO Should be able to implement ISigner?
+ public class PgpSignatureGenerator
+ {
+ private static readonly SignatureSubpacket[] EmptySignatureSubpackets = new SignatureSubpacket[0];
+
+ private PublicKeyAlgorithmTag keyAlgorithm;
+ private HashAlgorithmTag hashAlgorithm;
+ private PgpPrivateKey privKey;
+ private ISigner sig;
+ private IDigest dig;
+ private int signatureType;
+ private byte lastb;
+
+ private SignatureSubpacket[] unhashed = EmptySignatureSubpackets;
+ private SignatureSubpacket[] hashed = EmptySignatureSubpackets;
+
+ /// Create a generator for the passed in keyAlgorithm and hashAlgorithm codes.
+ public PgpSignatureGenerator(
+ PublicKeyAlgorithmTag keyAlgorithm,
+ HashAlgorithmTag hashAlgorithm)
+ {
+ this.keyAlgorithm = keyAlgorithm;
+ this.hashAlgorithm = hashAlgorithm;
+
+ dig = DigestUtilities.GetDigest(PgpUtilities.GetDigestName(hashAlgorithm));
+ sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(keyAlgorithm, hashAlgorithm));
+ }
+
+ /// Initialise the generator for signing.
+ public void InitSign(
+ int sigType,
+ PgpPrivateKey key)
+ {
+ InitSign(sigType, key, null);
+ }
+
+ /// Initialise the generator for signing.
+ public void InitSign(
+ int sigType,
+ PgpPrivateKey key,
+ SecureRandom random)
+ {
+ this.privKey = key;
+ this.signatureType = sigType;
+
+ try
+ {
+ ICipherParameters cp = key.Key;
+ if (random != null)
+ {
+ cp = new ParametersWithRandom(key.Key, random);
+ }
+
+ sig.Init(true, cp);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new PgpException("invalid key.", e);
+ }
+
+ dig.Reset();
+ lastb = 0;
+ }
+
+ public void Update(
+ byte b)
+ {
+ if (signatureType == PgpSignature.CanonicalTextDocument)
+ {
+ doCanonicalUpdateByte(b);
+ }
+ else
+ {
+ doUpdateByte(b);
+ }
+ }
+
+ private void doCanonicalUpdateByte(
+ byte b)
+ {
+ if (b == '\r')
+ {
+ doUpdateCRLF();
+ }
+ else if (b == '\n')
+ {
+ if (lastb != '\r')
+ {
+ doUpdateCRLF();
+ }
+ }
+ else
+ {
+ doUpdateByte(b);
+ }
+
+ lastb = b;
+ }
+
+ private void doUpdateCRLF()
+ {
+ doUpdateByte((byte)'\r');
+ doUpdateByte((byte)'\n');
+ }
+
+ private void doUpdateByte(
+ byte b)
+ {
+ sig.Update(b);
+ dig.Update(b);
+ }
+
+ public void Update(
+ params byte[] b)
+ {
+ Update(b, 0, b.Length);
+ }
+
+ public void Update(
+ byte[] b,
+ int off,
+ int len)
+ {
+ if (signatureType == PgpSignature.CanonicalTextDocument)
+ {
+ int finish = off + len;
+
+ for (int i = off; i != finish; i++)
+ {
+ doCanonicalUpdateByte(b[i]);
+ }
+ }
+ else
+ {
+ sig.BlockUpdate(b, off, len);
+ dig.BlockUpdate(b, off, len);
+ }
+ }
+
+ public void SetHashedSubpackets(
+ PgpSignatureSubpacketVector hashedPackets)
+ {
+ hashed = hashedPackets == null
+ ? EmptySignatureSubpackets
+ : hashedPackets.ToSubpacketArray();
+ }
+
+ public void SetUnhashedSubpackets(
+ PgpSignatureSubpacketVector unhashedPackets)
+ {
+ unhashed = unhashedPackets == null
+ ? EmptySignatureSubpackets
+ : unhashedPackets.ToSubpacketArray();
+ }
+
+ /// Return the one pass header associated with the current signature.
+ public PgpOnePassSignature GenerateOnePassVersion(
+ bool isNested)
+ {
+ return new PgpOnePassSignature(
+ new OnePassSignaturePacket(
+ signatureType, hashAlgorithm, keyAlgorithm, privKey.KeyId, isNested));
+ }
+
+ /// Return a signature object containing the current signature state.
+ public PgpSignature Generate()
+ {
+ SignatureSubpacket[] hPkts = hashed, unhPkts = unhashed;
+
+ if (!packetPresent(hashed, SignatureSubpacketTag.CreationTime))
+ {
+ hPkts = insertSubpacket(hPkts, new SignatureCreationTime(false, DateTime.UtcNow));
+ }
+
+ if (!packetPresent(hashed, SignatureSubpacketTag.IssuerKeyId)
+ && !packetPresent(unhashed, SignatureSubpacketTag.IssuerKeyId))
+ {
+ unhPkts = insertSubpacket(unhPkts, new IssuerKeyId(false, privKey.KeyId));
+ }
+
+ int version = 4;
+ byte[] hData;
+
+ try
+ {
+ MemoryStream hOut = new MemoryStream();
+
+ for (int i = 0; i != hPkts.Length; i++)
+ {
+ hPkts[i].Encode(hOut);
+ }
+
+ byte[] data = hOut.ToArray();
+
+ MemoryStream sOut = new MemoryStream(data.Length + 6);
+ sOut.WriteByte((byte)version);
+ sOut.WriteByte((byte)signatureType);
+ sOut.WriteByte((byte)keyAlgorithm);
+ sOut.WriteByte((byte)hashAlgorithm);
+ sOut.WriteByte((byte)(data.Length >> 8));
+ sOut.WriteByte((byte)data.Length);
+ sOut.Write(data, 0, data.Length);
+
+ hData = sOut.ToArray();
+ }
+ catch (IOException e)
+ {
+ throw new PgpException("exception encoding hashed data.", e);
+ }
+
+ sig.BlockUpdate(hData, 0, hData.Length);
+ dig.BlockUpdate(hData, 0, hData.Length);
+
+ hData = new byte[]
+ {
+ (byte) version,
+ 0xff,
+ (byte)(hData.Length >> 24),
+ (byte)(hData.Length >> 16),
+ (byte)(hData.Length >> 8),
+ (byte) hData.Length
+ };
+
+ sig.BlockUpdate(hData, 0, hData.Length);
+ dig.BlockUpdate(hData, 0, hData.Length);
+
+ byte[] sigBytes = sig.GenerateSignature();
+ byte[] digest = DigestUtilities.DoFinal(dig);
+ byte[] fingerPrint = new byte[] { digest[0], digest[1] };
+
+ // an RSA signature
+ bool isRsa = keyAlgorithm == PublicKeyAlgorithmTag.RsaSign
+ || keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral;
+
+ MPInteger[] sigValues = isRsa
+ ? PgpUtilities.RsaSigToMpi(sigBytes)
+ : PgpUtilities.DsaSigToMpi(sigBytes);
+
+ return new PgpSignature(
+ new SignaturePacket(signatureType, privKey.KeyId, keyAlgorithm,
+ hashAlgorithm, hPkts, unhPkts, fingerPrint, sigValues));
+ }
+
+ /// Generate a certification for the passed in ID and key.
+ /// The ID we are certifying against the public key.
+ /// The key we are certifying against the ID.
+ /// The certification.
+ public PgpSignature GenerateCertification(
+ string id,
+ PgpPublicKey pubKey)
+ {
+ UpdateWithPublicKey(pubKey);
+
+ //
+ // hash in the id
+ //
+ UpdateWithIdData(0xb4, Strings.ToUtf8ByteArray(id));
+
+ return Generate();
+ }
+
+ /// Generate a certification for the passed in userAttributes.
+ /// The ID we are certifying against the public key.
+ /// The key we are certifying against the ID.
+ /// The certification.
+ public PgpSignature GenerateCertification(
+ PgpUserAttributeSubpacketVector userAttributes,
+ PgpPublicKey pubKey)
+ {
+ UpdateWithPublicKey(pubKey);
+
+ //
+ // hash in the attributes
+ //
+ try
+ {
+ MemoryStream bOut = new MemoryStream();
+ foreach (UserAttributeSubpacket packet in userAttributes.ToSubpacketArray())
+ {
+ packet.Encode(bOut);
+ }
+ UpdateWithIdData(0xd1, bOut.ToArray());
+ }
+ catch (IOException e)
+ {
+ throw new PgpException("cannot encode subpacket array", e);
+ }
+
+ return this.Generate();
+ }
+
+ /// Generate a certification for the passed in key against the passed in master key.
+ /// The key we are certifying against.
+ /// The key we are certifying.
+ /// The certification.
+ public PgpSignature GenerateCertification(
+ PgpPublicKey masterKey,
+ PgpPublicKey pubKey)
+ {
+ UpdateWithPublicKey(masterKey);
+ UpdateWithPublicKey(pubKey);
+
+ return Generate();
+ }
+
+ /// Generate a certification, such as a revocation, for the passed in key.
+ /// The key we are certifying.
+ /// The certification.
+ public PgpSignature GenerateCertification(
+ PgpPublicKey pubKey)
+ {
+ UpdateWithPublicKey(pubKey);
+
+ return Generate();
+ }
+
+ private byte[] GetEncodedPublicKey(
+ PgpPublicKey pubKey)
+ {
+ try
+ {
+ return pubKey.publicPk.GetEncodedContents();
+ }
+ catch (IOException e)
+ {
+ throw new PgpException("exception preparing key.", e);
+ }
+ }
+
+ private bool packetPresent(
+ SignatureSubpacket[] packets,
+ SignatureSubpacketTag type)
+ {
+ for (int i = 0; i != packets.Length; i++)
+ {
+ if (packets[i].SubpacketType == type)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private SignatureSubpacket[] insertSubpacket(
+ SignatureSubpacket[] packets,
+ SignatureSubpacket subpacket)
+ {
+ SignatureSubpacket[] tmp = new SignatureSubpacket[packets.Length + 1];
+ tmp[0] = subpacket;
+ packets.CopyTo(tmp, 1);
+ return tmp;
+ }
+
+ private void UpdateWithIdData(
+ int header,
+ byte[] idBytes)
+ {
+ this.Update(
+ (byte) header,
+ (byte)(idBytes.Length >> 24),
+ (byte)(idBytes.Length >> 16),
+ (byte)(idBytes.Length >> 8),
+ (byte)(idBytes.Length));
+ this.Update(idBytes);
+ }
+
+ private void UpdateWithPublicKey(
+ PgpPublicKey key)
+ {
+ byte[] keyBytes = GetEncodedPublicKey(key);
+
+ this.Update(
+ (byte) 0x99,
+ (byte)(keyBytes.Length >> 8),
+ (byte)(keyBytes.Length));
+ this.Update(keyBytes);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpSignatureList.cs b/bc-sharp-crypto/src/openpgp/PgpSignatureList.cs
new file mode 100644
index 0000000000000000000000000000000000000000..61976fc4f6f7bbe15b46c8d0658a26ee05b58b95
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpSignatureList.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// A list of PGP signatures - normally in the signature block after literal data.
+ public class PgpSignatureList
+ : PgpObject
+ {
+ private PgpSignature[] sigs;
+
+ public PgpSignatureList(
+ PgpSignature[] sigs)
+ {
+ this.sigs = (PgpSignature[]) sigs.Clone();
+ }
+
+ public PgpSignatureList(
+ PgpSignature sig)
+ {
+ this.sigs = new PgpSignature[]{ sig };
+ }
+
+ public PgpSignature this[int index]
+ {
+ get { return sigs[index]; }
+ }
+
+ [Obsolete("Use 'object[index]' syntax instead")]
+ public PgpSignature Get(
+ int index)
+ {
+ return this[index];
+ }
+
+ [Obsolete("Use 'Count' property instead")]
+ public int Size
+ {
+ get { return sigs.Length; }
+ }
+
+ public int Count
+ {
+ get { return sigs.Length; }
+ }
+
+ public bool IsEmpty
+ {
+ get { return (sigs.Length == 0); }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs b/bc-sharp-crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d2177d09c1f1f555ef49aadf98767f744dd7e39e
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs
@@ -0,0 +1,210 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Bcpg.Sig;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Generator for signature subpackets.
+ public class PgpSignatureSubpacketGenerator
+ {
+ private IList list = Platform.CreateArrayList();
+
+ public void SetRevocable(
+ bool isCritical,
+ bool isRevocable)
+ {
+ list.Add(new Revocable(isCritical, isRevocable));
+ }
+
+ public void SetExportable(
+ bool isCritical,
+ bool isExportable)
+ {
+ list.Add(new Exportable(isCritical, isExportable));
+ }
+
+ public void SetFeature(
+ bool isCritical,
+ byte feature)
+ {
+ list.Add(new Features(isCritical, feature));
+ }
+
+ ///
+ /// Add a TrustSignature packet to the signature. The values for depth and trust are largely
+ /// installation dependent but there are some guidelines in RFC 4880 - 5.2.3.13.
+ ///
+ /// true if the packet is critical.
+ /// depth level.
+ /// trust amount.
+ public void SetTrust(
+ bool isCritical,
+ int depth,
+ int trustAmount)
+ {
+ list.Add(new TrustSignature(isCritical, depth, trustAmount));
+ }
+
+ ///
+ /// Set the number of seconds a key is valid for after the time of its creation.
+ /// A value of zero means the key never expires.
+ ///
+ /// True, if should be treated as critical, false otherwise.
+ /// The number of seconds the key is valid, or zero if no expiry.
+ public void SetKeyExpirationTime(
+ bool isCritical,
+ long seconds)
+ {
+ list.Add(new KeyExpirationTime(isCritical, seconds));
+ }
+
+ ///
+ /// Set the number of seconds a signature is valid for after the time of its creation.
+ /// A value of zero means the signature never expires.
+ ///
+ /// True, if should be treated as critical, false otherwise.
+ /// The number of seconds the signature is valid, or zero if no expiry.
+ public void SetSignatureExpirationTime(
+ bool isCritical,
+ long seconds)
+ {
+ list.Add(new SignatureExpirationTime(isCritical, seconds));
+ }
+
+ ///
+ /// Set the creation time for the signature.
+ ///
+ /// Note: this overrides the generation of a creation time when the signature
+ /// is generated.
+ ///
+ public void SetSignatureCreationTime(
+ bool isCritical,
+ DateTime date)
+ {
+ list.Add(new SignatureCreationTime(isCritical, date));
+ }
+
+ public void SetPreferredHashAlgorithms(
+ bool isCritical,
+ int[] algorithms)
+ {
+ list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredHashAlgorithms, isCritical, algorithms));
+ }
+
+ public void SetPreferredSymmetricAlgorithms(
+ bool isCritical,
+ int[] algorithms)
+ {
+ list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredSymmetricAlgorithms, isCritical, algorithms));
+ }
+
+ public void SetPreferredCompressionAlgorithms(
+ bool isCritical,
+ int[] algorithms)
+ {
+ list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredCompressionAlgorithms, isCritical, algorithms));
+ }
+
+ public void SetKeyFlags(
+ bool isCritical,
+ int flags)
+ {
+ list.Add(new KeyFlags(isCritical, flags));
+ }
+
+ public void SetSignerUserId(
+ bool isCritical,
+ string userId)
+ {
+ if (userId == null)
+ throw new ArgumentNullException("userId");
+
+ list.Add(new SignerUserId(isCritical, userId));
+ }
+
+ public void SetSignerUserId(
+ bool isCritical,
+ byte[] rawUserId)
+ {
+ if (rawUserId == null)
+ throw new ArgumentNullException("rawUserId");
+
+ list.Add(new SignerUserId(isCritical, false, rawUserId));
+ }
+
+ public void SetEmbeddedSignature(
+ bool isCritical,
+ PgpSignature pgpSignature)
+ {
+ byte[] sig = pgpSignature.GetEncoded();
+ byte[] data;
+
+ // TODO Should be >= ?
+ if (sig.Length - 1 > 256)
+ {
+ data = new byte[sig.Length - 3];
+ }
+ else
+ {
+ data = new byte[sig.Length - 2];
+ }
+
+ Array.Copy(sig, sig.Length - data.Length, data, 0, data.Length);
+
+ list.Add(new EmbeddedSignature(isCritical, false, data));
+ }
+
+ public void SetPrimaryUserId(
+ bool isCritical,
+ bool isPrimaryUserId)
+ {
+ list.Add(new PrimaryUserId(isCritical, isPrimaryUserId));
+ }
+
+ public void SetNotationData(
+ bool isCritical,
+ bool isHumanReadable,
+ string notationName,
+ string notationValue)
+ {
+ list.Add(new NotationData(isCritical, isHumanReadable, notationName, notationValue));
+ }
+
+ ///
+ /// Sets revocation reason sub packet
+ ///
+ public void SetRevocationReason(bool isCritical, RevocationReasonTag reason,
+ string description)
+ {
+ list.Add(new RevocationReason(isCritical, reason, description));
+ }
+
+ ///
+ /// Sets revocation key sub packet
+ ///
+ public void SetRevocationKey(bool isCritical, PublicKeyAlgorithmTag keyAlgorithm, byte[] fingerprint)
+ {
+ list.Add(new RevocationKey(isCritical, RevocationKeyTag.ClassDefault, keyAlgorithm, fingerprint));
+ }
+
+ ///
+ /// Sets issuer key sub packet
+ ///
+ public void SetIssuerKeyID(bool isCritical, long keyID)
+ {
+ list.Add(new IssuerKeyId(isCritical, keyID));
+ }
+
+ public PgpSignatureSubpacketVector Generate()
+ {
+ SignatureSubpacket[] a = new SignatureSubpacket[list.Count];
+ for (int i = 0; i < list.Count; ++i)
+ {
+ a[i] = (SignatureSubpacket)list[i];
+ }
+ return new PgpSignatureSubpacketVector(a);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpSignatureSubpacketVector.cs b/bc-sharp-crypto/src/openpgp/PgpSignatureSubpacketVector.cs
new file mode 100644
index 0000000000000000000000000000000000000000..156243f4eba9f1691aa08dc8fd8cbddba03184e8
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpSignatureSubpacketVector.cs
@@ -0,0 +1,239 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Bcpg.Sig;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Container for a list of signature subpackets.
+ public class PgpSignatureSubpacketVector
+ {
+ private readonly SignatureSubpacket[] packets;
+
+ internal PgpSignatureSubpacketVector(
+ SignatureSubpacket[] packets)
+ {
+ this.packets = packets;
+ }
+
+ public SignatureSubpacket GetSubpacket(
+ SignatureSubpacketTag type)
+ {
+ for (int i = 0; i != packets.Length; i++)
+ {
+ if (packets[i].SubpacketType == type)
+ {
+ return packets[i];
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Return true if a particular subpacket type exists.
+ *
+ * @param type type to look for.
+ * @return true if present, false otherwise.
+ */
+ public bool HasSubpacket(
+ SignatureSubpacketTag type)
+ {
+ return GetSubpacket(type) != null;
+ }
+
+ /**
+ * Return all signature subpackets of the passed in type.
+ * @param type subpacket type code
+ * @return an array of zero or more matching subpackets.
+ */
+ public SignatureSubpacket[] GetSubpackets(
+ SignatureSubpacketTag type)
+ {
+ int count = 0;
+ for (int i = 0; i < packets.Length; ++i)
+ {
+ if (packets[i].SubpacketType == type)
+ {
+ ++count;
+ }
+ }
+
+ SignatureSubpacket[] result = new SignatureSubpacket[count];
+
+ int pos = 0;
+ for (int i = 0; i < packets.Length; ++i)
+ {
+ if (packets[i].SubpacketType == type)
+ {
+ result[pos++] = packets[i];
+ }
+ }
+
+ return result;
+ }
+
+ public NotationData[] GetNotationDataOccurences()
+ {
+ SignatureSubpacket[] notations = GetSubpackets(SignatureSubpacketTag.NotationData);
+ NotationData[] vals = new NotationData[notations.Length];
+
+ for (int i = 0; i < notations.Length; i++)
+ {
+ vals[i] = (NotationData) notations[i];
+ }
+
+ return vals;
+ }
+
+ public long GetIssuerKeyId()
+ {
+ SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.IssuerKeyId);
+
+ return p == null ? 0 : ((IssuerKeyId) p).KeyId;
+ }
+
+ public bool HasSignatureCreationTime()
+ {
+ return GetSubpacket(SignatureSubpacketTag.CreationTime) != null;
+ }
+
+ public DateTime GetSignatureCreationTime()
+ {
+ SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.CreationTime);
+
+ if (p == null)
+ {
+ throw new PgpException("SignatureCreationTime not available");
+ }
+
+ return ((SignatureCreationTime)p).GetTime();
+ }
+
+ ///
+ /// Return the number of seconds a signature is valid for after its creation date.
+ /// A value of zero means the signature never expires.
+ ///
+ /// Seconds a signature is valid for.
+ public long GetSignatureExpirationTime()
+ {
+ SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.ExpireTime);
+
+ return p == null ? 0 : ((SignatureExpirationTime) p).Time;
+ }
+
+ ///
+ /// Return the number of seconds a key is valid for after its creation date.
+ /// A value of zero means the key never expires.
+ ///
+ /// Seconds a signature is valid for.
+ public long GetKeyExpirationTime()
+ {
+ SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.KeyExpireTime);
+
+ return p == null ? 0 : ((KeyExpirationTime) p).Time;
+ }
+
+ public int[] GetPreferredHashAlgorithms()
+ {
+ SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.PreferredHashAlgorithms);
+
+ return p == null ? null : ((PreferredAlgorithms) p).GetPreferences();
+ }
+
+ public int[] GetPreferredSymmetricAlgorithms()
+ {
+ SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.PreferredSymmetricAlgorithms);
+
+ return p == null ? null : ((PreferredAlgorithms) p).GetPreferences();
+ }
+
+ public int[] GetPreferredCompressionAlgorithms()
+ {
+ SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.PreferredCompressionAlgorithms);
+
+ return p == null ? null : ((PreferredAlgorithms) p).GetPreferences();
+ }
+
+ public int GetKeyFlags()
+ {
+ SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.KeyFlags);
+
+ return p == null ? 0 : ((KeyFlags) p).Flags;
+ }
+
+ public string GetSignerUserId()
+ {
+ SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.SignerUserId);
+
+ return p == null ? null : ((SignerUserId) p).GetId();
+ }
+
+ public bool IsPrimaryUserId()
+ {
+ PrimaryUserId primaryId = (PrimaryUserId)
+ this.GetSubpacket(SignatureSubpacketTag.PrimaryUserId);
+
+ if (primaryId != null)
+ {
+ return primaryId.IsPrimaryUserId();
+ }
+
+ return false;
+ }
+
+ public SignatureSubpacketTag[] GetCriticalTags()
+ {
+ int count = 0;
+ for (int i = 0; i != packets.Length; i++)
+ {
+ if (packets[i].IsCritical())
+ {
+ count++;
+ }
+ }
+
+ SignatureSubpacketTag[] list = new SignatureSubpacketTag[count];
+
+ count = 0;
+
+ for (int i = 0; i != packets.Length; i++)
+ {
+ if (packets[i].IsCritical())
+ {
+ list[count++] = packets[i].SubpacketType;
+ }
+ }
+
+ return list;
+ }
+
+ public Features GetFeatures()
+ {
+ SignatureSubpacket p = this.GetSubpacket(SignatureSubpacketTag.Features);
+
+ if (p == null)
+ return null;
+
+ return new Features(p.IsCritical(), p.IsLongLength(), p.GetData());
+ }
+
+ [Obsolete("Use 'Count' property instead")]
+ public int Size
+ {
+ get { return packets.Length; }
+ }
+
+ /// Return the number of packets this vector contains.
+ public int Count
+ {
+ get { return packets.Length; }
+ }
+
+ internal SignatureSubpacket[] ToSubpacketArray()
+ {
+ return packets;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpUserAttributeSubpacketVector.cs b/bc-sharp-crypto/src/openpgp/PgpUserAttributeSubpacketVector.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4cdbeda5401e2bcf1e26b4fb030b50e79c8fab98
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpUserAttributeSubpacketVector.cs
@@ -0,0 +1,81 @@
+using Org.BouncyCastle.Bcpg.Attr;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Container for a list of user attribute subpackets.
+ public class PgpUserAttributeSubpacketVector
+ {
+ private readonly UserAttributeSubpacket[] packets;
+
+ internal PgpUserAttributeSubpacketVector(
+ UserAttributeSubpacket[] packets)
+ {
+ this.packets = packets;
+ }
+
+ public UserAttributeSubpacket GetSubpacket(
+ UserAttributeSubpacketTag type)
+ {
+ for (int i = 0; i != packets.Length; i++)
+ {
+ if (packets[i].SubpacketType == type)
+ {
+ return packets[i];
+ }
+ }
+
+ return null;
+ }
+
+ public ImageAttrib GetImageAttribute()
+ {
+ UserAttributeSubpacket p = GetSubpacket(UserAttributeSubpacketTag.ImageAttribute);
+
+ return p == null ? null : (ImageAttrib) p;
+ }
+
+ internal UserAttributeSubpacket[] ToSubpacketArray()
+ {
+ return packets;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ PgpUserAttributeSubpacketVector other = obj as PgpUserAttributeSubpacketVector;
+
+ if (other == null)
+ return false;
+
+ if (other.packets.Length != packets.Length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != packets.Length; i++)
+ {
+ if (!other.packets[i].Equals(packets[i]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public override int GetHashCode()
+ {
+ int code = 0;
+
+ foreach (object o in packets)
+ {
+ code ^= o.GetHashCode();
+ }
+
+ return code;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpUtilities.cs b/bc-sharp-crypto/src/openpgp/PgpUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7d96dee8d06bddba516fbf7f725e8bd666025ea9
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpUtilities.cs
@@ -0,0 +1,518 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Basic utility class.
+ public sealed class PgpUtilities
+ {
+ private PgpUtilities()
+ {
+ }
+
+ public static MPInteger[] DsaSigToMpi(
+ byte[] encoding)
+ {
+ DerInteger i1, i2;
+
+ try
+ {
+ Asn1Sequence s = (Asn1Sequence) Asn1Object.FromByteArray(encoding);
+
+ i1 = (DerInteger) s[0];
+ i2 = (DerInteger) s[1];
+ }
+ catch (IOException e)
+ {
+ throw new PgpException("exception encoding signature", e);
+ }
+
+ return new MPInteger[]{ new MPInteger(i1.Value), new MPInteger(i2.Value) };
+ }
+
+ public static MPInteger[] RsaSigToMpi(
+ byte[] encoding)
+ {
+ return new MPInteger[]{ new MPInteger(new BigInteger(1, encoding)) };
+ }
+
+ public static string GetDigestName(
+ HashAlgorithmTag hashAlgorithm)
+ {
+ switch (hashAlgorithm)
+ {
+ case HashAlgorithmTag.Sha1:
+ return "SHA1";
+ case HashAlgorithmTag.MD2:
+ return "MD2";
+ case HashAlgorithmTag.MD5:
+ return "MD5";
+ case HashAlgorithmTag.RipeMD160:
+ return "RIPEMD160";
+ case HashAlgorithmTag.Sha224:
+ return "SHA224";
+ case HashAlgorithmTag.Sha256:
+ return "SHA256";
+ case HashAlgorithmTag.Sha384:
+ return "SHA384";
+ case HashAlgorithmTag.Sha512:
+ return "SHA512";
+ default:
+ throw new PgpException("unknown hash algorithm tag in GetDigestName: " + hashAlgorithm);
+ }
+ }
+
+ public static string GetSignatureName(
+ PublicKeyAlgorithmTag keyAlgorithm,
+ HashAlgorithmTag hashAlgorithm)
+ {
+ string encAlg;
+ switch (keyAlgorithm)
+ {
+ case PublicKeyAlgorithmTag.RsaGeneral:
+ case PublicKeyAlgorithmTag.RsaSign:
+ encAlg = "RSA";
+ break;
+ case PublicKeyAlgorithmTag.Dsa:
+ encAlg = "DSA";
+ break;
+ case PublicKeyAlgorithmTag.ECDH:
+ encAlg = "ECDH";
+ break;
+ case PublicKeyAlgorithmTag.ECDsa:
+ encAlg = "ECDSA";
+ break;
+ case PublicKeyAlgorithmTag.ElGamalEncrypt: // in some malformed cases.
+ case PublicKeyAlgorithmTag.ElGamalGeneral:
+ encAlg = "ElGamal";
+ break;
+ default:
+ throw new PgpException("unknown algorithm tag in signature:" + keyAlgorithm);
+ }
+
+ return GetDigestName(hashAlgorithm) + "with" + encAlg;
+ }
+
+ public static string GetSymmetricCipherName(
+ SymmetricKeyAlgorithmTag algorithm)
+ {
+ switch (algorithm)
+ {
+ case SymmetricKeyAlgorithmTag.Null:
+ return null;
+ case SymmetricKeyAlgorithmTag.TripleDes:
+ return "DESEDE";
+ case SymmetricKeyAlgorithmTag.Idea:
+ return "IDEA";
+ case SymmetricKeyAlgorithmTag.Cast5:
+ return "CAST5";
+ case SymmetricKeyAlgorithmTag.Blowfish:
+ return "Blowfish";
+ case SymmetricKeyAlgorithmTag.Safer:
+ return "SAFER";
+ case SymmetricKeyAlgorithmTag.Des:
+ return "DES";
+ case SymmetricKeyAlgorithmTag.Aes128:
+ return "AES";
+ case SymmetricKeyAlgorithmTag.Aes192:
+ return "AES";
+ case SymmetricKeyAlgorithmTag.Aes256:
+ return "AES";
+ case SymmetricKeyAlgorithmTag.Twofish:
+ return "Twofish";
+ case SymmetricKeyAlgorithmTag.Camellia128:
+ return "Camellia";
+ case SymmetricKeyAlgorithmTag.Camellia192:
+ return "Camellia";
+ case SymmetricKeyAlgorithmTag.Camellia256:
+ return "Camellia";
+ default:
+ throw new PgpException("unknown symmetric algorithm: " + algorithm);
+ }
+ }
+
+ public static int GetKeySize(SymmetricKeyAlgorithmTag algorithm)
+ {
+ int keySize;
+ switch (algorithm)
+ {
+ case SymmetricKeyAlgorithmTag.Des:
+ keySize = 64;
+ break;
+ case SymmetricKeyAlgorithmTag.Idea:
+ case SymmetricKeyAlgorithmTag.Cast5:
+ case SymmetricKeyAlgorithmTag.Blowfish:
+ case SymmetricKeyAlgorithmTag.Safer:
+ case SymmetricKeyAlgorithmTag.Aes128:
+ case SymmetricKeyAlgorithmTag.Camellia128:
+ keySize = 128;
+ break;
+ case SymmetricKeyAlgorithmTag.TripleDes:
+ case SymmetricKeyAlgorithmTag.Aes192:
+ case SymmetricKeyAlgorithmTag.Camellia192:
+ keySize = 192;
+ break;
+ case SymmetricKeyAlgorithmTag.Aes256:
+ case SymmetricKeyAlgorithmTag.Twofish:
+ case SymmetricKeyAlgorithmTag.Camellia256:
+ keySize = 256;
+ break;
+ default:
+ throw new PgpException("unknown symmetric algorithm: " + algorithm);
+ }
+
+ return keySize;
+ }
+
+ public static KeyParameter MakeKey(
+ SymmetricKeyAlgorithmTag algorithm,
+ byte[] keyBytes)
+ {
+ string algName = GetSymmetricCipherName(algorithm);
+
+ return ParameterUtilities.CreateKeyParameter(algName, keyBytes);
+ }
+
+ public static KeyParameter MakeRandomKey(
+ SymmetricKeyAlgorithmTag algorithm,
+ SecureRandom random)
+ {
+ int keySize = GetKeySize(algorithm);
+ byte[] keyBytes = new byte[(keySize + 7) / 8];
+ random.NextBytes(keyBytes);
+ return MakeKey(algorithm, keyBytes);
+ }
+
+ internal static byte[] EncodePassPhrase(char[] passPhrase, bool utf8)
+ {
+ return passPhrase == null
+ ? null
+ : utf8
+ ? Encoding.UTF8.GetBytes(passPhrase)
+ : Strings.ToByteArray(passPhrase);
+ }
+
+ ///
+ /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+ /// the historical behaviour of the library (1.7 and earlier).
+ ///
+ public static KeyParameter MakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag algorithm, S2k s2k, char[] passPhrase)
+ {
+ return DoMakeKeyFromPassPhrase(algorithm, s2k, EncodePassPhrase(passPhrase, false), true);
+ }
+
+ ///
+ /// The passphrase is encoded to bytes using UTF8 (Encoding.UTF8.GetBytes).
+ ///
+ public static KeyParameter MakeKeyFromPassPhraseUtf8(SymmetricKeyAlgorithmTag algorithm, S2k s2k, char[] passPhrase)
+ {
+ return DoMakeKeyFromPassPhrase(algorithm, s2k, EncodePassPhrase(passPhrase, true), true);
+ }
+
+ ///
+ /// Allows the caller to handle the encoding of the passphrase to bytes.
+ ///
+ public static KeyParameter MakeKeyFromPassPhraseRaw(SymmetricKeyAlgorithmTag algorithm, S2k s2k, byte[] rawPassPhrase)
+ {
+ return DoMakeKeyFromPassPhrase(algorithm, s2k, rawPassPhrase, false);
+ }
+
+ internal static KeyParameter DoMakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag algorithm, S2k s2k, byte[] rawPassPhrase, bool clearPassPhrase)
+ {
+ int keySize = GetKeySize(algorithm);
+ byte[] pBytes = rawPassPhrase;
+ byte[] keyBytes = new byte[(keySize + 7) / 8];
+
+ int generatedBytes = 0;
+ int loopCount = 0;
+
+ while (generatedBytes < keyBytes.Length)
+ {
+ IDigest digest;
+ if (s2k != null)
+ {
+ string digestName = GetDigestName(s2k.HashAlgorithm);
+
+ try
+ {
+ digest = DigestUtilities.GetDigest(digestName);
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("can't find S2k digest", e);
+ }
+
+ for (int i = 0; i != loopCount; i++)
+ {
+ digest.Update(0);
+ }
+
+ byte[] iv = s2k.GetIV();
+
+ switch (s2k.Type)
+ {
+ case S2k.Simple:
+ digest.BlockUpdate(pBytes, 0, pBytes.Length);
+ break;
+ case S2k.Salted:
+ digest.BlockUpdate(iv, 0, iv.Length);
+ digest.BlockUpdate(pBytes, 0, pBytes.Length);
+ break;
+ case S2k.SaltedAndIterated:
+ long count = s2k.IterationCount;
+ digest.BlockUpdate(iv, 0, iv.Length);
+ digest.BlockUpdate(pBytes, 0, pBytes.Length);
+
+ count -= iv.Length + pBytes.Length;
+
+ while (count > 0)
+ {
+ if (count < iv.Length)
+ {
+ digest.BlockUpdate(iv, 0, (int)count);
+ break;
+ }
+ else
+ {
+ digest.BlockUpdate(iv, 0, iv.Length);
+ count -= iv.Length;
+ }
+
+ if (count < pBytes.Length)
+ {
+ digest.BlockUpdate(pBytes, 0, (int)count);
+ count = 0;
+ }
+ else
+ {
+ digest.BlockUpdate(pBytes, 0, pBytes.Length);
+ count -= pBytes.Length;
+ }
+ }
+ break;
+ default:
+ throw new PgpException("unknown S2k type: " + s2k.Type);
+ }
+ }
+ else
+ {
+ try
+ {
+ digest = DigestUtilities.GetDigest("MD5");
+
+ for (int i = 0; i != loopCount; i++)
+ {
+ digest.Update(0);
+ }
+
+ digest.BlockUpdate(pBytes, 0, pBytes.Length);
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("can't find MD5 digest", e);
+ }
+ }
+
+ byte[] dig = DigestUtilities.DoFinal(digest);
+
+ if (dig.Length > (keyBytes.Length - generatedBytes))
+ {
+ Array.Copy(dig, 0, keyBytes, generatedBytes, keyBytes.Length - generatedBytes);
+ }
+ else
+ {
+ Array.Copy(dig, 0, keyBytes, generatedBytes, dig.Length);
+ }
+
+ generatedBytes += dig.Length;
+
+ loopCount++;
+ }
+
+ if (clearPassPhrase && rawPassPhrase != null)
+ {
+ Array.Clear(rawPassPhrase, 0, rawPassPhrase.Length);
+ }
+
+ return MakeKey(algorithm, keyBytes);
+ }
+
+#if !PORTABLE || DOTNET
+ /// Write out the passed in file as a literal data packet.
+ public static void WriteFileToLiteralData(
+ Stream output,
+ char fileType,
+ FileInfo file)
+ {
+ PgpLiteralDataGenerator lData = new PgpLiteralDataGenerator();
+ Stream pOut = lData.Open(output, fileType, file.Name, file.Length, file.LastWriteTime);
+ PipeFileContents(file, pOut, 4096);
+ }
+
+ /// Write out the passed in file as a literal data packet in partial packet format.
+ public static void WriteFileToLiteralData(
+ Stream output,
+ char fileType,
+ FileInfo file,
+ byte[] buffer)
+ {
+ PgpLiteralDataGenerator lData = new PgpLiteralDataGenerator();
+ Stream pOut = lData.Open(output, fileType, file.Name, file.LastWriteTime, buffer);
+ PipeFileContents(file, pOut, buffer.Length);
+ }
+
+ private static void PipeFileContents(FileInfo file, Stream pOut, int bufSize)
+ {
+ FileStream inputStream = file.OpenRead();
+ byte[] buf = new byte[bufSize];
+
+ int len;
+ while ((len = inputStream.Read(buf, 0, buf.Length)) > 0)
+ {
+ pOut.Write(buf, 0, len);
+ }
+
+ Platform.Dispose(pOut);
+ Platform.Dispose(inputStream);
+ }
+#endif
+
+ private const int ReadAhead = 60;
+
+ private static bool IsPossiblyBase64(
+ int ch)
+ {
+ return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')
+ || (ch >= '0' && ch <= '9') || (ch == '+') || (ch == '/')
+ || (ch == '\r') || (ch == '\n');
+ }
+
+ ///
+ /// Return either an ArmoredInputStream or a BcpgInputStream based on whether
+ /// the initial characters of the stream are binary PGP encodings or not.
+ ///
+ public static Stream GetDecoderStream(
+ Stream inputStream)
+ {
+ // TODO Remove this restriction?
+ if (!inputStream.CanSeek)
+ throw new ArgumentException("inputStream must be seek-able", "inputStream");
+
+ long markedPos = inputStream.Position;
+
+ int ch = inputStream.ReadByte();
+ if ((ch & 0x80) != 0)
+ {
+ inputStream.Position = markedPos;
+
+ return inputStream;
+ }
+
+ if (!IsPossiblyBase64(ch))
+ {
+ inputStream.Position = markedPos;
+
+ return new ArmoredInputStream(inputStream);
+ }
+
+ byte[] buf = new byte[ReadAhead];
+ int count = 1;
+ int index = 1;
+
+ buf[0] = (byte)ch;
+ while (count != ReadAhead && (ch = inputStream.ReadByte()) >= 0)
+ {
+ if (!IsPossiblyBase64(ch))
+ {
+ inputStream.Position = markedPos;
+
+ return new ArmoredInputStream(inputStream);
+ }
+
+ if (ch != '\n' && ch != '\r')
+ {
+ buf[index++] = (byte)ch;
+ }
+
+ count++;
+ }
+
+ inputStream.Position = markedPos;
+
+ //
+ // nothing but new lines, little else, assume regular armoring
+ //
+ if (count < 4)
+ {
+ return new ArmoredInputStream(inputStream);
+ }
+
+ //
+ // test our non-blank data
+ //
+ byte[] firstBlock = new byte[8];
+
+ Array.Copy(buf, 0, firstBlock, 0, firstBlock.Length);
+
+ try
+ {
+ byte[] decoded = Base64.Decode(firstBlock);
+
+ //
+ // it's a base64 PGP block.
+ //
+ bool hasHeaders = (decoded[0] & 0x80) == 0;
+
+ return new ArmoredInputStream(inputStream, hasHeaders);
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new IOException(e.Message);
+ }
+ }
+
+ internal static IWrapper CreateWrapper(SymmetricKeyAlgorithmTag encAlgorithm)
+ {
+ switch (encAlgorithm)
+ {
+ case SymmetricKeyAlgorithmTag.Aes128:
+ case SymmetricKeyAlgorithmTag.Aes192:
+ case SymmetricKeyAlgorithmTag.Aes256:
+ return WrapperUtilities.GetWrapper("AESWRAP");
+ case SymmetricKeyAlgorithmTag.Camellia128:
+ case SymmetricKeyAlgorithmTag.Camellia192:
+ case SymmetricKeyAlgorithmTag.Camellia256:
+ return WrapperUtilities.GetWrapper("CAMELLIAWRAP");
+ default:
+ throw new PgpException("unknown wrap algorithm: " + encAlgorithm);
+ }
+ }
+
+ internal static byte[] GenerateIV(int length, SecureRandom random)
+ {
+ byte[] iv = new byte[length];
+ random.NextBytes(iv);
+ return iv;
+ }
+
+ internal static S2k GenerateS2k(HashAlgorithmTag hashAlgorithm, int s2kCount, SecureRandom random)
+ {
+ byte[] iv = GenerateIV(8, random);
+ return new S2k(hashAlgorithm, iv, s2kCount);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/PgpV3SignatureGenerator.cs b/bc-sharp-crypto/src/openpgp/PgpV3SignatureGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fc8b42df2ca844d10bf52a38a202cead5d5d66dc
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/PgpV3SignatureGenerator.cs
@@ -0,0 +1,199 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /// Generator for old style PGP V3 Signatures.
+ // TODO Should be able to implement ISigner?
+ public class PgpV3SignatureGenerator
+ {
+ private PublicKeyAlgorithmTag keyAlgorithm;
+ private HashAlgorithmTag hashAlgorithm;
+ private PgpPrivateKey privKey;
+ private ISigner sig;
+ private IDigest dig;
+ private int signatureType;
+ private byte lastb;
+
+ /// Create a generator for the passed in keyAlgorithm and hashAlgorithm codes.
+ public PgpV3SignatureGenerator(
+ PublicKeyAlgorithmTag keyAlgorithm,
+ HashAlgorithmTag hashAlgorithm)
+ {
+ this.keyAlgorithm = keyAlgorithm;
+ this.hashAlgorithm = hashAlgorithm;
+
+ dig = DigestUtilities.GetDigest(PgpUtilities.GetDigestName(hashAlgorithm));
+ sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(keyAlgorithm, hashAlgorithm));
+ }
+
+ /// Initialise the generator for signing.
+ public void InitSign(
+ int sigType,
+ PgpPrivateKey key)
+ {
+ InitSign(sigType, key, null);
+ }
+
+ /// Initialise the generator for signing.
+ public void InitSign(
+ int sigType,
+ PgpPrivateKey key,
+ SecureRandom random)
+ {
+ this.privKey = key;
+ this.signatureType = sigType;
+
+ try
+ {
+ ICipherParameters cp = key.Key;
+ if (random != null)
+ {
+ cp = new ParametersWithRandom(key.Key, random);
+ }
+
+ sig.Init(true, cp);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new PgpException("invalid key.", e);
+ }
+
+ dig.Reset();
+ lastb = 0;
+ }
+
+ public void Update(
+ byte b)
+ {
+ if (signatureType == PgpSignature.CanonicalTextDocument)
+ {
+ doCanonicalUpdateByte(b);
+ }
+ else
+ {
+ doUpdateByte(b);
+ }
+ }
+
+ private void doCanonicalUpdateByte(
+ byte b)
+ {
+ if (b == '\r')
+ {
+ doUpdateCRLF();
+ }
+ else if (b == '\n')
+ {
+ if (lastb != '\r')
+ {
+ doUpdateCRLF();
+ }
+ }
+ else
+ {
+ doUpdateByte(b);
+ }
+
+ lastb = b;
+ }
+
+ private void doUpdateCRLF()
+ {
+ doUpdateByte((byte)'\r');
+ doUpdateByte((byte)'\n');
+ }
+
+ private void doUpdateByte(
+ byte b)
+ {
+ sig.Update(b);
+ dig.Update(b);
+ }
+
+ public void Update(
+ byte[] b)
+ {
+ if (signatureType == PgpSignature.CanonicalTextDocument)
+ {
+ for (int i = 0; i != b.Length; i++)
+ {
+ doCanonicalUpdateByte(b[i]);
+ }
+ }
+ else
+ {
+ sig.BlockUpdate(b, 0, b.Length);
+ dig.BlockUpdate(b, 0, b.Length);
+ }
+ }
+
+ public void Update(
+ byte[] b,
+ int off,
+ int len)
+ {
+ if (signatureType == PgpSignature.CanonicalTextDocument)
+ {
+ int finish = off + len;
+
+ for (int i = off; i != finish; i++)
+ {
+ doCanonicalUpdateByte(b[i]);
+ }
+ }
+ else
+ {
+ sig.BlockUpdate(b, off, len);
+ dig.BlockUpdate(b, off, len);
+ }
+ }
+
+ /// Return the one pass header associated with the current signature.
+ public PgpOnePassSignature GenerateOnePassVersion(
+ bool isNested)
+ {
+ return new PgpOnePassSignature(
+ new OnePassSignaturePacket(signatureType, hashAlgorithm, keyAlgorithm, privKey.KeyId, isNested));
+ }
+
+ /// Return a V3 signature object containing the current signature state.
+ public PgpSignature Generate()
+ {
+ long creationTime = DateTimeUtilities.CurrentUnixMs() / 1000L;
+
+ byte[] hData = new byte[]
+ {
+ (byte) signatureType,
+ (byte)(creationTime >> 24),
+ (byte)(creationTime >> 16),
+ (byte)(creationTime >> 8),
+ (byte) creationTime
+ };
+
+ sig.BlockUpdate(hData, 0, hData.Length);
+ dig.BlockUpdate(hData, 0, hData.Length);
+
+ byte[] sigBytes = sig.GenerateSignature();
+ byte[] digest = DigestUtilities.DoFinal(dig);
+ byte[] fingerPrint = new byte[]{ digest[0], digest[1] };
+
+ // an RSA signature
+ bool isRsa = keyAlgorithm == PublicKeyAlgorithmTag.RsaSign
+ || keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral;
+
+ MPInteger[] sigValues = isRsa
+ ? PgpUtilities.RsaSigToMpi(sigBytes)
+ : PgpUtilities.DsaSigToMpi(sigBytes);
+
+ return new PgpSignature(
+ new SignaturePacket(3, signatureType, privKey.KeyId, keyAlgorithm,
+ hashAlgorithm, creationTime * 1000L, fingerPrint, sigValues));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/Rfc6637Utilities.cs b/bc-sharp-crypto/src/openpgp/Rfc6637Utilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5d992ec515992683e7307c69ba4d9d9f54c50e27
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/Rfc6637Utilities.cs
@@ -0,0 +1,138 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ public sealed class Rfc6637Utilities
+ {
+ private Rfc6637Utilities()
+ {
+ }
+
+ // "Anonymous Sender ", which is the octet sequence
+ private static readonly byte[] ANONYMOUS_SENDER = Hex.Decode("416E6F6E796D6F75732053656E64657220202020");
+
+ public static string GetAgreementAlgorithm(PublicKeyPacket pubKeyData)
+ {
+ ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)pubKeyData.Key;
+
+ switch (ecKey.HashAlgorithm)
+ {
+ case HashAlgorithmTag.Sha256:
+ return "ECCDHwithSHA256CKDF";
+ case HashAlgorithmTag.Sha384:
+ return "ECCDHwithSHA384CKDF";
+ case HashAlgorithmTag.Sha512:
+ return "ECCDHwithSHA512CKDF";
+ default:
+ throw new ArgumentException("Unknown hash algorithm specified: " + ecKey.HashAlgorithm);
+ }
+ }
+
+ public static DerObjectIdentifier GetKeyEncryptionOID(SymmetricKeyAlgorithmTag algID)
+ {
+ switch (algID)
+ {
+ case SymmetricKeyAlgorithmTag.Aes128:
+ return NistObjectIdentifiers.IdAes128Wrap;
+ case SymmetricKeyAlgorithmTag.Aes192:
+ return NistObjectIdentifiers.IdAes192Wrap;
+ case SymmetricKeyAlgorithmTag.Aes256:
+ return NistObjectIdentifiers.IdAes256Wrap;
+ default:
+ throw new PgpException("unknown symmetric algorithm ID: " + algID);
+ }
+ }
+
+ public static int GetKeyLength(SymmetricKeyAlgorithmTag algID)
+ {
+ switch (algID)
+ {
+ case SymmetricKeyAlgorithmTag.Aes128:
+ return 16;
+ case SymmetricKeyAlgorithmTag.Aes192:
+ return 24;
+ case SymmetricKeyAlgorithmTag.Aes256:
+ return 32;
+ default:
+ throw new PgpException("unknown symmetric algorithm ID: " + algID);
+ }
+ }
+
+ public static byte[] CreateKey(PublicKeyPacket pubKeyData, ECPoint s)
+ {
+ byte[] userKeyingMaterial = CreateUserKeyingMaterial(pubKeyData);
+
+ ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)pubKeyData.Key;
+
+ return Kdf(ecKey.HashAlgorithm, s, GetKeyLength(ecKey.SymmetricKeyAlgorithm), userKeyingMaterial);
+ }
+
+ // RFC 6637 - Section 8
+ // curve_OID_len = (byte)len(curve_OID);
+ // Param = curve_OID_len || curve_OID || public_key_alg_ID || 03
+ // || 01 || KDF_hash_ID || KEK_alg_ID for AESKeyWrap || "Anonymous
+ // Sender " || recipient_fingerprint;
+ // Z_len = the key size for the KEK_alg_ID used with AESKeyWrap
+ // Compute Z = KDF( S, Z_len, Param );
+ public static byte[] CreateUserKeyingMaterial(PublicKeyPacket pubKeyData)
+ {
+ MemoryStream pOut = new MemoryStream();
+ ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)pubKeyData.Key;
+ byte[] encOid = ecKey.CurveOid.GetEncoded();
+
+ pOut.Write(encOid, 1, encOid.Length - 1);
+ pOut.WriteByte((byte)pubKeyData.Algorithm);
+ pOut.WriteByte(0x03);
+ pOut.WriteByte(0x01);
+ pOut.WriteByte((byte)ecKey.HashAlgorithm);
+ pOut.WriteByte((byte)ecKey.SymmetricKeyAlgorithm);
+ pOut.Write(ANONYMOUS_SENDER, 0, ANONYMOUS_SENDER.Length);
+
+ byte[] fingerprint = PgpPublicKey.CalculateFingerprint(pubKeyData);
+ pOut.Write(fingerprint, 0, fingerprint.Length);
+
+ return pOut.ToArray();
+ }
+
+ // RFC 6637 - Section 7
+ // Implements KDF( X, oBits, Param );
+ // Input: point X = (x,y)
+ // oBits - the desired size of output
+ // hBits - the size of output of hash function Hash
+ // Param - octets representing the parameters
+ // Assumes that oBits <= hBits
+ // Convert the point X to the octet string, see section 6:
+ // ZB' = 04 || x || y
+ // and extract the x portion from ZB'
+ // ZB = x;
+ // MB = Hash ( 00 || 00 || 00 || 01 || ZB || Param );
+ // return oBits leftmost bits of MB.
+ private static byte[] Kdf(HashAlgorithmTag digestAlg, ECPoint s, int keyLen, byte[] parameters)
+ {
+ byte[] ZB = s.XCoord.GetEncoded();
+
+ string digestName = PgpUtilities.GetDigestName(digestAlg);
+ IDigest digest = DigestUtilities.GetDigest(digestName);
+
+ digest.Update(0x00);
+ digest.Update(0x00);
+ digest.Update(0x00);
+ digest.Update(0x01);
+ digest.BlockUpdate(ZB, 0, ZB.Length);
+ digest.BlockUpdate(parameters, 0, parameters.Length);
+
+ byte[] hash = DigestUtilities.DoFinal(digest);
+
+ return Arrays.CopyOfRange(hash, 0, keyLen);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/SXprUtilities.cs b/bc-sharp-crypto/src/openpgp/SXprUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..68ff373a8386fee32d8d6ee5f87b12f14a5f151d
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/SXprUtilities.cs
@@ -0,0 +1,102 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ /**
+ * Utility functions for looking a S-expression keys. This class will move when it finds a better home!
+ *
+ * Format documented here:
+ * http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=agent/keyformat.txt;h=42c4b1f06faf1bbe71ffadc2fee0fad6bec91a97;hb=refs/heads/master
+ *
+ */
+ public sealed class SXprUtilities
+ {
+ private SXprUtilities()
+ {
+ }
+
+ private static int ReadLength(Stream input, int ch)
+ {
+ int len = ch - '0';
+
+ while ((ch = input.ReadByte()) >= 0 && ch != ':')
+ {
+ len = len * 10 + ch - '0';
+ }
+
+ return len;
+ }
+
+ internal static string ReadString(Stream input, int ch)
+ {
+ int len = ReadLength(input, ch);
+
+ char[] chars = new char[len];
+
+ for (int i = 0; i != chars.Length; i++)
+ {
+ chars[i] = (char)input.ReadByte();
+ }
+
+ return new string(chars);
+ }
+
+ internal static byte[] ReadBytes(Stream input, int ch)
+ {
+ int len = ReadLength(input, ch);
+
+ byte[] data = new byte[len];
+
+ Streams.ReadFully(input, data);
+
+ return data;
+ }
+
+ internal static S2k ParseS2k(Stream input)
+ {
+ SkipOpenParenthesis(input);
+
+ string alg = ReadString(input, input.ReadByte());
+ byte[] iv = ReadBytes(input, input.ReadByte());
+ long iterationCount = Int64.Parse(ReadString(input, input.ReadByte()));
+
+ SkipCloseParenthesis(input);
+
+ // we have to return the actual iteration count provided.
+ return new MyS2k(HashAlgorithmTag.Sha1, iv, iterationCount);
+ }
+
+ internal static void SkipOpenParenthesis(Stream input)
+ {
+ int ch = input.ReadByte();
+ if (ch != '(')
+ throw new IOException("unknown character encountered");
+ }
+
+ internal static void SkipCloseParenthesis(Stream input)
+ {
+ int ch = input.ReadByte();
+ if (ch != ')')
+ throw new IOException("unknown character encountered");
+ }
+
+ private class MyS2k : S2k
+ {
+ private readonly long mIterationCount64;
+
+ internal MyS2k(HashAlgorithmTag algorithm, byte[] iv, long iterationCount64)
+ : base(algorithm, iv, (int)iterationCount64)
+ {
+ this.mIterationCount64 = iterationCount64;
+ }
+
+ public override long IterationCount
+ {
+ get { return mIterationCount64; }
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openpgp/WrappedGeneratorStream.cs b/bc-sharp-crypto/src/openpgp/WrappedGeneratorStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5f4a4b045f9caee5b8d57b9d66d933abf5ba81b2
--- /dev/null
+++ b/bc-sharp-crypto/src/openpgp/WrappedGeneratorStream.cs
@@ -0,0 +1,37 @@
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+ public class WrappedGeneratorStream
+ : FilterStream
+ {
+ private readonly IStreamGenerator gen;
+
+ public WrappedGeneratorStream(
+ IStreamGenerator gen,
+ Stream str)
+ : base(str)
+ {
+ this.gen = gen;
+ }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ gen.Close();
+ return;
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ gen.Close();
+ }
+#endif
+ }
+}
diff --git a/bc-sharp-crypto/src/openssl/EncryptionException.cs b/bc-sharp-crypto/src/openssl/EncryptionException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..043e90234d2e40393fe45e12020946e200a5b112
--- /dev/null
+++ b/bc-sharp-crypto/src/openssl/EncryptionException.cs
@@ -0,0 +1,25 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Security
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class EncryptionException
+ : IOException
+ {
+ public EncryptionException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public EncryptionException(
+ string message,
+ Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openssl/IPasswordFinder.cs b/bc-sharp-crypto/src/openssl/IPasswordFinder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4fcef1bd79233942aab1642e6692d546d44e6b2d
--- /dev/null
+++ b/bc-sharp-crypto/src/openssl/IPasswordFinder.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.OpenSsl
+{
+ public interface IPasswordFinder
+ {
+ char[] GetPassword();
+ }
+}
diff --git a/bc-sharp-crypto/src/openssl/MiscPemGenerator.cs b/bc-sharp-crypto/src/openssl/MiscPemGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..22ae1eae1846435ff2ed5560e36b7aaac3d09a2a
--- /dev/null
+++ b/bc-sharp-crypto/src/openssl/MiscPemGenerator.cs
@@ -0,0 +1,275 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO.Pem;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.OpenSsl
+{
+ /**
+ * PEM generator for the original set of PEM objects used in Open SSL.
+ */
+ public class MiscPemGenerator
+ : PemObjectGenerator
+ {
+ private object obj;
+ private string algorithm;
+ private char[] password;
+ private SecureRandom random;
+
+ public MiscPemGenerator(object obj)
+ {
+ this.obj = obj;
+ }
+
+ public MiscPemGenerator(
+ object obj,
+ string algorithm,
+ char[] password,
+ SecureRandom random)
+ {
+ this.obj = obj;
+ this.algorithm = algorithm;
+ this.password = password;
+ this.random = random;
+ }
+
+ private static PemObject CreatePemObject(object obj)
+ {
+ if (obj == null)
+ throw new ArgumentNullException("obj");
+
+ if (obj is AsymmetricCipherKeyPair)
+ {
+ return CreatePemObject(((AsymmetricCipherKeyPair)obj).Private);
+ }
+
+ string type;
+ byte[] encoding;
+
+ if (obj is PemObject)
+ return (PemObject)obj;
+
+ if (obj is PemObjectGenerator)
+ return ((PemObjectGenerator)obj).Generate();
+
+ if (obj is X509Certificate)
+ {
+ // TODO Should we prefer "X509 CERTIFICATE" here?
+ type = "CERTIFICATE";
+ try
+ {
+ encoding = ((X509Certificate)obj).GetEncoded();
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Cannot Encode object: " + e.ToString());
+ }
+ }
+ else if (obj is X509Crl)
+ {
+ type = "X509 CRL";
+ try
+ {
+ encoding = ((X509Crl)obj).GetEncoded();
+ }
+ catch (CrlException e)
+ {
+ throw new IOException("Cannot Encode object: " + e.ToString());
+ }
+ }
+ else if (obj is AsymmetricKeyParameter)
+ {
+ AsymmetricKeyParameter akp = (AsymmetricKeyParameter) obj;
+ if (akp.IsPrivate)
+ {
+ string keyType;
+ encoding = EncodePrivateKey(akp, out keyType);
+
+ type = keyType + " PRIVATE KEY";
+ }
+ else
+ {
+ type = "PUBLIC KEY";
+
+ encoding = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(akp).GetDerEncoded();
+ }
+ }
+ else if (obj is IX509AttributeCertificate)
+ {
+ type = "ATTRIBUTE CERTIFICATE";
+ encoding = ((X509V2AttributeCertificate)obj).GetEncoded();
+ }
+ else if (obj is Pkcs10CertificationRequest)
+ {
+ type = "CERTIFICATE REQUEST";
+ encoding = ((Pkcs10CertificationRequest)obj).GetEncoded();
+ }
+ else if (obj is Asn1.Cms.ContentInfo)
+ {
+ type = "PKCS7";
+ encoding = ((Asn1.Cms.ContentInfo)obj).GetEncoded();
+ }
+ else
+ {
+ throw new PemGenerationException("Object type not supported: " + Platform.GetTypeName(obj));
+ }
+
+ return new PemObject(type, encoding);
+ }
+
+// private string GetHexEncoded(byte[] bytes)
+// {
+// bytes = Hex.Encode(bytes);
+//
+// char[] chars = new char[bytes.Length];
+//
+// for (int i = 0; i != bytes.Length; i++)
+// {
+// chars[i] = (char)bytes[i];
+// }
+//
+// return new string(chars);
+// }
+
+ private static PemObject CreatePemObject(
+ object obj,
+ string algorithm,
+ char[] password,
+ SecureRandom random)
+ {
+ if (obj == null)
+ throw new ArgumentNullException("obj");
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+ if (password == null)
+ throw new ArgumentNullException("password");
+ if (random == null)
+ throw new ArgumentNullException("random");
+
+ if (obj is AsymmetricCipherKeyPair)
+ {
+ return CreatePemObject(((AsymmetricCipherKeyPair)obj).Private, algorithm, password, random);
+ }
+
+ string type = null;
+ byte[] keyData = null;
+
+ if (obj is AsymmetricKeyParameter)
+ {
+ AsymmetricKeyParameter akp = (AsymmetricKeyParameter) obj;
+ if (akp.IsPrivate)
+ {
+ string keyType;
+ keyData = EncodePrivateKey(akp, out keyType);
+
+ type = keyType + " PRIVATE KEY";
+ }
+ }
+
+ if (type == null || keyData == null)
+ {
+ // TODO Support other types?
+ throw new PemGenerationException("Object type not supported: " + Platform.GetTypeName(obj));
+ }
+
+
+ string dekAlgName = Platform.ToUpperInvariant(algorithm);
+
+ // Note: For backward compatibility
+ if (dekAlgName == "DESEDE")
+ {
+ dekAlgName = "DES-EDE3-CBC";
+ }
+
+ int ivLength = Platform.StartsWith(dekAlgName, "AES-") ? 16 : 8;
+
+ byte[] iv = new byte[ivLength];
+ random.NextBytes(iv);
+
+ byte[] encData = PemUtilities.Crypt(true, keyData, password, dekAlgName, iv);
+
+ IList headers = Platform.CreateArrayList(2);
+
+ headers.Add(new PemHeader("Proc-Type", "4,ENCRYPTED"));
+ headers.Add(new PemHeader("DEK-Info", dekAlgName + "," + Hex.ToHexString(iv)));
+
+ return new PemObject(type, headers, encData);
+ }
+
+ private static byte[] EncodePrivateKey(
+ AsymmetricKeyParameter akp,
+ out string keyType)
+ {
+ PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(akp);
+ AlgorithmIdentifier algID = info.PrivateKeyAlgorithm;
+ DerObjectIdentifier oid = algID.Algorithm;
+
+ if (oid.Equals(X9ObjectIdentifiers.IdDsa))
+ {
+ keyType = "DSA";
+
+ DsaParameter p = DsaParameter.GetInstance(algID.Parameters);
+
+ BigInteger x = ((DsaPrivateKeyParameters) akp).X;
+ BigInteger y = p.G.ModPow(x, p.P);
+
+ // TODO Create an ASN1 object somewhere for this?
+ return new DerSequence(
+ new DerInteger(0),
+ new DerInteger(p.P),
+ new DerInteger(p.Q),
+ new DerInteger(p.G),
+ new DerInteger(y),
+ new DerInteger(x)).GetEncoded();
+ }
+
+ if (oid.Equals(PkcsObjectIdentifiers.RsaEncryption))
+ {
+ keyType = "RSA";
+ }
+ else if (oid.Equals(CryptoProObjectIdentifiers.GostR3410x2001)
+ || oid.Equals(X9ObjectIdentifiers.IdECPublicKey))
+ {
+ keyType = "EC";
+ }
+ else
+ {
+ throw new ArgumentException("Cannot handle private key of type: " + Platform.GetTypeName(akp), "akp");
+ }
+
+ return info.ParsePrivateKey().GetEncoded();
+ }
+
+ public PemObject Generate()
+ {
+ try
+ {
+ if (algorithm != null)
+ {
+ return CreatePemObject(obj, algorithm, password, random);
+ }
+
+ return CreatePemObject(obj);
+ }
+ catch (IOException e)
+ {
+ throw new PemGenerationException("encoding exception", e);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openssl/PEMException.cs b/bc-sharp-crypto/src/openssl/PEMException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6b3e51065082a132d4824d2277d5960f2fe8913a
--- /dev/null
+++ b/bc-sharp-crypto/src/openssl/PEMException.cs
@@ -0,0 +1,25 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.OpenSsl
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class PemException
+ : IOException
+ {
+ public PemException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public PemException(
+ string message,
+ Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openssl/PEMReader.cs b/bc-sharp-crypto/src/openssl/PEMReader.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9a5f99b1a9182c9b5a286670405898d9f21c1e97
--- /dev/null
+++ b/bc-sharp-crypto/src/openssl/PEMReader.cs
@@ -0,0 +1,401 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.EC;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO.Pem;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.OpenSsl
+{
+ /**
+ * Class for reading OpenSSL PEM encoded streams containing
+ * X509 certificates, PKCS8 encoded keys and PKCS7 objects.
+ *
+ * In the case of PKCS7 objects the reader will return a CMS ContentInfo object. Keys and
+ * Certificates will be returned using the appropriate java.security type.
+ */
+ public class PemReader
+ : Org.BouncyCastle.Utilities.IO.Pem.PemReader
+ {
+// private static readonly IDictionary parsers = new Hashtable();
+
+ static PemReader()
+ {
+// parsers.Add("CERTIFICATE REQUEST", new PKCS10CertificationRequestParser());
+// parsers.Add("NEW CERTIFICATE REQUEST", new PKCS10CertificationRequestParser());
+// parsers.Add("CERTIFICATE", new X509CertificateParser(provider));
+// parsers.Add("X509 CERTIFICATE", new X509CertificateParser(provider));
+// parsers.Add("X509 CRL", new X509CRLParser(provider));
+// parsers.Add("PKCS7", new PKCS7Parser());
+// parsers.Add("ATTRIBUTE CERTIFICATE", new X509AttributeCertificateParser());
+// parsers.Add("EC PARAMETERS", new ECNamedCurveSpecParser());
+// parsers.Add("PUBLIC KEY", new PublicKeyParser(provider));
+// parsers.Add("RSA PUBLIC KEY", new RSAPublicKeyParser(provider));
+// parsers.Add("RSA PRIVATE KEY", new RSAKeyPairParser(provider));
+// parsers.Add("DSA PRIVATE KEY", new DSAKeyPairParser(provider));
+// parsers.Add("EC PRIVATE KEY", new ECDSAKeyPairParser(provider));
+// parsers.Add("ENCRYPTED PRIVATE KEY", new EncryptedPrivateKeyParser(provider));
+// parsers.Add("PRIVATE KEY", new PrivateKeyParser(provider));
+ }
+
+ private readonly IPasswordFinder pFinder;
+
+ /**
+ * Create a new PemReader
+ *
+ * @param reader the Reader
+ */
+ public PemReader(
+ TextReader reader)
+ : this(reader, null)
+ {
+ }
+
+ /**
+ * Create a new PemReader with a password finder
+ *
+ * @param reader the Reader
+ * @param pFinder the password finder
+ */
+ public PemReader(
+ TextReader reader,
+ IPasswordFinder pFinder)
+ : base(reader)
+ {
+ this.pFinder = pFinder;
+ }
+
+ public object ReadObject()
+ {
+ PemObject obj = ReadPemObject();
+
+ if (obj == null)
+ return null;
+
+ // TODO Follow Java build and map to parser objects?
+// if (parsers.Contains(obj.Type))
+// return ((PemObjectParser)parsers[obj.Type]).ParseObject(obj);
+
+ if (Platform.EndsWith(obj.Type, "PRIVATE KEY"))
+ return ReadPrivateKey(obj);
+
+ switch (obj.Type)
+ {
+ case "PUBLIC KEY":
+ return ReadPublicKey(obj);
+ case "RSA PUBLIC KEY":
+ return ReadRsaPublicKey(obj);
+ case "CERTIFICATE REQUEST":
+ case "NEW CERTIFICATE REQUEST":
+ return ReadCertificateRequest(obj);
+ case "CERTIFICATE":
+ case "X509 CERTIFICATE":
+ return ReadCertificate(obj);
+ case "PKCS7":
+ case "CMS":
+ return ReadPkcs7(obj);
+ case "X509 CRL":
+ return ReadCrl(obj);
+ case "ATTRIBUTE CERTIFICATE":
+ return ReadAttributeCertificate(obj);
+ // TODO Add back in when tests done, and return type issue resolved
+ //case "EC PARAMETERS":
+ // return ReadECParameters(obj);
+ default:
+ throw new IOException("unrecognised object: " + obj.Type);
+ }
+ }
+
+ private AsymmetricKeyParameter ReadRsaPublicKey(PemObject pemObject)
+ {
+ RsaPublicKeyStructure rsaPubStructure = RsaPublicKeyStructure.GetInstance(
+ Asn1Object.FromByteArray(pemObject.Content));
+
+ return new RsaKeyParameters(
+ false, // not private
+ rsaPubStructure.Modulus,
+ rsaPubStructure.PublicExponent);
+ }
+
+ private AsymmetricKeyParameter ReadPublicKey(PemObject pemObject)
+ {
+ return PublicKeyFactory.CreateKey(pemObject.Content);
+ }
+
+ /**
+ * Reads in a X509Certificate.
+ *
+ * @return the X509Certificate
+ * @throws IOException if an I/O error occured
+ */
+ private X509Certificate ReadCertificate(PemObject pemObject)
+ {
+ try
+ {
+ return new X509CertificateParser().ReadCertificate(pemObject.Content);
+ }
+ catch (Exception e)
+ {
+ throw new PemException("problem parsing cert: " + e.ToString());
+ }
+ }
+
+ /**
+ * Reads in a X509CRL.
+ *
+ * @return the X509Certificate
+ * @throws IOException if an I/O error occured
+ */
+ private X509Crl ReadCrl(PemObject pemObject)
+ {
+ try
+ {
+ return new X509CrlParser().ReadCrl(pemObject.Content);
+ }
+ catch (Exception e)
+ {
+ throw new PemException("problem parsing cert: " + e.ToString());
+ }
+ }
+
+ /**
+ * Reads in a PKCS10 certification request.
+ *
+ * @return the certificate request.
+ * @throws IOException if an I/O error occured
+ */
+ private Pkcs10CertificationRequest ReadCertificateRequest(PemObject pemObject)
+ {
+ try
+ {
+ return new Pkcs10CertificationRequest(pemObject.Content);
+ }
+ catch (Exception e)
+ {
+ throw new PemException("problem parsing cert: " + e.ToString());
+ }
+ }
+
+ /**
+ * Reads in a X509 Attribute Certificate.
+ *
+ * @return the X509 Attribute Certificate
+ * @throws IOException if an I/O error occured
+ */
+ private IX509AttributeCertificate ReadAttributeCertificate(PemObject pemObject)
+ {
+ return new X509V2AttributeCertificate(pemObject.Content);
+ }
+
+ /**
+ * Reads in a PKCS7 object. This returns a ContentInfo object suitable for use with the CMS
+ * API.
+ *
+ * @return the X509Certificate
+ * @throws IOException if an I/O error occured
+ */
+ // TODO Consider returning Asn1.Pkcs.ContentInfo
+ private Asn1.Cms.ContentInfo ReadPkcs7(PemObject pemObject)
+ {
+ try
+ {
+ return Asn1.Cms.ContentInfo.GetInstance(
+ Asn1Object.FromByteArray(pemObject.Content));
+ }
+ catch (Exception e)
+ {
+ throw new PemException("problem parsing PKCS7 object: " + e.ToString());
+ }
+ }
+
+ /**
+ * Read a Key Pair
+ */
+ private object ReadPrivateKey(PemObject pemObject)
+ {
+ //
+ // extract the key
+ //
+ Debug.Assert(Platform.EndsWith(pemObject.Type, "PRIVATE KEY"));
+
+ string type = pemObject.Type.Substring(0, pemObject.Type.Length - "PRIVATE KEY".Length).Trim();
+ byte[] keyBytes = pemObject.Content;
+
+ IDictionary fields = Platform.CreateHashtable();
+ foreach (PemHeader header in pemObject.Headers)
+ {
+ fields[header.Name] = header.Value;
+ }
+
+ string procType = (string) fields["Proc-Type"];
+
+ if (procType == "4,ENCRYPTED")
+ {
+ if (pFinder == null)
+ throw new PasswordException("No password finder specified, but a password is required");
+
+ char[] password = pFinder.GetPassword();
+
+ if (password == null)
+ throw new PasswordException("Password is null, but a password is required");
+
+ string dekInfo = (string) fields["DEK-Info"];
+ string[] tknz = dekInfo.Split(',');
+
+ string dekAlgName = tknz[0].Trim();
+ byte[] iv = Hex.Decode(tknz[1].Trim());
+
+ keyBytes = PemUtilities.Crypt(false, keyBytes, password, dekAlgName, iv);
+ }
+
+ try
+ {
+ AsymmetricKeyParameter pubSpec, privSpec;
+ Asn1Sequence seq = Asn1Sequence.GetInstance(keyBytes);
+
+ switch (type)
+ {
+ case "RSA":
+ {
+ if (seq.Count != 9)
+ throw new PemException("malformed sequence in RSA private key");
+
+ RsaPrivateKeyStructure rsa = RsaPrivateKeyStructure.GetInstance(seq);
+
+ pubSpec = new RsaKeyParameters(false, rsa.Modulus, rsa.PublicExponent);
+ privSpec = new RsaPrivateCrtKeyParameters(
+ rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent,
+ rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2,
+ rsa.Coefficient);
+
+ break;
+ }
+
+ case "DSA":
+ {
+ if (seq.Count != 6)
+ throw new PemException("malformed sequence in DSA private key");
+
+ // TODO Create an ASN1 object somewhere for this?
+ //DerInteger v = (DerInteger)seq[0];
+ DerInteger p = (DerInteger)seq[1];
+ DerInteger q = (DerInteger)seq[2];
+ DerInteger g = (DerInteger)seq[3];
+ DerInteger y = (DerInteger)seq[4];
+ DerInteger x = (DerInteger)seq[5];
+
+ DsaParameters parameters = new DsaParameters(p.Value, q.Value, g.Value);
+
+ privSpec = new DsaPrivateKeyParameters(x.Value, parameters);
+ pubSpec = new DsaPublicKeyParameters(y.Value, parameters);
+
+ break;
+ }
+
+ case "EC":
+ {
+ ECPrivateKeyStructure pKey = ECPrivateKeyStructure.GetInstance(seq);
+ AlgorithmIdentifier algId = new AlgorithmIdentifier(
+ X9ObjectIdentifiers.IdECPublicKey, pKey.GetParameters());
+
+ PrivateKeyInfo privInfo = new PrivateKeyInfo(algId, pKey.ToAsn1Object());
+
+ // TODO Are the keys returned here ECDSA, as Java version forces?
+ privSpec = PrivateKeyFactory.CreateKey(privInfo);
+
+ DerBitString pubKey = pKey.GetPublicKey();
+ if (pubKey != null)
+ {
+ SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(algId, pubKey.GetBytes());
+
+ // TODO Are the keys returned here ECDSA, as Java version forces?
+ pubSpec = PublicKeyFactory.CreateKey(pubInfo);
+ }
+ else
+ {
+ pubSpec = ECKeyPairGenerator.GetCorrespondingPublicKey(
+ (ECPrivateKeyParameters)privSpec);
+ }
+
+ break;
+ }
+
+ case "ENCRYPTED":
+ {
+ char[] password = pFinder.GetPassword();
+
+ if (password == null)
+ throw new PasswordException("Password is null, but a password is required");
+
+ return PrivateKeyFactory.DecryptKey(password, EncryptedPrivateKeyInfo.GetInstance(seq));
+ }
+
+ case "":
+ {
+ return PrivateKeyFactory.CreateKey(PrivateKeyInfo.GetInstance(seq));
+ }
+
+ default:
+ throw new ArgumentException("Unknown key type: " + type, "type");
+ }
+
+ return new AsymmetricCipherKeyPair(pubSpec, privSpec);
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PemException(
+ "problem creating " + type + " private key: " + e.ToString());
+ }
+ }
+
+ // TODO Add an equivalent class for ECNamedCurveParameterSpec?
+ //private ECNamedCurveParameterSpec ReadECParameters(
+// private X9ECParameters ReadECParameters(PemObject pemObject)
+// {
+// DerObjectIdentifier oid = (DerObjectIdentifier)Asn1Object.FromByteArray(pemObject.Content);
+//
+// //return ECNamedCurveTable.getParameterSpec(oid.Id);
+// return GetCurveParameters(oid.Id);
+// }
+
+ //private static ECDomainParameters GetCurveParameters(
+ private static X9ECParameters GetCurveParameters(
+ string name)
+ {
+ // TODO ECGost3410NamedCurves support (returns ECDomainParameters though)
+
+ X9ECParameters ecP = CustomNamedCurves.GetByName(name);
+ if (ecP == null)
+ {
+ ecP = ECNamedCurveTable.GetByName(name);
+ }
+
+ if (ecP == null)
+ throw new Exception("unknown curve name: " + name);
+
+ //return new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());
+ return ecP;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openssl/PEMUtilities.cs b/bc-sharp-crypto/src/openssl/PEMUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b58e5e7652a2f882179db0b69c015bd214df9467
--- /dev/null
+++ b/bc-sharp-crypto/src/openssl/PEMUtilities.cs
@@ -0,0 +1,158 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.OpenSsl
+{
+ internal sealed class PemUtilities
+ {
+ private enum PemBaseAlg { AES_128, AES_192, AES_256, BF, DES, DES_EDE, DES_EDE3, RC2, RC2_40, RC2_64 };
+ private enum PemMode { CBC, CFB, ECB, OFB };
+
+ static PemUtilities()
+ {
+ // Signal to obfuscation tools not to change enum constants
+ ((PemBaseAlg)Enums.GetArbitraryValue(typeof(PemBaseAlg))).ToString();
+ ((PemMode)Enums.GetArbitraryValue(typeof(PemMode))).ToString();
+ }
+
+ private static void ParseDekAlgName(
+ string dekAlgName,
+ out PemBaseAlg baseAlg,
+ out PemMode mode)
+ {
+ try
+ {
+ mode = PemMode.ECB;
+
+ if (dekAlgName == "DES-EDE" || dekAlgName == "DES-EDE3")
+ {
+ baseAlg = (PemBaseAlg)Enums.GetEnumValue(typeof(PemBaseAlg), dekAlgName);
+ return;
+ }
+
+ int pos = dekAlgName.LastIndexOf('-');
+ if (pos >= 0)
+ {
+ baseAlg = (PemBaseAlg)Enums.GetEnumValue(typeof(PemBaseAlg), dekAlgName.Substring(0, pos));
+ mode = (PemMode)Enums.GetEnumValue(typeof(PemMode), dekAlgName.Substring(pos + 1));
+ return;
+ }
+ }
+ catch (ArgumentException)
+ {
+ }
+
+ throw new EncryptionException("Unknown DEK algorithm: " + dekAlgName);
+ }
+
+ internal static byte[] Crypt(
+ bool encrypt,
+ byte[] bytes,
+ char[] password,
+ string dekAlgName,
+ byte[] iv)
+ {
+ PemBaseAlg baseAlg;
+ PemMode mode;
+ ParseDekAlgName(dekAlgName, out baseAlg, out mode);
+
+ string padding;
+ switch (mode)
+ {
+ case PemMode.CBC:
+ case PemMode.ECB:
+ padding = "PKCS5Padding";
+ break;
+ case PemMode.CFB:
+ case PemMode.OFB:
+ padding = "NoPadding";
+ break;
+ default:
+ throw new EncryptionException("Unknown DEK algorithm: " + dekAlgName);
+ }
+
+ string algorithm;
+
+ byte[] salt = iv;
+ switch (baseAlg)
+ {
+ case PemBaseAlg.AES_128:
+ case PemBaseAlg.AES_192:
+ case PemBaseAlg.AES_256:
+ algorithm = "AES";
+ if (salt.Length > 8)
+ {
+ salt = new byte[8];
+ Array.Copy(iv, 0, salt, 0, salt.Length);
+ }
+ break;
+ case PemBaseAlg.BF:
+ algorithm = "BLOWFISH";
+ break;
+ case PemBaseAlg.DES:
+ algorithm = "DES";
+ break;
+ case PemBaseAlg.DES_EDE:
+ case PemBaseAlg.DES_EDE3:
+ algorithm = "DESede";
+ break;
+ case PemBaseAlg.RC2:
+ case PemBaseAlg.RC2_40:
+ case PemBaseAlg.RC2_64:
+ algorithm = "RC2";
+ break;
+ default:
+ throw new EncryptionException("Unknown DEK algorithm: " + dekAlgName);
+ }
+
+ string cipherName = algorithm + "/" + mode + "/" + padding;
+ IBufferedCipher cipher = CipherUtilities.GetCipher(cipherName);
+
+ ICipherParameters cParams = GetCipherParameters(password, baseAlg, salt);
+
+ if (mode != PemMode.ECB)
+ {
+ cParams = new ParametersWithIV(cParams, iv);
+ }
+
+ cipher.Init(encrypt, cParams);
+
+ return cipher.DoFinal(bytes);
+ }
+
+ private static ICipherParameters GetCipherParameters(
+ char[] password,
+ PemBaseAlg baseAlg,
+ byte[] salt)
+ {
+ string algorithm;
+ int keyBits;
+ switch (baseAlg)
+ {
+ case PemBaseAlg.AES_128: keyBits = 128; algorithm = "AES128"; break;
+ case PemBaseAlg.AES_192: keyBits = 192; algorithm = "AES192"; break;
+ case PemBaseAlg.AES_256: keyBits = 256; algorithm = "AES256"; break;
+ case PemBaseAlg.BF: keyBits = 128; algorithm = "BLOWFISH"; break;
+ case PemBaseAlg.DES: keyBits = 64; algorithm = "DES"; break;
+ case PemBaseAlg.DES_EDE: keyBits = 128; algorithm = "DESEDE"; break;
+ case PemBaseAlg.DES_EDE3: keyBits = 192; algorithm = "DESEDE3"; break;
+ case PemBaseAlg.RC2: keyBits = 128; algorithm = "RC2"; break;
+ case PemBaseAlg.RC2_40: keyBits = 40; algorithm = "RC2"; break;
+ case PemBaseAlg.RC2_64: keyBits = 64; algorithm = "RC2"; break;
+ default:
+ return null;
+ }
+
+ OpenSslPbeParametersGenerator pGen = new OpenSslPbeParametersGenerator();
+
+ pGen.Init(PbeParametersGenerator.Pkcs5PasswordToBytes(password), salt);
+
+ return pGen.GenerateDerivedParameters(algorithm, keyBits);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openssl/PEMWriter.cs b/bc-sharp-crypto/src/openssl/PEMWriter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..aefb018f32b1f065b3c9053168b2f103b5d6b3d9
--- /dev/null
+++ b/bc-sharp-crypto/src/openssl/PEMWriter.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO.Pem;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.OpenSsl
+{
+ /// General purpose writer for OpenSSL PEM objects.
+ public class PemWriter
+ : Org.BouncyCastle.Utilities.IO.Pem.PemWriter
+ {
+ /// The TextWriter object to write the output to.
+ public PemWriter(
+ TextWriter writer)
+ : base(writer)
+ {
+ }
+
+ public void WriteObject(
+ object obj)
+ {
+ try
+ {
+ base.WriteObject(new MiscPemGenerator(obj));
+ }
+ catch (PemGenerationException e)
+ {
+ if (e.InnerException is IOException)
+ throw (IOException)e.InnerException;
+
+ throw e;
+ }
+ }
+
+ public void WriteObject(
+ object obj,
+ string algorithm,
+ char[] password,
+ SecureRandom random)
+ {
+ base.WriteObject(new MiscPemGenerator(obj, algorithm, password, random));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openssl/PasswordException.cs b/bc-sharp-crypto/src/openssl/PasswordException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..38e679bb184291720bdd7c0eec3d60765bd8bab1
--- /dev/null
+++ b/bc-sharp-crypto/src/openssl/PasswordException.cs
@@ -0,0 +1,25 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Security
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class PasswordException
+ : IOException
+ {
+ public PasswordException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public PasswordException(
+ string message,
+ Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/openssl/Pkcs8Generator.cs b/bc-sharp-crypto/src/openssl/Pkcs8Generator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d03ea08d223ace2d678349e8c730b139490a5c53
--- /dev/null
+++ b/bc-sharp-crypto/src/openssl/Pkcs8Generator.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO.Pem;
+
+namespace Org.BouncyCastle.OpenSsl
+{
+ public class Pkcs8Generator
+ : PemObjectGenerator
+ {
+ // FIXME See PbeUtilities static constructor
+// public static readonly string Aes128Cbc = NistObjectIdentifiers.IdAes128Cbc.Id;
+// public static readonly string Aes192Cbc = NistObjectIdentifiers.IdAes192Cbc.Id;
+// public static readonly string Aes256Cbc = NistObjectIdentifiers.IdAes256Cbc.Id;
+//
+// public static readonly string Des3Cbc = PkcsObjectIdentifiers.DesEde3Cbc.Id;
+
+ public static readonly string PbeSha1_RC4_128 = PkcsObjectIdentifiers.PbeWithShaAnd128BitRC4.Id;
+ public static readonly string PbeSha1_RC4_40 = PkcsObjectIdentifiers.PbeWithShaAnd40BitRC4.Id;
+ public static readonly string PbeSha1_3DES = PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc.Id;
+ public static readonly string PbeSha1_2DES = PkcsObjectIdentifiers.PbeWithShaAnd2KeyTripleDesCbc.Id;
+ public static readonly string PbeSha1_RC2_128 = PkcsObjectIdentifiers.PbeWithShaAnd128BitRC2Cbc.Id;
+ public static readonly string PbeSha1_RC2_40 = PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc.Id;
+
+ private char[] password;
+ private string algorithm;
+ private int iterationCount;
+ private AsymmetricKeyParameter privKey;
+ private SecureRandom random;
+
+ /**
+ * Constructor for an unencrypted private key PEM object.
+ *
+ * @param key private key to be encoded.
+ */
+ public Pkcs8Generator(AsymmetricKeyParameter privKey)
+ {
+ this.privKey = privKey;
+ }
+
+ /**
+ * Constructor for an encrypted private key PEM object.
+ *
+ * @param key private key to be encoded
+ * @param algorithm encryption algorithm to use
+ * @param provider provider to use
+ * @throws NoSuchAlgorithmException if algorithm/mode cannot be found
+ */
+ public Pkcs8Generator(AsymmetricKeyParameter privKey, string algorithm)
+ {
+ // TODO Check privKey.IsPrivate
+ this.privKey = privKey;
+ this.algorithm = algorithm;
+ this.iterationCount = 2048;
+ }
+
+ public SecureRandom SecureRandom
+ {
+ set { this.random = value; }
+ }
+
+ public char[] Password
+ {
+ set { this.password = value; }
+ }
+
+ public int IterationCount
+ {
+ set { this.iterationCount = value; }
+ }
+
+ public PemObject Generate()
+ {
+ if (algorithm == null)
+ {
+ PrivateKeyInfo pki = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privKey);
+
+ return new PemObject("PRIVATE KEY", pki.GetEncoded());
+ }
+
+ // TODO Theoretically, the amount of salt needed depends on the algorithm
+ byte[] salt = new byte[20];
+ if (random == null)
+ {
+ random = new SecureRandom();
+ }
+ random.NextBytes(salt);
+
+ try
+ {
+ EncryptedPrivateKeyInfo epki = EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
+ algorithm, password, salt, iterationCount, privKey);
+
+ return new PemObject("ENCRYPTED PRIVATE KEY", epki.GetEncoded());
+ }
+ catch (Exception e)
+ {
+ throw new PemGenerationException("Couldn't encrypt private key", e);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkcs/AsymmetricKeyEntry.cs b/bc-sharp-crypto/src/pkcs/AsymmetricKeyEntry.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6da3ade3e0ee5cfdc173ca460f228d6bf26d1efd
--- /dev/null
+++ b/bc-sharp-crypto/src/pkcs/AsymmetricKeyEntry.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Pkcs
+{
+ public class AsymmetricKeyEntry
+ : Pkcs12Entry
+ {
+ private readonly AsymmetricKeyParameter key;
+
+ public AsymmetricKeyEntry(
+ AsymmetricKeyParameter key)
+ : base(Platform.CreateHashtable())
+ {
+ this.key = key;
+ }
+
+#if !(SILVERLIGHT || PORTABLE)
+ [Obsolete]
+ public AsymmetricKeyEntry(
+ AsymmetricKeyParameter key,
+ Hashtable attributes)
+ : base(attributes)
+ {
+ this.key = key;
+ }
+#endif
+
+ public AsymmetricKeyEntry(
+ AsymmetricKeyParameter key,
+ IDictionary attributes)
+ : base(attributes)
+ {
+ this.key = key;
+ }
+
+ public AsymmetricKeyParameter Key
+ {
+ get { return this.key; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ AsymmetricKeyEntry other = obj as AsymmetricKeyEntry;
+
+ if (other == null)
+ return false;
+
+ return key.Equals(other.key);
+ }
+
+ public override int GetHashCode()
+ {
+ return ~key.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs b/bc-sharp-crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b6b7bac651d37aabbf3ac1401dd064ae15c41992
--- /dev/null
+++ b/bc-sharp-crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs
@@ -0,0 +1,64 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Pkcs
+{
+ public sealed class EncryptedPrivateKeyInfoFactory
+ {
+ private EncryptedPrivateKeyInfoFactory()
+ {
+ }
+
+ public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo(
+ DerObjectIdentifier algorithm,
+ char[] passPhrase,
+ byte[] salt,
+ int iterationCount,
+ AsymmetricKeyParameter key)
+ {
+ return CreateEncryptedPrivateKeyInfo(
+ algorithm.Id, passPhrase, salt, iterationCount,
+ PrivateKeyInfoFactory.CreatePrivateKeyInfo(key));
+ }
+
+ public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo(
+ string algorithm,
+ char[] passPhrase,
+ byte[] salt,
+ int iterationCount,
+ AsymmetricKeyParameter key)
+ {
+ return CreateEncryptedPrivateKeyInfo(
+ algorithm, passPhrase, salt, iterationCount,
+ PrivateKeyInfoFactory.CreatePrivateKeyInfo(key));
+ }
+
+ public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo(
+ string algorithm,
+ char[] passPhrase,
+ byte[] salt,
+ int iterationCount,
+ PrivateKeyInfo keyInfo)
+ {
+ IBufferedCipher cipher = PbeUtilities.CreateEngine(algorithm) as IBufferedCipher;
+ if (cipher == null)
+ throw new Exception("Unknown encryption algorithm: " + algorithm);
+
+ Asn1Encodable pbeParameters = PbeUtilities.GenerateAlgorithmParameters(
+ algorithm, salt, iterationCount);
+ ICipherParameters cipherParameters = PbeUtilities.GenerateCipherParameters(
+ algorithm, passPhrase, pbeParameters);
+ cipher.Init(true, cipherParameters);
+ byte[] encoding = cipher.DoFinal(keyInfo.GetEncoded());
+
+ DerObjectIdentifier oid = PbeUtilities.GetObjectIdentifier(algorithm);
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(oid, pbeParameters);
+ return new EncryptedPrivateKeyInfo(algID, encoding);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkcs/PKCS12StoreBuilder.cs b/bc-sharp-crypto/src/pkcs/PKCS12StoreBuilder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c8fa0f603a4c43fbc72302b373a7ece0b81bf53b
--- /dev/null
+++ b/bc-sharp-crypto/src/pkcs/PKCS12StoreBuilder.cs
@@ -0,0 +1,41 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Pkcs
+{
+ public class Pkcs12StoreBuilder
+ {
+ private DerObjectIdentifier keyAlgorithm = PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc;
+ private DerObjectIdentifier certAlgorithm = PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc;
+ private bool useDerEncoding = false;
+
+ public Pkcs12StoreBuilder()
+ {
+ }
+
+ public Pkcs12Store Build()
+ {
+ return new Pkcs12Store(keyAlgorithm, certAlgorithm, useDerEncoding);
+ }
+
+ public Pkcs12StoreBuilder SetCertAlgorithm(DerObjectIdentifier certAlgorithm)
+ {
+ this.certAlgorithm = certAlgorithm;
+ return this;
+ }
+
+ public Pkcs12StoreBuilder SetKeyAlgorithm(DerObjectIdentifier keyAlgorithm)
+ {
+ this.keyAlgorithm = keyAlgorithm;
+ return this;
+ }
+
+ public Pkcs12StoreBuilder SetUseDerEncoding(bool useDerEncoding)
+ {
+ this.useDerEncoding = useDerEncoding;
+ return this;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkcs/Pkcs10CertificationRequest.cs b/bc-sharp-crypto/src/pkcs/Pkcs10CertificationRequest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c2504e6e59b7dbf4a5ea2b0bfc4173b4e04b1b28
--- /dev/null
+++ b/bc-sharp-crypto/src/pkcs/Pkcs10CertificationRequest.cs
@@ -0,0 +1,464 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.Crypto.Operators;
+
+namespace Org.BouncyCastle.Pkcs
+{
+ ///
+ /// A class for verifying and creating Pkcs10 Certification requests.
+ ///
+ ///
+ /// CertificationRequest ::= Sequence {
+ /// certificationRequestInfo CertificationRequestInfo,
+ /// signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
+ /// signature BIT STRING
+ /// }
+ ///
+ /// CertificationRequestInfo ::= Sequence {
+ /// version Integer { v1(0) } (v1,...),
+ /// subject Name,
+ /// subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+ /// attributes [0] Attributes{{ CRIAttributes }}
+ /// }
+ ///
+ /// Attributes { ATTRIBUTE:IOSet } ::= Set OF Attr{{ IOSet }}
+ ///
+ /// Attr { ATTRIBUTE:IOSet } ::= Sequence {
+ /// type ATTRIBUTE.&id({IOSet}),
+ /// values Set SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type})
+ /// }
+ ///
+ /// see
+ public class Pkcs10CertificationRequest
+ : CertificationRequest
+ {
+ protected static readonly IDictionary algorithms = Platform.CreateHashtable();
+ protected static readonly IDictionary exParams = Platform.CreateHashtable();
+ protected static readonly IDictionary keyAlgorithms = Platform.CreateHashtable();
+ protected static readonly IDictionary oids = Platform.CreateHashtable();
+ protected static readonly ISet noParams = new HashSet();
+
+ static Pkcs10CertificationRequest()
+ {
+ algorithms.Add("MD2WITHRSAENCRYPTION", new DerObjectIdentifier("1.2.840.113549.1.1.2"));
+ algorithms.Add("MD2WITHRSA", new DerObjectIdentifier("1.2.840.113549.1.1.2"));
+ algorithms.Add("MD5WITHRSAENCRYPTION", new DerObjectIdentifier("1.2.840.113549.1.1.4"));
+ algorithms.Add("MD5WITHRSA", new DerObjectIdentifier("1.2.840.113549.1.1.4"));
+ algorithms.Add("RSAWITHMD5", new DerObjectIdentifier("1.2.840.113549.1.1.4"));
+ algorithms.Add("SHA1WITHRSAENCRYPTION", new DerObjectIdentifier("1.2.840.113549.1.1.5"));
+ algorithms.Add("SHA1WITHRSA", new DerObjectIdentifier("1.2.840.113549.1.1.5"));
+ algorithms.Add("SHA224WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+ algorithms.Add("SHA224WITHRSA", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+ algorithms.Add("SHA256WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+ algorithms.Add("SHA256WITHRSA", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+ algorithms.Add("SHA384WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+ algorithms.Add("SHA384WITHRSA", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+ algorithms.Add("SHA512WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+ algorithms.Add("SHA512WITHRSA", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA224WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA256WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA384WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA512WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("RSAWITHSHA1", new DerObjectIdentifier("1.2.840.113549.1.1.5"));
+ algorithms.Add("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+ algorithms.Add("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+ algorithms.Add("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+ algorithms.Add("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+ algorithms.Add("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+ algorithms.Add("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+ algorithms.Add("SHA1WITHDSA", new DerObjectIdentifier("1.2.840.10040.4.3"));
+ algorithms.Add("DSAWITHSHA1", new DerObjectIdentifier("1.2.840.10040.4.3"));
+ algorithms.Add("SHA224WITHDSA", NistObjectIdentifiers.DsaWithSha224);
+ algorithms.Add("SHA256WITHDSA", NistObjectIdentifiers.DsaWithSha256);
+ algorithms.Add("SHA384WITHDSA", NistObjectIdentifiers.DsaWithSha384);
+ algorithms.Add("SHA512WITHDSA", NistObjectIdentifiers.DsaWithSha512);
+ algorithms.Add("SHA1WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha1);
+ algorithms.Add("SHA224WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha224);
+ algorithms.Add("SHA256WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha256);
+ algorithms.Add("SHA384WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha384);
+ algorithms.Add("SHA512WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha512);
+ algorithms.Add("ECDSAWITHSHA1", X9ObjectIdentifiers.ECDsaWithSha1);
+ algorithms.Add("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ algorithms.Add("GOST3410WITHGOST3411", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ algorithms.Add("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+ algorithms.Add("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+ algorithms.Add("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+ //
+ // reverse mappings
+ //
+ oids.Add(new DerObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.Sha224WithRsaEncryption, "SHA224WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.Sha256WithRsaEncryption, "SHA256WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.Sha384WithRsaEncryption, "SHA384WITHRSA");
+ oids.Add(PkcsObjectIdentifiers.Sha512WithRsaEncryption, "SHA512WITHRSA");
+ oids.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94, "GOST3411WITHGOST3410");
+ oids.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001, "GOST3411WITHECGOST3410");
+
+ oids.Add(new DerObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
+ oids.Add(new DerObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA");
+ oids.Add(new DerObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha1, "SHA1WITHECDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha224, "SHA224WITHECDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha256, "SHA256WITHECDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha384, "SHA384WITHECDSA");
+ oids.Add(X9ObjectIdentifiers.ECDsaWithSha512, "SHA512WITHECDSA");
+ oids.Add(OiwObjectIdentifiers.Sha1WithRsa, "SHA1WITHRSA");
+ oids.Add(OiwObjectIdentifiers.DsaWithSha1, "SHA1WITHDSA");
+ oids.Add(NistObjectIdentifiers.DsaWithSha224, "SHA224WITHDSA");
+ oids.Add(NistObjectIdentifiers.DsaWithSha256, "SHA256WITHDSA");
+
+ //
+ // key types
+ //
+ keyAlgorithms.Add(PkcsObjectIdentifiers.RsaEncryption, "RSA");
+ keyAlgorithms.Add(X9ObjectIdentifiers.IdDsa, "DSA");
+
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha1);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha224);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha256);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha384);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha512);
+ noParams.Add(X9ObjectIdentifiers.IdDsaWithSha1);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha224);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha256);
+
+ //
+ // RFC 4491
+ //
+ noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+ //
+ // explicit params
+ //
+ AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+ exParams.Add("SHA1WITHRSAANDMGF1", CreatePssParams(sha1AlgId, 20));
+
+ AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha224, DerNull.Instance);
+ exParams.Add("SHA224WITHRSAANDMGF1", CreatePssParams(sha224AlgId, 28));
+
+ AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha256, DerNull.Instance);
+ exParams.Add("SHA256WITHRSAANDMGF1", CreatePssParams(sha256AlgId, 32));
+
+ AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha384, DerNull.Instance);
+ exParams.Add("SHA384WITHRSAANDMGF1", CreatePssParams(sha384AlgId, 48));
+
+ AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha512, DerNull.Instance);
+ exParams.Add("SHA512WITHRSAANDMGF1", CreatePssParams(sha512AlgId, 64));
+ }
+
+ private static RsassaPssParameters CreatePssParams(
+ AlgorithmIdentifier hashAlgId,
+ int saltSize)
+ {
+ return new RsassaPssParameters(
+ hashAlgId,
+ new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, hashAlgId),
+ new DerInteger(saltSize),
+ new DerInteger(1));
+ }
+
+ protected Pkcs10CertificationRequest()
+ {
+ }
+
+ public Pkcs10CertificationRequest(
+ byte[] encoded)
+ : base((Asn1Sequence) Asn1Object.FromByteArray(encoded))
+ {
+ }
+
+ public Pkcs10CertificationRequest(
+ Asn1Sequence seq)
+ : base(seq)
+ {
+ }
+
+ public Pkcs10CertificationRequest(
+ Stream input)
+ : base((Asn1Sequence) Asn1Object.FromStream(input))
+ {
+ }
+
+ ///
+ /// Instantiate a Pkcs10CertificationRequest object with the necessary credentials.
+ ///
+ /// Name of Sig Alg.
+ /// X509Name of subject eg OU="My unit." O="My Organisatioin" C="au"
+ /// Public Key to be included in cert reqest.
+ /// ASN1Set of Attributes.
+ /// Matching Private key for nominated (above) public key to be used to sign the request.
+ [Obsolete("Use constructor with an ISignatureFactory")]
+ public Pkcs10CertificationRequest(
+ string signatureAlgorithm,
+ X509Name subject,
+ AsymmetricKeyParameter publicKey,
+ Asn1Set attributes,
+ AsymmetricKeyParameter signingKey)
+ {
+ if (signatureAlgorithm == null)
+ throw new ArgumentNullException("signatureAlgorithm");
+ if (subject == null)
+ throw new ArgumentNullException("subject");
+ if (publicKey == null)
+ throw new ArgumentNullException("publicKey");
+ if (publicKey.IsPrivate)
+ throw new ArgumentException("expected public key", "publicKey");
+ if (!signingKey.IsPrivate)
+ throw new ArgumentException("key for signing must be private", "signingKey");
+
+ init(new Asn1SignatureFactory(signatureAlgorithm, signingKey), subject, publicKey, attributes, signingKey);
+ }
+
+ ///
+ /// Instantiate a Pkcs10CertificationRequest object with the necessary credentials.
+ ///
+ /// The factory for signature calculators to sign the PKCS#10 request with.
+ /// X509Name of subject eg OU="My unit." O="My Organisatioin" C="au"
+ /// Public Key to be included in cert reqest.
+ /// ASN1Set of Attributes.
+ /// Matching Private key for nominated (above) public key to be used to sign the request.
+ public Pkcs10CertificationRequest(
+ ISignatureFactory signatureCalculatorFactory,
+ X509Name subject,
+ AsymmetricKeyParameter publicKey,
+ Asn1Set attributes,
+ AsymmetricKeyParameter signingKey)
+ {
+ if (signatureCalculatorFactory == null)
+ throw new ArgumentNullException("signatureCalculator");
+ if (subject == null)
+ throw new ArgumentNullException("subject");
+ if (publicKey == null)
+ throw new ArgumentNullException("publicKey");
+ if (publicKey.IsPrivate)
+ throw new ArgumentException("expected public key", "publicKey");
+ if (!signingKey.IsPrivate)
+ throw new ArgumentException("key for signing must be private", "signingKey");
+
+ init(signatureCalculatorFactory, subject, publicKey, attributes, signingKey);
+ }
+
+ private void init(
+ ISignatureFactory signatureCalculator,
+ X509Name subject,
+ AsymmetricKeyParameter publicKey,
+ Asn1Set attributes,
+ AsymmetricKeyParameter signingKey)
+ {
+ this.sigAlgId = (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails;
+
+ SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);
+
+ this.reqInfo = new CertificationRequestInfo(subject, pubInfo, attributes);
+
+ IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator();
+
+ byte[] reqInfoData = reqInfo.GetDerEncoded();
+
+ streamCalculator.Stream.Write(reqInfoData, 0, reqInfoData.Length);
+
+ Platform.Dispose(streamCalculator.Stream);
+
+ // Generate Signature.
+ sigBits = new DerBitString(((IBlockResult)streamCalculator.GetResult()).Collect());
+ }
+
+ // internal Pkcs10CertificationRequest(
+ // Asn1InputStream seqStream)
+ // {
+ // Asn1Sequence seq = (Asn1Sequence) seqStream.ReadObject();
+ // try
+ // {
+ // this.reqInfo = CertificationRequestInfo.GetInstance(seq[0]);
+ // this.sigAlgId = AlgorithmIdentifier.GetInstance(seq[1]);
+ // this.sigBits = (DerBitString) seq[2];
+ // }
+ // catch (Exception ex)
+ // {
+ // throw new ArgumentException("Create From Asn1Sequence: " + ex.Message);
+ // }
+ // }
+
+ ///
+ /// Get the public key.
+ ///
+ /// The public key.
+ public AsymmetricKeyParameter GetPublicKey()
+ {
+ return PublicKeyFactory.CreateKey(reqInfo.SubjectPublicKeyInfo);
+ }
+
+ ///
+ /// Verify Pkcs10 Cert Request is valid.
+ ///
+ /// true = valid.
+ public bool Verify()
+ {
+ return Verify(this.GetPublicKey());
+ }
+
+ public bool Verify(
+ AsymmetricKeyParameter publicKey)
+ {
+ return Verify(new Asn1VerifierFactoryProvider(publicKey));
+ }
+
+ public bool Verify(
+ IVerifierFactoryProvider verifierProvider)
+ {
+ return Verify(verifierProvider.CreateVerifierFactory(sigAlgId));
+ }
+
+ public bool Verify(
+ IVerifierFactory verifier)
+ {
+ try
+ {
+ byte[] b = reqInfo.GetDerEncoded();
+
+ IStreamCalculator streamCalculator = verifier.CreateCalculator();
+
+ streamCalculator.Stream.Write(b, 0, b.Length);
+
+ Platform.Dispose(streamCalculator.Stream);
+
+ return ((IVerifier)streamCalculator.GetResult()).IsVerified(sigBits.GetOctets());
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("exception encoding TBS cert request", e);
+ }
+ }
+
+ // ///
+ // /// Get the Der Encoded Pkcs10 Certification Request.
+ // ///
+ // /// A byte array.
+ // public byte[] GetEncoded()
+ // {
+ // return new CertificationRequest(reqInfo, sigAlgId, sigBits).GetDerEncoded();
+ // }
+
+ // TODO Figure out how to set parameters on an ISigner
+ private void SetSignatureParameters(
+ ISigner signature,
+ Asn1Encodable asn1Params)
+ {
+ if (asn1Params != null && !(asn1Params is Asn1Null))
+ {
+// AlgorithmParameters sigParams = AlgorithmParameters.GetInstance(signature.getAlgorithm());
+//
+// try
+// {
+// sigParams.init(asn1Params.ToAsn1Object().GetDerEncoded());
+// }
+// catch (IOException e)
+// {
+// throw new SignatureException("IOException decoding parameters: " + e.Message);
+// }
+
+ if (Platform.EndsWith(signature.AlgorithmName, "MGF1"))
+ {
+ throw Platform.CreateNotImplementedException("signature algorithm with MGF1");
+
+// try
+// {
+// signature.setParameter(sigParams.getParameterSpec(PSSParameterSpec.class));
+// }
+// catch (GeneralSecurityException e)
+// {
+// throw new SignatureException("Exception extracting parameters: " + e.getMessage());
+// }
+ }
+ }
+ }
+
+ internal static string GetSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ Asn1Encodable asn1Params = sigAlgId.Parameters;
+
+ if (asn1Params != null && !(asn1Params is Asn1Null))
+ {
+ if (sigAlgId.Algorithm.Equals(PkcsObjectIdentifiers.IdRsassaPss))
+ {
+ RsassaPssParameters rsaParams = RsassaPssParameters.GetInstance(asn1Params);
+ return GetDigestAlgName(rsaParams.HashAlgorithm.Algorithm) + "withRSAandMGF1";
+ }
+ }
+
+ return sigAlgId.Algorithm.Id;
+ }
+
+ private static string GetDigestAlgName(
+ DerObjectIdentifier digestAlgOID)
+ {
+ if (PkcsObjectIdentifiers.MD5.Equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OiwObjectIdentifiers.IdSha1.Equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ else if (NistObjectIdentifiers.IdSha224.Equals(digestAlgOID))
+ {
+ return "SHA224";
+ }
+ else if (NistObjectIdentifiers.IdSha256.Equals(digestAlgOID))
+ {
+ return "SHA256";
+ }
+ else if (NistObjectIdentifiers.IdSha384.Equals(digestAlgOID))
+ {
+ return "SHA384";
+ }
+ else if (NistObjectIdentifiers.IdSha512.Equals(digestAlgOID))
+ {
+ return "SHA512";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD128.Equals(digestAlgOID))
+ {
+ return "RIPEMD128";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD160.Equals(digestAlgOID))
+ {
+ return "RIPEMD160";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD256.Equals(digestAlgOID))
+ {
+ return "RIPEMD256";
+ }
+ else if (CryptoProObjectIdentifiers.GostR3411.Equals(digestAlgOID))
+ {
+ return "GOST3411";
+ }
+ else
+ {
+ return digestAlgOID.Id;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkcs/Pkcs10CertificationRequestDelaySigned.cs b/bc-sharp-crypto/src/pkcs/Pkcs10CertificationRequestDelaySigned.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ecbb4ab6222a6b5d9fa195302f12a6398cbd352e
--- /dev/null
+++ b/bc-sharp-crypto/src/pkcs/Pkcs10CertificationRequestDelaySigned.cs
@@ -0,0 +1,150 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Pkcs
+{
+ ///
+ /// A class for creating and verifying Pkcs10 Certification requests (this is an extension on ).
+ /// The requests are made using delay signing. This is useful for situations where
+ /// the private key is in another environment and not directly accessible (e.g. HSM)
+ /// So the first step creates the request, then the signing is done outside this
+ /// object and the signature is then used to complete the request.
+ ///
+ ///
+ /// CertificationRequest ::= Sequence {
+ /// certificationRequestInfo CertificationRequestInfo,
+ /// signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
+ /// signature BIT STRING
+ /// }
+ ///
+ /// CertificationRequestInfo ::= Sequence {
+ /// version Integer { v1(0) } (v1,...),
+ /// subject Name,
+ /// subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+ /// attributes [0] Attributes{{ CRIAttributes }}
+ /// }
+ ///
+ /// Attributes { ATTRIBUTE:IOSet } ::= Set OF Attr{{ IOSet }}
+ ///
+ /// Attr { ATTRIBUTE:IOSet } ::= Sequence {
+ /// type ATTRIBUTE.&id({IOSet}),
+ /// values Set SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type})
+ /// }
+ ///
+ /// see
+ public class Pkcs10CertificationRequestDelaySigned : Pkcs10CertificationRequest
+ {
+ protected Pkcs10CertificationRequestDelaySigned()
+ : base()
+ {
+ }
+ public Pkcs10CertificationRequestDelaySigned(
+ byte[] encoded)
+ : base(encoded)
+ {
+ }
+ public Pkcs10CertificationRequestDelaySigned(
+ Asn1Sequence seq)
+ : base(seq)
+ {
+ }
+ public Pkcs10CertificationRequestDelaySigned(
+ Stream input)
+ : base(input)
+ {
+ }
+ public Pkcs10CertificationRequestDelaySigned(
+ string signatureAlgorithm,
+ X509Name subject,
+ AsymmetricKeyParameter publicKey,
+ Asn1Set attributes,
+ AsymmetricKeyParameter signingKey)
+ : base(signatureAlgorithm, subject, publicKey, attributes, signingKey)
+ {
+ }
+ ///
+ /// Instantiate a Pkcs10CertificationRequest object with the necessary credentials.
+ ///
+ /// Name of Sig Alg.
+ /// X509Name of subject eg OU="My unit." O="My Organisatioin" C="au"
+ /// Public Key to be included in cert reqest.
+ /// ASN1Set of Attributes.
+ ///
+ /// After the object is constructed use the and finally the
+ /// SignRequest methods to finalize the request.
+ ///
+ public Pkcs10CertificationRequestDelaySigned(
+ string signatureAlgorithm,
+ X509Name subject,
+ AsymmetricKeyParameter publicKey,
+ Asn1Set attributes)
+ {
+ if (signatureAlgorithm == null)
+ throw new ArgumentNullException("signatureAlgorithm");
+ if (subject == null)
+ throw new ArgumentNullException("subject");
+ if (publicKey == null)
+ throw new ArgumentNullException("publicKey");
+ if (publicKey.IsPrivate)
+ throw new ArgumentException("expected public key", "publicKey");
+// DerObjectIdentifier sigOid = SignerUtilities.GetObjectIdentifier(signatureAlgorithm);
+ string algorithmName = Platform.ToUpperInvariant(signatureAlgorithm);
+ DerObjectIdentifier sigOid = (DerObjectIdentifier) algorithms[algorithmName];
+ if (sigOid == null)
+ {
+ try
+ {
+ sigOid = new DerObjectIdentifier(algorithmName);
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("Unknown signature type requested", e);
+ }
+ }
+ if (noParams.Contains(sigOid))
+ {
+ this.sigAlgId = new AlgorithmIdentifier(sigOid);
+ }
+ else if (exParams.Contains(algorithmName))
+ {
+ this.sigAlgId = new AlgorithmIdentifier(sigOid, (Asn1Encodable) exParams[algorithmName]);
+ }
+ else
+ {
+ this.sigAlgId = new AlgorithmIdentifier(sigOid, DerNull.Instance);
+ }
+ SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);
+ this.reqInfo = new CertificationRequestInfo(subject, pubInfo, attributes);
+ }
+ public byte[] GetDataToSign()
+ {
+ return reqInfo.GetDerEncoded();
+ }
+ public void SignRequest(byte[] signedData)
+ {
+ //build the signature from the signed data
+ sigBits = new DerBitString(signedData);
+ }
+ public void SignRequest(DerBitString signedData)
+ {
+ //build the signature from the signed data
+ sigBits = signedData;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkcs/Pkcs12Entry.cs b/bc-sharp-crypto/src/pkcs/Pkcs12Entry.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5dcc94e88b3f3708b99666718cc0f8b0ae9ab1bc
--- /dev/null
+++ b/bc-sharp-crypto/src/pkcs/Pkcs12Entry.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Pkcs
+{
+ public abstract class Pkcs12Entry
+ {
+ private readonly IDictionary attributes;
+
+ protected internal Pkcs12Entry(
+ IDictionary attributes)
+ {
+ this.attributes = attributes;
+
+ foreach (DictionaryEntry entry in attributes)
+ {
+ if (!(entry.Key is string))
+ throw new ArgumentException("Attribute keys must be of type: " + typeof(string).FullName, "attributes");
+ if (!(entry.Value is Asn1Encodable))
+ throw new ArgumentException("Attribute values must be of type: " + typeof(Asn1Encodable).FullName, "attributes");
+ }
+ }
+
+ [Obsolete("Use 'object[index]' syntax instead")]
+ public Asn1Encodable GetBagAttribute(
+ DerObjectIdentifier oid)
+ {
+ return (Asn1Encodable)this.attributes[oid.Id];
+ }
+
+ [Obsolete("Use 'object[index]' syntax instead")]
+ public Asn1Encodable GetBagAttribute(
+ string oid)
+ {
+ return (Asn1Encodable)this.attributes[oid];
+ }
+
+ [Obsolete("Use 'BagAttributeKeys' property")]
+ public IEnumerator GetBagAttributeKeys()
+ {
+ return this.attributes.Keys.GetEnumerator();
+ }
+
+ public Asn1Encodable this[
+ DerObjectIdentifier oid]
+ {
+ get { return (Asn1Encodable) this.attributes[oid.Id]; }
+ }
+
+ public Asn1Encodable this[
+ string oid]
+ {
+ get { return (Asn1Encodable) this.attributes[oid]; }
+ }
+
+ public IEnumerable BagAttributeKeys
+ {
+ get { return new EnumerableProxy(this.attributes.Keys); }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkcs/Pkcs12Store.cs b/bc-sharp-crypto/src/pkcs/Pkcs12Store.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e65788733d09e34b4457fa6da6714447895c1b84
--- /dev/null
+++ b/bc-sharp-crypto/src/pkcs/Pkcs12Store.cs
@@ -0,0 +1,1100 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Pkcs
+{
+ public class Pkcs12Store
+ {
+ private readonly IgnoresCaseHashtable keys = new IgnoresCaseHashtable();
+ private readonly IDictionary localIds = Platform.CreateHashtable();
+ private readonly IgnoresCaseHashtable certs = new IgnoresCaseHashtable();
+ private readonly IDictionary chainCerts = Platform.CreateHashtable();
+ private readonly IDictionary keyCerts = Platform.CreateHashtable();
+ private readonly DerObjectIdentifier keyAlgorithm;
+ private readonly DerObjectIdentifier certAlgorithm;
+ private readonly bool useDerEncoding;
+
+ private AsymmetricKeyEntry unmarkedKeyEntry = null;
+
+ private const int MinIterations = 1024;
+ private const int SaltSize = 20;
+
+ private static SubjectKeyIdentifier CreateSubjectKeyID(
+ AsymmetricKeyParameter pubKey)
+ {
+ return new SubjectKeyIdentifier(
+ SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey));
+ }
+
+ internal class CertId
+ {
+ private readonly byte[] id;
+
+ internal CertId(
+ AsymmetricKeyParameter pubKey)
+ {
+ this.id = CreateSubjectKeyID(pubKey).GetKeyIdentifier();
+ }
+
+ internal CertId(
+ byte[] id)
+ {
+ this.id = id;
+ }
+
+ internal byte[] Id
+ {
+ get { return id; }
+ }
+
+ public override int GetHashCode()
+ {
+ return Arrays.GetHashCode(id);
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ CertId other = obj as CertId;
+
+ if (other == null)
+ return false;
+
+ return Arrays.AreEqual(id, other.id);
+ }
+ }
+
+ internal Pkcs12Store(
+ DerObjectIdentifier keyAlgorithm,
+ DerObjectIdentifier certAlgorithm,
+ bool useDerEncoding)
+ {
+ this.keyAlgorithm = keyAlgorithm;
+ this.certAlgorithm = certAlgorithm;
+ this.useDerEncoding = useDerEncoding;
+ }
+
+ // TODO Consider making obsolete
+// [Obsolete("Use 'Pkcs12StoreBuilder' instead")]
+ public Pkcs12Store()
+ : this(PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc,
+ PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc, false)
+ {
+ }
+
+ // TODO Consider making obsolete
+// [Obsolete("Use 'Pkcs12StoreBuilder' and 'Load' method instead")]
+ public Pkcs12Store(
+ Stream input,
+ char[] password)
+ : this()
+ {
+ Load(input, password);
+ }
+
+ protected virtual void LoadKeyBag(PrivateKeyInfo privKeyInfo, Asn1Set bagAttributes)
+ {
+ AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privKeyInfo);
+
+ IDictionary attributes = Platform.CreateHashtable();
+ AsymmetricKeyEntry keyEntry = new AsymmetricKeyEntry(privKey, attributes);
+
+ string alias = null;
+ Asn1OctetString localId = null;
+
+ if (bagAttributes != null)
+ {
+ foreach (Asn1Sequence sq in bagAttributes)
+ {
+ DerObjectIdentifier aOid = DerObjectIdentifier.GetInstance(sq[0]);
+ Asn1Set attrSet = Asn1Set.GetInstance(sq[1]);
+ Asn1Encodable attr = null;
+
+ if (attrSet.Count > 0)
+ {
+ // TODO We should be adding all attributes in the set
+ attr = attrSet[0];
+
+ // TODO We might want to "merge" attribute sets with
+ // the same OID - currently, differing values give an error
+ if (attributes.Contains(aOid.Id))
+ {
+ // OK, but the value has to be the same
+ if (!attributes[aOid.Id].Equals(attr))
+ throw new IOException("attempt to add existing attribute with different value");
+ }
+ else
+ {
+ attributes.Add(aOid.Id, attr);
+ }
+
+ if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
+ {
+ alias = ((DerBmpString)attr).GetString();
+ // TODO Do these in a separate loop, just collect aliases here
+ keys[alias] = keyEntry;
+ }
+ else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
+ {
+ localId = (Asn1OctetString)attr;
+ }
+ }
+ }
+ }
+
+ if (localId != null)
+ {
+ string name = Hex.ToHexString(localId.GetOctets());
+
+ if (alias == null)
+ {
+ keys[name] = keyEntry;
+ }
+ else
+ {
+ // TODO There may have been more than one alias
+ localIds[alias] = name;
+ }
+ }
+ else
+ {
+ unmarkedKeyEntry = keyEntry;
+ }
+ }
+
+ protected virtual void LoadPkcs8ShroudedKeyBag(EncryptedPrivateKeyInfo encPrivKeyInfo, Asn1Set bagAttributes,
+ char[] password, bool wrongPkcs12Zero)
+ {
+ if (password != null)
+ {
+ PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(
+ password, wrongPkcs12Zero, encPrivKeyInfo);
+
+ LoadKeyBag(privInfo, bagAttributes);
+ }
+ }
+
+ public void Load(
+ Stream input,
+ char[] password)
+ {
+ if (input == null)
+ throw new ArgumentNullException("input");
+
+ Asn1Sequence obj = (Asn1Sequence) Asn1Object.FromStream(input);
+ Pfx bag = new Pfx(obj);
+ ContentInfo info = bag.AuthSafe;
+ bool wrongPkcs12Zero = false;
+
+ if (password != null && bag.MacData != null) // check the mac code
+ {
+ MacData mData = bag.MacData;
+ DigestInfo dInfo = mData.Mac;
+ AlgorithmIdentifier algId = dInfo.AlgorithmID;
+ byte[] salt = mData.GetSalt();
+ int itCount = mData.IterationCount.IntValue;
+
+ byte[] data = ((Asn1OctetString) info.Content).GetOctets();
+
+ byte[] mac = CalculatePbeMac(algId.Algorithm, salt, itCount, password, false, data);
+ byte[] dig = dInfo.GetDigest();
+
+ if (!Arrays.ConstantTimeAreEqual(mac, dig))
+ {
+ if (password.Length > 0)
+ throw new IOException("PKCS12 key store MAC invalid - wrong password or corrupted file.");
+
+ // Try with incorrect zero length password
+ mac = CalculatePbeMac(algId.Algorithm, salt, itCount, password, true, data);
+
+ if (!Arrays.ConstantTimeAreEqual(mac, dig))
+ throw new IOException("PKCS12 key store MAC invalid - wrong password or corrupted file.");
+
+ wrongPkcs12Zero = true;
+ }
+ }
+
+ keys.Clear();
+ localIds.Clear();
+ unmarkedKeyEntry = null;
+
+ IList certBags = Platform.CreateArrayList();
+
+ if (info.ContentType.Equals(PkcsObjectIdentifiers.Data))
+ {
+ byte[] octs = ((Asn1OctetString)info.Content).GetOctets();
+ AuthenticatedSafe authSafe = new AuthenticatedSafe(
+ (Asn1Sequence) Asn1OctetString.FromByteArray(octs));
+ ContentInfo[] cis = authSafe.GetContentInfo();
+
+ foreach (ContentInfo ci in cis)
+ {
+ DerObjectIdentifier oid = ci.ContentType;
+
+ byte[] octets = null;
+ if (oid.Equals(PkcsObjectIdentifiers.Data))
+ {
+ octets = ((Asn1OctetString)ci.Content).GetOctets();
+ }
+ else if (oid.Equals(PkcsObjectIdentifiers.EncryptedData))
+ {
+ if (password != null)
+ {
+ EncryptedData d = EncryptedData.GetInstance(ci.Content);
+ octets = CryptPbeData(false, d.EncryptionAlgorithm,
+ password, wrongPkcs12Zero, d.Content.GetOctets());
+ }
+ }
+ else
+ {
+ // TODO Other data types
+ }
+
+ if (octets != null)
+ {
+ Asn1Sequence seq = (Asn1Sequence)Asn1Object.FromByteArray(octets);
+
+ foreach (Asn1Sequence subSeq in seq)
+ {
+ SafeBag b = new SafeBag(subSeq);
+
+ if (b.BagID.Equals(PkcsObjectIdentifiers.CertBag))
+ {
+ certBags.Add(b);
+ }
+ else if (b.BagID.Equals(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag))
+ {
+ LoadPkcs8ShroudedKeyBag(EncryptedPrivateKeyInfo.GetInstance(b.BagValue),
+ b.BagAttributes, password, wrongPkcs12Zero);
+ }
+ else if (b.BagID.Equals(PkcsObjectIdentifiers.KeyBag))
+ {
+ LoadKeyBag(PrivateKeyInfo.GetInstance(b.BagValue), b.BagAttributes);
+ }
+ else
+ {
+ // TODO Other bag types
+ }
+ }
+ }
+ }
+ }
+
+ certs.Clear();
+ chainCerts.Clear();
+ keyCerts.Clear();
+
+ foreach (SafeBag b in certBags)
+ {
+ CertBag certBag = new CertBag((Asn1Sequence)b.BagValue);
+ byte[] octets = ((Asn1OctetString)certBag.CertValue).GetOctets();
+ X509Certificate cert = new X509CertificateParser().ReadCertificate(octets);
+
+ //
+ // set the attributes
+ //
+ IDictionary attributes = Platform.CreateHashtable();
+ Asn1OctetString localId = null;
+ string alias = null;
+
+ if (b.BagAttributes != null)
+ {
+ foreach (Asn1Sequence sq in b.BagAttributes)
+ {
+ DerObjectIdentifier aOid = DerObjectIdentifier.GetInstance(sq[0]);
+ Asn1Set attrSet = Asn1Set.GetInstance(sq[1]);
+
+ if (attrSet.Count > 0)
+ {
+ // TODO We should be adding all attributes in the set
+ Asn1Encodable attr = attrSet[0];
+
+ // TODO We might want to "merge" attribute sets with
+ // the same OID - currently, differing values give an error
+ if (attributes.Contains(aOid.Id))
+ {
+ // OK, but the value has to be the same
+ if (!attributes[aOid.Id].Equals(attr))
+ {
+ throw new IOException("attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ attributes.Add(aOid.Id, attr);
+ }
+
+ if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
+ {
+ alias = ((DerBmpString)attr).GetString();
+ }
+ else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
+ {
+ localId = (Asn1OctetString)attr;
+ }
+ }
+ }
+ }
+
+ CertId certId = new CertId(cert.GetPublicKey());
+ X509CertificateEntry certEntry = new X509CertificateEntry(cert, attributes);
+
+ chainCerts[certId] = certEntry;
+
+ if (unmarkedKeyEntry != null)
+ {
+ if (keyCerts.Count == 0)
+ {
+ string name = Hex.ToHexString(certId.Id);
+
+ keyCerts[name] = certEntry;
+ keys[name] = unmarkedKeyEntry;
+ }
+ }
+ else
+ {
+ if (localId != null)
+ {
+ string name = Hex.ToHexString(localId.GetOctets());
+
+ keyCerts[name] = certEntry;
+ }
+
+ if (alias != null)
+ {
+ // TODO There may have been more than one alias
+ certs[alias] = certEntry;
+ }
+ }
+ }
+ }
+
+ public AsymmetricKeyEntry GetKey(
+ string alias)
+ {
+ if (alias == null)
+ throw new ArgumentNullException("alias");
+
+ return (AsymmetricKeyEntry)keys[alias];
+ }
+
+ public bool IsCertificateEntry(
+ string alias)
+ {
+ if (alias == null)
+ throw new ArgumentNullException("alias");
+
+ return (certs[alias] != null && keys[alias] == null);
+ }
+
+ public bool IsKeyEntry(
+ string alias)
+ {
+ if (alias == null)
+ throw new ArgumentNullException("alias");
+
+ return (keys[alias] != null);
+ }
+
+ private IDictionary GetAliasesTable()
+ {
+ IDictionary tab = Platform.CreateHashtable();
+
+ foreach (string key in certs.Keys)
+ {
+ tab[key] = "cert";
+ }
+
+ foreach (string a in keys.Keys)
+ {
+ if (tab[a] == null)
+ {
+ tab[a] = "key";
+ }
+ }
+
+ return tab;
+ }
+
+ public IEnumerable Aliases
+ {
+ get { return new EnumerableProxy(GetAliasesTable().Keys); }
+ }
+
+ public bool ContainsAlias(
+ string alias)
+ {
+ return certs[alias] != null || keys[alias] != null;
+ }
+
+ /**
+ * simply return the cert entry for the private key
+ */
+ public X509CertificateEntry GetCertificate(
+ string alias)
+ {
+ if (alias == null)
+ throw new ArgumentNullException("alias");
+
+ X509CertificateEntry c = (X509CertificateEntry) certs[alias];
+
+ //
+ // look up the key table - and try the local key id
+ //
+ if (c == null)
+ {
+ string id = (string)localIds[alias];
+ if (id != null)
+ {
+ c = (X509CertificateEntry)keyCerts[id];
+ }
+ else
+ {
+ c = (X509CertificateEntry)keyCerts[alias];
+ }
+ }
+
+ return c;
+ }
+
+ public string GetCertificateAlias(
+ X509Certificate cert)
+ {
+ if (cert == null)
+ throw new ArgumentNullException("cert");
+
+ foreach (DictionaryEntry entry in certs)
+ {
+ X509CertificateEntry entryValue = (X509CertificateEntry) entry.Value;
+ if (entryValue.Certificate.Equals(cert))
+ {
+ return (string) entry.Key;
+ }
+ }
+
+ foreach (DictionaryEntry entry in keyCerts)
+ {
+ X509CertificateEntry entryValue = (X509CertificateEntry) entry.Value;
+ if (entryValue.Certificate.Equals(cert))
+ {
+ return (string) entry.Key;
+ }
+ }
+
+ return null;
+ }
+
+ public X509CertificateEntry[] GetCertificateChain(
+ string alias)
+ {
+ if (alias == null)
+ throw new ArgumentNullException("alias");
+
+ if (!IsKeyEntry(alias))
+ {
+ return null;
+ }
+
+ X509CertificateEntry c = GetCertificate(alias);
+
+ if (c != null)
+ {
+ IList cs = Platform.CreateArrayList();
+
+ while (c != null)
+ {
+ X509Certificate x509c = c.Certificate;
+ X509CertificateEntry nextC = null;
+
+ Asn1OctetString ext = x509c.GetExtensionValue(X509Extensions.AuthorityKeyIdentifier);
+ if (ext != null)
+ {
+ AuthorityKeyIdentifier id = AuthorityKeyIdentifier.GetInstance(
+ Asn1Object.FromByteArray(ext.GetOctets()));
+
+ if (id.GetKeyIdentifier() != null)
+ {
+ nextC = (X509CertificateEntry) chainCerts[new CertId(id.GetKeyIdentifier())];
+ }
+ }
+
+ if (nextC == null)
+ {
+ //
+ // no authority key id, try the Issuer DN
+ //
+ X509Name i = x509c.IssuerDN;
+ X509Name s = x509c.SubjectDN;
+
+ if (!i.Equivalent(s))
+ {
+ foreach (CertId certId in chainCerts.Keys)
+ {
+ X509CertificateEntry x509CertEntry = (X509CertificateEntry) chainCerts[certId];
+
+ X509Certificate crt = x509CertEntry.Certificate;
+
+ X509Name sub = crt.SubjectDN;
+ if (sub.Equivalent(i))
+ {
+ try
+ {
+ x509c.Verify(crt.GetPublicKey());
+
+ nextC = x509CertEntry;
+ break;
+ }
+ catch (InvalidKeyException)
+ {
+ // TODO What if it doesn't verify?
+ }
+ }
+ }
+ }
+ }
+
+ cs.Add(c);
+ if (nextC != c) // self signed - end of the chain
+ {
+ c = nextC;
+ }
+ else
+ {
+ c = null;
+ }
+ }
+
+ X509CertificateEntry[] result = new X509CertificateEntry[cs.Count];
+ for (int i = 0; i < cs.Count; ++i)
+ {
+ result[i] = (X509CertificateEntry)cs[i];
+ }
+ return result;
+ }
+
+ return null;
+ }
+
+ public void SetCertificateEntry(
+ string alias,
+ X509CertificateEntry certEntry)
+ {
+ if (alias == null)
+ throw new ArgumentNullException("alias");
+ if (certEntry == null)
+ throw new ArgumentNullException("certEntry");
+ if (keys[alias] != null)
+ throw new ArgumentException("There is a key entry with the name " + alias + ".");
+
+ certs[alias] = certEntry;
+ chainCerts[new CertId(certEntry.Certificate.GetPublicKey())] = certEntry;
+ }
+
+ public void SetKeyEntry(
+ string alias,
+ AsymmetricKeyEntry keyEntry,
+ X509CertificateEntry[] chain)
+ {
+ if (alias == null)
+ throw new ArgumentNullException("alias");
+ if (keyEntry == null)
+ throw new ArgumentNullException("keyEntry");
+ if (keyEntry.Key.IsPrivate && (chain == null))
+ throw new ArgumentException("No certificate chain for private key");
+
+ if (keys[alias] != null)
+ {
+ DeleteEntry(alias);
+ }
+
+ keys[alias] = keyEntry;
+ certs[alias] = chain[0];
+
+ for (int i = 0; i != chain.Length; i++)
+ {
+ chainCerts[new CertId(chain[i].Certificate.GetPublicKey())] = chain[i];
+ }
+ }
+
+ public void DeleteEntry(
+ string alias)
+ {
+ if (alias == null)
+ throw new ArgumentNullException("alias");
+
+ AsymmetricKeyEntry k = (AsymmetricKeyEntry)keys[alias];
+ if (k != null)
+ {
+ keys.Remove(alias);
+ }
+
+ X509CertificateEntry c = (X509CertificateEntry)certs[alias];
+
+ if (c != null)
+ {
+ certs.Remove(alias);
+ chainCerts.Remove(new CertId(c.Certificate.GetPublicKey()));
+ }
+
+ if (k != null)
+ {
+ string id = (string)localIds[alias];
+ if (id != null)
+ {
+ localIds.Remove(alias);
+ c = (X509CertificateEntry)keyCerts[id];
+ }
+ if (c != null)
+ {
+ keyCerts.Remove(id);
+ chainCerts.Remove(new CertId(c.Certificate.GetPublicKey()));
+ }
+ }
+
+ if (c == null && k == null)
+ {
+ throw new ArgumentException("no such entry as " + alias);
+ }
+ }
+
+ public bool IsEntryOfType(
+ string alias,
+ Type entryType)
+ {
+ if (entryType == typeof(X509CertificateEntry))
+ return IsCertificateEntry(alias);
+
+ if (entryType == typeof(AsymmetricKeyEntry))
+ return IsKeyEntry(alias) && GetCertificate(alias) != null;
+
+ return false;
+ }
+
+ [Obsolete("Use 'Count' property instead")]
+ public int Size()
+ {
+ return Count;
+ }
+
+ public int Count
+ {
+ // TODO Seems a little inefficient
+ get { return GetAliasesTable().Count; }
+ }
+
+ public void Save(
+ Stream stream,
+ char[] password,
+ SecureRandom random)
+ {
+ if (stream == null)
+ throw new ArgumentNullException("stream");
+ if (random == null)
+ throw new ArgumentNullException("random");
+
+ //
+ // handle the keys
+ //
+ Asn1EncodableVector keyBags = new Asn1EncodableVector();
+ foreach (string name in keys.Keys)
+ {
+ byte[] kSalt = new byte[SaltSize];
+ random.NextBytes(kSalt);
+
+ AsymmetricKeyEntry privKey = (AsymmetricKeyEntry)keys[name];
+
+ DerObjectIdentifier bagOid;
+ Asn1Encodable bagData;
+
+ if (password == null)
+ {
+ bagOid = PkcsObjectIdentifiers.KeyBag;
+ bagData = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privKey.Key);
+ }
+ else
+ {
+ bagOid = PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag;
+ bagData = EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
+ keyAlgorithm, password, kSalt, MinIterations, privKey.Key);
+ }
+
+ Asn1EncodableVector kName = new Asn1EncodableVector();
+
+ foreach (string oid in privKey.BagAttributeKeys)
+ {
+ Asn1Encodable entry = privKey[oid];
+
+ // NB: Ignore any existing FriendlyName
+ if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id))
+ continue;
+
+ kName.Add(
+ new DerSequence(
+ new DerObjectIdentifier(oid),
+ new DerSet(entry)));
+ }
+
+ //
+ // make sure we are using the local alias on store
+ //
+ // NB: We always set the FriendlyName based on 'name'
+ //if (privKey[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] == null)
+ {
+ kName.Add(
+ new DerSequence(
+ PkcsObjectIdentifiers.Pkcs9AtFriendlyName,
+ new DerSet(new DerBmpString(name))));
+ }
+
+ //
+ // make sure we have a local key-id
+ //
+ if (privKey[PkcsObjectIdentifiers.Pkcs9AtLocalKeyID] == null)
+ {
+ X509CertificateEntry ct = GetCertificate(name);
+ AsymmetricKeyParameter pubKey = ct.Certificate.GetPublicKey();
+ SubjectKeyIdentifier subjectKeyID = CreateSubjectKeyID(pubKey);
+
+ kName.Add(
+ new DerSequence(
+ PkcsObjectIdentifiers.Pkcs9AtLocalKeyID,
+ new DerSet(subjectKeyID)));
+ }
+
+ keyBags.Add(new SafeBag(bagOid, bagData.ToAsn1Object(), new DerSet(kName)));
+ }
+
+ byte[] keyBagsEncoding = new DerSequence(keyBags).GetDerEncoded();
+ ContentInfo keysInfo = new ContentInfo(PkcsObjectIdentifiers.Data, new BerOctetString(keyBagsEncoding));
+
+ //
+ // certificate processing
+ //
+ byte[] cSalt = new byte[SaltSize];
+
+ random.NextBytes(cSalt);
+
+ Asn1EncodableVector certBags = new Asn1EncodableVector();
+ Pkcs12PbeParams cParams = new Pkcs12PbeParams(cSalt, MinIterations);
+ AlgorithmIdentifier cAlgId = new AlgorithmIdentifier(certAlgorithm, cParams.ToAsn1Object());
+ ISet doneCerts = new HashSet();
+
+ foreach (string name in keys.Keys)
+ {
+ X509CertificateEntry certEntry = GetCertificate(name);
+ CertBag cBag = new CertBag(
+ PkcsObjectIdentifiers.X509Certificate,
+ new DerOctetString(certEntry.Certificate.GetEncoded()));
+
+ Asn1EncodableVector fName = new Asn1EncodableVector();
+
+ foreach (string oid in certEntry.BagAttributeKeys)
+ {
+ Asn1Encodable entry = certEntry[oid];
+
+ // NB: Ignore any existing FriendlyName
+ if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id))
+ continue;
+
+ fName.Add(
+ new DerSequence(
+ new DerObjectIdentifier(oid),
+ new DerSet(entry)));
+ }
+
+ //
+ // make sure we are using the local alias on store
+ //
+ // NB: We always set the FriendlyName based on 'name'
+ //if (certEntry[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] == null)
+ {
+ fName.Add(
+ new DerSequence(
+ PkcsObjectIdentifiers.Pkcs9AtFriendlyName,
+ new DerSet(new DerBmpString(name))));
+ }
+
+ //
+ // make sure we have a local key-id
+ //
+ if (certEntry[PkcsObjectIdentifiers.Pkcs9AtLocalKeyID] == null)
+ {
+ AsymmetricKeyParameter pubKey = certEntry.Certificate.GetPublicKey();
+ SubjectKeyIdentifier subjectKeyID = CreateSubjectKeyID(pubKey);
+
+ fName.Add(
+ new DerSequence(
+ PkcsObjectIdentifiers.Pkcs9AtLocalKeyID,
+ new DerSet(subjectKeyID)));
+ }
+
+ certBags.Add(new SafeBag(PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName)));
+
+ doneCerts.Add(certEntry.Certificate);
+ }
+
+ foreach (string certId in certs.Keys)
+ {
+ X509CertificateEntry cert = (X509CertificateEntry)certs[certId];
+
+ if (keys[certId] != null)
+ continue;
+
+ CertBag cBag = new CertBag(
+ PkcsObjectIdentifiers.X509Certificate,
+ new DerOctetString(cert.Certificate.GetEncoded()));
+
+ Asn1EncodableVector fName = new Asn1EncodableVector();
+
+ foreach (string oid in cert.BagAttributeKeys)
+ {
+ // a certificate not immediately linked to a key doesn't require
+ // a localKeyID and will confuse some PKCS12 implementations.
+ //
+ // If we find one, we'll prune it out.
+ if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID.Id))
+ continue;
+
+ Asn1Encodable entry = cert[oid];
+
+ // NB: Ignore any existing FriendlyName
+ if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id))
+ continue;
+
+ fName.Add(
+ new DerSequence(
+ new DerObjectIdentifier(oid),
+ new DerSet(entry)));
+ }
+
+ //
+ // make sure we are using the local alias on store
+ //
+ // NB: We always set the FriendlyName based on 'certId'
+ //if (cert[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] == null)
+ {
+ fName.Add(
+ new DerSequence(
+ PkcsObjectIdentifiers.Pkcs9AtFriendlyName,
+ new DerSet(new DerBmpString(certId))));
+ }
+
+ certBags.Add(new SafeBag(PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName)));
+
+ doneCerts.Add(cert.Certificate);
+ }
+
+ foreach (CertId certId in chainCerts.Keys)
+ {
+ X509CertificateEntry cert = (X509CertificateEntry)chainCerts[certId];
+
+ if (doneCerts.Contains(cert.Certificate))
+ continue;
+
+ CertBag cBag = new CertBag(
+ PkcsObjectIdentifiers.X509Certificate,
+ new DerOctetString(cert.Certificate.GetEncoded()));
+
+ Asn1EncodableVector fName = new Asn1EncodableVector();
+
+ foreach (string oid in cert.BagAttributeKeys)
+ {
+ // a certificate not immediately linked to a key doesn't require
+ // a localKeyID and will confuse some PKCS12 implementations.
+ //
+ // If we find one, we'll prune it out.
+ if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID.Id))
+ continue;
+
+ fName.Add(
+ new DerSequence(
+ new DerObjectIdentifier(oid),
+ new DerSet(cert[oid])));
+ }
+
+ certBags.Add(new SafeBag(PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName)));
+ }
+
+ byte[] certBagsEncoding = new DerSequence(certBags).GetDerEncoded();
+
+ ContentInfo certsInfo;
+ if (password == null)
+ {
+ certsInfo = new ContentInfo(PkcsObjectIdentifiers.Data, new BerOctetString(certBagsEncoding));
+ }
+ else
+ {
+ byte[] certBytes = CryptPbeData(true, cAlgId, password, false, certBagsEncoding);
+ EncryptedData cInfo = new EncryptedData(PkcsObjectIdentifiers.Data, cAlgId, new BerOctetString(certBytes));
+ certsInfo = new ContentInfo(PkcsObjectIdentifiers.EncryptedData, cInfo.ToAsn1Object());
+ }
+
+ ContentInfo[] info = new ContentInfo[]{ keysInfo, certsInfo };
+
+ byte[] data = new AuthenticatedSafe(info).GetEncoded(
+ useDerEncoding ? Asn1Encodable.Der : Asn1Encodable.Ber);
+
+ ContentInfo mainInfo = new ContentInfo(PkcsObjectIdentifiers.Data, new BerOctetString(data));
+
+ //
+ // create the mac
+ //
+ MacData macData = null;
+ if (password != null)
+ {
+ byte[] mSalt = new byte[20];
+ random.NextBytes(mSalt);
+
+ byte[] mac = CalculatePbeMac(OiwObjectIdentifiers.IdSha1,
+ mSalt, MinIterations, password, false, data);
+
+ AlgorithmIdentifier algId = new AlgorithmIdentifier(
+ OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+ DigestInfo dInfo = new DigestInfo(algId, mac);
+
+ macData = new MacData(dInfo, mSalt, MinIterations);
+ }
+
+ //
+ // output the Pfx
+ //
+ Pfx pfx = new Pfx(mainInfo, macData);
+
+ DerOutputStream derOut;
+ if (useDerEncoding)
+ {
+ derOut = new DerOutputStream(stream);
+ }
+ else
+ {
+ derOut = new BerOutputStream(stream);
+ }
+
+ derOut.WriteObject(pfx);
+ }
+
+ internal static byte[] CalculatePbeMac(
+ DerObjectIdentifier oid,
+ byte[] salt,
+ int itCount,
+ char[] password,
+ bool wrongPkcs12Zero,
+ byte[] data)
+ {
+ Asn1Encodable asn1Params = PbeUtilities.GenerateAlgorithmParameters(
+ oid, salt, itCount);
+ ICipherParameters cipherParams = PbeUtilities.GenerateCipherParameters(
+ oid, password, wrongPkcs12Zero, asn1Params);
+
+ IMac mac = (IMac) PbeUtilities.CreateEngine(oid);
+ mac.Init(cipherParams);
+ return MacUtilities.DoFinal(mac, data);
+ }
+
+ private static byte[] CryptPbeData(
+ bool forEncryption,
+ AlgorithmIdentifier algId,
+ char[] password,
+ bool wrongPkcs12Zero,
+ byte[] data)
+ {
+ IBufferedCipher cipher = PbeUtilities.CreateEngine(algId.Algorithm) as IBufferedCipher;
+
+ if (cipher == null)
+ throw new Exception("Unknown encryption algorithm: " + algId.Algorithm);
+
+ Pkcs12PbeParams pbeParameters = Pkcs12PbeParams.GetInstance(algId.Parameters);
+ ICipherParameters cipherParams = PbeUtilities.GenerateCipherParameters(
+ algId.Algorithm, password, wrongPkcs12Zero, pbeParameters);
+ cipher.Init(forEncryption, cipherParams);
+ return cipher.DoFinal(data);
+ }
+
+ private class IgnoresCaseHashtable
+ : IEnumerable
+ {
+ private readonly IDictionary orig = Platform.CreateHashtable();
+ private readonly IDictionary keys = Platform.CreateHashtable();
+
+ public void Clear()
+ {
+ orig.Clear();
+ keys.Clear();
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return orig.GetEnumerator();
+ }
+
+ public ICollection Keys
+ {
+ get { return orig.Keys; }
+ }
+
+ public object Remove(
+ string alias)
+ {
+ string upper = Platform.ToUpperInvariant(alias);
+ string k = (string)keys[upper];
+
+ if (k == null)
+ return null;
+
+ keys.Remove(upper);
+
+ object o = orig[k];
+ orig.Remove(k);
+ return o;
+ }
+
+ public object this[
+ string alias]
+ {
+ get
+ {
+ string upper = Platform.ToUpperInvariant(alias);
+ string k = (string)keys[upper];
+
+ if (k == null)
+ return null;
+
+ return orig[k];
+ }
+ set
+ {
+ string upper = Platform.ToUpperInvariant(alias);
+ string k = (string)keys[upper];
+ if (k != null)
+ {
+ orig.Remove(k);
+ }
+ keys[upper] = alias;
+ orig[alias] = value;
+ }
+ }
+
+ public ICollection Values
+ {
+ get { return orig.Values; }
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkcs/Pkcs12Utilities.cs b/bc-sharp-crypto/src/pkcs/Pkcs12Utilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..923eca5a55e614686f787dc76ab61ba166361a57
--- /dev/null
+++ b/bc-sharp-crypto/src/pkcs/Pkcs12Utilities.cs
@@ -0,0 +1,77 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Pkcs
+{
+ /**
+ * Utility class for reencoding PKCS#12 files to definite length.
+ */
+ public class Pkcs12Utilities
+ {
+ /**
+ * Just re-encode the outer layer of the PKCS#12 file to definite length encoding.
+ *
+ * @param berPKCS12File - original PKCS#12 file
+ * @return a byte array representing the DER encoding of the PFX structure
+ * @throws IOException
+ */
+ public static byte[] ConvertToDefiniteLength(
+ byte[] berPkcs12File)
+ {
+ Pfx pfx = new Pfx(Asn1Sequence.GetInstance(Asn1Object.FromByteArray(berPkcs12File)));
+
+ return pfx.GetEncoded(Asn1Encodable.Der);
+ }
+
+ /**
+ * Re-encode the PKCS#12 structure to definite length encoding at the inner layer
+ * as well, recomputing the MAC accordingly.
+ *
+ * @param berPKCS12File - original PKCS12 file.
+ * @param provider - provider to use for MAC calculation.
+ * @return a byte array representing the DER encoding of the PFX structure.
+ * @throws IOException on parsing, encoding errors.
+ */
+ public static byte[] ConvertToDefiniteLength(
+ byte[] berPkcs12File,
+ char[] passwd)
+ {
+ Pfx pfx = new Pfx(Asn1Sequence.GetInstance(Asn1Object.FromByteArray(berPkcs12File)));
+
+ ContentInfo info = pfx.AuthSafe;
+
+ Asn1OctetString content = Asn1OctetString.GetInstance(info.Content);
+ Asn1Object obj = Asn1Object.FromByteArray(content.GetOctets());
+
+ info = new ContentInfo(info.ContentType, new DerOctetString(obj.GetEncoded(Asn1Encodable.Der)));
+
+ MacData mData = pfx.MacData;
+
+ try
+ {
+ int itCount = mData.IterationCount.IntValue;
+ byte[] data = Asn1OctetString.GetInstance(info.Content).GetOctets();
+ byte[] res = Pkcs12Store.CalculatePbeMac(
+ mData.Mac.AlgorithmID.Algorithm, mData.GetSalt(), itCount, passwd, false, data);
+
+ AlgorithmIdentifier algId = new AlgorithmIdentifier(
+ mData.Mac.AlgorithmID.Algorithm, DerNull.Instance);
+ DigestInfo dInfo = new DigestInfo(algId, res);
+
+ mData = new MacData(dInfo, mData.GetSalt(), itCount);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error constructing MAC: " + e.ToString());
+ }
+
+ pfx = new Pfx(info, mData);
+
+ return pfx.GetEncoded(Asn1Encodable.Der);
+ }
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/pkcs/PrivateKeyInfoFactory.cs b/bc-sharp-crypto/src/pkcs/PrivateKeyInfoFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a349a11d2a8a91d756aaf90a2ca9f57d8f88a6e5
--- /dev/null
+++ b/bc-sharp-crypto/src/pkcs/PrivateKeyInfoFactory.cs
@@ -0,0 +1,205 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Pkcs
+{
+ public sealed class PrivateKeyInfoFactory
+ {
+ private PrivateKeyInfoFactory()
+ {
+ }
+
+ public static PrivateKeyInfo CreatePrivateKeyInfo(
+ AsymmetricKeyParameter key)
+ {
+ if (key == null)
+ throw new ArgumentNullException("key");
+ if (!key.IsPrivate)
+ throw new ArgumentException("Public key passed - private key expected", "key");
+
+ if (key is ElGamalPrivateKeyParameters)
+ {
+ ElGamalPrivateKeyParameters _key = (ElGamalPrivateKeyParameters)key;
+ return new PrivateKeyInfo(
+ new AlgorithmIdentifier(
+ OiwObjectIdentifiers.ElGamalAlgorithm,
+ new ElGamalParameter(
+ _key.Parameters.P,
+ _key.Parameters.G).ToAsn1Object()),
+ new DerInteger(_key.X));
+ }
+
+ if (key is DsaPrivateKeyParameters)
+ {
+ DsaPrivateKeyParameters _key = (DsaPrivateKeyParameters)key;
+ return new PrivateKeyInfo(
+ new AlgorithmIdentifier(
+ X9ObjectIdentifiers.IdDsa,
+ new DsaParameter(
+ _key.Parameters.P,
+ _key.Parameters.Q,
+ _key.Parameters.G).ToAsn1Object()),
+ new DerInteger(_key.X));
+ }
+
+ if (key is DHPrivateKeyParameters)
+ {
+ DHPrivateKeyParameters _key = (DHPrivateKeyParameters)key;
+
+ DHParameter p = new DHParameter(
+ _key.Parameters.P, _key.Parameters.G, _key.Parameters.L);
+
+ return new PrivateKeyInfo(
+ new AlgorithmIdentifier(_key.AlgorithmOid, p.ToAsn1Object()),
+ new DerInteger(_key.X));
+ }
+
+ if (key is RsaKeyParameters)
+ {
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(
+ PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance);
+
+ RsaPrivateKeyStructure keyStruct;
+ if (key is RsaPrivateCrtKeyParameters)
+ {
+ RsaPrivateCrtKeyParameters _key = (RsaPrivateCrtKeyParameters)key;
+
+ keyStruct = new RsaPrivateKeyStructure(
+ _key.Modulus,
+ _key.PublicExponent,
+ _key.Exponent,
+ _key.P,
+ _key.Q,
+ _key.DP,
+ _key.DQ,
+ _key.QInv);
+ }
+ else
+ {
+ RsaKeyParameters _key = (RsaKeyParameters) key;
+
+ keyStruct = new RsaPrivateKeyStructure(
+ _key.Modulus,
+ BigInteger.Zero,
+ _key.Exponent,
+ BigInteger.Zero,
+ BigInteger.Zero,
+ BigInteger.Zero,
+ BigInteger.Zero,
+ BigInteger.Zero);
+ }
+
+ return new PrivateKeyInfo(algID, keyStruct.ToAsn1Object());
+ }
+
+ if (key is ECPrivateKeyParameters)
+ {
+ ECPrivateKeyParameters priv = (ECPrivateKeyParameters)key;
+ ECDomainParameters dp = priv.Parameters;
+ int orderBitLength = dp.N.BitLength;
+
+ AlgorithmIdentifier algID;
+ ECPrivateKeyStructure ec;
+
+ if (priv.AlgorithmName == "ECGOST3410")
+ {
+ if (priv.PublicKeyParamSet == null)
+ throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
+
+ Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
+ priv.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
+
+ algID = new AlgorithmIdentifier(CryptoProObjectIdentifiers.GostR3410x2001, gostParams);
+
+ // TODO Do we need to pass any parameters here?
+ ec = new ECPrivateKeyStructure(orderBitLength, priv.D);
+ }
+ else
+ {
+ X962Parameters x962;
+ if (priv.PublicKeyParamSet == null)
+ {
+ X9ECParameters ecP = new X9ECParameters(dp.Curve, dp.G, dp.N, dp.H, dp.GetSeed());
+ x962 = new X962Parameters(ecP);
+ }
+ else
+ {
+ x962 = new X962Parameters(priv.PublicKeyParamSet);
+ }
+
+ // TODO Possible to pass the publicKey bitstring here?
+ ec = new ECPrivateKeyStructure(orderBitLength, priv.D, x962);
+
+ algID = new AlgorithmIdentifier(X9ObjectIdentifiers.IdECPublicKey, x962);
+ }
+
+ return new PrivateKeyInfo(algID, ec);
+ }
+
+ if (key is Gost3410PrivateKeyParameters)
+ {
+ Gost3410PrivateKeyParameters _key = (Gost3410PrivateKeyParameters)key;
+
+ if (_key.PublicKeyParamSet == null)
+ throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
+
+ byte[] keyEnc = _key.X.ToByteArrayUnsigned();
+ byte[] keyBytes = new byte[keyEnc.Length];
+
+ for (int i = 0; i != keyBytes.Length; i++)
+ {
+ keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // must be little endian
+ }
+
+ Gost3410PublicKeyAlgParameters algParams = new Gost3410PublicKeyAlgParameters(
+ _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet, null);
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(
+ CryptoProObjectIdentifiers.GostR3410x94,
+ algParams.ToAsn1Object());
+
+ return new PrivateKeyInfo(algID, new DerOctetString(keyBytes));
+ }
+
+ throw new ArgumentException("Class provided is not convertible: " + Platform.GetTypeName(key));
+ }
+
+ public static PrivateKeyInfo CreatePrivateKeyInfo(
+ char[] passPhrase,
+ EncryptedPrivateKeyInfo encInfo)
+ {
+ return CreatePrivateKeyInfo(passPhrase, false, encInfo);
+ }
+
+ public static PrivateKeyInfo CreatePrivateKeyInfo(
+ char[] passPhrase,
+ bool wrongPkcs12Zero,
+ EncryptedPrivateKeyInfo encInfo)
+ {
+ AlgorithmIdentifier algID = encInfo.EncryptionAlgorithm;
+
+ IBufferedCipher cipher = PbeUtilities.CreateEngine(algID) as IBufferedCipher;
+ if (cipher == null)
+ throw new Exception("Unknown encryption algorithm: " + algID.Algorithm);
+
+ ICipherParameters cipherParameters = PbeUtilities.GenerateCipherParameters(
+ algID, passPhrase, wrongPkcs12Zero);
+ cipher.Init(false, cipherParameters);
+ byte[] keyBytes = cipher.DoFinal(encInfo.GetEncryptedData());
+
+ return PrivateKeyInfo.GetInstance(keyBytes);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkcs/X509CertificateEntry.cs b/bc-sharp-crypto/src/pkcs/X509CertificateEntry.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2f81dd87b20c25cefad6fa75c5d1372852fe5ee2
--- /dev/null
+++ b/bc-sharp-crypto/src/pkcs/X509CertificateEntry.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Pkcs
+{
+ public class X509CertificateEntry
+ : Pkcs12Entry
+ {
+ private readonly X509Certificate cert;
+
+ public X509CertificateEntry(
+ X509Certificate cert)
+ : base(Platform.CreateHashtable())
+ {
+ this.cert = cert;
+ }
+
+#if !(SILVERLIGHT || PORTABLE)
+ [Obsolete]
+ public X509CertificateEntry(
+ X509Certificate cert,
+ Hashtable attributes)
+ : base(attributes)
+ {
+ this.cert = cert;
+ }
+#endif
+
+ public X509CertificateEntry(
+ X509Certificate cert,
+ IDictionary attributes)
+ : base(attributes)
+ {
+ this.cert = cert;
+ }
+
+ public X509Certificate Certificate
+ {
+ get { return this.cert; }
+ }
+
+ public override bool Equals(object obj)
+ {
+ X509CertificateEntry other = obj as X509CertificateEntry;
+
+ if (other == null)
+ return false;
+
+ return cert.Equals(other.cert);
+ }
+
+ public override int GetHashCode()
+ {
+ return ~cert.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/CertStatus.cs b/bc-sharp-crypto/src/pkix/CertStatus.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4f40b7bc6d98934fb1aa06fdf86a45dc9c9050b3
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/CertStatus.cs
@@ -0,0 +1,35 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Pkix
+{
+ public class CertStatus
+ {
+ public const int Unrevoked = 11;
+
+ public const int Undetermined = 12;
+
+ private int status = Unrevoked;
+
+ DateTimeObject revocationDate = null;
+
+ ///
+ /// Returns the revocationDate.
+ ///
+ public DateTimeObject RevocationDate
+ {
+ get { return revocationDate; }
+ set { this.revocationDate = value; }
+ }
+
+ ///
+ /// Returns the certStatus.
+ ///
+ public int Status
+ {
+ get { return status; }
+ set { this.status = value; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/PkixAttrCertChecker.cs b/bc-sharp-crypto/src/pkix/PkixAttrCertChecker.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a6eab8480f3438a7bea0aca4256dd15c001db91c
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/PkixAttrCertChecker.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Pkix
+{
+ public abstract class PkixAttrCertChecker
+ {
+ /**
+ * Returns an immutable Set
of X.509 attribute certificate
+ * extensions that this PkixAttrCertChecker
supports or
+ * null
if no extensions are supported.
+ *
+ * Each element of the set is a String
representing the
+ * Object Identifier (OID) of the X.509 extension that is supported.
+ *
+ *
+ * All X.509 attribute certificate extensions that a
+ * PkixAttrCertChecker
might possibly be able to process
+ * should be included in the set.
+ *
+ *
+ * @return an immutable Set
of X.509 extension OIDs (in
+ * String
format) supported by this
+ * PkixAttrCertChecker
, or null
if no
+ * extensions are supported
+ */
+ public abstract ISet GetSupportedExtensions();
+
+ /**
+ * Performs checks on the specified attribute certificate. Every handled
+ * extension is rmeoved from the unresolvedCritExts
+ * collection.
+ *
+ * @param attrCert The attribute certificate to be checked.
+ * @param certPath The certificate path which belongs to the attribute
+ * certificate issuer public key certificate.
+ * @param holderCertPath The certificate path which belongs to the holder
+ * certificate.
+ * @param unresolvedCritExts a Collection
of OID strings
+ * representing the current set of unresolved critical extensions
+ * @throws CertPathValidatorException if the specified attribute certificate
+ * does not pass the check.
+ */
+ public abstract void Check(IX509AttributeCertificate attrCert, PkixCertPath certPath,
+ PkixCertPath holderCertPath, ICollection unresolvedCritExts);
+
+ /**
+ * Returns a clone of this object.
+ *
+ * @return a copy of this PkixAttrCertChecker
+ */
+ public abstract PkixAttrCertChecker Clone();
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/PkixAttrCertPathBuilder.cs b/bc-sharp-crypto/src/pkix/PkixAttrCertPathBuilder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..646cc5db5452344b065488f9f49a5b93cab5c121
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/PkixAttrCertPathBuilder.cs
@@ -0,0 +1,215 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+ public class PkixAttrCertPathBuilder
+ {
+ /**
+ * Build and validate a CertPath using the given parameter.
+ *
+ * @param params PKIXBuilderParameters object containing all information to
+ * build the CertPath
+ */
+ public virtual PkixCertPathBuilderResult Build(
+ PkixBuilderParameters pkixParams)
+ {
+ // search target certificates
+
+ IX509Selector certSelect = pkixParams.GetTargetConstraints();
+ if (!(certSelect is X509AttrCertStoreSelector))
+ {
+ throw new PkixCertPathBuilderException(
+ "TargetConstraints must be an instance of "
+ + typeof(X509AttrCertStoreSelector).FullName
+ + " for "
+ + typeof(PkixAttrCertPathBuilder).FullName + " class.");
+ }
+
+ ICollection targets;
+ try
+ {
+ targets = PkixCertPathValidatorUtilities.FindCertificates(
+ (X509AttrCertStoreSelector)certSelect, pkixParams.GetStores());
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathBuilderException("Error finding target attribute certificate.", e);
+ }
+
+ if (targets.Count == 0)
+ {
+ throw new PkixCertPathBuilderException(
+ "No attribute certificate found matching targetContraints.");
+ }
+
+ PkixCertPathBuilderResult result = null;
+
+ // check all potential target certificates
+ foreach (IX509AttributeCertificate cert in targets)
+ {
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ X509Name[] principals = cert.Issuer.GetPrincipals();
+ ISet issuers = new HashSet();
+ for (int i = 0; i < principals.Length; i++)
+ {
+ try
+ {
+ selector.Subject = principals[i];
+
+ issuers.AddAll(PkixCertPathValidatorUtilities.FindCertificates(selector, pkixParams.GetStores()));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathBuilderException(
+ "Public key certificate for attribute certificate cannot be searched.",
+ e);
+ }
+ }
+
+ if (issuers.IsEmpty)
+ throw new PkixCertPathBuilderException("Public key certificate for attribute certificate cannot be found.");
+
+ IList certPathList = Platform.CreateArrayList();
+
+ foreach (X509Certificate issuer in issuers)
+ {
+ result = Build(cert, issuer, pkixParams, certPathList);
+
+ if (result != null)
+ break;
+ }
+
+ if (result != null)
+ break;
+ }
+
+ if (result == null && certPathException != null)
+ {
+ throw new PkixCertPathBuilderException(
+ "Possible certificate chain could not be validated.",
+ certPathException);
+ }
+
+ if (result == null && certPathException == null)
+ {
+ throw new PkixCertPathBuilderException(
+ "Unable to find certificate chain.");
+ }
+
+ return result;
+ }
+
+ private Exception certPathException;
+
+ private PkixCertPathBuilderResult Build(
+ IX509AttributeCertificate attrCert,
+ X509Certificate tbvCert,
+ PkixBuilderParameters pkixParams,
+ IList tbvPath)
+ {
+ // If tbvCert is readily present in tbvPath, it indicates having run
+ // into a cycle in the
+ // PKI graph.
+ if (tbvPath.Contains(tbvCert))
+ return null;
+
+ // step out, the certificate is not allowed to appear in a certification
+ // chain
+ if (pkixParams.GetExcludedCerts().Contains(tbvCert))
+ return null;
+
+ // test if certificate path exceeds maximum length
+ if (pkixParams.MaxPathLength != -1)
+ {
+ if (tbvPath.Count - 1 > pkixParams.MaxPathLength)
+ return null;
+ }
+
+ tbvPath.Add(tbvCert);
+
+ PkixCertPathBuilderResult builderResult = null;
+
+// X509CertificateParser certParser = new X509CertificateParser();
+ PkixAttrCertPathValidator validator = new PkixAttrCertPathValidator();
+
+ try
+ {
+ // check whether the issuer of is a TrustAnchor
+ if (PkixCertPathValidatorUtilities.FindTrustAnchor(tbvCert, pkixParams.GetTrustAnchors()) != null)
+ {
+ PkixCertPath certPath = new PkixCertPath(tbvPath);
+ PkixCertPathValidatorResult result;
+
+ try
+ {
+ result = validator.Validate(certPath, pkixParams);
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Certification path could not be validated.", e);
+ }
+
+ return new PkixCertPathBuilderResult(certPath, result.TrustAnchor,
+ result.PolicyTree, result.SubjectPublicKey);
+ }
+ else
+ {
+ // add additional X.509 stores from locations in certificate
+ try
+ {
+ PkixCertPathValidatorUtilities.AddAdditionalStoresFromAltNames(tbvCert, pkixParams);
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new Exception("No additional X.509 stores can be added from certificate locations.", e);
+ }
+
+ // try to get the issuer certificate from one of the stores
+ ISet issuers = new HashSet();
+ try
+ {
+ issuers.AddAll(PkixCertPathValidatorUtilities.FindIssuerCerts(tbvCert, pkixParams));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Cannot find issuer certificate for certificate in certification path.", e);
+ }
+
+ if (issuers.IsEmpty)
+ throw new Exception("No issuer certificate for certificate in certification path found.");
+
+ foreach (X509Certificate issuer in issuers)
+ {
+ // if untrusted self signed certificate continue
+ if (PkixCertPathValidatorUtilities.IsSelfIssued(issuer))
+ continue;
+
+ builderResult = Build(attrCert, issuer, pkixParams, tbvPath);
+
+ if (builderResult != null)
+ break;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ certPathException = new Exception("No valid certification path could be build.", e);
+ }
+
+ if (builderResult == null)
+ {
+ tbvPath.Remove(tbvCert);
+ }
+
+ return builderResult;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/PkixAttrCertPathValidator.cs b/bc-sharp-crypto/src/pkix/PkixAttrCertPathValidator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5f53bcde6e67f05f9b7c885b7e0adcd538322786
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/PkixAttrCertPathValidator.cs
@@ -0,0 +1,76 @@
+using System;
+
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+ /**
+ * CertPathValidatorSpi implementation for X.509 Attribute Certificates la RFC 3281.
+ *
+ * @see org.bouncycastle.x509.ExtendedPkixParameters
+ */
+ public class PkixAttrCertPathValidator
+ // extends CertPathValidatorSpi
+ {
+ /**
+ * Validates an attribute certificate with the given certificate path.
+ *
+ *
+ * params
must be an instance of
+ * ExtendedPkixParameters
.
+ *
+ * The target constraints in the params
must be an
+ * X509AttrCertStoreSelector
with at least the attribute
+ * certificate criterion set. Obey that also target informations may be
+ * necessary to correctly validate this attribute certificate.
+ *
+ * The attribute certificate issuer must be added to the trusted attribute
+ * issuers with {@link ExtendedPkixParameters#setTrustedACIssuers(Set)}.
+ *
+ * @param certPath The certificate path which belongs to the attribute
+ * certificate issuer public key certificate.
+ * @param params The PKIX parameters.
+ * @return A PKIXCertPathValidatorResult
of the result of
+ * validating the certPath
.
+ * @throws InvalidAlgorithmParameterException if params
is
+ * inappropriate for this validator.
+ * @throws CertPathValidatorException if the verification fails.
+ */
+ public virtual PkixCertPathValidatorResult Validate(
+ PkixCertPath certPath,
+ PkixParameters pkixParams)
+ {
+ IX509Selector certSelect = pkixParams.GetTargetConstraints();
+ if (!(certSelect is X509AttrCertStoreSelector))
+ {
+ throw new ArgumentException(
+ "TargetConstraints must be an instance of " + typeof(X509AttrCertStoreSelector).FullName,
+ "pkixParams");
+ }
+ IX509AttributeCertificate attrCert = ((X509AttrCertStoreSelector) certSelect).AttributeCert;
+
+ PkixCertPath holderCertPath = Rfc3281CertPathUtilities.ProcessAttrCert1(attrCert, pkixParams);
+ PkixCertPathValidatorResult result = Rfc3281CertPathUtilities.ProcessAttrCert2(certPath, pkixParams);
+ X509Certificate issuerCert = (X509Certificate)certPath.Certificates[0];
+ Rfc3281CertPathUtilities.ProcessAttrCert3(issuerCert, pkixParams);
+ Rfc3281CertPathUtilities.ProcessAttrCert4(issuerCert, pkixParams);
+ Rfc3281CertPathUtilities.ProcessAttrCert5(attrCert, pkixParams);
+ // 6 already done in X509AttrCertStoreSelector
+ Rfc3281CertPathUtilities.ProcessAttrCert7(attrCert, certPath, holderCertPath, pkixParams);
+ Rfc3281CertPathUtilities.AdditionalChecks(attrCert, pkixParams);
+ DateTime date;
+ try
+ {
+ date = PkixCertPathValidatorUtilities.GetValidCertDateFromValidityModel(pkixParams, null, -1);
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Could not get validity date from attribute certificate.", e);
+ }
+ Rfc3281CertPathUtilities.CheckCrls(attrCert, pkixParams, issuerCert, date, certPath.Certificates);
+ return result;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/PkixBuilderParameters.cs b/bc-sharp-crypto/src/pkix/PkixBuilderParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..32fc04360540a33dde8f84084607adfc91241dea
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/PkixBuilderParameters.cs
@@ -0,0 +1,140 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509.Store;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Pkix
+{
+ ///
+ /// Summary description for PkixBuilderParameters.
+ ///
+ public class PkixBuilderParameters
+ : PkixParameters
+ {
+ private int maxPathLength = 5;
+
+ private ISet excludedCerts = new HashSet();
+
+ /**
+ * Returns an instance of PkixBuilderParameters
.
+ *
+ * This method can be used to get a copy from other
+ * PKIXBuilderParameters
, PKIXParameters
,
+ * and ExtendedPKIXParameters
instances.
+ *
+ *
+ * @param pkixParams The PKIX parameters to create a copy of.
+ * @return An PkixBuilderParameters
instance.
+ */
+ public static PkixBuilderParameters GetInstance(
+ PkixParameters pkixParams)
+ {
+ PkixBuilderParameters parameters = new PkixBuilderParameters(
+ pkixParams.GetTrustAnchors(),
+ new X509CertStoreSelector(pkixParams.GetTargetCertConstraints()));
+ parameters.SetParams(pkixParams);
+ return parameters;
+ }
+
+ public PkixBuilderParameters(
+ ISet trustAnchors,
+ IX509Selector targetConstraints)
+ : base(trustAnchors)
+ {
+ SetTargetCertConstraints(targetConstraints);
+ }
+
+ public virtual int MaxPathLength
+ {
+ get { return maxPathLength; }
+ set
+ {
+ if (value < -1)
+ {
+ throw new InvalidParameterException(
+ "The maximum path length parameter can not be less than -1.");
+ }
+ this.maxPathLength = value;
+ }
+ }
+
+ ///
+ /// Excluded certificates are not used for building a certification path.
+ ///
+ /// the excluded certificates.
+ public virtual ISet GetExcludedCerts()
+ {
+ return new HashSet(excludedCerts);
+ }
+
+ ///
+ /// Sets the excluded certificates which are not used for building a
+ /// certification path. If the ISet
is null
an
+ /// empty set is assumed.
+ ///
+ ///
+ /// The given set is cloned to protect it against subsequent modifications.
+ ///
+ /// The excluded certificates to set.
+ public virtual void SetExcludedCerts(
+ ISet excludedCerts)
+ {
+ if (excludedCerts == null)
+ {
+ excludedCerts = new HashSet();
+ }
+ else
+ {
+ this.excludedCerts = new HashSet(excludedCerts);
+ }
+ }
+
+ /**
+ * Can alse handle ExtendedPKIXBuilderParameters
and
+ * PKIXBuilderParameters
.
+ *
+ * @param params Parameters to set.
+ * @see org.bouncycastle.x509.ExtendedPKIXParameters#setParams(java.security.cert.PKIXParameters)
+ */
+ protected override void SetParams(
+ PkixParameters parameters)
+ {
+ base.SetParams(parameters);
+ if (parameters is PkixBuilderParameters)
+ {
+ PkixBuilderParameters _params = (PkixBuilderParameters) parameters;
+ maxPathLength = _params.maxPathLength;
+ excludedCerts = new HashSet(_params.excludedCerts);
+ }
+ }
+
+ /**
+ * Makes a copy of this PKIXParameters
object. Changes to the
+ * copy will not affect the original and vice versa.
+ *
+ * @return a copy of this PKIXParameters
object
+ */
+ public override object Clone()
+ {
+ PkixBuilderParameters parameters = new PkixBuilderParameters(
+ GetTrustAnchors(), GetTargetCertConstraints());
+ parameters.SetParams(this);
+ return parameters;
+ }
+
+ public override string ToString()
+ {
+ string nl = Platform.NewLine;
+ StringBuilder s = new StringBuilder();
+ s.Append("PkixBuilderParameters [" + nl);
+ s.Append(base.ToString());
+ s.Append(" Maximum Path Length: ");
+ s.Append(MaxPathLength);
+ s.Append(nl + "]" + nl);
+ return s.ToString();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/PkixCertPath.cs b/bc-sharp-crypto/src/pkix/PkixCertPath.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3c428f6fb9a75ed383fe47c10a0b9ec6e7e6f165
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/PkixCertPath.cs
@@ -0,0 +1,460 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.OpenSsl;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Pkix
+{
+ /**
+ * An immutable sequence of certificates (a certification path).
+ *
+ * This is an abstract class that defines the methods common to all CertPaths.
+ * Subclasses can handle different kinds of certificates (X.509, PGP, etc.).
+ *
+ * All CertPath objects have a type, a list of Certificates, and one or more
+ * supported encodings. Because the CertPath class is immutable, a CertPath
+ * cannot change in any externally visible way after being constructed. This
+ * stipulation applies to all public fields and methods of this class and any
+ * added or overridden by subclasses.
+ *
+ * The type is a string that identifies the type of Certificates in the
+ * certification path. For each certificate cert in a certification path
+ * certPath, cert.getType().equals(certPath.getType()) must be true.
+ *
+ * The list of Certificates is an ordered List of zero or more Certificates.
+ * This List and all of the Certificates contained in it must be immutable.
+ *
+ * Each CertPath object must support one or more encodings so that the object
+ * can be translated into a byte array for storage or transmission to other
+ * parties. Preferably, these encodings should be well-documented standards
+ * (such as PKCS#7). One of the encodings supported by a CertPath is considered
+ * the default encoding. This encoding is used if no encoding is explicitly
+ * requested (for the {@link #getEncoded()} method, for instance).
+ *
+ * All CertPath objects are also Serializable. CertPath objects are resolved
+ * into an alternate {@link CertPathRep} object during serialization. This
+ * allows a CertPath object to be serialized into an equivalent representation
+ * regardless of its underlying implementation.
+ *
+ * CertPath objects can be created with a CertificateFactory or they can be
+ * returned by other classes, such as a CertPathBuilder.
+ *
+ * By convention, X.509 CertPaths (consisting of X509Certificates), are ordered
+ * starting with the target certificate and ending with a certificate issued by
+ * the trust anchor. That is, the issuer of one certificate is the subject of
+ * the following one. The certificate representing the
+ * {@link TrustAnchor TrustAnchor} should not be included in the certification
+ * path. Unvalidated X.509 CertPaths may not follow these conventions. PKIX
+ * CertPathValidators will detect any departure from these conventions that
+ * cause the certification path to be invalid and throw a
+ * CertPathValidatorException.
+ *
+ * Concurrent Access
+ *
+ * All CertPath objects must be thread-safe. That is, multiple threads may
+ * concurrently invoke the methods defined in this class on a single CertPath
+ * object (or more than one) with no ill effects. This is also true for the List
+ * returned by CertPath.getCertificates.
+ *
+ * Requiring CertPath objects to be immutable and thread-safe allows them to be
+ * passed around to various pieces of code without worrying about coordinating
+ * access. Providing this thread-safety is generally not difficult, since the
+ * CertPath and List objects in question are immutable.
+ *
+ * @see CertificateFactory
+ * @see CertPathBuilder
+ */
+ ///
+ /// CertPath implementation for X.509 certificates.
+ ///
+ public class PkixCertPath
+// : CertPath
+ {
+ internal static readonly IList certPathEncodings;
+
+ static PkixCertPath()
+ {
+ IList encodings = Platform.CreateArrayList();
+ encodings.Add("PkiPath");
+ encodings.Add("PEM");
+ encodings.Add("PKCS7");
+ certPathEncodings = CollectionUtilities.ReadOnly(encodings);
+ }
+
+ private readonly IList certificates;
+
+ /**
+ * @param certs
+ */
+ private static IList SortCerts(
+ IList certs)
+ {
+ if (certs.Count < 2)
+ return certs;
+
+ X509Name issuer = ((X509Certificate)certs[0]).IssuerDN;
+ bool okay = true;
+
+ for (int i = 1; i != certs.Count; i++)
+ {
+ X509Certificate cert = (X509Certificate)certs[i];
+
+ if (issuer.Equivalent(cert.SubjectDN, true))
+ {
+ issuer = ((X509Certificate)certs[i]).IssuerDN;
+ }
+ else
+ {
+ okay = false;
+ break;
+ }
+ }
+
+ if (okay)
+ return certs;
+
+ // find end-entity cert
+ IList retList = Platform.CreateArrayList(certs.Count);
+ IList orig = Platform.CreateArrayList(certs);
+
+ for (int i = 0; i < certs.Count; i++)
+ {
+ X509Certificate cert = (X509Certificate)certs[i];
+ bool found = false;
+
+ X509Name subject = cert.SubjectDN;
+ foreach (X509Certificate c in certs)
+ {
+ if (c.IssuerDN.Equivalent(subject, true))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ retList.Add(cert);
+ certs.RemoveAt(i);
+ }
+ }
+
+ // can only have one end entity cert - something's wrong, give up.
+ if (retList.Count > 1)
+ return orig;
+
+ for (int i = 0; i != retList.Count; i++)
+ {
+ issuer = ((X509Certificate)retList[i]).IssuerDN;
+
+ for (int j = 0; j < certs.Count; j++)
+ {
+ X509Certificate c = (X509Certificate)certs[j];
+ if (issuer.Equivalent(c.SubjectDN, true))
+ {
+ retList.Add(c);
+ certs.RemoveAt(j);
+ break;
+ }
+ }
+ }
+
+ // make sure all certificates are accounted for.
+ if (certs.Count > 0)
+ return orig;
+
+ return retList;
+ }
+
+ /**
+ * Creates a CertPath of the specified type.
+ * This constructor is protected because most users should use
+ * a CertificateFactory to create CertPaths.
+ * @param type the standard name of the type of Certificatesin this path
+ **/
+ public PkixCertPath(
+ ICollection certificates)
+// : base("X.509")
+ {
+ this.certificates = SortCerts(Platform.CreateArrayList(certificates));
+ }
+
+ public PkixCertPath(
+ Stream inStream)
+ : this(inStream, "PkiPath")
+ {
+ }
+
+ /**
+ * Creates a CertPath of the specified type.
+ * This constructor is protected because most users should use
+ * a CertificateFactory to create CertPaths.
+ *
+ * @param type the standard name of the type of Certificatesin this path
+ **/
+ public PkixCertPath(
+ Stream inStream,
+ string encoding)
+// : base("X.509")
+ {
+ string upper = Platform.ToUpperInvariant(encoding);
+
+ IList certs;
+ try
+ {
+ if (upper.Equals(Platform.ToUpperInvariant("PkiPath")))
+ {
+ Asn1InputStream derInStream = new Asn1InputStream(inStream);
+ Asn1Object derObject = derInStream.ReadObject();
+ if (!(derObject is Asn1Sequence))
+ {
+ throw new CertificateException(
+ "input stream does not contain a ASN1 SEQUENCE while reading PkiPath encoded data to load CertPath");
+ }
+
+ certs = Platform.CreateArrayList();
+
+ foreach (Asn1Encodable ae in (Asn1Sequence)derObject)
+ {
+ byte[] derBytes = ae.GetEncoded(Asn1Encodable.Der);
+ Stream certInStream = new MemoryStream(derBytes, false);
+
+ // TODO Is inserting at the front important (list will be sorted later anyway)?
+ certs.Insert(0, new X509CertificateParser().ReadCertificate(certInStream));
+ }
+ }
+ else if (upper.Equals("PKCS7") || upper.Equals("PEM"))
+ {
+ certs = Platform.CreateArrayList(new X509CertificateParser().ReadCertificates(inStream));
+ }
+ else
+ {
+ throw new CertificateException("unsupported encoding: " + encoding);
+ }
+ }
+ catch (IOException ex)
+ {
+ throw new CertificateException(
+ "IOException throw while decoding CertPath:\n"
+ + ex.ToString());
+ }
+
+ this.certificates = SortCerts(certs);
+ }
+
+ /**
+ * Returns an iteration of the encodings supported by this
+ * certification path, with the default encoding
+ * first. Attempts to modify the returned Iterator via its
+ * remove method result in an UnsupportedOperationException.
+ *
+ * @return an Iterator over the names of the supported encodings (as Strings)
+ **/
+ public virtual IEnumerable Encodings
+ {
+ get { return new EnumerableProxy(certPathEncodings); }
+ }
+
+ /**
+ * Compares this certification path for equality with the specified object.
+ * Two CertPaths are equal if and only if their types are equal and their
+ * certificate Lists (and by implication the Certificates in those Lists)
+ * are equal. A CertPath is never equal to an object that is not a CertPath.
+ *
+ * This algorithm is implemented by this method. If it is overridden, the
+ * behavior specified here must be maintained.
+ *
+ * @param other
+ * the object to test for equality with this certification path
+ *
+ * @return true if the specified object is equal to this certification path,
+ * false otherwise
+ *
+ * @see Object#hashCode() Object.hashCode()
+ */
+ public override bool Equals(
+ object obj)
+ {
+ if (this == obj)
+ return true;
+
+ PkixCertPath other = obj as PkixCertPath;
+ if (other == null)
+ return false;
+
+// if (!this.Type.Equals(other.Type))
+// return false;
+
+ //return this.Certificates.Equals(other.Certificates);
+
+ // TODO Extract this to a utility class
+ IList thisCerts = this.Certificates;
+ IList otherCerts = other.Certificates;
+
+ if (thisCerts.Count != otherCerts.Count)
+ return false;
+
+ IEnumerator e1 = thisCerts.GetEnumerator();
+ IEnumerator e2 = thisCerts.GetEnumerator();
+
+ while (e1.MoveNext())
+ {
+ e2.MoveNext();
+
+ if (!Platform.Equals(e1.Current, e2.Current))
+ return false;
+ }
+
+ return true;
+ }
+
+ public override int GetHashCode()
+ {
+ // FIXME?
+ return this.Certificates.GetHashCode();
+ }
+
+ /**
+ * Returns the encoded form of this certification path, using
+ * the default encoding.
+ *
+ * @return the encoded bytes
+ * @exception CertificateEncodingException if an encoding error occurs
+ **/
+ public virtual byte[] GetEncoded()
+ {
+ foreach (object enc in Encodings)
+ {
+ if (enc is string)
+ {
+ return GetEncoded((string)enc);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the encoded form of this certification path, using
+ * the specified encoding.
+ *
+ * @param encoding the name of the encoding to use
+ * @return the encoded bytes
+ * @exception CertificateEncodingException if an encoding error
+ * occurs or the encoding requested is not supported
+ *
+ */
+ public virtual byte[] GetEncoded(
+ string encoding)
+ {
+ if (Platform.EqualsIgnoreCase(encoding, "PkiPath"))
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ for (int i = certificates.Count - 1; i >= 0; i--)
+ {
+ v.Add(ToAsn1Object((X509Certificate) certificates[i]));
+ }
+
+ return ToDerEncoded(new DerSequence(v));
+ }
+ else if (Platform.EqualsIgnoreCase(encoding, "PKCS7"))
+ {
+ Asn1.Pkcs.ContentInfo encInfo = new Asn1.Pkcs.ContentInfo(
+ PkcsObjectIdentifiers.Data, null);
+
+ Asn1EncodableVector v = new Asn1EncodableVector();
+ for (int i = 0; i != certificates.Count; i++)
+ {
+ v.Add(ToAsn1Object((X509Certificate)certificates[i]));
+ }
+
+ Asn1.Pkcs.SignedData sd = new Asn1.Pkcs.SignedData(
+ new DerInteger(1),
+ new DerSet(),
+ encInfo,
+ new DerSet(v),
+ null,
+ new DerSet());
+
+ return ToDerEncoded(new Asn1.Pkcs.ContentInfo(PkcsObjectIdentifiers.SignedData, sd));
+ }
+ else if (Platform.EqualsIgnoreCase(encoding, "PEM"))
+ {
+ MemoryStream bOut = new MemoryStream();
+ PemWriter pWrt = new PemWriter(new StreamWriter(bOut));
+
+ try
+ {
+ for (int i = 0; i != certificates.Count; i++)
+ {
+ pWrt.WriteObject(certificates[i]);
+ }
+
+ Platform.Dispose(pWrt.Writer);
+ }
+ catch (Exception)
+ {
+ throw new CertificateEncodingException("can't encode certificate for PEM encoded path");
+ }
+
+ return bOut.ToArray();
+ }
+ else
+ {
+ throw new CertificateEncodingException("unsupported encoding: " + encoding);
+ }
+ }
+
+ ///
+ /// Returns the list of certificates in this certification
+ /// path.
+ ///
+ public virtual IList Certificates
+ {
+ get { return CollectionUtilities.ReadOnly(certificates); }
+ }
+
+ /**
+ * Return a DERObject containing the encoded certificate.
+ *
+ * @param cert the X509Certificate object to be encoded
+ *
+ * @return the DERObject
+ **/
+ private Asn1Object ToAsn1Object(
+ X509Certificate cert)
+ {
+ try
+ {
+ return Asn1Object.FromByteArray(cert.GetEncoded());
+ }
+ catch (Exception e)
+ {
+ throw new CertificateEncodingException("Exception while encoding certificate", e);
+ }
+ }
+
+ private byte[] ToDerEncoded(Asn1Encodable obj)
+ {
+ try
+ {
+ return obj.GetEncoded(Asn1Encodable.Der);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException("Exception thrown", e);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/PkixCertPathBuilder.cs b/bc-sharp-crypto/src/pkix/PkixCertPathBuilder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fa38a5ec0f26a4b01ef62ce51a5676ca739da24d
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/PkixCertPathBuilder.cs
@@ -0,0 +1,205 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using Org.BouncyCastle.Asn1.IsisMtt;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+ /**
+ * Implements the PKIX CertPathBuilding algorithm for BouncyCastle.
+ *
+ * @see CertPathBuilderSpi
+ */
+ public class PkixCertPathBuilder
+ // : CertPathBuilderSpi
+ {
+ /**
+ * Build and validate a CertPath using the given parameter.
+ *
+ * @param params PKIXBuilderParameters object containing all information to
+ * build the CertPath
+ */
+ public virtual PkixCertPathBuilderResult Build(
+ PkixBuilderParameters pkixParams)
+ {
+ // search target certificates
+
+ IX509Selector certSelect = pkixParams.GetTargetCertConstraints();
+ if (!(certSelect is X509CertStoreSelector))
+ {
+ throw new PkixCertPathBuilderException(
+ "TargetConstraints must be an instance of "
+ + typeof(X509CertStoreSelector).FullName + " for "
+ + Platform.GetTypeName(this) + " class.");
+ }
+
+ ISet targets = new HashSet();
+ try
+ {
+ targets.AddAll(PkixCertPathValidatorUtilities.FindCertificates((X509CertStoreSelector)certSelect, pkixParams.GetStores()));
+ // TODO Should this include an entry for pkixParams.GetAdditionalStores() too?
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathBuilderException(
+ "Error finding target certificate.", e);
+ }
+
+ if (targets.IsEmpty)
+ throw new PkixCertPathBuilderException("No certificate found matching targetContraints.");
+
+ PkixCertPathBuilderResult result = null;
+ IList certPathList = Platform.CreateArrayList();
+
+ // check all potential target certificates
+ foreach (X509Certificate cert in targets)
+ {
+ result = Build(cert, pkixParams, certPathList);
+
+ if (result != null)
+ break;
+ }
+
+ if (result == null && certPathException != null)
+ {
+ throw new PkixCertPathBuilderException(certPathException.Message, certPathException.InnerException);
+ }
+
+ if (result == null && certPathException == null)
+ {
+ throw new PkixCertPathBuilderException("Unable to find certificate chain.");
+ }
+
+ return result;
+ }
+
+ private Exception certPathException;
+
+ protected virtual PkixCertPathBuilderResult Build(
+ X509Certificate tbvCert,
+ PkixBuilderParameters pkixParams,
+ IList tbvPath)
+ {
+ // If tbvCert is readily present in tbvPath, it indicates having run
+ // into a cycle in the PKI graph.
+ if (tbvPath.Contains(tbvCert))
+ return null;
+
+ // step out, the certificate is not allowed to appear in a certification
+ // chain.
+ if (pkixParams.GetExcludedCerts().Contains(tbvCert))
+ return null;
+
+ // test if certificate path exceeds maximum length
+ if (pkixParams.MaxPathLength != -1)
+ {
+ if (tbvPath.Count - 1 > pkixParams.MaxPathLength)
+ return null;
+ }
+
+ tbvPath.Add(tbvCert);
+
+// X509CertificateParser certParser = new X509CertificateParser();
+ PkixCertPathBuilderResult builderResult = null;
+ PkixCertPathValidator validator = new PkixCertPathValidator();
+
+ try
+ {
+ // check whether the issuer of is a TrustAnchor
+ if (PkixCertPathValidatorUtilities.FindTrustAnchor(tbvCert, pkixParams.GetTrustAnchors()) != null)
+ {
+ // exception message from possibly later tried certification
+ // chains
+ PkixCertPath certPath = null;
+ try
+ {
+ certPath = new PkixCertPath(tbvPath);
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Certification path could not be constructed from certificate list.",
+ e);
+ }
+
+ PkixCertPathValidatorResult result = null;
+ try
+ {
+ result = (PkixCertPathValidatorResult)validator.Validate(
+ certPath, pkixParams);
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Certification path could not be validated.", e);
+ }
+
+ return new PkixCertPathBuilderResult(certPath, result.TrustAnchor,
+ result.PolicyTree, result.SubjectPublicKey);
+ }
+ else
+ {
+ // add additional X.509 stores from locations in certificate
+ try
+ {
+ PkixCertPathValidatorUtilities.AddAdditionalStoresFromAltNames(
+ tbvCert, pkixParams);
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new Exception(
+ "No additiontal X.509 stores can be added from certificate locations.",
+ e);
+ }
+
+ // try to get the issuer certificate from one of the stores
+ HashSet issuers = new HashSet();
+ try
+ {
+ issuers.AddAll(PkixCertPathValidatorUtilities.FindIssuerCerts(tbvCert, pkixParams));
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Cannot find issuer certificate for certificate in certification path.",
+ e);
+ }
+
+ if (issuers.IsEmpty)
+ throw new Exception("No issuer certificate for certificate in certification path found.");
+
+ foreach (X509Certificate issuer in issuers)
+ {
+ builderResult = Build(issuer, pkixParams, tbvPath);
+
+ if (builderResult != null)
+ break;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ certPathException = e;
+ }
+
+ if (builderResult == null)
+ {
+ tbvPath.Remove(tbvCert);
+ }
+
+ return builderResult;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/PkixCertPathBuilderException.cs b/bc-sharp-crypto/src/pkix/PkixCertPathBuilderException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0f10179ddf34125f57718988dd5d6ae63efa5524
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/PkixCertPathBuilderException.cs
@@ -0,0 +1,22 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Pkix
+{
+ ///
+ /// Summary description for PkixCertPathBuilderException.
+ ///
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class PkixCertPathBuilderException : GeneralSecurityException
+ {
+ public PkixCertPathBuilderException() : base() { }
+
+ public PkixCertPathBuilderException(string message) : base(message) { }
+
+ public PkixCertPathBuilderException(string message, Exception exception) : base(message, exception) { }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/PkixCertPathBuilderResult.cs b/bc-sharp-crypto/src/pkix/PkixCertPathBuilderResult.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f8003032f41c3b4e0c18a61d81ba951512639cbc
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/PkixCertPathBuilderResult.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Pkix;
+
+namespace Org.BouncyCastle.Pkix
+{
+ ///
+ /// Summary description for PkixCertPathBuilderResult.
+ ///
+ public class PkixCertPathBuilderResult
+ : PkixCertPathValidatorResult//, ICertPathBuilderResult
+ {
+ private PkixCertPath certPath;
+
+ public PkixCertPathBuilderResult(
+ PkixCertPath certPath,
+ TrustAnchor trustAnchor,
+ PkixPolicyNode policyTree,
+ AsymmetricKeyParameter subjectPublicKey)
+ : base(trustAnchor, policyTree, subjectPublicKey)
+ {
+ if (certPath == null)
+ throw new ArgumentNullException("certPath");
+
+ this.certPath = certPath;
+ }
+
+ public PkixCertPath CertPath
+ {
+ get { return certPath; }
+ }
+
+ public override string ToString()
+ {
+ StringBuilder s = new StringBuilder();
+ s.Append("SimplePKIXCertPathBuilderResult: [\n");
+ s.Append(" Certification Path: ").Append(CertPath).Append('\n');
+ s.Append(" Trust Anchor: ").Append(this.TrustAnchor.TrustedCert.IssuerDN.ToString()).Append('\n');
+ s.Append(" Subject Public Key: ").Append(this.SubjectPublicKey).Append("\n]");
+ return s.ToString();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/PkixCertPathChecker.cs b/bc-sharp-crypto/src/pkix/PkixCertPathChecker.cs
new file mode 100644
index 0000000000000000000000000000000000000000..da7e82b465b6c8ec51e6429c9b88b9eb98da4ce7
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/PkixCertPathChecker.cs
@@ -0,0 +1,99 @@
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Pkix
+{
+ public abstract class PkixCertPathChecker
+ {
+ protected PkixCertPathChecker()
+ {
+ }
+
+ /**
+ * Initializes the internal state of this PKIXCertPathChecker
.
+ *
+ * The forward
flag specifies the order that certificates
+ * will be passed to the {@link #check check} method (forward or reverse). A
+ * PKIXCertPathChecker
must support reverse checking
+ * and may support forward checking.
+ *
+ *
+ * @param forward
+ * the order that certificates are presented to the
+ * check
method. If true
,
+ * certificates are presented from target to most-trusted CA
+ * (forward); if false
, from most-trusted CA to
+ * target (reverse).
+ * @exception CertPathValidatorException
+ * if this PKIXCertPathChecker
is unable to
+ * check certificates in the specified order; it should never
+ * be thrown if the forward flag is false since reverse
+ * checking must be supported
+ */
+ public abstract void Init(bool forward);
+ //throws CertPathValidatorException;
+
+ /**
+ * Indicates if forward checking is supported. Forward checking refers to
+ * the ability of the PKIXCertPathChecker
to perform its
+ * checks when certificates are presented to the check
method
+ * in the forward direction (from target to most-trusted CA).
+ *
+ * @return true
if forward checking is supported,
+ * false
otherwise
+ */
+ public abstract bool IsForwardCheckingSupported();
+
+ /**
+ * Returns an immutable Set
of X.509 certificate extensions
+ * that this PKIXCertPathChecker
supports (i.e. recognizes,
+ * is able to process), or null
if no extensions are
+ * supported.
+ *
+ * Each element of the set is a String
representing the
+ * Object Identifier (OID) of the X.509 extension that is supported. The OID
+ * is represented by a set of nonnegative integers separated by periods.
+ *
+ * All X.509 certificate extensions that a PKIXCertPathChecker
+ * might possibly be able to process should be included in the set.
+ *
+ *
+ * @return an immutable Set
of X.509 extension OIDs (in
+ * String
format) supported by this
+ * PKIXCertPathChecker
, or null
if no
+ * extensions are supported
+ */
+ public abstract ISet GetSupportedExtensions();
+
+ /**
+ * Performs the check(s) on the specified certificate using its internal
+ * state and removes any critical extensions that it processes from the
+ * specified collection of OID strings that represent the unresolved
+ * critical extensions. The certificates are presented in the order
+ * specified by the init
method.
+ *
+ * @param cert
+ * the Certificate
to be checked
+ * @param unresolvedCritExts
+ * a Collection
of OID strings representing the
+ * current set of unresolved critical extensions
+ * @exception CertPathValidatorException
+ * if the specified certificate does not pass the check
+ */
+ public abstract void Check(X509Certificate cert, ISet unresolvedCritExts);
+ //throws CertPathValidatorException;
+
+ /**
+ * Returns a clone of this object. Calls the Object.clone()
+ * method. All subclasses which maintain state must support and override
+ * this method, if necessary.
+ *
+ * @return a copy of this PKIXCertPathChecker
+ */
+ public virtual object Clone()
+ {
+ // TODO Check this
+ return base.MemberwiseClone();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/PkixCertPathValidator.cs b/bc-sharp-crypto/src/pkix/PkixCertPathValidator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fcfa63837e10e36c1cc878076bbdf05f4a1cd0f5
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/PkixCertPathValidator.cs
@@ -0,0 +1,420 @@
+using System;
+using System.Collections;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+ /**
+ * The Service Provider Interface (SPI )
+ * for the {@link CertPathValidator CertPathValidator} class. All
+ * CertPathValidator
implementations must include a class (the
+ * SPI class) that extends this class (CertPathValidatorSpi
)
+ * and implements all of its methods. In general, instances of this class
+ * should only be accessed through the CertPathValidator
class.
+ * For details, see the Java Cryptography Architecture.
+ *
+ * Concurrent Access
+ *
+ * Instances of this class need not be protected against concurrent
+ * access from multiple threads. Threads that need to access a single
+ * CertPathValidatorSpi
instance concurrently should synchronize
+ * amongst themselves and provide the necessary locking before calling the
+ * wrapping CertPathValidator
object.
+ *
+ * However, implementations of CertPathValidatorSpi
may still
+ * encounter concurrency issues, since multiple threads each
+ * manipulating a different CertPathValidatorSpi
instance need not
+ * synchronize.
+ */
+ ///
+ /// CertPathValidatorSpi implementation for X.509 Certificate validation a la RFC
+ /// 3280.
+ ///
+ public class PkixCertPathValidator
+ {
+ public virtual PkixCertPathValidatorResult Validate(
+ PkixCertPath certPath,
+ PkixParameters paramsPkix)
+ {
+ if (paramsPkix.GetTrustAnchors() == null)
+ {
+ throw new ArgumentException(
+ "trustAnchors is null, this is not allowed for certification path validation.",
+ "parameters");
+ }
+
+ //
+ // 6.1.1 - inputs
+ //
+
+ //
+ // (a)
+ //
+ IList certs = certPath.Certificates;
+ int n = certs.Count;
+
+ if (certs.Count == 0)
+ throw new PkixCertPathValidatorException("Certification path is empty.", null, certPath, 0);
+
+ //
+ // (b)
+ //
+ // DateTime validDate = PkixCertPathValidatorUtilities.GetValidDate(paramsPkix);
+
+ //
+ // (c)
+ //
+ ISet userInitialPolicySet = paramsPkix.GetInitialPolicies();
+
+ //
+ // (d)
+ //
+ TrustAnchor trust;
+ try
+ {
+ trust = PkixCertPathValidatorUtilities.FindTrustAnchor(
+ (X509Certificate)certs[certs.Count - 1],
+ paramsPkix.GetTrustAnchors());
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(e.Message, e, certPath, certs.Count - 1);
+ }
+
+ if (trust == null)
+ throw new PkixCertPathValidatorException("Trust anchor for certification path not found.", null, certPath, -1);
+
+ //
+ // (e), (f), (g) are part of the paramsPkix object.
+ //
+ IEnumerator certIter;
+ int index = 0;
+ int i;
+ // Certificate for each interation of the validation loop
+ // Signature information for each iteration of the validation loop
+ //
+ // 6.1.2 - setup
+ //
+
+ //
+ // (a)
+ //
+ IList[] policyNodes = new IList[n + 1];
+ for (int j = 0; j < policyNodes.Length; j++)
+ {
+ policyNodes[j] = Platform.CreateArrayList();
+ }
+
+ ISet policySet = new HashSet();
+
+ policySet.Add(Rfc3280CertPathUtilities.ANY_POLICY);
+
+ PkixPolicyNode validPolicyTree = new PkixPolicyNode(Platform.CreateArrayList(), 0, policySet, null, new HashSet(),
+ Rfc3280CertPathUtilities.ANY_POLICY, false);
+
+ policyNodes[0].Add(validPolicyTree);
+
+ //
+ // (b) and (c)
+ //
+ PkixNameConstraintValidator nameConstraintValidator = new PkixNameConstraintValidator();
+
+ // (d)
+ //
+ int explicitPolicy;
+ ISet acceptablePolicies = new HashSet();
+
+ if (paramsPkix.IsExplicitPolicyRequired)
+ {
+ explicitPolicy = 0;
+ }
+ else
+ {
+ explicitPolicy = n + 1;
+ }
+
+ //
+ // (e)
+ //
+ int inhibitAnyPolicy;
+
+ if (paramsPkix.IsAnyPolicyInhibited)
+ {
+ inhibitAnyPolicy = 0;
+ }
+ else
+ {
+ inhibitAnyPolicy = n + 1;
+ }
+
+ //
+ // (f)
+ //
+ int policyMapping;
+
+ if (paramsPkix.IsPolicyMappingInhibited)
+ {
+ policyMapping = 0;
+ }
+ else
+ {
+ policyMapping = n + 1;
+ }
+
+ //
+ // (g), (h), (i), (j)
+ //
+ AsymmetricKeyParameter workingPublicKey;
+ X509Name workingIssuerName;
+
+ X509Certificate sign = trust.TrustedCert;
+ try
+ {
+ if (sign != null)
+ {
+ workingIssuerName = sign.SubjectDN;
+ workingPublicKey = sign.GetPublicKey();
+ }
+ else
+ {
+ workingIssuerName = new X509Name(trust.CAName);
+ workingPublicKey = trust.CAPublicKey;
+ }
+ }
+ catch (ArgumentException ex)
+ {
+ throw new PkixCertPathValidatorException("Subject of trust anchor could not be (re)encoded.", ex, certPath,
+ -1);
+ }
+
+ AlgorithmIdentifier workingAlgId = null;
+ try
+ {
+ workingAlgId = PkixCertPathValidatorUtilities.GetAlgorithmIdentifier(workingPublicKey);
+ }
+ catch (PkixCertPathValidatorException e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Algorithm identifier of public key of trust anchor could not be read.", e, certPath, -1);
+ }
+
+// DerObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.Algorithm;
+// Asn1Encodable workingPublicKeyParameters = workingAlgId.Parameters;
+
+ //
+ // (k)
+ //
+ int maxPathLength = n;
+
+ //
+ // 6.1.3
+ //
+
+ X509CertStoreSelector certConstraints = paramsPkix.GetTargetCertConstraints();
+ if (certConstraints != null && !certConstraints.Match((X509Certificate)certs[0]))
+ {
+ throw new PkixCertPathValidatorException(
+ "Target certificate in certification path does not match targetConstraints.", null, certPath, 0);
+ }
+
+ //
+ // initialize CertPathChecker's
+ //
+ IList pathCheckers = paramsPkix.GetCertPathCheckers();
+ certIter = pathCheckers.GetEnumerator();
+
+ while (certIter.MoveNext())
+ {
+ ((PkixCertPathChecker)certIter.Current).Init(false);
+ }
+
+ X509Certificate cert = null;
+
+ for (index = certs.Count - 1; index >= 0; index--)
+ {
+ // try
+ // {
+ //
+ // i as defined in the algorithm description
+ //
+ i = n - index;
+
+ //
+ // set certificate to be checked in this round
+ // sign and workingPublicKey and workingIssuerName are set
+ // at the end of the for loop and initialized the
+ // first time from the TrustAnchor
+ //
+ cert = (X509Certificate)certs[index];
+
+ //
+ // 6.1.3
+ //
+
+ Rfc3280CertPathUtilities.ProcessCertA(certPath, paramsPkix, index, workingPublicKey,
+ workingIssuerName, sign);
+
+ Rfc3280CertPathUtilities.ProcessCertBC(certPath, index, nameConstraintValidator);
+
+ validPolicyTree = Rfc3280CertPathUtilities.ProcessCertD(certPath, index,
+ acceptablePolicies, validPolicyTree, policyNodes, inhibitAnyPolicy);
+
+ validPolicyTree = Rfc3280CertPathUtilities.ProcessCertE(certPath, index, validPolicyTree);
+
+ Rfc3280CertPathUtilities.ProcessCertF(certPath, index, validPolicyTree, explicitPolicy);
+
+ //
+ // 6.1.4
+ //
+
+ if (i != n)
+ {
+ if (cert != null && cert.Version == 1)
+ {
+ throw new PkixCertPathValidatorException(
+ "Version 1 certificates can't be used as CA ones.", null, certPath, index);
+ }
+
+ Rfc3280CertPathUtilities.PrepareNextCertA(certPath, index);
+
+ validPolicyTree = Rfc3280CertPathUtilities.PrepareCertB(certPath, index, policyNodes,
+ validPolicyTree, policyMapping);
+
+ Rfc3280CertPathUtilities.PrepareNextCertG(certPath, index, nameConstraintValidator);
+
+ // (h)
+ explicitPolicy = Rfc3280CertPathUtilities.PrepareNextCertH1(certPath, index, explicitPolicy);
+ policyMapping = Rfc3280CertPathUtilities.PrepareNextCertH2(certPath, index, policyMapping);
+ inhibitAnyPolicy = Rfc3280CertPathUtilities.PrepareNextCertH3(certPath, index, inhibitAnyPolicy);
+
+ //
+ // (i)
+ //
+ explicitPolicy = Rfc3280CertPathUtilities.PrepareNextCertI1(certPath, index, explicitPolicy);
+ policyMapping = Rfc3280CertPathUtilities.PrepareNextCertI2(certPath, index, policyMapping);
+
+ // (j)
+ inhibitAnyPolicy = Rfc3280CertPathUtilities.PrepareNextCertJ(certPath, index, inhibitAnyPolicy);
+
+ // (k)
+ Rfc3280CertPathUtilities.PrepareNextCertK(certPath, index);
+
+ // (l)
+ maxPathLength = Rfc3280CertPathUtilities.PrepareNextCertL(certPath, index, maxPathLength);
+
+ // (m)
+ maxPathLength = Rfc3280CertPathUtilities.PrepareNextCertM(certPath, index, maxPathLength);
+
+ // (n)
+ Rfc3280CertPathUtilities.PrepareNextCertN(certPath, index);
+
+ ISet criticalExtensions1 = cert.GetCriticalExtensionOids();
+
+ if (criticalExtensions1 != null)
+ {
+ criticalExtensions1 = new HashSet(criticalExtensions1);
+
+ // these extensions are handled by the algorithm
+ criticalExtensions1.Remove(X509Extensions.KeyUsage.Id);
+ criticalExtensions1.Remove(X509Extensions.CertificatePolicies.Id);
+ criticalExtensions1.Remove(X509Extensions.PolicyMappings.Id);
+ criticalExtensions1.Remove(X509Extensions.InhibitAnyPolicy.Id);
+ criticalExtensions1.Remove(X509Extensions.IssuingDistributionPoint.Id);
+ criticalExtensions1.Remove(X509Extensions.DeltaCrlIndicator.Id);
+ criticalExtensions1.Remove(X509Extensions.PolicyConstraints.Id);
+ criticalExtensions1.Remove(X509Extensions.BasicConstraints.Id);
+ criticalExtensions1.Remove(X509Extensions.SubjectAlternativeName.Id);
+ criticalExtensions1.Remove(X509Extensions.NameConstraints.Id);
+ }
+ else
+ {
+ criticalExtensions1 = new HashSet();
+ }
+
+ // (o)
+ Rfc3280CertPathUtilities.PrepareNextCertO(certPath, index, criticalExtensions1, pathCheckers);
+
+ // set signing certificate for next round
+ sign = cert;
+
+ // (c)
+ workingIssuerName = sign.SubjectDN;
+
+ // (d)
+ try
+ {
+ workingPublicKey = PkixCertPathValidatorUtilities.GetNextWorkingKey(certPath.Certificates, index);
+ }
+ catch (PkixCertPathValidatorException e)
+ {
+ throw new PkixCertPathValidatorException("Next working key could not be retrieved.", e, certPath, index);
+ }
+
+ workingAlgId = PkixCertPathValidatorUtilities.GetAlgorithmIdentifier(workingPublicKey);
+ // (f)
+// workingPublicKeyAlgorithm = workingAlgId.Algorithm;
+ // (e)
+// workingPublicKeyParameters = workingAlgId.Parameters;
+ }
+ }
+
+ //
+ // 6.1.5 Wrap-up procedure
+ //
+
+ explicitPolicy = Rfc3280CertPathUtilities.WrapupCertA(explicitPolicy, cert);
+
+ explicitPolicy = Rfc3280CertPathUtilities.WrapupCertB(certPath, index + 1, explicitPolicy);
+
+ //
+ // (c) (d) and (e) are already done
+ //
+
+ //
+ // (f)
+ //
+ ISet criticalExtensions = cert.GetCriticalExtensionOids();
+
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+
+ // Requires .Id
+ // these extensions are handled by the algorithm
+ criticalExtensions.Remove(X509Extensions.KeyUsage.Id);
+ criticalExtensions.Remove(X509Extensions.CertificatePolicies.Id);
+ criticalExtensions.Remove(X509Extensions.PolicyMappings.Id);
+ criticalExtensions.Remove(X509Extensions.InhibitAnyPolicy.Id);
+ criticalExtensions.Remove(X509Extensions.IssuingDistributionPoint.Id);
+ criticalExtensions.Remove(X509Extensions.DeltaCrlIndicator.Id);
+ criticalExtensions.Remove(X509Extensions.PolicyConstraints.Id);
+ criticalExtensions.Remove(X509Extensions.BasicConstraints.Id);
+ criticalExtensions.Remove(X509Extensions.SubjectAlternativeName.Id);
+ criticalExtensions.Remove(X509Extensions.NameConstraints.Id);
+ criticalExtensions.Remove(X509Extensions.CrlDistributionPoints.Id);
+ }
+ else
+ {
+ criticalExtensions = new HashSet();
+ }
+
+ Rfc3280CertPathUtilities.WrapupCertF(certPath, index + 1, pathCheckers, criticalExtensions);
+
+ PkixPolicyNode intersection = Rfc3280CertPathUtilities.WrapupCertG(certPath, paramsPkix, userInitialPolicySet,
+ index + 1, policyNodes, validPolicyTree, acceptablePolicies);
+
+ if ((explicitPolicy > 0) || (intersection != null))
+ {
+ return new PkixCertPathValidatorResult(trust, intersection, cert.GetPublicKey());
+ }
+
+ throw new PkixCertPathValidatorException("Path processing failed on policy.", null, certPath, index);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/PkixCertPathValidatorException.cs b/bc-sharp-crypto/src/pkix/PkixCertPathValidatorException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a477f7dc47f02643671fa8c53659ff84adfa8cfc
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/PkixCertPathValidatorException.cs
@@ -0,0 +1,221 @@
+using System;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Pkix
+{
+ /**
+ * An exception indicating one of a variety of problems encountered when
+ * validating a certification path.
+ *
+ * A CertPathValidatorException
provides support for wrapping
+ * exceptions. The {@link #getCause getCause} method returns the throwable,
+ * if any, that caused this exception to be thrown.
+ *
+ * A CertPathValidatorException
may also include the
+ * certification path that was being validated when the exception was thrown
+ * and the index of the certificate in the certification path that caused the
+ * exception to be thrown. Use the {@link #getCertPath getCertPath} and
+ * {@link #getIndex getIndex} methods to retrieve this information.
+ *
+ * Concurrent Access
+ *
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CertPathValidator
+ **/
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class PkixCertPathValidatorException
+ : GeneralSecurityException
+ {
+ private Exception cause;
+ private PkixCertPath certPath;
+ private int index = -1;
+
+ public PkixCertPathValidatorException() : base() { }
+
+ ///
+ /// Creates a PkixCertPathValidatorException
with the given detail
+ /// message. A detail message is a String
that describes this
+ /// particular exception.
+ ///
+ /// the detail message
+ public PkixCertPathValidatorException(string message) : base(message) { }
+
+ ///
+ /// Creates a PkixCertPathValidatorException
with the specified
+ /// detail message and cause.
+ ///
+ /// the detail message
+ /// the cause (which is saved for later retrieval by the
+ /// {@link #getCause getCause()} method). (A null
+ /// value is permitted, and indicates that the cause is
+ /// nonexistent or unknown.)
+ public PkixCertPathValidatorException(string message, Exception cause) : base(message)
+ {
+ this.cause = cause;
+ }
+
+ ///
+ /// Creates a PkixCertPathValidatorException
with the specified
+ /// detail message, cause, certification path, and index.
+ ///
+ /// the detail message (or null
if none)
+ /// the cause (or null
if none)
+ /// the certification path that was in the process of being
+ /// validated when the error was encountered
+ /// the index of the certificate in the certification path that *
+ public PkixCertPathValidatorException(
+ string message,
+ Exception cause,
+ PkixCertPath certPath,
+ int index)
+ : base(message)
+ {
+ if (certPath == null && index != -1)
+ {
+ throw new ArgumentNullException(
+ "certPath = null and index != -1");
+ }
+ if (index < -1
+ || (certPath != null && index >= certPath.Certificates.Count))
+ {
+ throw new IndexOutOfRangeException(
+ " index < -1 or out of bound of certPath.getCertificates()");
+ }
+
+ this.cause = cause;
+ this.certPath = certPath;
+ this.index = index;
+ }
+
+ //
+ // Prints a stack trace to a PrintWriter
, including the
+ // backtrace of the cause, if any.
+ //
+ // @param pw
+ // the PrintWriter
to use for output
+ //
+ // public void printStackTrace(PrintWriter pw)
+ // {
+ // super.printStackTrace(pw);
+ // if (getCause() != null)
+ // {
+ // getCause().printStackTrace(pw);
+ // }
+ // }
+ //}
+
+
+ // /**
+ // * Creates a CertPathValidatorException
that wraps the
+ // * specified throwable. This allows any exception to be converted into a
+ // * CertPathValidatorException
, while retaining information
+ // * about the wrapped exception, which may be useful for debugging. The
+ // * detail message is set to (cause==null ? null : cause.toString()
+ // *
)
+ // * (which typically contains the class and detail message of cause).
+ // *
+ // * @param cause
+ // * the cause (which is saved for later retrieval by the
+ // * {@link #getCause getCause()} method). (A null
+ // * value is permitted, and indicates that the cause is
+ // * nonexistent or unknown.)
+ // */
+ // public PkixCertPathValidatorException(Throwable cause)
+ // {
+ // this.cause = cause;
+ // }
+ //
+
+ ///
+ /// Returns the detail message for this CertPathValidatorException
.
+ ///
+ /// the detail message, or null
if neither the message nor cause were specified
+ public override string Message
+ {
+ get
+ {
+ string message = base.Message;
+
+ if (message != null)
+ {
+ return message;
+ }
+
+ if (cause != null)
+ {
+ return cause.Message;
+ }
+
+ return null;
+ }
+ }
+
+ /**
+ * Returns the certification path that was being validated when the
+ * exception was thrown.
+ *
+ * @return the CertPath
that was being validated when the
+ * exception was thrown (or null
if not specified)
+ */
+ public PkixCertPath CertPath
+ {
+ get { return certPath; }
+ }
+
+ /**
+ * Returns the index of the certificate in the certification path that
+ * caused the exception to be thrown. Note that the list of certificates in
+ * a CertPath
is zero based. If no index has been set, -1 is
+ * returned.
+ *
+ * @return the index that has been set, or -1 if none has been set
+ */
+ public int Index
+ {
+ get { return index; }
+ }
+
+// /**
+// * Returns the cause of this CertPathValidatorException
or
+// * null
if the cause is nonexistent or unknown.
+// *
+// * @return the cause of this throwable or null
if the cause
+// * is nonexistent or unknown.
+// */
+// public Throwable getCause()
+// {
+// return cause;
+// }
+//
+// /**
+// * Returns a string describing this exception, including a description of
+// * the internal (wrapped) cause if there is one.
+// *
+// * @return a string representation of this
+// * CertPathValidatorException
+// */
+// public String toString()
+// {
+// StringBuffer sb = new StringBuffer();
+// String s = getMessage();
+// if (s != null)
+// {
+// sb.append(s);
+// }
+// if (getIndex() >= 0)
+// {
+// sb.append("index in certpath: ").append(getIndex()).append('\n');
+// sb.append(getCertPath());
+// }
+// return sb.toString();
+// }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/PkixCertPathValidatorResult.cs b/bc-sharp-crypto/src/pkix/PkixCertPathValidatorResult.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c7d81c7f5a62058c7ded57631bda075c6818a392
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/PkixCertPathValidatorResult.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Pkix
+{
+ ///
+ /// Summary description for PkixCertPathValidatorResult.
+ ///
+ public class PkixCertPathValidatorResult
+ //: ICertPathValidatorResult
+ {
+ private TrustAnchor trustAnchor;
+ private PkixPolicyNode policyTree;
+ private AsymmetricKeyParameter subjectPublicKey;
+
+ public PkixPolicyNode PolicyTree
+ {
+ get { return this.policyTree; }
+ }
+
+ public TrustAnchor TrustAnchor
+ {
+ get { return this.trustAnchor; }
+ }
+
+ public AsymmetricKeyParameter SubjectPublicKey
+ {
+ get { return this.subjectPublicKey; }
+ }
+
+ public PkixCertPathValidatorResult(
+ TrustAnchor trustAnchor,
+ PkixPolicyNode policyTree,
+ AsymmetricKeyParameter subjectPublicKey)
+ {
+ if (subjectPublicKey == null)
+ {
+ throw new NullReferenceException("subjectPublicKey must be non-null");
+ }
+ if (trustAnchor == null)
+ {
+ throw new NullReferenceException("trustAnchor must be non-null");
+ }
+
+ this.trustAnchor = trustAnchor;
+ this.policyTree = policyTree;
+ this.subjectPublicKey = subjectPublicKey;
+ }
+
+ public object Clone()
+ {
+ return new PkixCertPathValidatorResult(this.TrustAnchor, this.PolicyTree, this.SubjectPublicKey);
+ }
+
+ public override String ToString()
+ {
+ StringBuilder sB = new StringBuilder();
+ sB.Append("PKIXCertPathValidatorResult: [ \n");
+ sB.Append(" Trust Anchor: ").Append(this.TrustAnchor).Append('\n');
+ sB.Append(" Policy Tree: ").Append(this.PolicyTree).Append('\n');
+ sB.Append(" Subject Public Key: ").Append(this.SubjectPublicKey).Append("\n]");
+ return sB.ToString();
+ }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/PkixCertPathValidatorUtilities.cs b/bc-sharp-crypto/src/pkix/PkixCertPathValidatorUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a2704a7469fd63542630d6c3f3f52ce977c20368
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/PkixCertPathValidatorUtilities.cs
@@ -0,0 +1,1194 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.IsisMtt;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Extension;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+ ///
+ /// Summary description for PkixCertPathValidatorUtilities.
+ ///
+ public class PkixCertPathValidatorUtilities
+ {
+ private static readonly PkixCrlUtilities CrlUtilities = new PkixCrlUtilities();
+
+ internal static readonly string ANY_POLICY = "2.5.29.32.0";
+
+ internal static readonly string CRL_NUMBER = X509Extensions.CrlNumber.Id;
+
+ ///
+ /// key usage bits
+ ///
+ internal static readonly int KEY_CERT_SIGN = 5;
+ internal static readonly int CRL_SIGN = 6;
+
+ internal static readonly string[] crlReasons = new string[]
+ {
+ "unspecified",
+ "keyCompromise",
+ "cACompromise",
+ "affiliationChanged",
+ "superseded",
+ "cessationOfOperation",
+ "certificateHold",
+ "unknown",
+ "removeFromCRL",
+ "privilegeWithdrawn",
+ "aACompromise"
+ };
+
+ ///
+ /// Search the given Set of TrustAnchor's for one that is the
+ /// issuer of the given X509 certificate.
+ ///
+ /// the X509 certificate
+ /// a Set of TrustAnchor's
+ /// the TrustAnchor
object if found or
+ /// null
if not.
+ ///
+ /// @exception
+ internal static TrustAnchor FindTrustAnchor(
+ X509Certificate cert,
+ ISet trustAnchors)
+ {
+ IEnumerator iter = trustAnchors.GetEnumerator();
+ TrustAnchor trust = null;
+ AsymmetricKeyParameter trustPublicKey = null;
+ Exception invalidKeyEx = null;
+
+ X509CertStoreSelector certSelectX509 = new X509CertStoreSelector();
+
+ try
+ {
+ certSelectX509.Subject = GetIssuerPrincipal(cert);
+ }
+ catch (IOException ex)
+ {
+ throw new Exception("Cannot set subject search criteria for trust anchor.", ex);
+ }
+
+ while (iter.MoveNext() && trust == null)
+ {
+ trust = (TrustAnchor) iter.Current;
+ if (trust.TrustedCert != null)
+ {
+ if (certSelectX509.Match(trust.TrustedCert))
+ {
+ trustPublicKey = trust.TrustedCert.GetPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ else if (trust.CAName != null && trust.CAPublicKey != null)
+ {
+ try
+ {
+ X509Name certIssuer = GetIssuerPrincipal(cert);
+ X509Name caName = new X509Name(trust.CAName);
+
+ if (certIssuer.Equivalent(caName, true))
+ {
+ trustPublicKey = trust.CAPublicKey;
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ catch (InvalidParameterException)
+ {
+ trust = null;
+ }
+ }
+ else
+ {
+ trust = null;
+ }
+
+ if (trustPublicKey != null)
+ {
+ try
+ {
+ cert.Verify(trustPublicKey);
+ }
+ catch (Exception ex)
+ {
+ invalidKeyEx = ex;
+ trust = null;
+ }
+ }
+ }
+
+ if (trust == null && invalidKeyEx != null)
+ {
+ throw new Exception("TrustAnchor found but certificate validation failed.", invalidKeyEx);
+ }
+
+ return trust;
+ }
+
+ internal static void AddAdditionalStoresFromAltNames(
+ X509Certificate cert,
+ PkixParameters pkixParams)
+ {
+ // if in the IssuerAltName extension an URI
+ // is given, add an additinal X.509 store
+ if (cert.GetIssuerAlternativeNames() != null)
+ {
+ IEnumerator it = cert.GetIssuerAlternativeNames().GetEnumerator();
+ while (it.MoveNext())
+ {
+ // look for URI
+ IList list = (IList)it.Current;
+ //if (list[0].Equals(new Integer(GeneralName.UniformResourceIdentifier)))
+ if (list[0].Equals(GeneralName.UniformResourceIdentifier))
+ {
+ // found
+ string temp = (string)list[1];
+ PkixCertPathValidatorUtilities.AddAdditionalStoreFromLocation(temp, pkixParams);
+ }
+ }
+ }
+ }
+
+ internal static DateTime GetValidDate(PkixParameters paramsPKIX)
+ {
+ DateTimeObject validDate = paramsPKIX.Date;
+
+ if (validDate == null)
+ return DateTime.UtcNow;
+
+ return validDate.Value;
+ }
+
+ ///
+ /// Returns the issuer of an attribute certificate or certificate.
+ ///
+ /// The attribute certificate or certificate.
+ /// The issuer as X500Principal
.
+ internal static X509Name GetIssuerPrincipal(
+ object cert)
+ {
+ if (cert is X509Certificate)
+ {
+ return ((X509Certificate)cert).IssuerDN;
+ }
+ else
+ {
+ return ((IX509AttributeCertificate)cert).Issuer.GetPrincipals()[0];
+ }
+ }
+
+ internal static bool IsSelfIssued(
+ X509Certificate cert)
+ {
+ return cert.SubjectDN.Equivalent(cert.IssuerDN, true);
+ }
+
+ internal static AlgorithmIdentifier GetAlgorithmIdentifier(
+ AsymmetricKeyParameter key)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(key);
+
+ return info.AlgorithmID;
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException("Subject public key cannot be decoded.", e);
+ }
+ }
+
+ internal static bool IsAnyPolicy(
+ ISet policySet)
+ {
+ return policySet == null || policySet.Contains(ANY_POLICY) || policySet.Count == 0;
+ }
+
+ internal static void AddAdditionalStoreFromLocation(
+ string location,
+ PkixParameters pkixParams)
+ {
+ if (pkixParams.IsAdditionalLocationsEnabled)
+ {
+ try
+ {
+ if (Platform.StartsWith(location, "ldap://"))
+ {
+ // ldap://directory.d-trust.net/CN=D-TRUST
+ // Qualified CA 2003 1:PN,O=D-Trust GmbH,C=DE
+ // skip "ldap://"
+ location = location.Substring(7);
+ // after first / baseDN starts
+ string url;//, baseDN;
+ int slashPos = location.IndexOf('/');
+ if (slashPos != -1)
+ {
+ url = "ldap://" + location.Substring(0, slashPos);
+// baseDN = location.Substring(slashPos);
+ }
+ else
+ {
+ url = "ldap://" + location;
+// baseDN = nsull;
+ }
+
+ throw Platform.CreateNotImplementedException("LDAP cert/CRL stores");
+
+ // use all purpose parameters
+ //X509LDAPCertStoreParameters ldapParams = new X509LDAPCertStoreParameters.Builder(
+ // url, baseDN).build();
+ //pkixParams.AddAdditionalStore(X509Store.getInstance(
+ // "CERTIFICATE/LDAP", ldapParams));
+ //pkixParams.AddAdditionalStore(X509Store.getInstance(
+ // "CRL/LDAP", ldapParams));
+ //pkixParams.AddAdditionalStore(X509Store.getInstance(
+ // "ATTRIBUTECERTIFICATE/LDAP", ldapParams));
+ //pkixParams.AddAdditionalStore(X509Store.getInstance(
+ // "CERTIFICATEPAIR/LDAP", ldapParams));
+ }
+ }
+ catch (Exception)
+ {
+ // cannot happen
+ throw new Exception("Exception adding X.509 stores.");
+ }
+ }
+ }
+
+ private static BigInteger GetSerialNumber(
+ object cert)
+ {
+ if (cert is X509Certificate)
+ {
+ return ((X509Certificate)cert).SerialNumber;
+ }
+ else
+ {
+ return ((X509V2AttributeCertificate)cert).SerialNumber;
+ }
+ }
+
+ //
+ // policy checking
+ //
+
+ internal static ISet GetQualifierSet(Asn1Sequence qualifiers)
+ {
+ ISet pq = new HashSet();
+
+ if (qualifiers == null)
+ {
+ return pq;
+ }
+
+ foreach (Asn1Encodable ae in qualifiers)
+ {
+ try
+ {
+// pq.Add(PolicyQualifierInfo.GetInstance(Asn1Object.FromByteArray(ae.GetEncoded())));
+ pq.Add(PolicyQualifierInfo.GetInstance(ae.ToAsn1Object()));
+ }
+ catch (IOException ex)
+ {
+ throw new PkixCertPathValidatorException("Policy qualifier info cannot be decoded.", ex);
+ }
+ }
+
+ return pq;
+ }
+
+ internal static PkixPolicyNode RemovePolicyNode(
+ PkixPolicyNode validPolicyTree,
+ IList[] policyNodes,
+ PkixPolicyNode _node)
+ {
+ PkixPolicyNode _parent = (PkixPolicyNode)_node.Parent;
+
+ if (validPolicyTree == null)
+ {
+ return null;
+ }
+
+ if (_parent == null)
+ {
+ for (int j = 0; j < policyNodes.Length; j++)
+ {
+ policyNodes[j] = Platform.CreateArrayList();
+ }
+
+ return null;
+ }
+ else
+ {
+ _parent.RemoveChild(_node);
+ RemovePolicyNodeRecurse(policyNodes, _node);
+
+ return validPolicyTree;
+ }
+ }
+
+ private static void RemovePolicyNodeRecurse(IList[] policyNodes, PkixPolicyNode _node)
+ {
+ policyNodes[_node.Depth].Remove(_node);
+
+ if (_node.HasChildren)
+ {
+ foreach (PkixPolicyNode _child in _node.Children)
+ {
+ RemovePolicyNodeRecurse(policyNodes, _child);
+ }
+ }
+ }
+
+ internal static void PrepareNextCertB1(
+ int i,
+ IList[] policyNodes,
+ string id_p,
+ IDictionary m_idp,
+ X509Certificate cert)
+ {
+ bool idp_found = false;
+ IEnumerator nodes_i = policyNodes[i].GetEnumerator();
+ while (nodes_i.MoveNext())
+ {
+ PkixPolicyNode node = (PkixPolicyNode)nodes_i.Current;
+ if (node.ValidPolicy.Equals(id_p))
+ {
+ idp_found = true;
+ node.ExpectedPolicies = (ISet)m_idp[id_p];
+ break;
+ }
+ }
+
+ if (!idp_found)
+ {
+ nodes_i = policyNodes[i].GetEnumerator();
+ while (nodes_i.MoveNext())
+ {
+ PkixPolicyNode node = (PkixPolicyNode)nodes_i.Current;
+ if (ANY_POLICY.Equals(node.ValidPolicy))
+ {
+ ISet pq = null;
+ Asn1Sequence policies = null;
+ try
+ {
+ policies = DerSequence.GetInstance(GetExtensionValue(cert, X509Extensions.CertificatePolicies));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Certificate policies cannot be decoded.", e);
+ }
+
+ IEnumerator enm = policies.GetEnumerator();
+ while (enm.MoveNext())
+ {
+ PolicyInformation pinfo = null;
+
+ try
+ {
+ pinfo = PolicyInformation.GetInstance(enm.Current);
+ }
+ catch (Exception ex)
+ {
+ throw new Exception("Policy information cannot be decoded.", ex);
+ }
+
+ if (ANY_POLICY.Equals(pinfo.PolicyIdentifier.Id))
+ {
+ try
+ {
+ pq = GetQualifierSet(pinfo.PolicyQualifiers);
+ }
+ catch (PkixCertPathValidatorException ex)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy qualifier info set could not be built.", ex);
+ }
+ break;
+ }
+ }
+ bool ci = false;
+ ISet critExtOids = cert.GetCriticalExtensionOids();
+ if (critExtOids != null)
+ {
+ ci = critExtOids.Contains(X509Extensions.CertificatePolicies.Id);
+ }
+
+ PkixPolicyNode p_node = (PkixPolicyNode)node.Parent;
+ if (ANY_POLICY.Equals(p_node.ValidPolicy))
+ {
+ PkixPolicyNode c_node = new PkixPolicyNode(
+ Platform.CreateArrayList(), i,
+ (ISet)m_idp[id_p],
+ p_node, pq, id_p, ci);
+ p_node.AddChild(c_node);
+ policyNodes[i].Add(c_node);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ internal static PkixPolicyNode PrepareNextCertB2(
+ int i,
+ IList[] policyNodes,
+ string id_p,
+ PkixPolicyNode validPolicyTree)
+ {
+ int pos = 0;
+
+ // Copy to avoid RemoveAt calls interfering with enumeration
+ foreach (PkixPolicyNode node in Platform.CreateArrayList(policyNodes[i]))
+ {
+ if (node.ValidPolicy.Equals(id_p))
+ {
+ PkixPolicyNode p_node = (PkixPolicyNode)node.Parent;
+ p_node.RemoveChild(node);
+
+ // Removal of element at current iterator position not supported in C#
+ //nodes_i.remove();
+ policyNodes[i].RemoveAt(pos);
+
+ for (int k = (i - 1); k >= 0; k--)
+ {
+ IList nodes = policyNodes[k];
+ for (int l = 0; l < nodes.Count; l++)
+ {
+ PkixPolicyNode node2 = (PkixPolicyNode)nodes[l];
+ if (!node2.HasChildren)
+ {
+ validPolicyTree = RemovePolicyNode(validPolicyTree, policyNodes, node2);
+ if (validPolicyTree == null)
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ ++pos;
+ }
+ }
+ return validPolicyTree;
+ }
+
+ internal static void GetCertStatus(
+ DateTime validDate,
+ X509Crl crl,
+ Object cert,
+ CertStatus certStatus)
+ {
+ X509Crl bcCRL = null;
+
+ try
+ {
+ bcCRL = new X509Crl(CertificateList.GetInstance((Asn1Sequence)Asn1Sequence.FromByteArray(crl.GetEncoded())));
+ }
+ catch (Exception exception)
+ {
+ throw new Exception("Bouncy Castle X509Crl could not be created.", exception);
+ }
+
+ X509CrlEntry crl_entry = (X509CrlEntry)bcCRL.GetRevokedCertificate(GetSerialNumber(cert));
+
+ if (crl_entry == null)
+ return;
+
+ X509Name issuer = GetIssuerPrincipal(cert);
+
+ if (issuer.Equivalent(crl_entry.GetCertificateIssuer(), true)
+ || issuer.Equivalent(crl.IssuerDN, true))
+ {
+ DerEnumerated reasonCode = null;
+ if (crl_entry.HasExtensions)
+ {
+ try
+ {
+ reasonCode = DerEnumerated.GetInstance(
+ GetExtensionValue(crl_entry, X509Extensions.ReasonCode));
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Reason code CRL entry extension could not be decoded.",
+ e);
+ }
+ }
+
+ // for reason keyCompromise, caCompromise, aACompromise or
+ // unspecified
+ if (!(validDate.Ticks < crl_entry.RevocationDate.Ticks)
+ || reasonCode == null
+ || reasonCode.Value.TestBit(0)
+ || reasonCode.Value.TestBit(1)
+ || reasonCode.Value.TestBit(2)
+ || reasonCode.Value.TestBit(8))
+ {
+ if (reasonCode != null) // (i) or (j) (1)
+ {
+ certStatus.Status = reasonCode.Value.SignValue;
+ }
+ else // (i) or (j) (2)
+ {
+ certStatus.Status = CrlReason.Unspecified;
+ }
+ certStatus.RevocationDate = new DateTimeObject(crl_entry.RevocationDate);
+ }
+ }
+ }
+
+ /**
+ * Return the next working key inheriting DSA parameters if necessary.
+ *
+ * This methods inherits DSA parameters from the indexed certificate or
+ * previous certificates in the certificate chain to the returned
+ * PublicKey
. The list is searched upwards, meaning the end
+ * certificate is at position 0 and previous certificates are following.
+ *
+ *
+ * If the indexed certificate does not contain a DSA key this method simply
+ * returns the public key. If the DSA key already contains DSA parameters
+ * the key is also only returned.
+ *
+ *
+ * @param certs The certification path.
+ * @param index The index of the certificate which contains the public key
+ * which should be extended with DSA parameters.
+ * @return The public key of the certificate in list position
+ * index
extended with DSA parameters if applicable.
+ * @throws Exception if DSA parameters cannot be inherited.
+ */
+ internal static AsymmetricKeyParameter GetNextWorkingKey(
+ IList certs,
+ int index)
+ {
+ //Only X509Certificate
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ AsymmetricKeyParameter pubKey = cert.GetPublicKey();
+
+ if (!(pubKey is DsaPublicKeyParameters))
+ return pubKey;
+
+ DsaPublicKeyParameters dsaPubKey = (DsaPublicKeyParameters)pubKey;
+
+ if (dsaPubKey.Parameters != null)
+ return dsaPubKey;
+
+ for (int i = index + 1; i < certs.Count; i++)
+ {
+ X509Certificate parentCert = (X509Certificate)certs[i];
+ pubKey = parentCert.GetPublicKey();
+
+ if (!(pubKey is DsaPublicKeyParameters))
+ {
+ throw new PkixCertPathValidatorException(
+ "DSA parameters cannot be inherited from previous certificate.");
+ }
+
+ DsaPublicKeyParameters prevDSAPubKey = (DsaPublicKeyParameters)pubKey;
+
+ if (prevDSAPubKey.Parameters == null)
+ continue;
+
+ DsaParameters dsaParams = prevDSAPubKey.Parameters;
+
+ try
+ {
+ return new DsaPublicKeyParameters(dsaPubKey.Y, dsaParams);
+ }
+ catch (Exception exception)
+ {
+ throw new Exception(exception.Message);
+ }
+ }
+
+ throw new PkixCertPathValidatorException("DSA parameters cannot be inherited from previous certificate.");
+ }
+
+ internal static DateTime GetValidCertDateFromValidityModel(
+ PkixParameters paramsPkix,
+ PkixCertPath certPath,
+ int index)
+ {
+ if (paramsPkix.ValidityModel != PkixParameters.ChainValidityModel)
+ {
+ return GetValidDate(paramsPkix);
+ }
+
+ // if end cert use given signing/encryption/... time
+ if (index <= 0)
+ {
+ return PkixCertPathValidatorUtilities.GetValidDate(paramsPkix);
+ // else use time when previous cert was created
+ }
+
+ if (index - 1 == 0)
+ {
+ DerGeneralizedTime dateOfCertgen = null;
+ try
+ {
+ X509Certificate cert = (X509Certificate)certPath.Certificates[index - 1];
+ Asn1OctetString extVal = cert.GetExtensionValue(
+ IsisMttObjectIdentifiers.IdIsisMttATDateOfCertGen);
+ dateOfCertgen = DerGeneralizedTime.GetInstance(extVal);
+ }
+ catch (ArgumentException)
+ {
+ throw new Exception(
+ "Date of cert gen extension could not be read.");
+ }
+ if (dateOfCertgen != null)
+ {
+ try
+ {
+ return dateOfCertgen.ToDateTime();
+ }
+ catch (ArgumentException e)
+ {
+ throw new Exception(
+ "Date from date of cert gen extension could not be parsed.",
+ e);
+ }
+ }
+ }
+
+ return ((X509Certificate)certPath.Certificates[index - 1]).NotBefore;
+ }
+
+ ///
+ /// Return a Collection of all certificates or attribute certificates found
+ /// in the X509Store's that are matching the certSelect criteriums.
+ ///
+ /// a {@link Selector} object that will be used to select
+ /// the certificates
+ /// a List containing only X509Store objects. These
+ /// are used to search for certificates.
+ /// a Collection of all found or
+ /// objects.
+ /// May be empty but never null
.
+ ///
+ internal static ICollection FindCertificates(
+ X509CertStoreSelector certSelect,
+ IList certStores)
+ {
+ ISet certs = new HashSet();
+
+ foreach (IX509Store certStore in certStores)
+ {
+ try
+ {
+// certs.AddAll(certStore.GetMatches(certSelect));
+ foreach (X509Certificate c in certStore.GetMatches(certSelect))
+ {
+ certs.Add(c);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Problem while picking certificates from X.509 store.", e);
+ }
+ }
+
+ return certs;
+ }
+
+ /**
+ * Add the CRL issuers from the cRLIssuer field of the distribution point or
+ * from the certificate if not given to the issuer criterion of the
+ * selector
.
+ *
+ * The issuerPrincipals
are a collection with a single
+ * X500Principal
for X509Certificate
s. For
+ * {@link X509AttributeCertificate}s the issuer may contain more than one
+ * X500Principal
.
+ *
+ *
+ * @param dp The distribution point.
+ * @param issuerPrincipals The issuers of the certificate or attribute
+ * certificate which contains the distribution point.
+ * @param selector The CRL selector.
+ * @param pkixParams The PKIX parameters containing the cert stores.
+ * @throws Exception if an exception occurs while processing.
+ * @throws ClassCastException if issuerPrincipals
does not
+ * contain only X500Principal
s.
+ */
+ internal static void GetCrlIssuersFromDistributionPoint(
+ DistributionPoint dp,
+ ICollection issuerPrincipals,
+ X509CrlStoreSelector selector,
+ PkixParameters pkixParams)
+ {
+ IList issuers = Platform.CreateArrayList();
+ // indirect CRL
+ if (dp.CrlIssuer != null)
+ {
+ GeneralName[] genNames = dp.CrlIssuer.GetNames();
+ // look for a DN
+ for (int j = 0; j < genNames.Length; j++)
+ {
+ if (genNames[j].TagNo == GeneralName.DirectoryName)
+ {
+ try
+ {
+ issuers.Add(X509Name.GetInstance(genNames[j].Name.ToAsn1Object()));
+ }
+ catch (IOException e)
+ {
+ throw new Exception(
+ "CRL issuer information from distribution point cannot be decoded.",
+ e);
+ }
+ }
+ }
+ }
+ else
+ {
+ /*
+ * certificate issuer is CRL issuer, distributionPoint field MUST be
+ * present.
+ */
+ if (dp.DistributionPointName == null)
+ {
+ throw new Exception(
+ "CRL issuer is omitted from distribution point but no distributionPoint field present.");
+ }
+
+ // add and check issuer principals
+ for (IEnumerator it = issuerPrincipals.GetEnumerator(); it.MoveNext(); )
+ {
+ issuers.Add((X509Name)it.Current);
+ }
+ }
+ // TODO: is not found although this should correctly add the rel name. selector of Sun is buggy here or PKI test case is invalid
+ // distributionPoint
+ // if (dp.getDistributionPoint() != null)
+ // {
+ // // look for nameRelativeToCRLIssuer
+ // if (dp.getDistributionPoint().getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
+ // {
+ // // append fragment to issuer, only one
+ // // issuer can be there, if this is given
+ // if (issuers.size() != 1)
+ // {
+ // throw new AnnotatedException(
+ // "nameRelativeToCRLIssuer field is given but more than one CRL issuer is given.");
+ // }
+ // DEREncodable relName = dp.getDistributionPoint().getName();
+ // Iterator it = issuers.iterator();
+ // List issuersTemp = new ArrayList(issuers.size());
+ // while (it.hasNext())
+ // {
+ // Enumeration e = null;
+ // try
+ // {
+ // e = ASN1Sequence.getInstance(
+ // new ASN1InputStream(((X500Principal) it.next())
+ // .getEncoded()).readObject()).getObjects();
+ // }
+ // catch (IOException ex)
+ // {
+ // throw new AnnotatedException(
+ // "Cannot decode CRL issuer information.", ex);
+ // }
+ // ASN1EncodableVector v = new ASN1EncodableVector();
+ // while (e.hasMoreElements())
+ // {
+ // v.add((DEREncodable) e.nextElement());
+ // }
+ // v.add(relName);
+ // issuersTemp.add(new X500Principal(new DERSequence(v)
+ // .getDEREncoded()));
+ // }
+ // issuers.clear();
+ // issuers.addAll(issuersTemp);
+ // }
+ // }
+
+ selector.Issuers = issuers;
+ }
+
+ /**
+ * Fetches complete CRLs according to RFC 3280.
+ *
+ * @param dp The distribution point for which the complete CRL
+ * @param cert The X509Certificate
or
+ * {@link org.bouncycastle.x509.X509AttributeCertificate} for
+ * which the CRL should be searched.
+ * @param currentDate The date for which the delta CRLs must be valid.
+ * @param paramsPKIX The extended PKIX parameters.
+ * @return A Set
of X509CRL
s with complete
+ * CRLs.
+ * @throws Exception if an exception occurs while picking the CRLs
+ * or no CRLs are found.
+ */
+ internal static ISet GetCompleteCrls(
+ DistributionPoint dp,
+ object cert,
+ DateTime currentDate,
+ PkixParameters paramsPKIX)
+ {
+ X509CrlStoreSelector crlselect = new X509CrlStoreSelector();
+ try
+ {
+ ISet issuers = new HashSet();
+ if (cert is X509V2AttributeCertificate)
+ {
+ issuers.Add(((X509V2AttributeCertificate)cert)
+ .Issuer.GetPrincipals()[0]);
+ }
+ else
+ {
+ issuers.Add(GetIssuerPrincipal(cert));
+ }
+ PkixCertPathValidatorUtilities.GetCrlIssuersFromDistributionPoint(dp, issuers, crlselect, paramsPKIX);
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Could not get issuer information from distribution point.", e);
+ }
+
+ if (cert is X509Certificate)
+ {
+ crlselect.CertificateChecking = (X509Certificate)cert;
+ }
+ else if (cert is X509V2AttributeCertificate)
+ {
+ crlselect.AttrCertChecking = (IX509AttributeCertificate)cert;
+ }
+
+ crlselect.CompleteCrlEnabled = true;
+ ISet crls = CrlUtilities.FindCrls(crlselect, paramsPKIX, currentDate);
+
+ if (crls.IsEmpty)
+ {
+ if (cert is IX509AttributeCertificate)
+ {
+ IX509AttributeCertificate aCert = (IX509AttributeCertificate)cert;
+
+ throw new Exception("No CRLs found for issuer \"" + aCert.Issuer.GetPrincipals()[0] + "\"");
+ }
+ else
+ {
+ X509Certificate xCert = (X509Certificate)cert;
+
+ throw new Exception("No CRLs found for issuer \"" + xCert.IssuerDN + "\"");
+ }
+ }
+
+ return crls;
+ }
+
+ /**
+ * Fetches delta CRLs according to RFC 3280 section 5.2.4.
+ *
+ * @param currentDate The date for which the delta CRLs must be valid.
+ * @param paramsPKIX The extended PKIX parameters.
+ * @param completeCRL The complete CRL the delta CRL is for.
+ * @return A Set
of X509CRL
s with delta CRLs.
+ * @throws Exception if an exception occurs while picking the delta
+ * CRLs.
+ */
+ internal static ISet GetDeltaCrls(
+ DateTime currentDate,
+ PkixParameters paramsPKIX,
+ X509Crl completeCRL)
+ {
+ X509CrlStoreSelector deltaSelect = new X509CrlStoreSelector();
+
+ // 5.2.4 (a)
+ try
+ {
+ IList deltaSelectIssuer = Platform.CreateArrayList();
+ deltaSelectIssuer.Add(completeCRL.IssuerDN);
+ deltaSelect.Issuers = deltaSelectIssuer;
+ }
+ catch (IOException e)
+ {
+ throw new Exception("Cannot extract issuer from CRL.", e);
+ }
+
+ BigInteger completeCRLNumber = null;
+ try
+ {
+ Asn1Object asn1Object = GetExtensionValue(completeCRL, X509Extensions.CrlNumber);
+ if (asn1Object != null)
+ {
+ completeCRLNumber = CrlNumber.GetInstance(asn1Object).PositiveValue;
+ }
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "CRL number extension could not be extracted from CRL.", e);
+ }
+
+ // 5.2.4 (b)
+ byte[] idp = null;
+
+ try
+ {
+ Asn1Object obj = GetExtensionValue(completeCRL, X509Extensions.IssuingDistributionPoint);
+ if (obj != null)
+ {
+ idp = obj.GetDerEncoded();
+ }
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Issuing distribution point extension value could not be read.",
+ e);
+ }
+
+ // 5.2.4 (d)
+
+ deltaSelect.MinCrlNumber = (completeCRLNumber == null)
+ ? null
+ : completeCRLNumber.Add(BigInteger.One);
+
+ deltaSelect.IssuingDistributionPoint = idp;
+ deltaSelect.IssuingDistributionPointEnabled = true;
+
+ // 5.2.4 (c)
+ deltaSelect.MaxBaseCrlNumber = completeCRLNumber;
+
+ // find delta CRLs
+ ISet temp = CrlUtilities.FindCrls(deltaSelect, paramsPKIX, currentDate);
+
+ ISet result = new HashSet();
+
+ foreach (X509Crl crl in temp)
+ {
+ if (isDeltaCrl(crl))
+ {
+ result.Add(crl);
+ }
+ }
+
+ return result;
+ }
+
+ private static bool isDeltaCrl(
+ X509Crl crl)
+ {
+ ISet critical = crl.GetCriticalExtensionOids();
+
+ return critical.Contains(X509Extensions.DeltaCrlIndicator.Id);
+ }
+
+ internal static ICollection FindCertificates(
+ X509AttrCertStoreSelector certSelect,
+ IList certStores)
+ {
+ ISet certs = new HashSet();
+
+ foreach (IX509Store certStore in certStores)
+ {
+ try
+ {
+// certs.AddAll(certStore.GetMatches(certSelect));
+ foreach (X509V2AttributeCertificate ac in certStore.GetMatches(certSelect))
+ {
+ certs.Add(ac);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Problem while picking certificates from X.509 store.", e);
+ }
+ }
+
+ return certs;
+ }
+
+ internal static void AddAdditionalStoresFromCrlDistributionPoint(
+ CrlDistPoint crldp,
+ PkixParameters pkixParams)
+ {
+ if (crldp != null)
+ {
+ DistributionPoint[] dps = null;
+ try
+ {
+ dps = crldp.GetDistributionPoints();
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Distribution points could not be read.", e);
+ }
+ for (int i = 0; i < dps.Length; i++)
+ {
+ DistributionPointName dpn = dps[i].DistributionPointName;
+ // look for URIs in fullName
+ if (dpn != null)
+ {
+ if (dpn.PointType == DistributionPointName.FullName)
+ {
+ GeneralName[] genNames = GeneralNames.GetInstance(
+ dpn.Name).GetNames();
+ // look for an URI
+ for (int j = 0; j < genNames.Length; j++)
+ {
+ if (genNames[j].TagNo == GeneralName.UniformResourceIdentifier)
+ {
+ string location = DerIA5String.GetInstance(
+ genNames[j].Name).GetString();
+ PkixCertPathValidatorUtilities.AddAdditionalStoreFromLocation(
+ location, pkixParams);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ internal static bool ProcessCertD1i(
+ int index,
+ IList[] policyNodes,
+ DerObjectIdentifier pOid,
+ ISet pq)
+ {
+ IList policyNodeVec = policyNodes[index - 1];
+
+ for (int j = 0; j < policyNodeVec.Count; j++)
+ {
+ PkixPolicyNode node = (PkixPolicyNode)policyNodeVec[j];
+ ISet expectedPolicies = node.ExpectedPolicies;
+
+ if (expectedPolicies.Contains(pOid.Id))
+ {
+ ISet childExpectedPolicies = new HashSet();
+ childExpectedPolicies.Add(pOid.Id);
+
+ PkixPolicyNode child = new PkixPolicyNode(Platform.CreateArrayList(),
+ index,
+ childExpectedPolicies,
+ node,
+ pq,
+ pOid.Id,
+ false);
+ node.AddChild(child);
+ policyNodes[index].Add(child);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ internal static void ProcessCertD1ii(
+ int index,
+ IList[] policyNodes,
+ DerObjectIdentifier _poid,
+ ISet _pq)
+ {
+ IList policyNodeVec = policyNodes[index - 1];
+
+ for (int j = 0; j < policyNodeVec.Count; j++)
+ {
+ PkixPolicyNode _node = (PkixPolicyNode)policyNodeVec[j];
+
+ if (ANY_POLICY.Equals(_node.ValidPolicy))
+ {
+ ISet _childExpectedPolicies = new HashSet();
+ _childExpectedPolicies.Add(_poid.Id);
+
+ PkixPolicyNode _child = new PkixPolicyNode(Platform.CreateArrayList(),
+ index,
+ _childExpectedPolicies,
+ _node,
+ _pq,
+ _poid.Id,
+ false);
+ _node.AddChild(_child);
+ policyNodes[index].Add(_child);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Find the issuer certificates of a given certificate.
+ *
+ * @param cert
+ * The certificate for which an issuer should be found.
+ * @param pkixParams
+ * @return A Collection
object containing the issuer
+ * X509Certificate
s. Never null
.
+ *
+ * @exception Exception
+ * if an error occurs.
+ */
+ internal static ICollection FindIssuerCerts(
+ X509Certificate cert,
+ PkixBuilderParameters pkixParams)
+ {
+ X509CertStoreSelector certSelect = new X509CertStoreSelector();
+ ISet certs = new HashSet();
+ try
+ {
+ certSelect.Subject = cert.IssuerDN;
+ }
+ catch (IOException ex)
+ {
+ throw new Exception(
+ "Subject criteria for certificate selector to find issuer certificate could not be set.", ex);
+ }
+
+ try
+ {
+ certs.AddAll(PkixCertPathValidatorUtilities.FindCertificates(certSelect, pkixParams.GetStores()));
+ certs.AddAll(PkixCertPathValidatorUtilities.FindCertificates(certSelect, pkixParams.GetAdditionalStores()));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Issuer certificate cannot be searched.", e);
+ }
+
+ return certs;
+ }
+
+ ///
+ /// Extract the value of the given extension, if it exists.
+ ///
+ /// The extension object.
+ /// The object identifier to obtain.
+ /// Asn1Object
+ /// if the extension cannot be read.
+ internal static Asn1Object GetExtensionValue(
+ IX509Extension ext,
+ DerObjectIdentifier oid)
+ {
+ Asn1OctetString bytes = ext.GetExtensionValue(oid);
+
+ if (bytes == null)
+ return null;
+
+ return X509ExtensionUtilities.FromExtensionValue(bytes);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/PkixCrlUtilities.cs b/bc-sharp-crypto/src/pkix/PkixCrlUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c386b8a057155a776f321f0b572b011c01ddf236
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/PkixCrlUtilities.cs
@@ -0,0 +1,114 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+ public class PkixCrlUtilities
+ {
+ public virtual ISet FindCrls(X509CrlStoreSelector crlselect, PkixParameters paramsPkix, DateTime currentDate)
+ {
+ ISet initialSet = new HashSet();
+
+ // get complete CRL(s)
+ try
+ {
+ initialSet.AddAll(FindCrls(crlselect, paramsPkix.GetAdditionalStores()));
+ initialSet.AddAll(FindCrls(crlselect, paramsPkix.GetStores()));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Exception obtaining complete CRLs.", e);
+ }
+
+ ISet finalSet = new HashSet();
+ DateTime validityDate = currentDate;
+
+ if (paramsPkix.Date != null)
+ {
+ validityDate = paramsPkix.Date.Value;
+ }
+
+ // based on RFC 5280 6.3.3
+ foreach (X509Crl crl in initialSet)
+ {
+ if (crl.NextUpdate.Value.CompareTo(validityDate) > 0)
+ {
+ X509Certificate cert = crlselect.CertificateChecking;
+
+ if (cert != null)
+ {
+ if (crl.ThisUpdate.CompareTo(cert.NotAfter) < 0)
+ {
+ finalSet.Add(crl);
+ }
+ }
+ else
+ {
+ finalSet.Add(crl);
+ }
+ }
+ }
+
+ return finalSet;
+ }
+
+ public virtual ISet FindCrls(X509CrlStoreSelector crlselect, PkixParameters paramsPkix)
+ {
+ ISet completeSet = new HashSet();
+
+ // get complete CRL(s)
+ try
+ {
+ completeSet.AddAll(FindCrls(crlselect, paramsPkix.GetStores()));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Exception obtaining complete CRLs.", e);
+ }
+
+ return completeSet;
+ }
+
+ ///
+ /// crl checking
+ /// Return a Collection of all CRLs found in the X509Store's that are
+ /// matching the crlSelect criteriums.
+ ///
+ /// a {@link X509CRLStoreSelector} object that will be used
+ /// to select the CRLs
+ /// a List containing only {@link org.bouncycastle.x509.X509Store
+ /// X509Store} objects. These are used to search for CRLs
+ /// a Collection of all found {@link X509CRL X509CRL} objects. May be
+ /// empty but never null
.
+ ///
+ private ICollection FindCrls(X509CrlStoreSelector crlSelect, IList crlStores)
+ {
+ ISet crls = new HashSet();
+
+ Exception lastException = null;
+ bool foundValidStore = false;
+
+ foreach (IX509Store store in crlStores)
+ {
+ try
+ {
+ crls.AddAll(store.GetMatches(crlSelect));
+ foundValidStore = true;
+ }
+ catch (X509StoreException e)
+ {
+ lastException = new Exception("Exception searching in X.509 CRL store.", e);
+ }
+ }
+
+ if (!foundValidStore && lastException != null)
+ throw lastException;
+
+ return crls;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/PkixNameConstraintValidator.cs b/bc-sharp-crypto/src/pkix/PkixNameConstraintValidator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f4ae73925d937ce7c4f45f458a5635cde4e44da3
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/PkixNameConstraintValidator.cs
@@ -0,0 +1,1939 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Pkix
+{
+ public class PkixNameConstraintValidator
+ {
+ private ISet excludedSubtreesDN = new HashSet();
+
+ private ISet excludedSubtreesDNS = new HashSet();
+
+ private ISet excludedSubtreesEmail = new HashSet();
+
+ private ISet excludedSubtreesURI = new HashSet();
+
+ private ISet excludedSubtreesIP = new HashSet();
+
+ private ISet permittedSubtreesDN;
+
+ private ISet permittedSubtreesDNS;
+
+ private ISet permittedSubtreesEmail;
+
+ private ISet permittedSubtreesURI;
+
+ private ISet permittedSubtreesIP;
+
+ public PkixNameConstraintValidator()
+ {
+ }
+
+ private static bool WithinDNSubtree(
+ Asn1Sequence dns,
+ Asn1Sequence subtree)
+ {
+ if (subtree.Count < 1)
+ {
+ return false;
+ }
+
+ if (subtree.Count > dns.Count)
+ {
+ return false;
+ }
+
+ for (int j = subtree.Count - 1; j >= 0; j--)
+ {
+ if (!(subtree[j].Equals(dns[j])))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public void CheckPermittedDN(Asn1Sequence dns)
+ //throws PkixNameConstraintValidatorException
+ {
+ CheckPermittedDN(permittedSubtreesDN, dns);
+ }
+
+ public void CheckExcludedDN(Asn1Sequence dns)
+ //throws PkixNameConstraintValidatorException
+ {
+ CheckExcludedDN(excludedSubtreesDN, dns);
+ }
+
+ private void CheckPermittedDN(ISet permitted, Asn1Sequence dns)
+ //throws PkixNameConstraintValidatorException
+ {
+ if (permitted == null)
+ {
+ return;
+ }
+
+ if ((permitted.Count == 0) && dns.Count == 0)
+ {
+ return;
+ }
+
+ IEnumerator it = permitted.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ Asn1Sequence subtree = (Asn1Sequence)it.Current;
+
+ if (WithinDNSubtree(dns, subtree))
+ {
+ return;
+ }
+ }
+
+ throw new PkixNameConstraintValidatorException(
+ "Subject distinguished name is not from a permitted subtree");
+ }
+
+ private void CheckExcludedDN(ISet excluded, Asn1Sequence dns)
+ //throws PkixNameConstraintValidatorException
+ {
+ if (excluded.IsEmpty)
+ {
+ return;
+ }
+
+ IEnumerator it = excluded.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ Asn1Sequence subtree = (Asn1Sequence)it.Current;
+
+ if (WithinDNSubtree(dns, subtree))
+ {
+ throw new PkixNameConstraintValidatorException(
+ "Subject distinguished name is from an excluded subtree");
+ }
+ }
+ }
+
+ private ISet IntersectDN(ISet permitted, ISet dns)
+ {
+ ISet intersect = new HashSet();
+ for (IEnumerator it = dns.GetEnumerator(); it.MoveNext(); )
+ {
+ Asn1Sequence dn = Asn1Sequence.GetInstance(((GeneralSubtree)it
+ .Current).Base.Name.ToAsn1Object());
+ if (permitted == null)
+ {
+ if (dn != null)
+ {
+ intersect.Add(dn);
+ }
+ }
+ else
+ {
+ IEnumerator _iter = permitted.GetEnumerator();
+ while (_iter.MoveNext())
+ {
+ Asn1Sequence subtree = (Asn1Sequence)_iter.Current;
+
+ if (WithinDNSubtree(dn, subtree))
+ {
+ intersect.Add(dn);
+ }
+ else if (WithinDNSubtree(subtree, dn))
+ {
+ intersect.Add(subtree);
+ }
+ }
+ }
+ }
+ return intersect;
+ }
+
+ private ISet UnionDN(ISet excluded, Asn1Sequence dn)
+ {
+ if (excluded.IsEmpty)
+ {
+ if (dn == null)
+ {
+ return excluded;
+ }
+ excluded.Add(dn);
+
+ return excluded;
+ }
+ else
+ {
+ ISet intersect = new HashSet();
+
+ IEnumerator it = excluded.GetEnumerator();
+ while (it.MoveNext())
+ {
+ Asn1Sequence subtree = (Asn1Sequence)it.Current;
+
+ if (WithinDNSubtree(dn, subtree))
+ {
+ intersect.Add(subtree);
+ }
+ else if (WithinDNSubtree(subtree, dn))
+ {
+ intersect.Add(dn);
+ }
+ else
+ {
+ intersect.Add(subtree);
+ intersect.Add(dn);
+ }
+ }
+
+ return intersect;
+ }
+ }
+
+ private ISet IntersectEmail(ISet permitted, ISet emails)
+ {
+ ISet intersect = new HashSet();
+ for (IEnumerator it = emails.GetEnumerator(); it.MoveNext(); )
+ {
+ String email = ExtractNameAsString(((GeneralSubtree)it.Current)
+ .Base);
+
+ if (permitted == null)
+ {
+ if (email != null)
+ {
+ intersect.Add(email);
+ }
+ }
+ else
+ {
+ IEnumerator it2 = permitted.GetEnumerator();
+ while (it2.MoveNext())
+ {
+ String _permitted = (String)it2.Current;
+
+ intersectEmail(email, _permitted, intersect);
+ }
+ }
+ }
+ return intersect;
+ }
+
+ private ISet UnionEmail(ISet excluded, String email)
+ {
+ if (excluded.IsEmpty)
+ {
+ if (email == null)
+ {
+ return excluded;
+ }
+ excluded.Add(email);
+ return excluded;
+ }
+ else
+ {
+ ISet union = new HashSet();
+
+ IEnumerator it = excluded.GetEnumerator();
+ while (it.MoveNext())
+ {
+ String _excluded = (String)it.Current;
+
+ unionEmail(_excluded, email, union);
+ }
+
+ return union;
+ }
+ }
+
+ /**
+ * Returns the intersection of the permitted IP ranges in
+ * permitted
with ip
.
+ *
+ * @param permitted A Set
of permitted IP addresses with
+ * their subnet mask as byte arrays.
+ * @param ips The IP address with its subnet mask.
+ * @return The Set
of permitted IP ranges intersected with
+ * ip
.
+ */
+ private ISet IntersectIP(ISet permitted, ISet ips)
+ {
+ ISet intersect = new HashSet();
+ for (IEnumerator it = ips.GetEnumerator(); it.MoveNext(); )
+ {
+ byte[] ip = Asn1OctetString.GetInstance(
+ ((GeneralSubtree)it.Current).Base.Name).GetOctets();
+ if (permitted == null)
+ {
+ if (ip != null)
+ {
+ intersect.Add(ip);
+ }
+ }
+ else
+ {
+ IEnumerator it2 = permitted.GetEnumerator();
+ while (it2.MoveNext())
+ {
+ byte[] _permitted = (byte[])it2.Current;
+ intersect.AddAll(IntersectIPRange(_permitted, ip));
+ }
+ }
+ }
+ return intersect;
+ }
+
+ /**
+ * Returns the union of the excluded IP ranges in excluded
+ * with ip
.
+ *
+ * @param excluded A Set
of excluded IP addresses with their
+ * subnet mask as byte arrays.
+ * @param ip The IP address with its subnet mask.
+ * @return The Set
of excluded IP ranges unified with
+ * ip
as byte arrays.
+ */
+ private ISet UnionIP(ISet excluded, byte[] ip)
+ {
+ if (excluded.IsEmpty)
+ {
+ if (ip == null)
+ {
+ return excluded;
+ }
+ excluded.Add(ip);
+
+ return excluded;
+ }
+ else
+ {
+ ISet union = new HashSet();
+
+ IEnumerator it = excluded.GetEnumerator();
+ while (it.MoveNext())
+ {
+ byte[] _excluded = (byte[])it.Current;
+ union.AddAll(UnionIPRange(_excluded, ip));
+ }
+
+ return union;
+ }
+ }
+
+ /**
+ * Calculates the union if two IP ranges.
+ *
+ * @param ipWithSubmask1 The first IP address with its subnet mask.
+ * @param ipWithSubmask2 The second IP address with its subnet mask.
+ * @return A Set
with the union of both addresses.
+ */
+ private ISet UnionIPRange(byte[] ipWithSubmask1, byte[] ipWithSubmask2)
+ {
+ ISet set = new HashSet();
+
+ // difficult, adding always all IPs is not wrong
+ if (Org.BouncyCastle.Utilities.Arrays.AreEqual(ipWithSubmask1, ipWithSubmask2))
+ {
+ set.Add(ipWithSubmask1);
+ }
+ else
+ {
+ set.Add(ipWithSubmask1);
+ set.Add(ipWithSubmask2);
+ }
+ return set;
+ }
+
+ /**
+ * Calculates the interesction if two IP ranges.
+ *
+ * @param ipWithSubmask1 The first IP address with its subnet mask.
+ * @param ipWithSubmask2 The second IP address with its subnet mask.
+ * @return A Set
with the single IP address with its subnet
+ * mask as a byte array or an empty Set
.
+ */
+ private ISet IntersectIPRange(byte[] ipWithSubmask1, byte[] ipWithSubmask2)
+ {
+ if (ipWithSubmask1.Length != ipWithSubmask2.Length)
+ {
+ //Collections.EMPTY_SET;
+ return new HashSet();
+ }
+
+ byte[][] temp = ExtractIPsAndSubnetMasks(ipWithSubmask1, ipWithSubmask2);
+ byte[] ip1 = temp[0];
+ byte[] subnetmask1 = temp[1];
+ byte[] ip2 = temp[2];
+ byte[] subnetmask2 = temp[3];
+
+ byte[][] minMax = MinMaxIPs(ip1, subnetmask1, ip2, subnetmask2);
+ byte[] min;
+ byte[] max;
+ max = Min(minMax[1], minMax[3]);
+ min = Max(minMax[0], minMax[2]);
+
+ // minimum IP address must be bigger than max
+ if (CompareTo(min, max) == 1)
+ {
+ //return Collections.EMPTY_SET;
+ return new HashSet();
+ }
+ // OR keeps all significant bits
+ byte[] ip = Or(minMax[0], minMax[2]);
+ byte[] subnetmask = Or(subnetmask1, subnetmask2);
+
+ //return new HashSet( ICollectionsingleton(IpWithSubnetMask(ip, subnetmask));
+ ISet hs = new HashSet();
+ hs.Add(IpWithSubnetMask(ip, subnetmask));
+
+ return hs;
+ }
+
+ /**
+ * Concatenates the IP address with its subnet mask.
+ *
+ * @param ip The IP address.
+ * @param subnetMask Its subnet mask.
+ * @return The concatenated IP address with its subnet mask.
+ */
+ private byte[] IpWithSubnetMask(byte[] ip, byte[] subnetMask)
+ {
+ int ipLength = ip.Length;
+ byte[] temp = new byte[ipLength * 2];
+ Array.Copy(ip, 0, temp, 0, ipLength);
+ Array.Copy(subnetMask, 0, temp, ipLength, ipLength);
+ return temp;
+ }
+
+ /**
+ * Splits the IP addresses and their subnet mask.
+ *
+ * @param ipWithSubmask1 The first IP address with the subnet mask.
+ * @param ipWithSubmask2 The second IP address with the subnet mask.
+ * @return An array with two elements. Each element contains the IP address
+ * and the subnet mask in this order.
+ */
+ private byte[][] ExtractIPsAndSubnetMasks(
+ byte[] ipWithSubmask1,
+ byte[] ipWithSubmask2)
+ {
+ int ipLength = ipWithSubmask1.Length / 2;
+ byte[] ip1 = new byte[ipLength];
+ byte[] subnetmask1 = new byte[ipLength];
+ Array.Copy(ipWithSubmask1, 0, ip1, 0, ipLength);
+ Array.Copy(ipWithSubmask1, ipLength, subnetmask1, 0, ipLength);
+
+ byte[] ip2 = new byte[ipLength];
+ byte[] subnetmask2 = new byte[ipLength];
+ Array.Copy(ipWithSubmask2, 0, ip2, 0, ipLength);
+ Array.Copy(ipWithSubmask2, ipLength, subnetmask2, 0, ipLength);
+ return new byte[][]
+ {ip1, subnetmask1, ip2, subnetmask2};
+ }
+
+ /**
+ * Based on the two IP addresses and their subnet masks the IP range is
+ * computed for each IP address - subnet mask pair and returned as the
+ * minimum IP address and the maximum address of the range.
+ *
+ * @param ip1 The first IP address.
+ * @param subnetmask1 The subnet mask of the first IP address.
+ * @param ip2 The second IP address.
+ * @param subnetmask2 The subnet mask of the second IP address.
+ * @return A array with two elements. The first/second element contains the
+ * min and max IP address of the first/second IP address and its
+ * subnet mask.
+ */
+ private byte[][] MinMaxIPs(
+ byte[] ip1,
+ byte[] subnetmask1,
+ byte[] ip2,
+ byte[] subnetmask2)
+ {
+ int ipLength = ip1.Length;
+ byte[] min1 = new byte[ipLength];
+ byte[] max1 = new byte[ipLength];
+
+ byte[] min2 = new byte[ipLength];
+ byte[] max2 = new byte[ipLength];
+
+ for (int i = 0; i < ipLength; i++)
+ {
+ min1[i] = (byte)(ip1[i] & subnetmask1[i]);
+ max1[i] = (byte)(ip1[i] & subnetmask1[i] | ~subnetmask1[i]);
+
+ min2[i] = (byte)(ip2[i] & subnetmask2[i]);
+ max2[i] = (byte)(ip2[i] & subnetmask2[i] | ~subnetmask2[i]);
+ }
+
+ return new byte[][] { min1, max1, min2, max2 };
+ }
+
+ private void CheckPermittedEmail(ISet permitted, String email)
+ //throws PkixNameConstraintValidatorException
+ {
+ if (permitted == null)
+ {
+ return;
+ }
+
+ IEnumerator it = permitted.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ String str = ((String)it.Current);
+
+ if (EmailIsConstrained(email, str))
+ {
+ return;
+ }
+ }
+
+ if (email.Length == 0 && permitted.Count == 0)
+ {
+ return;
+ }
+
+ throw new PkixNameConstraintValidatorException(
+ "Subject email address is not from a permitted subtree.");
+ }
+
+ private void CheckExcludedEmail(ISet excluded, String email)
+ //throws PkixNameConstraintValidatorException
+ {
+ if (excluded.IsEmpty)
+ {
+ return;
+ }
+
+ IEnumerator it = excluded.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ String str = (String)it.Current;
+
+ if (EmailIsConstrained(email, str))
+ {
+ throw new PkixNameConstraintValidatorException(
+ "Email address is from an excluded subtree.");
+ }
+ }
+ }
+
+ /**
+ * Checks if the IP ip
is included in the permitted ISet
+ * permitted
.
+ *
+ * @param permitted A Set
of permitted IP addresses with
+ * their subnet mask as byte arrays.
+ * @param ip The IP address.
+ * @throws PkixNameConstraintValidatorException
+ * if the IP is not permitted.
+ */
+ private void CheckPermittedIP(ISet permitted, byte[] ip)
+ //throws PkixNameConstraintValidatorException
+ {
+ if (permitted == null)
+ {
+ return;
+ }
+
+ IEnumerator it = permitted.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ byte[] ipWithSubnet = (byte[])it.Current;
+
+ if (IsIPConstrained(ip, ipWithSubnet))
+ {
+ return;
+ }
+ }
+ if (ip.Length == 0 && permitted.Count == 0)
+ {
+ return;
+ }
+ throw new PkixNameConstraintValidatorException(
+ "IP is not from a permitted subtree.");
+ }
+
+ /**
+ * Checks if the IP ip
is included in the excluded ISet
+ * excluded
.
+ *
+ * @param excluded A Set
of excluded IP addresses with their
+ * subnet mask as byte arrays.
+ * @param ip The IP address.
+ * @throws PkixNameConstraintValidatorException
+ * if the IP is excluded.
+ */
+ private void checkExcludedIP(ISet excluded, byte[] ip)
+ //throws PkixNameConstraintValidatorException
+ {
+ if (excluded.IsEmpty)
+ {
+ return;
+ }
+
+ IEnumerator it = excluded.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ byte[] ipWithSubnet = (byte[])it.Current;
+
+ if (IsIPConstrained(ip, ipWithSubnet))
+ {
+ throw new PkixNameConstraintValidatorException(
+ "IP is from an excluded subtree.");
+ }
+ }
+ }
+
+ /**
+ * Checks if the IP address ip
is constrained by
+ * constraint
.
+ *
+ * @param ip The IP address.
+ * @param constraint The constraint. This is an IP address concatenated with
+ * its subnetmask.
+ * @return true
if constrained, false
+ * otherwise.
+ */
+ private bool IsIPConstrained(byte[] ip, byte[] constraint)
+ {
+ int ipLength = ip.Length;
+
+ if (ipLength != (constraint.Length / 2))
+ {
+ return false;
+ }
+
+ byte[] subnetMask = new byte[ipLength];
+ Array.Copy(constraint, ipLength, subnetMask, 0, ipLength);
+
+ byte[] permittedSubnetAddress = new byte[ipLength];
+
+ byte[] ipSubnetAddress = new byte[ipLength];
+
+ // the resulting IP address by applying the subnet mask
+ for (int i = 0; i < ipLength; i++)
+ {
+ permittedSubnetAddress[i] = (byte)(constraint[i] & subnetMask[i]);
+ ipSubnetAddress[i] = (byte)(ip[i] & subnetMask[i]);
+ }
+
+ return Org.BouncyCastle.Utilities.Arrays.AreEqual(permittedSubnetAddress, ipSubnetAddress);
+ }
+
+ private bool EmailIsConstrained(String email, String constraint)
+ {
+ String sub = email.Substring(email.IndexOf('@') + 1);
+ // a particular mailbox
+ if (constraint.IndexOf('@') != -1)
+ {
+ if (Platform.ToUpperInvariant(email).Equals(Platform.ToUpperInvariant(constraint)))
+ {
+ return true;
+ }
+ }
+ // on particular host
+ else if (!(constraint[0].Equals('.')))
+ {
+ if (Platform.ToUpperInvariant(sub).Equals(Platform.ToUpperInvariant(constraint)))
+ {
+ return true;
+ }
+ }
+ // address in sub domain
+ else if (WithinDomain(sub, constraint))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ private bool WithinDomain(String testDomain, String domain)
+ {
+ String tempDomain = domain;
+ if (Platform.StartsWith(tempDomain, "."))
+ {
+ tempDomain = tempDomain.Substring(1);
+ }
+ String[] domainParts = tempDomain.Split('.'); // Strings.split(tempDomain, '.');
+ String[] testDomainParts = testDomain.Split('.'); // Strings.split(testDomain, '.');
+
+ // must have at least one subdomain
+ if (testDomainParts.Length <= domainParts.Length)
+ {
+ return false;
+ }
+
+ int d = testDomainParts.Length - domainParts.Length;
+ for (int i = -1; i < domainParts.Length; i++)
+ {
+ if (i == -1)
+ {
+ if (testDomainParts[i + d].Equals(""))
+ {
+ return false;
+ }
+ }
+ else if (!Platform.EqualsIgnoreCase(testDomainParts[i + d], domainParts[i]))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private void CheckPermittedDNS(ISet permitted, String dns)
+ //throws PkixNameConstraintValidatorException
+ {
+ if (permitted == null)
+ {
+ return;
+ }
+
+ IEnumerator it = permitted.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ String str = ((String)it.Current);
+
+ // is sub domain
+ if (WithinDomain(dns, str)
+ || Platform.ToUpperInvariant(dns).Equals(Platform.ToUpperInvariant(str)))
+ {
+ return;
+ }
+ }
+ if (dns.Length == 0 && permitted.Count == 0)
+ {
+ return;
+ }
+ throw new PkixNameConstraintValidatorException(
+ "DNS is not from a permitted subtree.");
+ }
+
+ private void checkExcludedDNS(ISet excluded, String dns)
+ // throws PkixNameConstraintValidatorException
+ {
+ if (excluded.IsEmpty)
+ {
+ return;
+ }
+
+ IEnumerator it = excluded.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ String str = ((String)it.Current);
+
+ // is sub domain or the same
+ if (WithinDomain(dns, str) || Platform.EqualsIgnoreCase(dns, str))
+ {
+ throw new PkixNameConstraintValidatorException(
+ "DNS is from an excluded subtree.");
+ }
+ }
+ }
+
+ /**
+ * The common part of email1
and email2
is
+ * added to the union union
. If email1
and
+ * email2
have nothing in common they are added both.
+ *
+ * @param email1 Email address constraint 1.
+ * @param email2 Email address constraint 2.
+ * @param union The union.
+ */
+ private void unionEmail(String email1, String email2, ISet union)
+ {
+ // email1 is a particular address
+ if (email1.IndexOf('@') != -1)
+ {
+ String _sub = email1.Substring(email1.IndexOf('@') + 1);
+ // both are a particular mailbox
+ if (email2.IndexOf('@') != -1)
+ {
+ if (Platform.EqualsIgnoreCase(email1, email2))
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (Platform.StartsWith(email2, "."))
+ {
+ if (WithinDomain(_sub, email2))
+ {
+ union.Add(email2);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (Platform.EqualsIgnoreCase(_sub, email2))
+ {
+ union.Add(email2);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ }
+ // email1 specifies a domain
+ else if (Platform.StartsWith(email1, "."))
+ {
+ if (email2.IndexOf('@') != -1)
+ {
+ String _sub = email2.Substring(email1.IndexOf('@') + 1);
+ if (WithinDomain(_sub, email1))
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (Platform.StartsWith(email2, "."))
+ {
+ if (WithinDomain(email1, email2) || Platform.EqualsIgnoreCase(email1, email2))
+ {
+ union.Add(email2);
+ }
+ else if (WithinDomain(email2, email1))
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ else
+ {
+ if (WithinDomain(email2, email1))
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ }
+ // email specifies a host
+ else
+ {
+ if (email2.IndexOf('@') != -1)
+ {
+ String _sub = email2.Substring(email1.IndexOf('@') + 1);
+ if (Platform.EqualsIgnoreCase(_sub, email1))
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (Platform.StartsWith(email2, "."))
+ {
+ if (WithinDomain(email1, email2))
+ {
+ union.Add(email2);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (Platform.EqualsIgnoreCase(email1, email2))
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ }
+ }
+
+ private void unionURI(String email1, String email2, ISet union)
+ {
+ // email1 is a particular address
+ if (email1.IndexOf('@') != -1)
+ {
+ String _sub = email1.Substring(email1.IndexOf('@') + 1);
+ // both are a particular mailbox
+ if (email2.IndexOf('@') != -1)
+ {
+ if (Platform.EqualsIgnoreCase(email1, email2))
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (Platform.StartsWith(email2, "."))
+ {
+ if (WithinDomain(_sub, email2))
+ {
+ union.Add(email2);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (Platform.EqualsIgnoreCase(_sub, email2))
+ {
+ union.Add(email2);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+
+ }
+ }
+ }
+ // email1 specifies a domain
+ else if (Platform.StartsWith(email1, "."))
+ {
+ if (email2.IndexOf('@') != -1)
+ {
+ String _sub = email2.Substring(email1.IndexOf('@') + 1);
+ if (WithinDomain(_sub, email1))
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (Platform.StartsWith(email2, "."))
+ {
+ if (WithinDomain(email1, email2) || Platform.EqualsIgnoreCase(email1, email2))
+ {
+ union.Add(email2);
+ }
+ else if (WithinDomain(email2, email1))
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ else
+ {
+ if (WithinDomain(email2, email1))
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ }
+ // email specifies a host
+ else
+ {
+ if (email2.IndexOf('@') != -1)
+ {
+ String _sub = email2.Substring(email1.IndexOf('@') + 1);
+ if (Platform.EqualsIgnoreCase(_sub, email1))
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (Platform.StartsWith(email2, "."))
+ {
+ if (WithinDomain(email1, email2))
+ {
+ union.Add(email2);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (Platform.EqualsIgnoreCase(email1, email2))
+ {
+ union.Add(email1);
+ }
+ else
+ {
+ union.Add(email1);
+ union.Add(email2);
+ }
+ }
+ }
+ }
+
+ private ISet intersectDNS(ISet permitted, ISet dnss)
+ {
+ ISet intersect = new HashSet();
+ for (IEnumerator it = dnss.GetEnumerator(); it.MoveNext(); )
+ {
+ String dns = ExtractNameAsString(((GeneralSubtree)it.Current)
+ .Base);
+ if (permitted == null)
+ {
+ if (dns != null)
+ {
+ intersect.Add(dns);
+ }
+ }
+ else
+ {
+ IEnumerator _iter = permitted.GetEnumerator();
+ while (_iter.MoveNext())
+ {
+ String _permitted = (String)_iter.Current;
+
+ if (WithinDomain(_permitted, dns))
+ {
+ intersect.Add(_permitted);
+ }
+ else if (WithinDomain(dns, _permitted))
+ {
+ intersect.Add(dns);
+ }
+ }
+ }
+ }
+
+ return intersect;
+ }
+
+ protected ISet unionDNS(ISet excluded, String dns)
+ {
+ if (excluded.IsEmpty)
+ {
+ if (dns == null)
+ {
+ return excluded;
+ }
+ excluded.Add(dns);
+
+ return excluded;
+ }
+ else
+ {
+ ISet union = new HashSet();
+
+ IEnumerator _iter = excluded.GetEnumerator();
+ while (_iter.MoveNext())
+ {
+ String _permitted = (String)_iter.Current;
+
+ if (WithinDomain(_permitted, dns))
+ {
+ union.Add(dns);
+ }
+ else if (WithinDomain(dns, _permitted))
+ {
+ union.Add(_permitted);
+ }
+ else
+ {
+ union.Add(_permitted);
+ union.Add(dns);
+ }
+ }
+
+ return union;
+ }
+ }
+
+ /**
+ * The most restricting part from email1
and
+ * email2
is added to the intersection intersect
.
+ *
+ * @param email1 Email address constraint 1.
+ * @param email2 Email address constraint 2.
+ * @param intersect The intersection.
+ */
+ private void intersectEmail(String email1, String email2, ISet intersect)
+ {
+ // email1 is a particular address
+ if (email1.IndexOf('@') != -1)
+ {
+ String _sub = email1.Substring(email1.IndexOf('@') + 1);
+ // both are a particular mailbox
+ if (email2.IndexOf('@') != -1)
+ {
+ if (Platform.EqualsIgnoreCase(email1, email2))
+ {
+ intersect.Add(email1);
+ }
+ }
+ // email2 specifies a domain
+ else if (Platform.StartsWith(email2, "."))
+ {
+ if (WithinDomain(_sub, email2))
+ {
+ intersect.Add(email1);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (Platform.EqualsIgnoreCase(_sub, email2))
+ {
+ intersect.Add(email1);
+ }
+ }
+ }
+ // email specifies a domain
+ else if (Platform.StartsWith(email1, "."))
+ {
+ if (email2.IndexOf('@') != -1)
+ {
+ String _sub = email2.Substring(email1.IndexOf('@') + 1);
+ if (WithinDomain(_sub, email1))
+ {
+ intersect.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (Platform.StartsWith(email2, "."))
+ {
+ if (WithinDomain(email1, email2) || Platform.EqualsIgnoreCase(email1, email2))
+ {
+ intersect.Add(email1);
+ }
+ else if (WithinDomain(email2, email1))
+ {
+ intersect.Add(email2);
+ }
+ }
+ else
+ {
+ if (WithinDomain(email2, email1))
+ {
+ intersect.Add(email2);
+ }
+ }
+ }
+ // email1 specifies a host
+ else
+ {
+ if (email2.IndexOf('@') != -1)
+ {
+ String _sub = email2.Substring(email2.IndexOf('@') + 1);
+ if (Platform.EqualsIgnoreCase(_sub, email1))
+ {
+ intersect.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (Platform.StartsWith(email2, "."))
+ {
+ if (WithinDomain(email1, email2))
+ {
+ intersect.Add(email1);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (Platform.EqualsIgnoreCase(email1, email2))
+ {
+ intersect.Add(email1);
+ }
+ }
+ }
+ }
+
+ private void checkExcludedURI(ISet excluded, String uri)
+ // throws PkixNameConstraintValidatorException
+ {
+ if (excluded.IsEmpty)
+ {
+ return;
+ }
+
+ IEnumerator it = excluded.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ String str = ((String)it.Current);
+
+ if (IsUriConstrained(uri, str))
+ {
+ throw new PkixNameConstraintValidatorException(
+ "URI is from an excluded subtree.");
+ }
+ }
+ }
+
+ private ISet intersectURI(ISet permitted, ISet uris)
+ {
+ ISet intersect = new HashSet();
+ for (IEnumerator it = uris.GetEnumerator(); it.MoveNext(); )
+ {
+ String uri = ExtractNameAsString(((GeneralSubtree)it.Current)
+ .Base);
+ if (permitted == null)
+ {
+ if (uri != null)
+ {
+ intersect.Add(uri);
+ }
+ }
+ else
+ {
+ IEnumerator _iter = permitted.GetEnumerator();
+ while (_iter.MoveNext())
+ {
+ String _permitted = (String)_iter.Current;
+ intersectURI(_permitted, uri, intersect);
+ }
+ }
+ }
+ return intersect;
+ }
+
+ private ISet unionURI(ISet excluded, String uri)
+ {
+ if (excluded.IsEmpty)
+ {
+ if (uri == null)
+ {
+ return excluded;
+ }
+ excluded.Add(uri);
+
+ return excluded;
+ }
+ else
+ {
+ ISet union = new HashSet();
+
+ IEnumerator _iter = excluded.GetEnumerator();
+ while (_iter.MoveNext())
+ {
+ String _excluded = (String)_iter.Current;
+
+ unionURI(_excluded, uri, union);
+ }
+
+ return union;
+ }
+ }
+
+ private void intersectURI(String email1, String email2, ISet intersect)
+ {
+ // email1 is a particular address
+ if (email1.IndexOf('@') != -1)
+ {
+ String _sub = email1.Substring(email1.IndexOf('@') + 1);
+ // both are a particular mailbox
+ if (email2.IndexOf('@') != -1)
+ {
+ if (Platform.EqualsIgnoreCase(email1, email2))
+ {
+ intersect.Add(email1);
+ }
+ }
+ // email2 specifies a domain
+ else if (Platform.StartsWith(email2, "."))
+ {
+ if (WithinDomain(_sub, email2))
+ {
+ intersect.Add(email1);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (Platform.EqualsIgnoreCase(_sub, email2))
+ {
+ intersect.Add(email1);
+ }
+ }
+ }
+ // email specifies a domain
+ else if (Platform.StartsWith(email1, "."))
+ {
+ if (email2.IndexOf('@') != -1)
+ {
+ String _sub = email2.Substring(email1.IndexOf('@') + 1);
+ if (WithinDomain(_sub, email1))
+ {
+ intersect.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (Platform.StartsWith(email2, "."))
+ {
+ if (WithinDomain(email1, email2) || Platform.EqualsIgnoreCase(email1, email2))
+ {
+ intersect.Add(email1);
+ }
+ else if (WithinDomain(email2, email1))
+ {
+ intersect.Add(email2);
+ }
+ }
+ else
+ {
+ if (WithinDomain(email2, email1))
+ {
+ intersect.Add(email2);
+ }
+ }
+ }
+ // email1 specifies a host
+ else
+ {
+ if (email2.IndexOf('@') != -1)
+ {
+ String _sub = email2.Substring(email2.IndexOf('@') + 1);
+ if (Platform.EqualsIgnoreCase(_sub, email1))
+ {
+ intersect.Add(email2);
+ }
+ }
+ // email2 specifies a domain
+ else if (Platform.StartsWith(email2, "."))
+ {
+ if (WithinDomain(email1, email2))
+ {
+ intersect.Add(email1);
+ }
+ }
+ // email2 specifies a particular host
+ else
+ {
+ if (Platform.EqualsIgnoreCase(email1, email2))
+ {
+ intersect.Add(email1);
+ }
+ }
+ }
+ }
+
+ private void CheckPermittedURI(ISet permitted, String uri)
+ // throws PkixNameConstraintValidatorException
+ {
+ if (permitted == null)
+ {
+ return;
+ }
+
+ IEnumerator it = permitted.GetEnumerator();
+
+ while (it.MoveNext())
+ {
+ String str = ((String)it.Current);
+
+ if (IsUriConstrained(uri, str))
+ {
+ return;
+ }
+ }
+ if (uri.Length == 0 && permitted.Count == 0)
+ {
+ return;
+ }
+ throw new PkixNameConstraintValidatorException(
+ "URI is not from a permitted subtree.");
+ }
+
+ private bool IsUriConstrained(String uri, String constraint)
+ {
+ String host = ExtractHostFromURL(uri);
+ // a host
+ if (!Platform.StartsWith(constraint, "."))
+ {
+ if (Platform.EqualsIgnoreCase(host, constraint))
+ {
+ return true;
+ }
+ }
+
+ // in sub domain or domain
+ else if (WithinDomain(host, constraint))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private static String ExtractHostFromURL(String url)
+ {
+ // see RFC 1738
+ // remove ':' after protocol, e.g. http:
+ String sub = url.Substring(url.IndexOf(':') + 1);
+ // extract host from Common Internet Scheme Syntax, e.g. http://
+ int idxOfSlashes = Platform.IndexOf(sub, "//");
+ if (idxOfSlashes != -1)
+ {
+ sub = sub.Substring(idxOfSlashes + 2);
+ }
+ // first remove port, e.g. http://test.com:21
+ if (sub.LastIndexOf(':') != -1)
+ {
+ sub = sub.Substring(0, sub.LastIndexOf(':'));
+ }
+ // remove user and password, e.g. http://john:password@test.com
+ sub = sub.Substring(sub.IndexOf(':') + 1);
+ sub = sub.Substring(sub.IndexOf('@') + 1);
+ // remove local parts, e.g. http://test.com/bla
+ if (sub.IndexOf('/') != -1)
+ {
+ sub = sub.Substring(0, sub.IndexOf('/'));
+ }
+ return sub;
+ }
+
+ /**
+ * Checks if the given GeneralName is in the permitted ISet.
+ *
+ * @param name The GeneralName
+ * @throws PkixNameConstraintValidatorException
+ * If the name
+ */
+ public void checkPermitted(GeneralName name)
+ // throws PkixNameConstraintValidatorException
+ {
+ switch (name.TagNo)
+ {
+ case 1:
+ CheckPermittedEmail(permittedSubtreesEmail,
+ ExtractNameAsString(name));
+ break;
+ case 2:
+ CheckPermittedDNS(permittedSubtreesDNS, DerIA5String.GetInstance(
+ name.Name).GetString());
+ break;
+ case 4:
+ CheckPermittedDN(Asn1Sequence.GetInstance(name.Name.ToAsn1Object()));
+ break;
+ case 6:
+ CheckPermittedURI(permittedSubtreesURI, DerIA5String.GetInstance(
+ name.Name).GetString());
+ break;
+ case 7:
+ byte[] ip = Asn1OctetString.GetInstance(name.Name).GetOctets();
+
+ CheckPermittedIP(permittedSubtreesIP, ip);
+ break;
+ }
+ }
+
+ /**
+ * Check if the given GeneralName is contained in the excluded ISet.
+ *
+ * @param name The GeneralName.
+ * @throws PkixNameConstraintValidatorException
+ * If the name
is
+ * excluded.
+ */
+ public void checkExcluded(GeneralName name)
+ // throws PkixNameConstraintValidatorException
+ {
+ switch (name.TagNo)
+ {
+ case 1:
+ CheckExcludedEmail(excludedSubtreesEmail, ExtractNameAsString(name));
+ break;
+ case 2:
+ checkExcludedDNS(excludedSubtreesDNS, DerIA5String.GetInstance(
+ name.Name).GetString());
+ break;
+ case 4:
+ CheckExcludedDN(Asn1Sequence.GetInstance(name.Name.ToAsn1Object()));
+ break;
+ case 6:
+ checkExcludedURI(excludedSubtreesURI, DerIA5String.GetInstance(
+ name.Name).GetString());
+ break;
+ case 7:
+ byte[] ip = Asn1OctetString.GetInstance(name.Name).GetOctets();
+
+ checkExcludedIP(excludedSubtreesIP, ip);
+ break;
+ }
+ }
+
+ /**
+ * Updates the permitted ISet of these name constraints with the intersection
+ * with the given subtree.
+ *
+ * @param permitted The permitted subtrees
+ */
+
+ public void IntersectPermittedSubtree(Asn1Sequence permitted)
+ {
+ IDictionary subtreesMap = Platform.CreateHashtable();
+
+ // group in ISets in a map ordered by tag no.
+ for (IEnumerator e = permitted.GetEnumerator(); e.MoveNext(); )
+ {
+ GeneralSubtree subtree = GeneralSubtree.GetInstance(e.Current);
+
+ int tagNo = subtree.Base.TagNo;
+ if (subtreesMap[tagNo] == null)
+ {
+ subtreesMap[tagNo] = new HashSet();
+ }
+
+ ((ISet)subtreesMap[tagNo]).Add(subtree);
+ }
+
+ for (IEnumerator it = subtreesMap.GetEnumerator(); it.MoveNext(); )
+ {
+ DictionaryEntry entry = (DictionaryEntry)it.Current;
+
+ // go through all subtree groups
+ switch ((int)entry.Key )
+ {
+ case 1:
+ permittedSubtreesEmail = IntersectEmail(permittedSubtreesEmail,
+ (ISet)entry.Value);
+ break;
+ case 2:
+ permittedSubtreesDNS = intersectDNS(permittedSubtreesDNS,
+ (ISet)entry.Value);
+ break;
+ case 4:
+ permittedSubtreesDN = IntersectDN(permittedSubtreesDN,
+ (ISet)entry.Value);
+ break;
+ case 6:
+ permittedSubtreesURI = intersectURI(permittedSubtreesURI,
+ (ISet)entry.Value);
+ break;
+ case 7:
+ permittedSubtreesIP = IntersectIP(permittedSubtreesIP,
+ (ISet)entry.Value);
+ break;
+ }
+ }
+ }
+
+ private String ExtractNameAsString(GeneralName name)
+ {
+ return DerIA5String.GetInstance(name.Name).GetString();
+ }
+
+ public void IntersectEmptyPermittedSubtree(int nameType)
+ {
+ switch (nameType)
+ {
+ case 1:
+ permittedSubtreesEmail = new HashSet();
+ break;
+ case 2:
+ permittedSubtreesDNS = new HashSet();
+ break;
+ case 4:
+ permittedSubtreesDN = new HashSet();
+ break;
+ case 6:
+ permittedSubtreesURI = new HashSet();
+ break;
+ case 7:
+ permittedSubtreesIP = new HashSet();
+ break;
+ }
+ }
+
+ /**
+ * Adds a subtree to the excluded ISet of these name constraints.
+ *
+ * @param subtree A subtree with an excluded GeneralName.
+ */
+ public void AddExcludedSubtree(GeneralSubtree subtree)
+ {
+ GeneralName subTreeBase = subtree.Base;
+
+ switch (subTreeBase.TagNo)
+ {
+ case 1:
+ excludedSubtreesEmail = UnionEmail(excludedSubtreesEmail,
+ ExtractNameAsString(subTreeBase));
+ break;
+ case 2:
+ excludedSubtreesDNS = unionDNS(excludedSubtreesDNS,
+ ExtractNameAsString(subTreeBase));
+ break;
+ case 4:
+ excludedSubtreesDN = UnionDN(excludedSubtreesDN,
+ (Asn1Sequence)subTreeBase.Name.ToAsn1Object());
+ break;
+ case 6:
+ excludedSubtreesURI = unionURI(excludedSubtreesURI,
+ ExtractNameAsString(subTreeBase));
+ break;
+ case 7:
+ excludedSubtreesIP = UnionIP(excludedSubtreesIP, Asn1OctetString
+ .GetInstance(subTreeBase.Name).GetOctets());
+ break;
+ }
+ }
+
+ /**
+ * Returns the maximum IP address.
+ *
+ * @param ip1 The first IP address.
+ * @param ip2 The second IP address.
+ * @return The maximum IP address.
+ */
+ private static byte[] Max(byte[] ip1, byte[] ip2)
+ {
+ for (int i = 0; i < ip1.Length; i++)
+ {
+ if ((ip1[i] & 0xFFFF) > (ip2[i] & 0xFFFF))
+ {
+ return ip1;
+ }
+ }
+ return ip2;
+ }
+
+ /**
+ * Returns the minimum IP address.
+ *
+ * @param ip1 The first IP address.
+ * @param ip2 The second IP address.
+ * @return The minimum IP address.
+ */
+ private static byte[] Min(byte[] ip1, byte[] ip2)
+ {
+ for (int i = 0; i < ip1.Length; i++)
+ {
+ if ((ip1[i] & 0xFFFF) < (ip2[i] & 0xFFFF))
+ {
+ return ip1;
+ }
+ }
+ return ip2;
+ }
+
+ /**
+ * Compares IP address ip1
with ip2
. If ip1
+ * is equal to ip2 0 is returned. If ip1 is bigger 1 is returned, -1
+ * otherwise.
+ *
+ * @param ip1 The first IP address.
+ * @param ip2 The second IP address.
+ * @return 0 if ip1 is equal to ip2, 1 if ip1 is bigger, -1 otherwise.
+ */
+ private static int CompareTo(byte[] ip1, byte[] ip2)
+ {
+ if (Org.BouncyCastle.Utilities.Arrays.AreEqual(ip1, ip2))
+ {
+ return 0;
+ }
+ if (Org.BouncyCastle.Utilities.Arrays.AreEqual(Max(ip1, ip2), ip1))
+ {
+ return 1;
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the logical OR of the IP addresses ip1
and
+ * ip2
.
+ *
+ * @param ip1 The first IP address.
+ * @param ip2 The second IP address.
+ * @return The OR of ip1
and ip2
.
+ */
+ private static byte[] Or(byte[] ip1, byte[] ip2)
+ {
+ byte[] temp = new byte[ip1.Length];
+ for (int i = 0; i < ip1.Length; i++)
+ {
+ temp[i] = (byte)(ip1[i] | ip2[i]);
+ }
+ return temp;
+ }
+
+ [Obsolete("Use GetHashCode instead")]
+ public int HashCode()
+ {
+ return GetHashCode();
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCollection(excludedSubtreesDN)
+ + HashCollection(excludedSubtreesDNS)
+ + HashCollection(excludedSubtreesEmail)
+ + HashCollection(excludedSubtreesIP)
+ + HashCollection(excludedSubtreesURI)
+ + HashCollection(permittedSubtreesDN)
+ + HashCollection(permittedSubtreesDNS)
+ + HashCollection(permittedSubtreesEmail)
+ + HashCollection(permittedSubtreesIP)
+ + HashCollection(permittedSubtreesURI);
+ }
+
+ private int HashCollection(ICollection coll)
+ {
+ if (coll == null)
+ {
+ return 0;
+ }
+ int hash = 0;
+ IEnumerator it1 = coll.GetEnumerator();
+ while (it1.MoveNext())
+ {
+ Object o = it1.Current;
+ if (o is byte[])
+ {
+ hash += Org.BouncyCastle.Utilities.Arrays.GetHashCode((byte[])o);
+ }
+ else
+ {
+ hash += o.GetHashCode();
+ }
+ }
+ return hash;
+ }
+
+ public override bool Equals(Object o)
+ {
+ if (!(o is PkixNameConstraintValidator))
+ return false;
+
+ PkixNameConstraintValidator constraintValidator = (PkixNameConstraintValidator)o;
+
+ return CollectionsAreEqual(constraintValidator.excludedSubtreesDN, excludedSubtreesDN)
+ && CollectionsAreEqual(constraintValidator.excludedSubtreesDNS, excludedSubtreesDNS)
+ && CollectionsAreEqual(constraintValidator.excludedSubtreesEmail, excludedSubtreesEmail)
+ && CollectionsAreEqual(constraintValidator.excludedSubtreesIP, excludedSubtreesIP)
+ && CollectionsAreEqual(constraintValidator.excludedSubtreesURI, excludedSubtreesURI)
+ && CollectionsAreEqual(constraintValidator.permittedSubtreesDN, permittedSubtreesDN)
+ && CollectionsAreEqual(constraintValidator.permittedSubtreesDNS, permittedSubtreesDNS)
+ && CollectionsAreEqual(constraintValidator.permittedSubtreesEmail, permittedSubtreesEmail)
+ && CollectionsAreEqual(constraintValidator.permittedSubtreesIP, permittedSubtreesIP)
+ && CollectionsAreEqual(constraintValidator.permittedSubtreesURI, permittedSubtreesURI);
+ }
+
+ private bool CollectionsAreEqual(ICollection coll1, ICollection coll2)
+ {
+ if (coll1 == coll2)
+ {
+ return true;
+ }
+ if (coll1 == null || coll2 == null)
+ {
+ return false;
+ }
+ if (coll1.Count != coll2.Count)
+ {
+ return false;
+ }
+ IEnumerator it1 = coll1.GetEnumerator();
+
+ while (it1.MoveNext())
+ {
+ Object a = it1.Current;
+ IEnumerator it2 = coll2.GetEnumerator();
+ bool found = false;
+ while (it2.MoveNext())
+ {
+ Object b = it2.Current;
+ if (SpecialEquals(a, b))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private bool SpecialEquals(Object o1, Object o2)
+ {
+ if (o1 == o2)
+ {
+ return true;
+ }
+ if (o1 == null || o2 == null)
+ {
+ return false;
+ }
+ if ((o1 is byte[]) && (o2 is byte[]))
+ {
+ return Org.BouncyCastle.Utilities.Arrays.AreEqual((byte[])o1, (byte[])o2);
+ }
+ else
+ {
+ return o1.Equals(o2);
+ }
+ }
+
+ /**
+ * Stringifies an IPv4 or v6 address with subnet mask.
+ *
+ * @param ip The IP with subnet mask.
+ * @return The stringified IP address.
+ */
+ private String StringifyIP(byte[] ip)
+ {
+ String temp = "";
+ for (int i = 0; i < ip.Length / 2; i++)
+ {
+ //temp += Integer.toString(ip[i] & 0x00FF) + ".";
+ temp += (ip[i] & 0x00FF) + ".";
+ }
+ temp = temp.Substring(0, temp.Length - 1);
+ temp += "/";
+ for (int i = ip.Length / 2; i < ip.Length; i++)
+ {
+ //temp += Integer.toString(ip[i] & 0x00FF) + ".";
+ temp += (ip[i] & 0x00FF) + ".";
+ }
+ temp = temp.Substring(0, temp.Length - 1);
+ return temp;
+ }
+
+ private String StringifyIPCollection(ISet ips)
+ {
+ String temp = "";
+ temp += "[";
+ for (IEnumerator it = ips.GetEnumerator(); it.MoveNext(); )
+ {
+ temp += StringifyIP((byte[])it.Current) + ",";
+ }
+ if (temp.Length > 1)
+ {
+ temp = temp.Substring(0, temp.Length - 1);
+ }
+ temp += "]";
+
+ return temp;
+ }
+
+ public override String ToString()
+ {
+ String temp = "";
+
+ temp += "permitted:\n";
+ if (permittedSubtreesDN != null)
+ {
+ temp += "DN:\n";
+ temp += permittedSubtreesDN.ToString() + "\n";
+ }
+ if (permittedSubtreesDNS != null)
+ {
+ temp += "DNS:\n";
+ temp += permittedSubtreesDNS.ToString() + "\n";
+ }
+ if (permittedSubtreesEmail != null)
+ {
+ temp += "Email:\n";
+ temp += permittedSubtreesEmail.ToString() + "\n";
+ }
+ if (permittedSubtreesURI != null)
+ {
+ temp += "URI:\n";
+ temp += permittedSubtreesURI.ToString() + "\n";
+ }
+ if (permittedSubtreesIP != null)
+ {
+ temp += "IP:\n";
+ temp += StringifyIPCollection(permittedSubtreesIP) + "\n";
+ }
+ temp += "excluded:\n";
+ if (!(excludedSubtreesDN.IsEmpty))
+ {
+ temp += "DN:\n";
+ temp += excludedSubtreesDN.ToString() + "\n";
+ }
+ if (!excludedSubtreesDNS.IsEmpty)
+ {
+ temp += "DNS:\n";
+ temp += excludedSubtreesDNS.ToString() + "\n";
+ }
+ if (!excludedSubtreesEmail.IsEmpty)
+ {
+ temp += "Email:\n";
+ temp += excludedSubtreesEmail.ToString() + "\n";
+ }
+ if (!excludedSubtreesURI.IsEmpty)
+ {
+ temp += "URI:\n";
+ temp += excludedSubtreesURI.ToString() + "\n";
+ }
+ if (!excludedSubtreesIP.IsEmpty)
+ {
+ temp += "IP:\n";
+ temp += StringifyIPCollection(excludedSubtreesIP) + "\n";
+ }
+ return temp;
+ }
+
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/PkixNameConstraintValidatorException.cs b/bc-sharp-crypto/src/pkix/PkixNameConstraintValidatorException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b187525e07a1bc01b848bba7d0e7baf732ccc522
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/PkixNameConstraintValidatorException.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Org.BouncyCastle.Pkix
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class PkixNameConstraintValidatorException
+ : Exception
+ {
+ public PkixNameConstraintValidatorException(String msg)
+ : base(msg)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/PkixParameters.cs b/bc-sharp-crypto/src/pkix/PkixParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..01ed9d4fa2aa83301db45e9762a09c62ebce9729
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/PkixParameters.cs
@@ -0,0 +1,893 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+ ///
+ /// Summary description for PkixParameters.
+ ///
+ public class PkixParameters
+// : ICertPathParameters
+ {
+ /**
+ * This is the default PKIX validity model. Actually there are two variants
+ * of this: The PKIX model and the modified PKIX model. The PKIX model
+ * verifies that all involved certificates must have been valid at the
+ * current time. The modified PKIX model verifies that all involved
+ * certificates were valid at the signing time. Both are indirectly choosen
+ * with the {@link PKIXParameters#setDate(java.util.Date)} method, so this
+ * methods sets the Date when all certificates must have been
+ * valid.
+ */
+ public const int PkixValidityModel = 0;
+
+ /**
+ * This model uses the following validity model. Each certificate must have
+ * been valid at the moment where is was used. That means the end
+ * certificate must have been valid at the time the signature was done. The
+ * CA certificate which signed the end certificate must have been valid,
+ * when the end certificate was signed. The CA (or Root CA) certificate must
+ * have been valid, when the CA certificate was signed and so on. So the
+ * {@link PKIXParameters#setDate(java.util.Date)} method sets the time, when
+ * the end certificate must have been valid.
It is used e.g.
+ * in the German signature law.
+ */
+ public const int ChainValidityModel = 1;
+
+ private ISet trustAnchors;
+ private DateTimeObject date;
+ private IList certPathCheckers;
+ private bool revocationEnabled = true;
+ private ISet initialPolicies;
+ //private bool checkOnlyEECertificateCrl = false;
+ private bool explicitPolicyRequired = false;
+ private bool anyPolicyInhibited = false;
+ private bool policyMappingInhibited = false;
+ private bool policyQualifiersRejected = true;
+ private IX509Selector certSelector;
+ private IList stores;
+ private IX509Selector selector;
+ private bool additionalLocationsEnabled;
+ private IList additionalStores;
+ private ISet trustedACIssuers;
+ private ISet necessaryACAttributes;
+ private ISet prohibitedACAttributes;
+ private ISet attrCertCheckers;
+ private int validityModel = PkixValidityModel;
+ private bool useDeltas = false;
+
+ /**
+ * Creates an instance of PKIXParameters with the specified Set of
+ * most-trusted CAs. Each element of the set is a TrustAnchor.
+ *
+ * Note that the Set is copied to protect against subsequent modifications.
+ *
+ * @param trustAnchors
+ * a Set of TrustAnchors
+ *
+ * @exception InvalidAlgorithmParameterException
+ * if the specified Set is empty
+ * (trustAnchors.isEmpty() == true)
+ * @exception NullPointerException
+ * if the specified Set is null
+ * @exception ClassCastException
+ * if any of the elements in the Set are not of type
+ * java.security.cert.TrustAnchor
+ */
+ public PkixParameters(
+ ISet trustAnchors)
+ {
+ SetTrustAnchors(trustAnchors);
+
+ this.initialPolicies = new HashSet();
+ this.certPathCheckers = Platform.CreateArrayList();
+ this.stores = Platform.CreateArrayList();
+ this.additionalStores = Platform.CreateArrayList();
+ this.trustedACIssuers = new HashSet();
+ this.necessaryACAttributes = new HashSet();
+ this.prohibitedACAttributes = new HashSet();
+ this.attrCertCheckers = new HashSet();
+ }
+
+// // TODO implement for other keystores (see Java build)?
+// /**
+// * Creates an instance of PKIXParameters
that
+// * populates the set of most-trusted CAs from the trusted
+// * certificate entries contained in the specified KeyStore
.
+// * Only keystore entries that contain trusted X509Certificates
+// * are considered; all other certificate types are ignored.
+// *
+// * @param keystore a KeyStore
from which the set of
+// * most-trusted CAs will be populated
+// * @throws KeyStoreException if the keystore has not been initialized
+// * @throws InvalidAlgorithmParameterException if the keystore does
+// * not contain at least one trusted certificate entry
+// * @throws NullPointerException if the keystore is null
+// */
+// public PkixParameters(
+// Pkcs12Store keystore)
+//// throws KeyStoreException, InvalidAlgorithmParameterException
+// {
+// if (keystore == null)
+// throw new ArgumentNullException("keystore");
+// ISet trustAnchors = new HashSet();
+// foreach (string alias in keystore.Aliases)
+// {
+// if (keystore.IsCertificateEntry(alias))
+// {
+// X509CertificateEntry x509Entry = keystore.GetCertificate(alias);
+// trustAnchors.Add(new TrustAnchor(x509Entry.Certificate, null));
+// }
+// }
+// SetTrustAnchors(trustAnchors);
+//
+// this.initialPolicies = new HashSet();
+// this.certPathCheckers = new ArrayList();
+// this.stores = new ArrayList();
+// this.additionalStores = new ArrayList();
+// this.trustedACIssuers = new HashSet();
+// this.necessaryACAttributes = new HashSet();
+// this.prohibitedACAttributes = new HashSet();
+// this.attrCertCheckers = new HashSet();
+// }
+
+ public virtual bool IsRevocationEnabled
+ {
+ get { return revocationEnabled; }
+ set { revocationEnabled = value; }
+ }
+
+ public virtual bool IsExplicitPolicyRequired
+ {
+ get { return explicitPolicyRequired; }
+ set { this.explicitPolicyRequired = value; }
+ }
+
+ public virtual bool IsAnyPolicyInhibited
+ {
+ get { return anyPolicyInhibited; }
+ set { this.anyPolicyInhibited = value; }
+ }
+
+ public virtual bool IsPolicyMappingInhibited
+ {
+ get { return policyMappingInhibited; }
+ set { this.policyMappingInhibited = value; }
+ }
+
+ public virtual bool IsPolicyQualifiersRejected
+ {
+ get { return policyQualifiersRejected; }
+ set { this.policyQualifiersRejected = value; }
+ }
+
+ //public bool IsCheckOnlyEECertificateCrl
+ //{
+ // get { return this.checkOnlyEECertificateCrl; }
+ // set { this.checkOnlyEECertificateCrl = value; }
+ //}
+
+ public virtual DateTimeObject Date
+ {
+ get { return this.date; }
+ set { this.date = value; }
+ }
+
+ // Returns a Set of the most-trusted CAs.
+ public virtual ISet GetTrustAnchors()
+ {
+ return new HashSet(this.trustAnchors);
+ }
+
+ // Sets the set of most-trusted CAs.
+ // Set is copied to protect against subsequent modifications.
+ public virtual void SetTrustAnchors(
+ ISet tas)
+ {
+ if (tas == null)
+ throw new ArgumentNullException("value");
+ if (tas.IsEmpty)
+ throw new ArgumentException("non-empty set required", "value");
+
+ // Explicit copy to enforce type-safety
+ this.trustAnchors = new HashSet();
+ foreach (TrustAnchor ta in tas)
+ {
+ if (ta != null)
+ {
+ trustAnchors.Add(ta);
+ }
+ }
+ }
+
+ /**
+ * Returns the required constraints on the target certificate. The
+ * constraints are returned as an instance of CertSelector. If
+ * null
, no constraints are defined.
+ *
+ * Note that the CertSelector returned is cloned to protect against
+ * subsequent modifications.
+ *
+ * @return a CertSelector specifying the constraints on the target
+ * certificate (or null
)
+ *
+ * @see #setTargetCertConstraints(CertSelector)
+ */
+ public virtual X509CertStoreSelector GetTargetCertConstraints()
+ {
+ if (certSelector == null)
+ {
+ return null;
+ }
+
+ return (X509CertStoreSelector)certSelector.Clone();
+ }
+
+ /**
+ * Sets the required constraints on the target certificate. The constraints
+ * are specified as an instance of CertSelector. If null, no constraints are
+ * defined.
+ *
+ * Note that the CertSelector specified is cloned to protect against
+ * subsequent modifications.
+ *
+ * @param selector
+ * a CertSelector specifying the constraints on the target
+ * certificate (or null
)
+ *
+ * @see #getTargetCertConstraints()
+ */
+ public virtual void SetTargetCertConstraints(
+ IX509Selector selector)
+ {
+ if (selector == null)
+ {
+ certSelector = null;
+ }
+ else
+ {
+ certSelector = (IX509Selector)selector.Clone();
+ }
+ }
+
+ /**
+ * Returns an immutable Set of initial policy identifiers (OID strings),
+ * indicating that any one of these policies would be acceptable to the
+ * certificate user for the purposes of certification path processing. The
+ * default return value is an empty Set
, which is
+ * interpreted as meaning that any policy would be acceptable.
+ *
+ * @return an immutable Set
of initial policy OIDs in String
+ * format, or an empty Set
(implying any policy is
+ * acceptable). Never returns null
.
+ *
+ * @see #setInitialPolicies(java.util.Set)
+ */
+ public virtual ISet GetInitialPolicies()
+ {
+ ISet returnSet = initialPolicies;
+
+ // TODO Can it really be null?
+ if (initialPolicies == null)
+ {
+ returnSet = new HashSet();
+ }
+
+ return new HashSet(returnSet);
+ }
+
+ /**
+ * Sets the Set
of initial policy identifiers (OID strings),
+ * indicating that any one of these policies would be acceptable to the
+ * certificate user for the purposes of certification path processing. By
+ * default, any policy is acceptable (i.e. all policies), so a user that
+ * wants to allow any policy as acceptable does not need to call this
+ * method, or can call it with an empty Set
(or
+ * null
).
+ *
+ * Note that the Set is copied to protect against subsequent modifications.
+ *
+ *
+ * @param initialPolicies
+ * a Set of initial policy OIDs in String format (or
+ * null
)
+ *
+ * @exception ClassCastException
+ * if any of the elements in the set are not of type String
+ *
+ * @see #getInitialPolicies()
+ */
+ public virtual void SetInitialPolicies(
+ ISet initialPolicies)
+ {
+ this.initialPolicies = new HashSet();
+ if (initialPolicies != null)
+ {
+ foreach (string obj in initialPolicies)
+ {
+ if (obj != null)
+ {
+ this.initialPolicies.Add(obj);
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets a List
of additional certification path checkers. If
+ * the specified List contains an object that is not a PKIXCertPathChecker,
+ * it is ignored.
+ *
+ * Each PKIXCertPathChecker
specified implements additional
+ * checks on a certificate. Typically, these are checks to process and
+ * verify private extensions contained in certificates. Each
+ * PKIXCertPathChecker
should be instantiated with any
+ * initialization parameters needed to execute the check.
+ *
+ * This method allows sophisticated applications to extend a PKIX
+ * CertPathValidator
or CertPathBuilder
. Each
+ * of the specified PKIXCertPathCheckers will be called, in turn, by a PKIX
+ * CertPathValidator
or CertPathBuilder
for
+ * each certificate processed or validated.
+ *
+ * Regardless of whether these additional PKIXCertPathCheckers are set, a
+ * PKIX CertPathValidator
or CertPathBuilder
+ * must perform all of the required PKIX checks on each certificate. The one
+ * exception to this rule is if the RevocationEnabled flag is set to false
+ * (see the {@link #setRevocationEnabled(boolean) setRevocationEnabled}
+ * method).
+ *
+ * Note that the List supplied here is copied and each PKIXCertPathChecker
+ * in the list is cloned to protect against subsequent modifications.
+ *
+ * @param checkers
+ * a List of PKIXCertPathCheckers. May be null, in which case no
+ * additional checkers will be used.
+ * @exception ClassCastException
+ * if any of the elements in the list are not of type
+ * java.security.cert.PKIXCertPathChecker
+ * @see #getCertPathCheckers()
+ */
+ public virtual void SetCertPathCheckers(IList checkers)
+ {
+ certPathCheckers = Platform.CreateArrayList();
+ if (checkers != null)
+ {
+ foreach (PkixCertPathChecker obj in checkers)
+ {
+ certPathCheckers.Add(obj.Clone());
+ }
+ }
+ }
+
+ /**
+ * Returns the List of certification path checkers. Each PKIXCertPathChecker
+ * in the returned IList is cloned to protect against subsequent modifications.
+ *
+ * @return an immutable List of PKIXCertPathCheckers (may be empty, but not
+ * null
)
+ *
+ * @see #setCertPathCheckers(java.util.List)
+ */
+ public virtual IList GetCertPathCheckers()
+ {
+ IList checkers = Platform.CreateArrayList();
+ foreach (PkixCertPathChecker obj in certPathCheckers)
+ {
+ checkers.Add(obj.Clone());
+ }
+ return checkers;
+ }
+
+ /**
+ * Adds a PKIXCertPathChecker
to the list of certification
+ * path checkers. See the {@link #setCertPathCheckers setCertPathCheckers}
+ * method for more details.
+ *
+ * Note that the PKIXCertPathChecker
is cloned to protect
+ * against subsequent modifications.
+ *
+ * @param checker a PKIXCertPathChecker
to add to the list of
+ * checks. If null
, the checker is ignored (not added to list).
+ */
+ public virtual void AddCertPathChecker(
+ PkixCertPathChecker checker)
+ {
+ if (checker != null)
+ {
+ certPathCheckers.Add(checker.Clone());
+ }
+ }
+
+ public virtual object Clone()
+ {
+ // FIXME Check this whole method against the Java implementation!
+
+ PkixParameters parameters = new PkixParameters(GetTrustAnchors());
+ parameters.SetParams(this);
+ return parameters;
+
+
+// PkixParameters obj = new PkixParameters(new HashSet());
+//// (PkixParameters) this.MemberwiseClone();
+// obj.x509Stores = new ArrayList(x509Stores);
+// obj.certPathCheckers = new ArrayList(certPathCheckers);
+//
+// //Iterator iter = certPathCheckers.iterator();
+// //obj.certPathCheckers = new ArrayList();
+// //while (iter.hasNext())
+// //{
+// // obj.certPathCheckers.add(((PKIXCertPathChecker)iter.next())
+// // .clone());
+// //}
+// //if (initialPolicies != null)
+// //{
+// // obj.initialPolicies = new HashSet(initialPolicies);
+// //}
+//// if (trustAnchors != null)
+//// {
+//// obj.trustAnchors = new HashSet(trustAnchors);
+//// }
+//// if (certSelector != null)
+//// {
+//// obj.certSelector = (X509CertStoreSelector) certSelector.Clone();
+//// }
+// return obj;
+ }
+
+ /**
+ * Method to support Clone()
under J2ME.
+ * super.Clone()
does not exist and fields are not copied.
+ *
+ * @param params Parameters to set. If this are
+ * ExtendedPkixParameters
they are copied to.
+ */
+ protected virtual void SetParams(
+ PkixParameters parameters)
+ {
+ Date = parameters.Date;
+ SetCertPathCheckers(parameters.GetCertPathCheckers());
+ IsAnyPolicyInhibited = parameters.IsAnyPolicyInhibited;
+ IsExplicitPolicyRequired = parameters.IsExplicitPolicyRequired;
+ IsPolicyMappingInhibited = parameters.IsPolicyMappingInhibited;
+ IsRevocationEnabled = parameters.IsRevocationEnabled;
+ SetInitialPolicies(parameters.GetInitialPolicies());
+ IsPolicyQualifiersRejected = parameters.IsPolicyQualifiersRejected;
+ SetTargetCertConstraints(parameters.GetTargetCertConstraints());
+ SetTrustAnchors(parameters.GetTrustAnchors());
+
+ validityModel = parameters.validityModel;
+ useDeltas = parameters.useDeltas;
+ additionalLocationsEnabled = parameters.additionalLocationsEnabled;
+ selector = parameters.selector == null ? null
+ : (IX509Selector) parameters.selector.Clone();
+ stores = Platform.CreateArrayList(parameters.stores);
+ additionalStores = Platform.CreateArrayList(parameters.additionalStores);
+ trustedACIssuers = new HashSet(parameters.trustedACIssuers);
+ prohibitedACAttributes = new HashSet(parameters.prohibitedACAttributes);
+ necessaryACAttributes = new HashSet(parameters.necessaryACAttributes);
+ attrCertCheckers = new HashSet(parameters.attrCertCheckers);
+ }
+
+ /**
+ * Whether delta CRLs should be used for checking the revocation status.
+ * Defaults to false
.
+ */
+ public virtual bool IsUseDeltasEnabled
+ {
+ get { return useDeltas; }
+ set { useDeltas = value; }
+ }
+
+ /**
+ * The validity model.
+ * @see #CHAIN_VALIDITY_MODEL
+ * @see #PKIX_VALIDITY_MODEL
+ */
+ public virtual int ValidityModel
+ {
+ get { return validityModel; }
+ set { validityModel = value; }
+ }
+
+ /**
+ * Sets the Bouncy Castle Stores for finding CRLs, certificates, attribute
+ * certificates or cross certificates.
+ *
+ * The IList
is cloned.
+ *
+ *
+ * @param stores A list of stores to use.
+ * @see #getStores
+ * @throws ClassCastException if an element of stores
is not
+ * a {@link Store}.
+ */
+ public virtual void SetStores(
+ IList stores)
+ {
+ if (stores == null)
+ {
+ this.stores = Platform.CreateArrayList();
+ }
+ else
+ {
+ foreach (object obj in stores)
+ {
+ if (!(obj is IX509Store))
+ {
+ throw new InvalidCastException(
+ "All elements of list must be of type " + typeof(IX509Store).FullName);
+ }
+ }
+ this.stores = Platform.CreateArrayList(stores);
+ }
+ }
+
+ /**
+ * Adds a Bouncy Castle {@link Store} to find CRLs, certificates, attribute
+ * certificates or cross certificates.
+ *
+ * This method should be used to add local stores, like collection based
+ * X.509 stores, if available. Local stores should be considered first,
+ * before trying to use additional (remote) locations, because they do not
+ * need possible additional network traffic.
+ *
+ * If store
is null
it is ignored.
+ *
+ *
+ * @param store The store to add.
+ * @see #getStores
+ */
+ public virtual void AddStore(
+ IX509Store store)
+ {
+ if (store != null)
+ {
+ stores.Add(store);
+ }
+ }
+
+ /**
+ * Adds an additional Bouncy Castle {@link Store} to find CRLs, certificates,
+ * attribute certificates or cross certificates.
+ *
+ * You should not use this method. This method is used for adding additional
+ * X.509 stores, which are used to add (remote) locations, e.g. LDAP, found
+ * during X.509 object processing, e.g. in certificates or CRLs. This method
+ * is used in PKIX certification path processing.
+ *
+ * If store
is null
it is ignored.
+ *
+ *
+ * @param store The store to add.
+ * @see #getStores()
+ */
+ public virtual void AddAdditionalStore(
+ IX509Store store)
+ {
+ if (store != null)
+ {
+ additionalStores.Add(store);
+ }
+ }
+
+ /**
+ * Returns an IList
of additional Bouncy Castle
+ * Store
s used for finding CRLs, certificates, attribute
+ * certificates or cross certificates.
+ *
+ * @return an immutable IList
of additional Bouncy Castle
+ * Store
s. Never null
.
+ *
+ * @see #addAddionalStore(Store)
+ */
+ public virtual IList GetAdditionalStores()
+ {
+ return Platform.CreateArrayList(additionalStores);
+ }
+
+ /**
+ * Returns an IList
of Bouncy Castle
+ * Store
s used for finding CRLs, certificates, attribute
+ * certificates or cross certificates.
+ *
+ * @return an immutable IList
of Bouncy Castle
+ * Store
s. Never null
.
+ *
+ * @see #setStores(IList)
+ */
+ public virtual IList GetStores()
+ {
+ return Platform.CreateArrayList(stores);
+ }
+
+ /**
+ * Returns if additional {@link X509Store}s for locations like LDAP found
+ * in certificates or CRLs should be used.
+ *
+ * @return Returns true
if additional stores are used.
+ */
+ public virtual bool IsAdditionalLocationsEnabled
+ {
+ get { return additionalLocationsEnabled; }
+ }
+
+ /**
+ * Sets if additional {@link X509Store}s for locations like LDAP found in
+ * certificates or CRLs should be used.
+ *
+ * @param enabled true
if additional stores are used.
+ */
+ public virtual void SetAdditionalLocationsEnabled(
+ bool enabled)
+ {
+ additionalLocationsEnabled = enabled;
+ }
+
+ /**
+ * Returns the required constraints on the target certificate or attribute
+ * certificate. The constraints are returned as an instance of
+ * IX509Selector
. If null
, no constraints are
+ * defined.
+ *
+ *
+ * The target certificate in a PKIX path may be a certificate or an
+ * attribute certificate.
+ *
+ * Note that the IX509Selector
returned is cloned to protect
+ * against subsequent modifications.
+ *
+ * @return a IX509Selector
specifying the constraints on the
+ * target certificate or attribute certificate (or null
)
+ * @see #setTargetConstraints
+ * @see X509CertStoreSelector
+ * @see X509AttributeCertStoreSelector
+ */
+ public virtual IX509Selector GetTargetConstraints()
+ {
+ if (selector != null)
+ {
+ return (IX509Selector) selector.Clone();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Sets the required constraints on the target certificate or attribute
+ * certificate. The constraints are specified as an instance of
+ * IX509Selector
. If null
, no constraints are
+ * defined.
+ *
+ * The target certificate in a PKIX path may be a certificate or an
+ * attribute certificate.
+ *
+ * Note that the IX509Selector
specified is cloned to protect
+ * against subsequent modifications.
+ *
+ *
+ * @param selector a IX509Selector
specifying the constraints on
+ * the target certificate or attribute certificate (or
+ * null
)
+ * @see #getTargetConstraints
+ * @see X509CertStoreSelector
+ * @see X509AttributeCertStoreSelector
+ */
+ public virtual void SetTargetConstraints(IX509Selector selector)
+ {
+ if (selector != null)
+ {
+ this.selector = (IX509Selector) selector.Clone();
+ }
+ else
+ {
+ this.selector = null;
+ }
+ }
+
+ /**
+ * Returns the trusted attribute certificate issuers. If attribute
+ * certificates is verified the trusted AC issuers must be set.
+ *
+ * The returned ISet
consists of TrustAnchor
s.
+ *
+ * The returned ISet
is immutable. Never null
+ *
+ *
+ * @return Returns an immutable set of the trusted AC issuers.
+ */
+ public virtual ISet GetTrustedACIssuers()
+ {
+ return new HashSet(trustedACIssuers);
+ }
+
+ /**
+ * Sets the trusted attribute certificate issuers. If attribute certificates
+ * is verified the trusted AC issuers must be set.
+ *
+ * The trustedACIssuers
must be a ISet
of
+ * TrustAnchor
+ *
+ * The given set is cloned.
+ *
+ *
+ * @param trustedACIssuers The trusted AC issuers to set. Is never
+ * null
.
+ * @throws ClassCastException if an element of stores
is not
+ * a TrustAnchor
.
+ */
+ public virtual void SetTrustedACIssuers(
+ ISet trustedACIssuers)
+ {
+ if (trustedACIssuers == null)
+ {
+ this.trustedACIssuers = new HashSet();
+ }
+ else
+ {
+ foreach (object obj in trustedACIssuers)
+ {
+ if (!(obj is TrustAnchor))
+ {
+ throw new InvalidCastException("All elements of set must be "
+ + "of type " + typeof(TrustAnchor).FullName + ".");
+ }
+ }
+ this.trustedACIssuers = new HashSet(trustedACIssuers);
+ }
+ }
+
+ /**
+ * Returns the necessary attributes which must be contained in an attribute
+ * certificate.
+ *
+ * The returned ISet
is immutable and contains
+ * String
s with the OIDs.
+ *
+ *
+ * @return Returns the necessary AC attributes.
+ */
+ public virtual ISet GetNecessaryACAttributes()
+ {
+ return new HashSet(necessaryACAttributes);
+ }
+
+ /**
+ * Sets the necessary which must be contained in an attribute certificate.
+ *
+ * The ISet
must contain String
s with the
+ * OIDs.
+ *
+ * The set is cloned.
+ *
+ *
+ * @param necessaryACAttributes The necessary AC attributes to set.
+ * @throws ClassCastException if an element of
+ * necessaryACAttributes
is not a
+ * String
.
+ */
+ public virtual void SetNecessaryACAttributes(
+ ISet necessaryACAttributes)
+ {
+ if (necessaryACAttributes == null)
+ {
+ this.necessaryACAttributes = new HashSet();
+ }
+ else
+ {
+ foreach (object obj in necessaryACAttributes)
+ {
+ if (!(obj is string))
+ {
+ throw new InvalidCastException("All elements of set must be "
+ + "of type string.");
+ }
+ }
+ this.necessaryACAttributes = new HashSet(necessaryACAttributes);
+ }
+ }
+
+ /**
+ * Returns the attribute certificates which are not allowed.
+ *
+ * The returned ISet
is immutable and contains
+ * String
s with the OIDs.
+ *
+ *
+ * @return Returns the prohibited AC attributes. Is never null
.
+ */
+ public virtual ISet GetProhibitedACAttributes()
+ {
+ return new HashSet(prohibitedACAttributes);
+ }
+
+ /**
+ * Sets the attribute certificates which are not allowed.
+ *
+ * The ISet
must contain String
s with the
+ * OIDs.
+ *
+ * The set is cloned.
+ *
+ *
+ * @param prohibitedACAttributes The prohibited AC attributes to set.
+ * @throws ClassCastException if an element of
+ * prohibitedACAttributes
is not a
+ * String
.
+ */
+ public virtual void SetProhibitedACAttributes(
+ ISet prohibitedACAttributes)
+ {
+ if (prohibitedACAttributes == null)
+ {
+ this.prohibitedACAttributes = new HashSet();
+ }
+ else
+ {
+ foreach (object obj in prohibitedACAttributes)
+ {
+ if (!(obj is String))
+ {
+ throw new InvalidCastException("All elements of set must be "
+ + "of type string.");
+ }
+ }
+ this.prohibitedACAttributes = new HashSet(prohibitedACAttributes);
+ }
+ }
+
+ /**
+ * Returns the attribute certificate checker. The returned set contains
+ * {@link PKIXAttrCertChecker}s and is immutable.
+ *
+ * @return Returns the attribute certificate checker. Is never
+ * null
.
+ */
+ public virtual ISet GetAttrCertCheckers()
+ {
+ return new HashSet(attrCertCheckers);
+ }
+
+ /**
+ * Sets the attribute certificate checkers.
+ *
+ * All elements in the ISet
must a {@link PKIXAttrCertChecker}.
+ *
+ *
+ * The given set is cloned.
+ *
+ *
+ * @param attrCertCheckers The attribute certificate checkers to set. Is
+ * never null
.
+ * @throws ClassCastException if an element of attrCertCheckers
+ * is not a PKIXAttrCertChecker
.
+ */
+ public virtual void SetAttrCertCheckers(
+ ISet attrCertCheckers)
+ {
+ if (attrCertCheckers == null)
+ {
+ this.attrCertCheckers = new HashSet();
+ }
+ else
+ {
+ foreach (object obj in attrCertCheckers)
+ {
+ if (!(obj is PkixAttrCertChecker))
+ {
+ throw new InvalidCastException("All elements of set must be "
+ + "of type " + typeof(PkixAttrCertChecker).FullName + ".");
+ }
+ }
+ this.attrCertCheckers = new HashSet(attrCertCheckers);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/PkixPolicyNode.cs b/bc-sharp-crypto/src/pkix/PkixPolicyNode.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fc5b82f6f94feca78e18409cfe359ae386f7b868
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/PkixPolicyNode.cs
@@ -0,0 +1,158 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Pkix
+{
+ ///
+ /// Summary description for PkixPolicyNode.
+ ///
+ public class PkixPolicyNode
+// : IPolicyNode
+ {
+ protected IList mChildren;
+ protected int mDepth;
+ protected ISet mExpectedPolicies;
+ protected PkixPolicyNode mParent;
+ protected ISet mPolicyQualifiers;
+ protected string mValidPolicy;
+ protected bool mCritical;
+
+ public virtual int Depth
+ {
+ get { return this.mDepth; }
+ }
+
+ public virtual IEnumerable Children
+ {
+ get { return new EnumerableProxy(mChildren); }
+ }
+
+ public virtual bool IsCritical
+ {
+ get { return this.mCritical; }
+ set { this.mCritical = value; }
+ }
+
+ public virtual ISet PolicyQualifiers
+ {
+ get { return new HashSet(this.mPolicyQualifiers); }
+ }
+
+ public virtual string ValidPolicy
+ {
+ get { return this.mValidPolicy; }
+ }
+
+ public virtual bool HasChildren
+ {
+ get { return mChildren.Count != 0; }
+ }
+
+ public virtual ISet ExpectedPolicies
+ {
+ get { return new HashSet(this.mExpectedPolicies); }
+ set { this.mExpectedPolicies = new HashSet(value); }
+ }
+
+ public virtual PkixPolicyNode Parent
+ {
+ get { return this.mParent; }
+ set { this.mParent = value; }
+ }
+
+ /// Constructors
+ public PkixPolicyNode(
+ IList children,
+ int depth,
+ ISet expectedPolicies,
+ PkixPolicyNode parent,
+ ISet policyQualifiers,
+ string validPolicy,
+ bool critical)
+ {
+ if (children == null)
+ {
+ this.mChildren = Platform.CreateArrayList();
+ }
+ else
+ {
+ this.mChildren = Platform.CreateArrayList(children);
+ }
+
+ this.mDepth = depth;
+ this.mExpectedPolicies = expectedPolicies;
+ this.mParent = parent;
+ this.mPolicyQualifiers = policyQualifiers;
+ this.mValidPolicy = validPolicy;
+ this.mCritical = critical;
+ }
+
+ public virtual void AddChild(
+ PkixPolicyNode child)
+ {
+ child.Parent = this;
+ mChildren.Add(child);
+ }
+
+ public virtual void RemoveChild(
+ PkixPolicyNode child)
+ {
+ mChildren.Remove(child);
+ }
+
+ public override string ToString()
+ {
+ return ToString("");
+ }
+
+ public virtual string ToString(
+ string indent)
+ {
+ StringBuilder buf = new StringBuilder();
+ buf.Append(indent);
+ buf.Append(mValidPolicy);
+ buf.Append(" {");
+ buf.Append(Platform.NewLine);
+
+ foreach (PkixPolicyNode child in mChildren)
+ {
+ buf.Append(child.ToString(indent + " "));
+ }
+
+ buf.Append(indent);
+ buf.Append("}");
+ buf.Append(Platform.NewLine);
+ return buf.ToString();
+ }
+
+ public virtual object Clone()
+ {
+ return Copy();
+ }
+
+ public virtual PkixPolicyNode Copy()
+ {
+ PkixPolicyNode node = new PkixPolicyNode(
+ Platform.CreateArrayList(),
+ mDepth,
+ new HashSet(mExpectedPolicies),
+ null,
+ new HashSet(mPolicyQualifiers),
+ mValidPolicy,
+ mCritical);
+
+ foreach (PkixPolicyNode child in mChildren)
+ {
+ PkixPolicyNode copy = child.Copy();
+ copy.Parent = node;
+ node.AddChild(copy);
+ }
+
+ return node;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/ReasonsMask.cs b/bc-sharp-crypto/src/pkix/ReasonsMask.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e389bfe113071c87cf16230efd2cff10d0f8322d
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/ReasonsMask.cs
@@ -0,0 +1,96 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Pkix
+{
+ ///
+ /// This class helps to handle CRL revocation reasons mask. Each CRL handles a
+ /// certain set of revocation reasons.
+ ///
+ internal class ReasonsMask
+ {
+ private int _reasons;
+
+ ///
+ /// Constructs are reason mask with the reasons.
+ ///
+ /// The reasons.
+ internal ReasonsMask(
+ int reasons)
+ {
+ _reasons = reasons;
+ }
+
+ ///
+ /// A reason mask with no reason.
+ ///
+ internal ReasonsMask()
+ : this(0)
+ {
+ }
+
+ ///
+ /// A mask with all revocation reasons.
+ ///
+ internal static readonly ReasonsMask AllReasons = new ReasonsMask(
+ ReasonFlags.AACompromise | ReasonFlags.AffiliationChanged | ReasonFlags.CACompromise
+ | ReasonFlags.CertificateHold | ReasonFlags.CessationOfOperation
+ | ReasonFlags.KeyCompromise | ReasonFlags.PrivilegeWithdrawn | ReasonFlags.Unused
+ | ReasonFlags.Superseded);
+
+ /**
+ * Adds all reasons from the reasons mask to this mask.
+ *
+ * @param mask The reasons mask to add.
+ */
+ internal void AddReasons(
+ ReasonsMask mask)
+ {
+ _reasons = _reasons | mask.Reasons.IntValue;
+ }
+
+ ///
+ /// Returns true
if this reasons mask contains all possible
+ /// reasons.
+ ///
+ /// true if this reasons mask contains all possible reasons.
+ ///
+ internal bool IsAllReasons
+ {
+ get { return _reasons == AllReasons._reasons; }
+ }
+
+ ///
+ /// Intersects this mask with the given reasons mask.
+ ///
+ /// mask The mask to intersect with.
+ /// The intersection of this and teh given mask.
+ internal ReasonsMask Intersect(
+ ReasonsMask mask)
+ {
+ ReasonsMask _mask = new ReasonsMask();
+ _mask.AddReasons(new ReasonsMask(_reasons & mask.Reasons.IntValue));
+ return _mask;
+ }
+
+ ///
+ /// Returns true if the passed reasons mask has new reasons.
+ ///
+ /// The reasons mask which should be tested for new reasons.
+ /// true if the passed reasons mask has new reasons.
+ internal bool HasNewReasons(
+ ReasonsMask mask)
+ {
+ return ((_reasons | mask.Reasons.IntValue ^ _reasons) != 0);
+ }
+
+ ///
+ /// Returns the reasons in this mask.
+ ///
+ public ReasonFlags Reasons
+ {
+ get { return new ReasonFlags(_reasons); }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/Rfc3280CertPathUtilities.cs b/bc-sharp-crypto/src/pkix/Rfc3280CertPathUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c6f3fbff9f06787feeb78f18af48e711c833f7eb
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/Rfc3280CertPathUtilities.cs
@@ -0,0 +1,2448 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+ public class Rfc3280CertPathUtilities
+ {
+ private static readonly PkixCrlUtilities CrlUtilities = new PkixCrlUtilities();
+
+ internal static readonly string ANY_POLICY = "2.5.29.32.0";
+
+ // key usage bits
+ internal static readonly int KEY_CERT_SIGN = 5;
+ internal static readonly int CRL_SIGN = 6;
+
+ /**
+ * If the complete CRL includes an issuing distribution point (IDP) CRL
+ * extension check the following:
+ *
+ * (i) If the distribution point name is present in the IDP CRL extension
+ * and the distribution field is present in the DP, then verify that one of
+ * the names in the IDP matches one of the names in the DP. If the
+ * distribution point name is present in the IDP CRL extension and the
+ * distribution field is omitted from the DP, then verify that one of the
+ * names in the IDP matches one of the names in the cRLIssuer field of the
+ * DP.
+ *
+ *
+ * (ii) If the onlyContainsUserCerts boolean is asserted in the IDP CRL
+ * extension, verify that the certificate does not include the basic
+ * constraints extension with the cA boolean asserted.
+ *
+ *
+ * (iii) If the onlyContainsCACerts boolean is asserted in the IDP CRL
+ * extension, verify that the certificate includes the basic constraints
+ * extension with the cA boolean asserted.
+ *
+ *
+ * (iv) Verify that the onlyContainsAttributeCerts boolean is not asserted.
+ *
+ *
+ * @param dp The distribution point.
+ * @param cert The certificate.
+ * @param crl The CRL.
+ * @throws AnnotatedException if one of the conditions is not met or an error occurs.
+ */
+ internal static void ProcessCrlB2(
+ DistributionPoint dp,
+ object cert,
+ X509Crl crl)
+ {
+ IssuingDistributionPoint idp = null;
+ try
+ {
+ idp = IssuingDistributionPoint.GetInstance(PkixCertPathValidatorUtilities.GetExtensionValue(crl, X509Extensions.IssuingDistributionPoint));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("0 Issuing distribution point extension could not be decoded.", e);
+ }
+ // (b) (2) (i)
+ // distribution point name is present
+ if (idp != null)
+ {
+ if (idp.DistributionPoint != null)
+ {
+ // make list of names
+ DistributionPointName dpName = IssuingDistributionPoint.GetInstance(idp).DistributionPoint;
+ IList names = Platform.CreateArrayList();
+
+ if (dpName.PointType == DistributionPointName.FullName)
+ {
+ GeneralName[] genNames = GeneralNames.GetInstance(dpName.Name).GetNames();
+ for (int j = 0; j < genNames.Length; j++)
+ {
+ names.Add(genNames[j]);
+ }
+ }
+ if (dpName.PointType == DistributionPointName.NameRelativeToCrlIssuer)
+ {
+ Asn1EncodableVector vec = new Asn1EncodableVector();
+ try
+ {
+ IEnumerator e = Asn1Sequence.GetInstance(
+ Asn1Sequence.FromByteArray(crl.IssuerDN.GetEncoded())).GetEnumerator();
+ while (e.MoveNext())
+ {
+ vec.Add((Asn1Encodable)e.Current);
+ }
+ }
+ catch (IOException e)
+ {
+ throw new Exception("Could not read CRL issuer.", e);
+ }
+ vec.Add(dpName.Name);
+ names.Add(new GeneralName(X509Name.GetInstance(new DerSequence(vec))));
+ }
+ bool matches = false;
+ // verify that one of the names in the IDP matches one
+ // of the names in the DP.
+ if (dp.DistributionPointName != null)
+ {
+ dpName = dp.DistributionPointName;
+ GeneralName[] genNames = null;
+ if (dpName.PointType == DistributionPointName.FullName)
+ {
+ genNames = GeneralNames.GetInstance(dpName.Name).GetNames();
+ }
+ if (dpName.PointType == DistributionPointName.NameRelativeToCrlIssuer)
+ {
+ if (dp.CrlIssuer != null)
+ {
+ genNames = dp.CrlIssuer.GetNames();
+ }
+ else
+ {
+ genNames = new GeneralName[1];
+ try
+ {
+ genNames[0] = new GeneralName(
+ PkixCertPathValidatorUtilities.GetIssuerPrincipal(cert));
+ }
+ catch (IOException e)
+ {
+ throw new Exception("Could not read certificate issuer.", e);
+ }
+ }
+ for (int j = 0; j < genNames.Length; j++)
+ {
+ IEnumerator e = Asn1Sequence.GetInstance(genNames[j].Name.ToAsn1Object()).GetEnumerator();
+ Asn1EncodableVector vec = new Asn1EncodableVector();
+ while (e.MoveNext())
+ {
+ vec.Add((Asn1Encodable)e.Current);
+ }
+ vec.Add(dpName.Name);
+ genNames[j] = new GeneralName(X509Name.GetInstance(new DerSequence(vec)));
+ }
+ }
+ if (genNames != null)
+ {
+ for (int j = 0; j < genNames.Length; j++)
+ {
+ if (names.Contains(genNames[j]))
+ {
+ matches = true;
+ break;
+ }
+ }
+ }
+ if (!matches)
+ {
+ throw new Exception(
+ "No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point.");
+ }
+ }
+ // verify that one of the names in
+ // the IDP matches one of the names in the cRLIssuer field of
+ // the DP
+ else
+ {
+ if (dp.CrlIssuer == null)
+ {
+ throw new Exception("Either the cRLIssuer or the distributionPoint field must "
+ + "be contained in DistributionPoint.");
+ }
+ GeneralName[] genNames = dp.CrlIssuer.GetNames();
+ for (int j = 0; j < genNames.Length; j++)
+ {
+ if (names.Contains(genNames[j]))
+ {
+ matches = true;
+ break;
+ }
+ }
+ if (!matches)
+ {
+ throw new Exception(
+ "No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point.");
+ }
+ }
+ }
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.GetInstance(PkixCertPathValidatorUtilities.GetExtensionValue(
+ (IX509Extension)cert, X509Extensions.BasicConstraints));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Basic constraints extension could not be decoded.", e);
+ }
+
+ //if (cert is X509Certificate)
+ {
+ // (b) (2) (ii)
+ if (idp.OnlyContainsUserCerts && ((bc != null) && bc.IsCA()))
+ {
+ throw new Exception("CA Cert CRL only contains user certificates.");
+ }
+
+ // (b) (2) (iii)
+ if (idp.OnlyContainsCACerts && (bc == null || !bc.IsCA()))
+ {
+ throw new Exception("End CRL only contains CA certificates.");
+ }
+ }
+
+ // (b) (2) (iv)
+ if (idp.OnlyContainsAttributeCerts)
+ {
+ throw new Exception("onlyContainsAttributeCerts boolean is asserted.");
+ }
+ }
+ }
+
+ internal static void ProcessCertBC(
+ PkixCertPath certPath,
+ int index,
+ PkixNameConstraintValidator nameConstraintValidator)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+ int n = certs.Count;
+ // i as defined in the algorithm description
+ int i = n - index;
+ //
+ // (b), (c) permitted and excluded subtree checking.
+ //
+ if (!(PkixCertPathValidatorUtilities.IsSelfIssued(cert) && (i < n)))
+ {
+ X509Name principal = cert.SubjectDN;
+ Asn1InputStream aIn = new Asn1InputStream(principal.GetEncoded());
+ Asn1Sequence dns;
+
+ try
+ {
+ dns = DerSequence.GetInstance(aIn.ReadObject());
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Exception extracting subject name when checking subtrees.", e, certPath, index);
+ }
+
+ try
+ {
+ nameConstraintValidator.CheckPermittedDN(dns);
+ nameConstraintValidator.CheckExcludedDN(dns);
+ }
+ catch (PkixNameConstraintValidatorException e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Subtree check for certificate subject failed.", e, certPath, index);
+ }
+
+ GeneralNames altName = null;
+ try
+ {
+ altName = GeneralNames.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.SubjectAlternativeName));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Subject alternative name extension could not be decoded.", e, certPath, index);
+ }
+
+ IList emails = X509Name.GetInstance(dns).GetValueList(X509Name.EmailAddress);
+ foreach (string email in emails)
+ {
+ GeneralName emailAsGeneralName = new GeneralName(GeneralName.Rfc822Name, email);
+ try
+ {
+ nameConstraintValidator.checkPermitted(emailAsGeneralName);
+ nameConstraintValidator.checkExcluded(emailAsGeneralName);
+ }
+ catch (PkixNameConstraintValidatorException ex)
+ {
+ throw new PkixCertPathValidatorException(
+ "Subtree check for certificate subject alternative email failed.", ex, certPath, index);
+ }
+ }
+ if (altName != null)
+ {
+ GeneralName[] genNames = null;
+ try
+ {
+ genNames = altName.GetNames();
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Subject alternative name contents could not be decoded.", e, certPath, index);
+ }
+ foreach (GeneralName genName in genNames)
+ {
+ try
+ {
+ nameConstraintValidator.checkPermitted(genName);
+ nameConstraintValidator.checkExcluded(genName);
+ }
+ catch (PkixNameConstraintValidatorException e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Subtree check for certificate subject alternative name failed.", e, certPath, index);
+ }
+ }
+ }
+ }
+ }
+
+ internal static void PrepareNextCertA(
+ PkixCertPath certPath,
+ int index)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+ //
+ //
+ // (a) check the policy mappings
+ //
+ Asn1Sequence pm = null;
+ try
+ {
+ pm = Asn1Sequence.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.PolicyMappings));
+ }
+ catch (Exception ex)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy mappings extension could not be decoded.", ex, certPath, index);
+ }
+ if (pm != null)
+ {
+ Asn1Sequence mappings = pm;
+
+ for (int j = 0; j < mappings.Count; j++)
+ {
+ DerObjectIdentifier issuerDomainPolicy = null;
+ DerObjectIdentifier subjectDomainPolicy = null;
+ try
+ {
+ Asn1Sequence mapping = DerSequence.GetInstance(mappings[j]);
+
+ issuerDomainPolicy = DerObjectIdentifier.GetInstance(mapping[0]);
+ subjectDomainPolicy = DerObjectIdentifier.GetInstance(mapping[1]);
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy mappings extension contents could not be decoded.", e, certPath, index);
+ }
+
+ if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(issuerDomainPolicy.Id))
+ throw new PkixCertPathValidatorException(
+ "IssuerDomainPolicy is anyPolicy", null, certPath, index);
+
+ if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(subjectDomainPolicy.Id))
+ throw new PkixCertPathValidatorException(
+ "SubjectDomainPolicy is anyPolicy,", null, certPath, index);
+ }
+ }
+ }
+
+ internal static PkixPolicyNode ProcessCertD(
+ PkixCertPath certPath,
+ int index,
+ ISet acceptablePolicies,
+ PkixPolicyNode validPolicyTree,
+ IList[] policyNodes,
+ int inhibitAnyPolicy)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+ int n = certs.Count;
+ // i as defined in the algorithm description
+ int i = n - index;
+ //
+ // (d) policy Information checking against initial policy and
+ // policy mapping
+ //
+ Asn1Sequence certPolicies = null;
+ try
+ {
+ certPolicies = DerSequence.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.CertificatePolicies));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Could not read certificate policies extension from certificate.", e, certPath, index);
+ }
+ if (certPolicies != null && validPolicyTree != null)
+ {
+ //
+ // (d) (1)
+ //
+ ISet pols = new HashSet();
+
+ foreach (Asn1Encodable ae in certPolicies)
+ {
+ PolicyInformation pInfo = PolicyInformation.GetInstance(ae.ToAsn1Object());
+ DerObjectIdentifier pOid = pInfo.PolicyIdentifier;
+
+ pols.Add(pOid.Id);
+
+ if (!Rfc3280CertPathUtilities.ANY_POLICY.Equals(pOid.Id))
+ {
+ ISet pq = null;
+ try
+ {
+ pq = PkixCertPathValidatorUtilities.GetQualifierSet(pInfo.PolicyQualifiers);
+ }
+ catch (PkixCertPathValidatorException ex)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy qualifier info set could not be build.", ex, certPath, index);
+ }
+
+ bool match = PkixCertPathValidatorUtilities.ProcessCertD1i(i, policyNodes, pOid, pq);
+
+ if (!match)
+ {
+ PkixCertPathValidatorUtilities.ProcessCertD1ii(i, policyNodes, pOid, pq);
+ }
+ }
+ }
+
+ if (acceptablePolicies.IsEmpty || acceptablePolicies.Contains(Rfc3280CertPathUtilities.ANY_POLICY))
+ {
+ acceptablePolicies.Clear();
+ acceptablePolicies.AddAll(pols);
+ }
+ else
+ {
+ ISet t1 = new HashSet();
+
+ foreach (object o in acceptablePolicies)
+ {
+ if (pols.Contains(o))
+ {
+ t1.Add(o);
+ }
+ }
+ acceptablePolicies.Clear();
+ acceptablePolicies.AddAll(t1);
+ }
+
+ //
+ // (d) (2)
+ //
+ if ((inhibitAnyPolicy > 0) || ((i < n) && PkixCertPathValidatorUtilities.IsSelfIssued(cert)))
+ {
+ foreach (Asn1Encodable ae in certPolicies)
+ {
+ PolicyInformation pInfo = PolicyInformation.GetInstance(ae.ToAsn1Object());
+ if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(pInfo.PolicyIdentifier.Id))
+ {
+ ISet _apq = PkixCertPathValidatorUtilities.GetQualifierSet(pInfo.PolicyQualifiers);
+ IList _nodes = policyNodes[i - 1];
+
+ for (int k = 0; k < _nodes.Count; k++)
+ {
+ PkixPolicyNode _node = (PkixPolicyNode)_nodes[k];
+
+ IEnumerator _policySetIter = _node.ExpectedPolicies.GetEnumerator();
+ while (_policySetIter.MoveNext())
+ {
+ object _tmp = _policySetIter.Current;
+
+ string _policy;
+ if (_tmp is string)
+ {
+ _policy = (string)_tmp;
+ }
+ else if (_tmp is DerObjectIdentifier)
+ {
+ _policy = ((DerObjectIdentifier)_tmp).Id;
+ }
+ else
+ {
+ continue;
+ }
+
+ bool _found = false;
+
+ foreach (PkixPolicyNode _child in _node.Children)
+ {
+ if (_policy.Equals(_child.ValidPolicy))
+ {
+ _found = true;
+ }
+ }
+
+ if (!_found)
+ {
+ ISet _newChildExpectedPolicies = new HashSet();
+ _newChildExpectedPolicies.Add(_policy);
+
+ PkixPolicyNode _newChild = new PkixPolicyNode(Platform.CreateArrayList(), i,
+ _newChildExpectedPolicies, _node, _apq, _policy, false);
+ _node.AddChild(_newChild);
+ policyNodes[i].Add(_newChild);
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ PkixPolicyNode _validPolicyTree = validPolicyTree;
+ //
+ // (d) (3)
+ //
+ for (int j = (i - 1); j >= 0; j--)
+ {
+ IList nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.Count; k++)
+ {
+ PkixPolicyNode node = (PkixPolicyNode)nodes[k];
+ if (!node.HasChildren)
+ {
+ _validPolicyTree = PkixCertPathValidatorUtilities.RemovePolicyNode(_validPolicyTree, policyNodes,
+ node);
+ if (_validPolicyTree == null)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // d (4)
+ //
+ ISet criticalExtensionOids = cert.GetCriticalExtensionOids();
+
+ if (criticalExtensionOids != null)
+ {
+ bool critical = criticalExtensionOids.Contains(X509Extensions.CertificatePolicies.Id);
+
+ IList nodes = policyNodes[i];
+ for (int j = 0; j < nodes.Count; j++)
+ {
+ PkixPolicyNode node = (PkixPolicyNode)nodes[j];
+ node.IsCritical = critical;
+ }
+ }
+ return _validPolicyTree;
+ }
+ return null;
+ }
+
+ /**
+ * If the DP includes cRLIssuer, then verify that the issuer field in the
+ * complete CRL matches cRLIssuer in the DP and that the complete CRL
+ * contains an
+ * g distribution point extension with the indirectCRL
+ * boolean asserted. Otherwise, verify that the CRL issuer matches the
+ * certificate issuer.
+ *
+ * @param dp The distribution point.
+ * @param cert The certificate ot attribute certificate.
+ * @param crl The CRL for cert
.
+ * @throws AnnotatedException if one of the above conditions does not apply or an error
+ * occurs.
+ */
+ internal static void ProcessCrlB1(
+ DistributionPoint dp,
+ object cert,
+ X509Crl crl)
+ {
+ Asn1Object idp = PkixCertPathValidatorUtilities.GetExtensionValue(
+ crl, X509Extensions.IssuingDistributionPoint);
+
+ bool isIndirect = false;
+ if (idp != null)
+ {
+ if (IssuingDistributionPoint.GetInstance(idp).IsIndirectCrl)
+ {
+ isIndirect = true;
+ }
+ }
+ byte[] issuerBytes = crl.IssuerDN.GetEncoded();
+
+ bool matchIssuer = false;
+ if (dp.CrlIssuer != null)
+ {
+ GeneralName[] genNames = dp.CrlIssuer.GetNames();
+ for (int j = 0; j < genNames.Length; j++)
+ {
+ if (genNames[j].TagNo == GeneralName.DirectoryName)
+ {
+ try
+ {
+ if (Org.BouncyCastle.Utilities.Arrays.AreEqual(genNames[j].Name.ToAsn1Object().GetEncoded(), issuerBytes))
+ {
+ matchIssuer = true;
+ }
+ }
+ catch (IOException e)
+ {
+ throw new Exception(
+ "CRL issuer information from distribution point cannot be decoded.", e);
+ }
+ }
+ }
+ if (matchIssuer && !isIndirect)
+ {
+ throw new Exception("Distribution point contains cRLIssuer field but CRL is not indirect.");
+ }
+ if (!matchIssuer)
+ {
+ throw new Exception("CRL issuer of CRL does not match CRL issuer of distribution point.");
+ }
+ }
+ else
+ {
+ if (crl.IssuerDN.Equivalent(PkixCertPathValidatorUtilities.GetIssuerPrincipal(cert), true))
+ {
+ matchIssuer = true;
+ }
+ }
+ if (!matchIssuer)
+ {
+ throw new Exception("Cannot find matching CRL issuer for certificate.");
+ }
+ }
+
+ internal static ReasonsMask ProcessCrlD(
+ X509Crl crl,
+ DistributionPoint dp)
+ //throws AnnotatedException
+ {
+ IssuingDistributionPoint idp = null;
+ try
+ {
+ idp = IssuingDistributionPoint.GetInstance(PkixCertPathValidatorUtilities.GetExtensionValue(crl, X509Extensions.IssuingDistributionPoint));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("issuing distribution point extension could not be decoded.", e);
+ }
+
+ // (d) (1)
+ if (idp != null && idp.OnlySomeReasons != null && dp.Reasons != null)
+ {
+ return new ReasonsMask(dp.Reasons.IntValue).Intersect(new ReasonsMask(idp.OnlySomeReasons
+ .IntValue));
+ }
+ // (d) (4)
+ if ((idp == null || idp.OnlySomeReasons == null) && dp.Reasons == null)
+ {
+ return ReasonsMask.AllReasons;
+ }
+
+ // (d) (2) and (d)(3)
+
+ ReasonsMask dpReasons = null;
+
+ if (dp.Reasons == null)
+ {
+ dpReasons = ReasonsMask.AllReasons;
+ }
+ else
+ {
+ dpReasons = new ReasonsMask(dp.Reasons.IntValue);
+ }
+
+ ReasonsMask idpReasons = null;
+
+ if (idp == null)
+ {
+ idpReasons = ReasonsMask.AllReasons;
+ }
+ else
+ {
+ idpReasons = new ReasonsMask(idp.OnlySomeReasons.IntValue);
+ }
+
+ return dpReasons.Intersect(idpReasons);
+ }
+
+ /**
+ * Obtain and validate the certification path for the complete CRL issuer.
+ * If a key usage extension is present in the CRL issuer's certificate,
+ * verify that the cRLSign bit is set.
+ *
+ * @param crl CRL which contains revocation information for the certificate
+ * cert
.
+ * @param cert The attribute certificate or certificate to check if it is
+ * revoked.
+ * @param defaultCRLSignCert The issuer certificate of the certificate cert
.
+ * @param defaultCRLSignKey The public key of the issuer certificate
+ * defaultCRLSignCert
.
+ * @param paramsPKIX paramsPKIX PKIX parameters.
+ * @param certPathCerts The certificates on the certification path.
+ * @return A Set
with all keys of possible CRL issuer
+ * certificates.
+ * @throws AnnotatedException if the CRL is not valid or the status cannot be checked or
+ * some error occurs.
+ */
+ internal static ISet ProcessCrlF(
+ X509Crl crl,
+ object cert,
+ X509Certificate defaultCRLSignCert,
+ AsymmetricKeyParameter defaultCRLSignKey,
+ PkixParameters paramsPKIX,
+ IList certPathCerts)
+ {
+ // (f)
+
+ // get issuer from CRL
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ try
+ {
+ selector.Subject = crl.IssuerDN;
+ }
+ catch (IOException e)
+ {
+ throw new Exception(
+ "Subject criteria for certificate selector to find issuer certificate for CRL could not be set.", e);
+ }
+
+ // get CRL signing certs
+ IList coll = Platform.CreateArrayList();
+
+ try
+ {
+ CollectionUtilities.AddRange(coll, PkixCertPathValidatorUtilities.FindCertificates(selector, paramsPKIX.GetStores()));
+ CollectionUtilities.AddRange(coll, PkixCertPathValidatorUtilities.FindCertificates(selector, paramsPKIX.GetAdditionalStores()));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Issuer certificate for CRL cannot be searched.", e);
+ }
+
+ coll.Add(defaultCRLSignCert);
+
+ IEnumerator cert_it = coll.GetEnumerator();
+
+ IList validCerts = Platform.CreateArrayList();
+ IList validKeys = Platform.CreateArrayList();
+
+ while (cert_it.MoveNext())
+ {
+ X509Certificate signingCert = (X509Certificate)cert_it.Current;
+
+ /*
+ * CA of the certificate, for which this CRL is checked, has also
+ * signed CRL, so skip the path validation, because is already done
+ */
+ if (signingCert.Equals(defaultCRLSignCert))
+ {
+ validCerts.Add(signingCert);
+ validKeys.Add(defaultCRLSignKey);
+ continue;
+ }
+ try
+ {
+// CertPathBuilder builder = CertPathBuilder.GetInstance("PKIX");
+ PkixCertPathBuilder builder = new PkixCertPathBuilder();
+ selector = new X509CertStoreSelector();
+ selector.Certificate = signingCert;
+
+ PkixParameters temp = (PkixParameters)paramsPKIX.Clone();
+ temp.SetTargetCertConstraints(selector);
+
+ PkixBuilderParameters parameters = (PkixBuilderParameters)
+ PkixBuilderParameters.GetInstance(temp);
+
+ /*
+ * if signingCert is placed not higher on the cert path a
+ * dependency loop results. CRL for cert is checked, but
+ * signingCert is needed for checking the CRL which is dependent
+ * on checking cert because it is higher in the cert path and so
+ * signing signingCert transitively. so, revocation is disabled,
+ * forgery attacks of the CRL are detected in this outer loop
+ * for all other it must be enabled to prevent forgery attacks
+ */
+ if (certPathCerts.Contains(signingCert))
+ {
+ parameters.IsRevocationEnabled = false;
+ }
+ else
+ {
+ parameters.IsRevocationEnabled = true;
+ }
+ IList certs = builder.Build(parameters).CertPath.Certificates;
+ validCerts.Add(signingCert);
+ validKeys.Add(PkixCertPathValidatorUtilities.GetNextWorkingKey(certs, 0));
+ }
+ catch (PkixCertPathBuilderException e)
+ {
+ throw new Exception("Internal error.", e);
+ }
+ catch (PkixCertPathValidatorException e)
+ {
+ throw new Exception("Public key of issuer certificate of CRL could not be retrieved.", e);
+ }
+ //catch (Exception e)
+ //{
+ // throw new Exception(e.Message);
+ //}
+ }
+
+ ISet checkKeys = new HashSet();
+
+ Exception lastException = null;
+ for (int i = 0; i < validCerts.Count; i++)
+ {
+ X509Certificate signCert = (X509Certificate)validCerts[i];
+ bool[] keyusage = signCert.GetKeyUsage();
+
+ if (keyusage != null && (keyusage.Length < 7 || !keyusage[CRL_SIGN]))
+ {
+ lastException = new Exception(
+ "Issuer certificate key usage extension does not permit CRL signing.");
+ }
+ else
+ {
+ checkKeys.Add(validKeys[i]);
+ }
+ }
+
+ if ((checkKeys.Count == 0) && lastException == null)
+ {
+ throw new Exception("Cannot find a valid issuer certificate.");
+ }
+ if ((checkKeys.Count == 0) && lastException != null)
+ {
+ throw lastException;
+ }
+
+ return checkKeys;
+ }
+
+ internal static AsymmetricKeyParameter ProcessCrlG(
+ X509Crl crl,
+ ISet keys)
+ {
+ Exception lastException = null;
+ foreach (AsymmetricKeyParameter key in keys)
+ {
+ try
+ {
+ crl.Verify(key);
+ return key;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+ throw new Exception("Cannot verify CRL.", lastException);
+ }
+
+ internal static X509Crl ProcessCrlH(
+ ISet deltaCrls,
+ AsymmetricKeyParameter key)
+ {
+ Exception lastException = null;
+ foreach (X509Crl crl in deltaCrls)
+ {
+ try
+ {
+ crl.Verify(key);
+ return crl;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+ if (lastException != null)
+ {
+ throw new Exception("Cannot verify delta CRL.", lastException);
+ }
+ return null;
+ }
+
+ /**
+ * Checks a distribution point for revocation information for the
+ * certificate cert
.
+ *
+ * @param dp The distribution point to consider.
+ * @param paramsPKIX PKIX parameters.
+ * @param cert Certificate to check if it is revoked.
+ * @param validDate The date when the certificate revocation status should be
+ * checked.
+ * @param defaultCRLSignCert The issuer certificate of the certificate cert
.
+ * @param defaultCRLSignKey The public key of the issuer certificate
+ * defaultCRLSignCert
.
+ * @param certStatus The current certificate revocation status.
+ * @param reasonMask The reasons mask which is already checked.
+ * @param certPathCerts The certificates of the certification path.
+ * @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+ * or some error occurs.
+ */
+ private static void CheckCrl(
+ DistributionPoint dp,
+ PkixParameters paramsPKIX,
+ X509Certificate cert,
+ DateTime validDate,
+ X509Certificate defaultCRLSignCert,
+ AsymmetricKeyParameter defaultCRLSignKey,
+ CertStatus certStatus,
+ ReasonsMask reasonMask,
+ IList certPathCerts)
+ //throws AnnotatedException
+ {
+ DateTime currentDate = DateTime.UtcNow;
+
+ if (validDate.Ticks > currentDate.Ticks)
+ {
+ throw new Exception("Validation time is in future.");
+ }
+
+ // (a)
+ /*
+ * We always get timely valid CRLs, so there is no step (a) (1).
+ * "locally cached" CRLs are assumed to be in getStore(), additional
+ * CRLs must be enabled in the ExtendedPKIXParameters and are in
+ * getAdditionalStore()
+ */
+
+ ISet crls = PkixCertPathValidatorUtilities.GetCompleteCrls(dp, cert, currentDate, paramsPKIX);
+ bool validCrlFound = false;
+ Exception lastException = null;
+
+ IEnumerator crl_iter = crls.GetEnumerator();
+
+ while (crl_iter.MoveNext() && certStatus.Status == CertStatus.Unrevoked && !reasonMask.IsAllReasons)
+ {
+ try
+ {
+ X509Crl crl = (X509Crl)crl_iter.Current;
+
+ // (d)
+ ReasonsMask interimReasonsMask = Rfc3280CertPathUtilities.ProcessCrlD(crl, dp);
+
+ // (e)
+ /*
+ * The reasons mask is updated at the end, so only valid CRLs
+ * can update it. If this CRL does not contain new reasons it
+ * must be ignored.
+ */
+ if (!interimReasonsMask.HasNewReasons(reasonMask))
+ {
+ continue;
+ }
+
+ // (f)
+ ISet keys = Rfc3280CertPathUtilities.ProcessCrlF(crl, cert, defaultCRLSignCert, defaultCRLSignKey,
+ paramsPKIX, certPathCerts);
+ // (g)
+ AsymmetricKeyParameter key = Rfc3280CertPathUtilities.ProcessCrlG(crl, keys);
+
+ X509Crl deltaCRL = null;
+
+ if (paramsPKIX.IsUseDeltasEnabled)
+ {
+ // get delta CRLs
+ ISet deltaCRLs = PkixCertPathValidatorUtilities.GetDeltaCrls(currentDate, paramsPKIX, crl);
+ // we only want one valid delta CRL
+ // (h)
+ deltaCRL = Rfc3280CertPathUtilities.ProcessCrlH(deltaCRLs, key);
+ }
+
+ /*
+ * CRL must be be valid at the current time, not the validation
+ * time. If a certificate is revoked with reason keyCompromise,
+ * cACompromise, it can be used for forgery, also for the past.
+ * This reason may not be contained in older CRLs.
+ */
+
+ /*
+ * in the chain model signatures stay valid also after the
+ * certificate has been expired, so they do not have to be in
+ * the CRL validity time
+ */
+
+ if (paramsPKIX.ValidityModel != PkixParameters.ChainValidityModel)
+ {
+ /*
+ * if a certificate has expired, but was revoked, it is not
+ * more in the CRL, so it would be regarded as valid if the
+ * first check is not done
+ */
+ if (cert.NotAfter.Ticks < crl.ThisUpdate.Ticks)
+ {
+ throw new Exception("No valid CRL for current time found.");
+ }
+ }
+
+ Rfc3280CertPathUtilities.ProcessCrlB1(dp, cert, crl);
+
+ // (b) (2)
+ Rfc3280CertPathUtilities.ProcessCrlB2(dp, cert, crl);
+
+ // (c)
+ Rfc3280CertPathUtilities.ProcessCrlC(deltaCRL, crl, paramsPKIX);
+
+ // (i)
+ Rfc3280CertPathUtilities.ProcessCrlI(validDate, deltaCRL, cert, certStatus, paramsPKIX);
+
+ // (j)
+ Rfc3280CertPathUtilities.ProcessCrlJ(validDate, crl, cert, certStatus);
+
+ // (k)
+ if (certStatus.Status == CrlReason.RemoveFromCrl)
+ {
+ certStatus.Status = CertStatus.Unrevoked;
+ }
+
+ // update reasons mask
+ reasonMask.AddReasons(interimReasonsMask);
+
+ ISet criticalExtensions = crl.GetCriticalExtensionOids();
+
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+ criticalExtensions.Remove(X509Extensions.IssuingDistributionPoint.Id);
+ criticalExtensions.Remove(X509Extensions.DeltaCrlIndicator.Id);
+
+ if (!criticalExtensions.IsEmpty)
+ throw new Exception("CRL contains unsupported critical extensions.");
+ }
+
+ if (deltaCRL != null)
+ {
+ criticalExtensions = deltaCRL.GetCriticalExtensionOids();
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+ criticalExtensions.Remove(X509Extensions.IssuingDistributionPoint.Id);
+ criticalExtensions.Remove(X509Extensions.DeltaCrlIndicator.Id);
+
+ if (!criticalExtensions.IsEmpty)
+ throw new Exception("Delta CRL contains unsupported critical extension.");
+ }
+ }
+
+ validCrlFound = true;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+ if (!validCrlFound)
+ {
+ throw lastException;
+ }
+ }
+
+ /**
+ * Checks a certificate if it is revoked.
+ *
+ * @param paramsPKIX PKIX parameters.
+ * @param cert Certificate to check if it is revoked.
+ * @param validDate The date when the certificate revocation status should be
+ * checked.
+ * @param sign The issuer certificate of the certificate cert
.
+ * @param workingPublicKey The public key of the issuer certificate sign
.
+ * @param certPathCerts The certificates of the certification path.
+ * @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+ * or some error occurs.
+ */
+ protected static void CheckCrls(
+ PkixParameters paramsPKIX,
+ X509Certificate cert,
+ DateTime validDate,
+ X509Certificate sign,
+ AsymmetricKeyParameter workingPublicKey,
+ IList certPathCerts)
+ {
+ Exception lastException = null;
+ CrlDistPoint crldp = null;
+
+ try
+ {
+ crldp = CrlDistPoint.GetInstance(PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.CrlDistributionPoints));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("CRL distribution point extension could not be read.", e);
+ }
+
+ try
+ {
+ PkixCertPathValidatorUtilities.AddAdditionalStoresFromCrlDistributionPoint(crldp, paramsPKIX);
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "No additional CRL locations could be decoded from CRL distribution point extension.", e);
+ }
+ CertStatus certStatus = new CertStatus();
+ ReasonsMask reasonsMask = new ReasonsMask();
+
+ bool validCrlFound = false;
+
+ // for each distribution point
+ if (crldp != null)
+ {
+ DistributionPoint[] dps = null;
+ try
+ {
+ dps = crldp.GetDistributionPoints();
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Distribution points could not be read.", e);
+ }
+ if (dps != null)
+ {
+ for (int i = 0; i < dps.Length && certStatus.Status == CertStatus.Unrevoked && !reasonsMask.IsAllReasons; i++)
+ {
+ PkixParameters paramsPKIXClone = (PkixParameters)paramsPKIX.Clone();
+ try
+ {
+ CheckCrl(dps[i], paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask, certPathCerts);
+ validCrlFound = true;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+ }
+ }
+
+ /*
+ * If the revocation status has not been determined, repeat the process
+ * above with any available CRLs not specified in a distribution point
+ * but issued by the certificate issuer.
+ */
+
+ if (certStatus.Status == CertStatus.Unrevoked && !reasonsMask.IsAllReasons)
+ {
+ try
+ {
+ /*
+ * assume a DP with both the reasons and the cRLIssuer fields
+ * omitted and a distribution point name of the certificate
+ * issuer.
+ */
+ Asn1Object issuer = null;
+ try
+ {
+ issuer = new Asn1InputStream(cert.IssuerDN.GetEncoded()).ReadObject();
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Issuer from certificate for CRL could not be reencoded.", e);
+ }
+ DistributionPoint dp = new DistributionPoint(new DistributionPointName(0, new GeneralNames(
+ new GeneralName(GeneralName.DirectoryName, issuer))), null, null);
+ PkixParameters paramsPKIXClone = (PkixParameters)paramsPKIX.Clone();
+
+ CheckCrl(dp, paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask,
+ certPathCerts);
+
+ validCrlFound = true;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+
+ if (!validCrlFound)
+ {
+ throw lastException;
+ }
+ if (certStatus.Status != CertStatus.Unrevoked)
+ {
+ // This format is enforced by the NistCertPath tests
+ string formattedDate = certStatus.RevocationDate.Value.ToString(
+ "ddd MMM dd HH:mm:ss K yyyy");
+ string message = "Certificate revocation after " + formattedDate;
+ message += ", reason: " + CrlReasons[certStatus.Status];
+ throw new Exception(message);
+ }
+
+ if (!reasonsMask.IsAllReasons && certStatus.Status == CertStatus.Unrevoked)
+ {
+ certStatus.Status = CertStatus.Undetermined;
+ }
+
+ if (certStatus.Status == CertStatus.Undetermined)
+ {
+ throw new Exception("Certificate status could not be determined.");
+ }
+ }
+
+ internal static PkixPolicyNode PrepareCertB(
+ PkixCertPath certPath,
+ int index,
+ IList[] policyNodes,
+ PkixPolicyNode validPolicyTree,
+ int policyMapping)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+ int n = certs.Count;
+ // i as defined in the algorithm description
+ int i = n - index;
+ // (b)
+ //
+ Asn1Sequence pm = null;
+ try
+ {
+ pm = (Asn1Sequence)Asn1Sequence.GetInstance(PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.PolicyMappings));
+ }
+ catch (Exception ex)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy mappings extension could not be decoded.", ex, certPath, index);
+ }
+ PkixPolicyNode _validPolicyTree = validPolicyTree;
+ if (pm != null)
+ {
+ Asn1Sequence mappings = (Asn1Sequence)pm;
+ IDictionary m_idp = Platform.CreateHashtable();
+ ISet s_idp = new HashSet();
+
+ for (int j = 0; j < mappings.Count; j++)
+ {
+ Asn1Sequence mapping = (Asn1Sequence) mappings[j];
+ string id_p = ((DerObjectIdentifier) mapping[0]).Id;
+ string sd_p = ((DerObjectIdentifier) mapping[1]).Id;
+ ISet tmp;
+
+ if (!m_idp.Contains(id_p))
+ {
+ tmp = new HashSet();
+ tmp.Add(sd_p);
+ m_idp[id_p] = tmp;
+ s_idp.Add(id_p);
+ }
+ else
+ {
+ tmp = (ISet)m_idp[id_p];
+ tmp.Add(sd_p);
+ }
+ }
+
+ IEnumerator it_idp = s_idp.GetEnumerator();
+ while (it_idp.MoveNext())
+ {
+ string id_p = (string)it_idp.Current;
+
+ //
+ // (1)
+ //
+ if (policyMapping > 0)
+ {
+ bool idp_found = false;
+ IEnumerator nodes_i = policyNodes[i].GetEnumerator();
+
+ while (nodes_i.MoveNext())
+ {
+ PkixPolicyNode node = (PkixPolicyNode)nodes_i.Current;
+ if (node.ValidPolicy.Equals(id_p))
+ {
+ idp_found = true;
+ node.ExpectedPolicies = (ISet)m_idp[id_p];
+ break;
+ }
+ }
+
+ if (!idp_found)
+ {
+ nodes_i = policyNodes[i].GetEnumerator();
+ while (nodes_i.MoveNext())
+ {
+ PkixPolicyNode node = (PkixPolicyNode)nodes_i.Current;
+ if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(node.ValidPolicy))
+ {
+ ISet pq = null;
+ Asn1Sequence policies = null;
+ try
+ {
+ policies = (Asn1Sequence)PkixCertPathValidatorUtilities.GetExtensionValue(cert,
+ X509Extensions.CertificatePolicies);
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Certificate policies extension could not be decoded.", e, certPath, index);
+ }
+
+ foreach (Asn1Encodable ae in policies)
+ {
+ PolicyInformation pinfo = null;
+ try
+ {
+ pinfo = PolicyInformation.GetInstance(ae.ToAsn1Object());
+ }
+ catch (Exception ex)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy information could not be decoded.", ex, certPath, index);
+ }
+ if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(pinfo.PolicyIdentifier.Id))
+ {
+ try
+ {
+ pq = PkixCertPathValidatorUtilities
+ .GetQualifierSet(pinfo.PolicyQualifiers);
+ }
+ catch (PkixCertPathValidatorException ex)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy qualifier info set could not be decoded.", ex, certPath,
+ index);
+ }
+ break;
+ }
+ }
+ bool ci = false;
+ ISet critExtOids = cert.GetCriticalExtensionOids();
+ if (critExtOids != null)
+ {
+ ci = critExtOids.Contains(X509Extensions.CertificatePolicies.Id);
+ }
+
+ PkixPolicyNode p_node = (PkixPolicyNode)node.Parent;
+ if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(p_node.ValidPolicy))
+ {
+ PkixPolicyNode c_node = new PkixPolicyNode(Platform.CreateArrayList(), i,
+ (ISet)m_idp[id_p], p_node, pq, id_p, ci);
+ p_node.AddChild(c_node);
+ policyNodes[i].Add(c_node);
+ }
+ break;
+ }
+ }
+ }
+
+ //
+ // (2)
+ //
+ }
+ else if (policyMapping <= 0)
+ {
+ foreach (PkixPolicyNode node in Platform.CreateArrayList(policyNodes[i]))
+ {
+ if (node.ValidPolicy.Equals(id_p))
+ {
+ node.Parent.RemoveChild(node);
+
+ for (int k = i - 1; k >= 0; k--)
+ {
+ foreach (PkixPolicyNode node2 in Platform.CreateArrayList(policyNodes[k]))
+ {
+ if (!node2.HasChildren)
+ {
+ _validPolicyTree = PkixCertPathValidatorUtilities.RemovePolicyNode(
+ _validPolicyTree, policyNodes, node2);
+
+ if (_validPolicyTree == null)
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return _validPolicyTree;
+ }
+
+ internal static ISet[] ProcessCrlA1ii(
+ DateTime currentDate,
+ PkixParameters paramsPKIX,
+ X509Certificate cert,
+ X509Crl crl)
+ {
+ ISet deltaSet = new HashSet();
+ X509CrlStoreSelector crlselect = new X509CrlStoreSelector();
+ crlselect.CertificateChecking = cert;
+
+ try
+ {
+ IList issuer = Platform.CreateArrayList();
+ issuer.Add(crl.IssuerDN);
+ crlselect.Issuers = issuer;
+ }
+ catch (IOException e)
+ {
+ throw new Exception("Cannot extract issuer from CRL." + e, e);
+ }
+
+ crlselect.CompleteCrlEnabled = true;
+ ISet completeSet = CrlUtilities.FindCrls(crlselect, paramsPKIX, currentDate);
+
+ if (paramsPKIX.IsUseDeltasEnabled)
+ {
+ // get delta CRL(s)
+ try
+ {
+ deltaSet.AddAll(PkixCertPathValidatorUtilities.GetDeltaCrls(currentDate, paramsPKIX, crl));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Exception obtaining delta CRLs.", e);
+ }
+ }
+
+ return new ISet[]{ completeSet, deltaSet };
+ }
+
+ internal static ISet ProcessCrlA1i(
+ DateTime currentDate,
+ PkixParameters paramsPKIX,
+ X509Certificate cert,
+ X509Crl crl)
+ {
+ ISet deltaSet = new HashSet();
+ if (paramsPKIX.IsUseDeltasEnabled)
+ {
+ CrlDistPoint freshestCRL = null;
+ try
+ {
+ freshestCRL = CrlDistPoint.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.FreshestCrl));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Freshest CRL extension could not be decoded from certificate.", e);
+ }
+
+ if (freshestCRL == null)
+ {
+ try
+ {
+ freshestCRL = CrlDistPoint.GetInstance(PkixCertPathValidatorUtilities.GetExtensionValue(crl, X509Extensions.FreshestCrl));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Freshest CRL extension could not be decoded from CRL.", e);
+ }
+ }
+ if (freshestCRL != null)
+ {
+ try
+ {
+ PkixCertPathValidatorUtilities.AddAdditionalStoresFromCrlDistributionPoint(freshestCRL, paramsPKIX);
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "No new delta CRL locations could be added from Freshest CRL extension.", e);
+ }
+ // get delta CRL(s)
+ try
+ {
+ deltaSet.AddAll(PkixCertPathValidatorUtilities.GetDeltaCrls(currentDate, paramsPKIX, crl));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Exception obtaining delta CRLs.", e);
+ }
+ }
+ }
+ return deltaSet;
+ }
+
+ internal static void ProcessCertF(
+ PkixCertPath certPath,
+ int index,
+ PkixPolicyNode validPolicyTree,
+ int explicitPolicy)
+ {
+ //
+ // (f)
+ //
+ if (explicitPolicy <= 0 && validPolicyTree == null)
+ {
+ throw new PkixCertPathValidatorException(
+ "No valid policy tree found when one expected.", null, certPath, index);
+ }
+ }
+
+ internal static void ProcessCertA(
+ PkixCertPath certPath,
+ PkixParameters paramsPKIX,
+ int index,
+ AsymmetricKeyParameter workingPublicKey,
+ X509Name workingIssuerName,
+ X509Certificate sign)
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+ //
+ // (a) verify
+ //
+ try
+ {
+ // (a) (1)
+ //
+ cert.Verify(workingPublicKey);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new PkixCertPathValidatorException("Could not validate certificate signature.", e, certPath, index);
+ }
+
+ try
+ {
+ // (a) (2)
+ //
+ cert.CheckValidity(PkixCertPathValidatorUtilities
+ .GetValidCertDateFromValidityModel(paramsPKIX, certPath, index));
+ }
+ catch (CertificateExpiredException e)
+ {
+ throw new PkixCertPathValidatorException("Could not validate certificate: " + e.Message, e, certPath, index);
+ }
+ catch (CertificateNotYetValidException e)
+ {
+ throw new PkixCertPathValidatorException("Could not validate certificate: " + e.Message, e, certPath, index);
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException("Could not validate time of certificate.", e, certPath, index);
+ }
+
+ //
+ // (a) (3)
+ //
+ if (paramsPKIX.IsRevocationEnabled)
+ {
+ try
+ {
+ CheckCrls(paramsPKIX, cert, PkixCertPathValidatorUtilities.GetValidCertDateFromValidityModel(paramsPKIX,
+ certPath, index), sign, workingPublicKey, certs);
+ }
+ catch (Exception e)
+ {
+ Exception cause = e.InnerException;
+ if (cause == null)
+ {
+ cause = e;
+ }
+ throw new PkixCertPathValidatorException(e.Message, cause, certPath, index);
+ }
+ }
+
+ //
+ // (a) (4) name chaining
+ //
+ X509Name issuer = PkixCertPathValidatorUtilities.GetIssuerPrincipal(cert);
+ if (!issuer.Equivalent(workingIssuerName, true))
+ {
+ throw new PkixCertPathValidatorException("IssuerName(" + issuer
+ + ") does not match SubjectName(" + workingIssuerName + ") of signing certificate.", null,
+ certPath, index);
+ }
+ }
+
+ internal static int PrepareNextCertI1(
+ PkixCertPath certPath,
+ int index,
+ int explicitPolicy)
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+ //
+ // (i)
+ //
+ Asn1Sequence pc = null;
+ try
+ {
+ pc = DerSequence.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.PolicyConstraints));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy constraints extension cannot be decoded.", e, certPath, index);
+ }
+
+ int tmpInt;
+
+ if (pc != null)
+ {
+ IEnumerator policyConstraints = pc.GetEnumerator();
+
+ while (policyConstraints.MoveNext())
+ {
+ try
+ {
+ Asn1TaggedObject constraint = Asn1TaggedObject.GetInstance(policyConstraints.Current);
+ if (constraint.TagNo == 0)
+ {
+ tmpInt = DerInteger.GetInstance(constraint, false).Value.IntValue;
+ if (tmpInt < explicitPolicy)
+ {
+ return tmpInt;
+ }
+ break;
+ }
+ }
+ catch (ArgumentException e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy constraints extension contents cannot be decoded.", e, certPath, index);
+ }
+ }
+ }
+ return explicitPolicy;
+ }
+
+ internal static int PrepareNextCertI2(
+ PkixCertPath certPath,
+ int index,
+ int policyMapping)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (i)
+ //
+ Asn1Sequence pc = null;
+ try
+ {
+ pc = DerSequence.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.PolicyConstraints));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy constraints extension cannot be decoded.", e, certPath, index);
+ }
+
+ int tmpInt;
+
+ if (pc != null)
+ {
+ IEnumerator policyConstraints = pc.GetEnumerator();
+
+ while (policyConstraints.MoveNext())
+ {
+ try
+ {
+ Asn1TaggedObject constraint = Asn1TaggedObject.GetInstance(policyConstraints.Current);
+ if (constraint.TagNo == 1)
+ {
+ tmpInt = DerInteger.GetInstance(constraint, false).Value.IntValue;
+ if (tmpInt < policyMapping)
+ {
+ return tmpInt;
+ }
+ break;
+ }
+ }
+ catch (ArgumentException e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy constraints extension contents cannot be decoded.", e, certPath, index);
+ }
+ }
+ }
+ return policyMapping;
+ }
+
+ internal static void PrepareNextCertG(
+ PkixCertPath certPath,
+ int index,
+ PkixNameConstraintValidator nameConstraintValidator)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (g) handle the name constraints extension
+ //
+ NameConstraints nc = null;
+ try
+ {
+ Asn1Sequence ncSeq = DerSequence.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.NameConstraints));
+ if (ncSeq != null)
+ {
+ nc = new NameConstraints(ncSeq);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Name constraints extension could not be decoded.", e, certPath, index);
+ }
+ if (nc != null)
+ {
+ //
+ // (g) (1) permitted subtrees
+ //
+ Asn1Sequence permitted = nc.PermittedSubtrees;
+ if (permitted != null)
+ {
+ try
+ {
+ nameConstraintValidator.IntersectPermittedSubtree(permitted);
+ }
+ catch (Exception ex)
+ {
+ throw new PkixCertPathValidatorException(
+ "Permitted subtrees cannot be build from name constraints extension.", ex, certPath, index);
+ }
+ }
+
+ //
+ // (g) (2) excluded subtrees
+ //
+ Asn1Sequence excluded = nc.ExcludedSubtrees;
+ if (excluded != null)
+ {
+ IEnumerator e = excluded.GetEnumerator();
+ try
+ {
+ while (e.MoveNext())
+ {
+ GeneralSubtree subtree = GeneralSubtree.GetInstance(e.Current);
+ nameConstraintValidator.AddExcludedSubtree(subtree);
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new PkixCertPathValidatorException(
+ "Excluded subtrees cannot be build from name constraints extension.", ex, certPath, index);
+ }
+ }
+ }
+ }
+
+ internal static int PrepareNextCertJ(
+ PkixCertPath certPath,
+ int index,
+ int inhibitAnyPolicy)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (j)
+ //
+ DerInteger iap = null;
+ try
+ {
+ iap = DerInteger.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.InhibitAnyPolicy));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Inhibit any-policy extension cannot be decoded.", e, certPath, index);
+ }
+
+ if (iap != null)
+ {
+ int _inhibitAnyPolicy = iap.Value.IntValue;
+
+ if (_inhibitAnyPolicy < inhibitAnyPolicy)
+ return _inhibitAnyPolicy;
+ }
+ return inhibitAnyPolicy;
+ }
+
+ internal static void PrepareNextCertK(
+ PkixCertPath certPath,
+ int index)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+ //
+ // (k)
+ //
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.BasicConstraints));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+ if (bc != null)
+ {
+ if (!(bc.IsCA()))
+ throw new PkixCertPathValidatorException("Not a CA certificate");
+ }
+ else
+ {
+ throw new PkixCertPathValidatorException("Intermediate certificate lacks BasicConstraints");
+ }
+ }
+
+ internal static int PrepareNextCertL(
+ PkixCertPath certPath,
+ int index,
+ int maxPathLength)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+ //
+ // (l)
+ //
+ if (!PkixCertPathValidatorUtilities.IsSelfIssued(cert))
+ {
+ if (maxPathLength <= 0)
+ {
+ throw new PkixCertPathValidatorException("Max path length not greater than zero", null, certPath, index);
+ }
+
+ return maxPathLength - 1;
+ }
+ return maxPathLength;
+ }
+
+ internal static int PrepareNextCertM(
+ PkixCertPath certPath,
+ int index,
+ int maxPathLength)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (m)
+ //
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.BasicConstraints));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+ if (bc != null)
+ {
+ BigInteger _pathLengthConstraint = bc.PathLenConstraint;
+
+ if (_pathLengthConstraint != null)
+ {
+ int _plc = _pathLengthConstraint.IntValue;
+
+ if (_plc < maxPathLength)
+ {
+ return _plc;
+ }
+ }
+ }
+ return maxPathLength;
+ }
+
+ internal static void PrepareNextCertN(
+ PkixCertPath certPath,
+ int index)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (n)
+ //
+ bool[] _usage = cert.GetKeyUsage();
+
+ if ((_usage != null) && !_usage[Rfc3280CertPathUtilities.KEY_CERT_SIGN])
+ {
+ throw new PkixCertPathValidatorException(
+ "Issuer certificate keyusage extension is critical and does not permit key signing.", null,
+ certPath, index);
+ }
+ }
+
+ internal static void PrepareNextCertO(
+ PkixCertPath certPath,
+ int index,
+ ISet criticalExtensions,
+ IList pathCheckers)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (o)
+ //
+ IEnumerator tmpIter = pathCheckers.GetEnumerator();
+ while (tmpIter.MoveNext())
+ {
+ try
+ {
+ ((PkixCertPathChecker)tmpIter.Current).Check(cert, criticalExtensions);
+ }
+ catch (PkixCertPathValidatorException e)
+ {
+ throw new PkixCertPathValidatorException(e.Message, e.InnerException, certPath, index);
+ }
+ }
+ if (!criticalExtensions.IsEmpty)
+ {
+ throw new PkixCertPathValidatorException("Certificate has unsupported critical extension.", null, certPath,
+ index);
+ }
+ }
+
+ internal static int PrepareNextCertH1(
+ PkixCertPath certPath,
+ int index,
+ int explicitPolicy)
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (h)
+ //
+ if (!PkixCertPathValidatorUtilities.IsSelfIssued(cert))
+ {
+ //
+ // (1)
+ //
+ if (explicitPolicy != 0)
+ return explicitPolicy - 1;
+ }
+ return explicitPolicy;
+ }
+
+ internal static int PrepareNextCertH2(
+ PkixCertPath certPath,
+ int index,
+ int policyMapping)
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (h)
+ //
+ if (!PkixCertPathValidatorUtilities.IsSelfIssued(cert))
+ {
+ //
+ // (2)
+ //
+ if (policyMapping != 0)
+ return policyMapping - 1;
+ }
+ return policyMapping;
+ }
+
+
+ internal static int PrepareNextCertH3(
+ PkixCertPath certPath,
+ int index,
+ int inhibitAnyPolicy)
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (h)
+ //
+ if (!PkixCertPathValidatorUtilities.IsSelfIssued(cert))
+ {
+ //
+ // (3)
+ //
+ if (inhibitAnyPolicy != 0)
+ return inhibitAnyPolicy - 1;
+ }
+ return inhibitAnyPolicy;
+ }
+
+ internal static int WrapupCertA(
+ int explicitPolicy,
+ X509Certificate cert)
+ {
+ //
+ // (a)
+ //
+ if (!PkixCertPathValidatorUtilities.IsSelfIssued(cert) && (explicitPolicy != 0))
+ {
+ explicitPolicy--;
+ }
+ return explicitPolicy;
+ }
+
+ internal static int WrapupCertB(
+ PkixCertPath certPath,
+ int index,
+ int explicitPolicy)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (b)
+ //
+ int tmpInt;
+ Asn1Sequence pc = null;
+ try
+ {
+ pc = DerSequence.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.PolicyConstraints));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException("Policy constraints could not be decoded.", e, certPath, index);
+ }
+
+ if (pc != null)
+ {
+ IEnumerator policyConstraints = pc.GetEnumerator();
+
+ while (policyConstraints.MoveNext())
+ {
+ Asn1TaggedObject constraint = (Asn1TaggedObject)policyConstraints.Current;
+ switch (constraint.TagNo)
+ {
+ case 0:
+ try
+ {
+ tmpInt = DerInteger.GetInstance(constraint, false).Value.IntValue;
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Policy constraints requireExplicitPolicy field could not be decoded.", e, certPath,
+ index);
+ }
+ if (tmpInt == 0)
+ {
+ return 0;
+ }
+ break;
+ }
+ }
+ }
+ return explicitPolicy;
+ }
+
+ internal static void WrapupCertF(
+ PkixCertPath certPath,
+ int index,
+ IList pathCheckers,
+ ISet criticalExtensions)
+ //throws CertPathValidatorException
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+ IEnumerator tmpIter = pathCheckers.GetEnumerator();
+
+ while (tmpIter.MoveNext())
+ {
+ try
+ {
+ ((PkixCertPathChecker)tmpIter.Current).Check(cert, criticalExtensions);
+ }
+ catch (PkixCertPathValidatorException e)
+ {
+ throw new PkixCertPathValidatorException("Additional certificate path checker failed.", e, certPath,
+ index);
+ }
+ }
+
+ if (!criticalExtensions.IsEmpty)
+ {
+ throw new PkixCertPathValidatorException("Certificate has unsupported critical extension",
+ null, certPath, index);
+ }
+ }
+
+ internal static PkixPolicyNode WrapupCertG(
+ PkixCertPath certPath,
+ PkixParameters paramsPKIX,
+ ISet userInitialPolicySet,
+ int index,
+ IList[] policyNodes,
+ PkixPolicyNode validPolicyTree,
+ ISet acceptablePolicies)
+ {
+ int n = certPath.Certificates.Count;
+
+ //
+ // (g)
+ //
+ PkixPolicyNode intersection;
+
+ //
+ // (g) (i)
+ //
+ if (validPolicyTree == null)
+ {
+ if (paramsPKIX.IsExplicitPolicyRequired)
+ {
+ throw new PkixCertPathValidatorException(
+ "Explicit policy requested but none available.", null, certPath, index);
+ }
+ intersection = null;
+ }
+ else if (PkixCertPathValidatorUtilities.IsAnyPolicy(userInitialPolicySet)) // (g)
+ // (ii)
+ {
+ if (paramsPKIX.IsExplicitPolicyRequired)
+ {
+ if (acceptablePolicies.IsEmpty)
+ {
+ throw new PkixCertPathValidatorException(
+ "Explicit policy requested but none available.", null, certPath, index);
+ }
+ else
+ {
+ ISet _validPolicyNodeSet = new HashSet();
+
+ for (int j = 0; j < policyNodes.Length; j++)
+ {
+ IList _nodeDepth = policyNodes[j];
+
+ for (int k = 0; k < _nodeDepth.Count; k++)
+ {
+ PkixPolicyNode _node = (PkixPolicyNode)_nodeDepth[k];
+
+ if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(_node.ValidPolicy))
+ {
+ foreach (object o in _node.Children)
+ {
+ _validPolicyNodeSet.Add(o);
+ }
+ }
+ }
+ }
+
+ foreach (PkixPolicyNode _node in _validPolicyNodeSet)
+ {
+ string _validPolicy = _node.ValidPolicy;
+
+ if (!acceptablePolicies.Contains(_validPolicy))
+ {
+ // TODO?
+ // validPolicyTree =
+ // removePolicyNode(validPolicyTree, policyNodes,
+ // _node);
+ }
+ }
+ if (validPolicyTree != null)
+ {
+ for (int j = (n - 1); j >= 0; j--)
+ {
+ IList nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.Count; k++)
+ {
+ PkixPolicyNode node = (PkixPolicyNode)nodes[k];
+ if (!node.HasChildren)
+ {
+ validPolicyTree = PkixCertPathValidatorUtilities.RemovePolicyNode(validPolicyTree,
+ policyNodes, node);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ intersection = validPolicyTree;
+ }
+ else
+ {
+ //
+ // (g) (iii)
+ //
+ // This implementation is not exactly same as the one described in
+ // RFC3280.
+ // However, as far as the validation result is concerned, both
+ // produce
+ // adequate result. The only difference is whether AnyPolicy is
+ // remain
+ // in the policy tree or not.
+ //
+ // (g) (iii) 1
+ //
+ ISet _validPolicyNodeSet = new HashSet();
+
+ for (int j = 0; j < policyNodes.Length; j++)
+ {
+ IList _nodeDepth = policyNodes[j];
+
+ for (int k = 0; k < _nodeDepth.Count; k++)
+ {
+ PkixPolicyNode _node = (PkixPolicyNode)_nodeDepth[k];
+
+ if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(_node.ValidPolicy))
+ {
+ foreach (PkixPolicyNode _c_node in _node.Children)
+ {
+ if (!Rfc3280CertPathUtilities.ANY_POLICY.Equals(_c_node.ValidPolicy))
+ {
+ _validPolicyNodeSet.Add(_c_node);
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // (g) (iii) 2
+ //
+ IEnumerator _vpnsIter = _validPolicyNodeSet.GetEnumerator();
+ while (_vpnsIter.MoveNext())
+ {
+ PkixPolicyNode _node = (PkixPolicyNode)_vpnsIter.Current;
+ string _validPolicy = _node.ValidPolicy;
+
+ if (!userInitialPolicySet.Contains(_validPolicy))
+ {
+ validPolicyTree = PkixCertPathValidatorUtilities.RemovePolicyNode(validPolicyTree, policyNodes, _node);
+ }
+ }
+
+ //
+ // (g) (iii) 4
+ //
+ if (validPolicyTree != null)
+ {
+ for (int j = (n - 1); j >= 0; j--)
+ {
+ IList nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.Count; k++)
+ {
+ PkixPolicyNode node = (PkixPolicyNode)nodes[k];
+ if (!node.HasChildren)
+ {
+ validPolicyTree = PkixCertPathValidatorUtilities.RemovePolicyNode(validPolicyTree, policyNodes,
+ node);
+ }
+ }
+ }
+ }
+
+ intersection = validPolicyTree;
+ }
+ return intersection;
+ }
+
+ /**
+ * If use-deltas is set, verify the issuer and scope of the delta CRL.
+ *
+ * @param deltaCRL The delta CRL.
+ * @param completeCRL The complete CRL.
+ * @param pkixParams The PKIX paramaters.
+ * @throws AnnotatedException if an exception occurs.
+ */
+ internal static void ProcessCrlC(
+ X509Crl deltaCRL,
+ X509Crl completeCRL,
+ PkixParameters pkixParams)
+ {
+ if (deltaCRL == null)
+ return;
+
+ IssuingDistributionPoint completeidp = null;
+ try
+ {
+ completeidp = IssuingDistributionPoint.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(completeCRL, X509Extensions.IssuingDistributionPoint));
+ }
+ catch (Exception e)
+ {
+ throw new Exception("000 Issuing distribution point extension could not be decoded.", e);
+ }
+
+ if (pkixParams.IsUseDeltasEnabled)
+ {
+ // (c) (1)
+ if (!deltaCRL.IssuerDN.Equivalent(completeCRL.IssuerDN, true))
+ throw new Exception("Complete CRL issuer does not match delta CRL issuer.");
+
+ // (c) (2)
+ IssuingDistributionPoint deltaidp = null;
+ try
+ {
+ deltaidp = IssuingDistributionPoint.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(deltaCRL, X509Extensions.IssuingDistributionPoint));
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Issuing distribution point extension from delta CRL could not be decoded.", e);
+ }
+
+ if (!Platform.Equals(completeidp, deltaidp))
+ {
+ throw new Exception(
+ "Issuing distribution point extension from delta CRL and complete CRL does not match.");
+ }
+
+ // (c) (3)
+ Asn1Object completeKeyIdentifier = null;
+ try
+ {
+ completeKeyIdentifier = PkixCertPathValidatorUtilities.GetExtensionValue(
+ completeCRL, X509Extensions.AuthorityKeyIdentifier);
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Authority key identifier extension could not be extracted from complete CRL.", e);
+ }
+
+ Asn1Object deltaKeyIdentifier = null;
+ try
+ {
+ deltaKeyIdentifier = PkixCertPathValidatorUtilities.GetExtensionValue(
+ deltaCRL, X509Extensions.AuthorityKeyIdentifier);
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Authority key identifier extension could not be extracted from delta CRL.", e);
+ }
+
+ if (completeKeyIdentifier == null)
+ throw new Exception("CRL authority key identifier is null.");
+
+ if (deltaKeyIdentifier == null)
+ throw new Exception("Delta CRL authority key identifier is null.");
+
+ if (!completeKeyIdentifier.Equals(deltaKeyIdentifier))
+ {
+ throw new Exception(
+ "Delta CRL authority key identifier does not match complete CRL authority key identifier.");
+ }
+ }
+ }
+
+ internal static void ProcessCrlI(
+ DateTime validDate,
+ X509Crl deltacrl,
+ object cert,
+ CertStatus certStatus,
+ PkixParameters pkixParams)
+ {
+ if (pkixParams.IsUseDeltasEnabled && deltacrl != null)
+ {
+ PkixCertPathValidatorUtilities.GetCertStatus(validDate, deltacrl, cert, certStatus);
+ }
+ }
+
+ internal static void ProcessCrlJ(
+ DateTime validDate,
+ X509Crl completecrl,
+ object cert,
+ CertStatus certStatus)
+ {
+ if (certStatus.Status == CertStatus.Unrevoked)
+ {
+ PkixCertPathValidatorUtilities.GetCertStatus(validDate, completecrl, cert, certStatus);
+ }
+ }
+
+ internal static PkixPolicyNode ProcessCertE(
+ PkixCertPath certPath,
+ int index,
+ PkixPolicyNode validPolicyTree)
+ {
+ IList certs = certPath.Certificates;
+ X509Certificate cert = (X509Certificate)certs[index];
+
+ //
+ // (e)
+ //
+ Asn1Sequence certPolicies = null;
+ try
+ {
+ certPolicies = DerSequence.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.CertificatePolicies));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException("Could not read certificate policies extension from certificate.",
+ e, certPath, index);
+ }
+ if (certPolicies == null)
+ {
+ validPolicyTree = null;
+ }
+ return validPolicyTree;
+ }
+
+ internal static readonly string[] CrlReasons = new string[]
+ {
+ "unspecified",
+ "keyCompromise",
+ "cACompromise",
+ "affiliationChanged",
+ "superseded",
+ "cessationOfOperation",
+ "certificateHold",
+ "unknown",
+ "removeFromCRL",
+ "privilegeWithdrawn",
+ "aACompromise"
+ };
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/Rfc3281CertPathUtilities.cs b/bc-sharp-crypto/src/pkix/Rfc3281CertPathUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..101ef5e11807feafe408a3cdc13c1c1f35a0a51c
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/Rfc3281CertPathUtilities.cs
@@ -0,0 +1,608 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+ internal class Rfc3281CertPathUtilities
+ {
+ internal static void ProcessAttrCert7(
+ IX509AttributeCertificate attrCert,
+ PkixCertPath certPath,
+ PkixCertPath holderCertPath,
+ PkixParameters pkixParams)
+ {
+ // TODO:
+ // AA Controls
+ // Attribute encryption
+ // Proxy
+ ISet critExtOids = attrCert.GetCriticalExtensionOids();
+
+ // 7.1
+ // process extensions
+
+ // target information checked in step 6 / X509AttributeCertStoreSelector
+ if (critExtOids.Contains(X509Extensions.TargetInformation.Id))
+ {
+ try
+ {
+ TargetInformation.GetInstance(PkixCertPathValidatorUtilities
+ .GetExtensionValue(attrCert, X509Extensions.TargetInformation));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Target information extension could not be read.", e);
+ }
+ }
+ critExtOids.Remove(X509Extensions.TargetInformation.Id);
+ foreach (PkixAttrCertChecker checker in pkixParams.GetAttrCertCheckers())
+ {
+ checker.Check(attrCert, certPath, holderCertPath, critExtOids);
+ }
+ if (!critExtOids.IsEmpty)
+ {
+ throw new PkixCertPathValidatorException(
+ "Attribute certificate contains unsupported critical extensions: "
+ + critExtOids);
+ }
+ }
+
+ /**
+ * Checks if an attribute certificate is revoked.
+ *
+ * @param attrCert Attribute certificate to check if it is revoked.
+ * @param paramsPKIX PKIX parameters.
+ * @param issuerCert The issuer certificate of the attribute certificate
+ * attrCert
.
+ * @param validDate The date when the certificate revocation status should
+ * be checked.
+ * @param certPathCerts The certificates of the certification path to be
+ * checked.
+ *
+ * @throws CertPathValidatorException if the certificate is revoked or the
+ * status cannot be checked or some error occurs.
+ */
+ internal static void CheckCrls(
+ IX509AttributeCertificate attrCert,
+ PkixParameters paramsPKIX,
+ X509Certificate issuerCert,
+ DateTime validDate,
+ IList certPathCerts)
+ {
+ if (paramsPKIX.IsRevocationEnabled)
+ {
+ // check if revocation is available
+ if (attrCert.GetExtensionValue(X509Extensions.NoRevAvail) == null)
+ {
+ CrlDistPoint crldp = null;
+ try
+ {
+ crldp = CrlDistPoint.GetInstance(
+ PkixCertPathValidatorUtilities.GetExtensionValue(
+ attrCert, X509Extensions.CrlDistributionPoints));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "CRL distribution point extension could not be read.", e);
+ }
+ try
+ {
+ PkixCertPathValidatorUtilities
+ .AddAdditionalStoresFromCrlDistributionPoint(crldp, paramsPKIX);
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "No additional CRL locations could be decoded from CRL distribution point extension.", e);
+ }
+ CertStatus certStatus = new CertStatus();
+ ReasonsMask reasonsMask = new ReasonsMask();
+
+ Exception lastException = null;
+ bool validCrlFound = false;
+ // for each distribution point
+ if (crldp != null)
+ {
+ DistributionPoint[] dps = null;
+ try
+ {
+ dps = crldp.GetDistributionPoints();
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Distribution points could not be read.", e);
+ }
+ try
+ {
+ for (int i = 0; i < dps.Length
+ && certStatus.Status == CertStatus.Unrevoked
+ && !reasonsMask.IsAllReasons; i++)
+ {
+ PkixParameters paramsPKIXClone = (PkixParameters) paramsPKIX
+ .Clone();
+ CheckCrl(dps[i], attrCert, paramsPKIXClone,
+ validDate, issuerCert, certStatus, reasonsMask,
+ certPathCerts);
+ validCrlFound = true;
+ }
+ }
+ catch (Exception e)
+ {
+ lastException = new Exception(
+ "No valid CRL for distribution point found.", e);
+ }
+ }
+
+ /*
+ * If the revocation status has not been determined, repeat the
+ * process above with any available CRLs not specified in a
+ * distribution point but issued by the certificate issuer.
+ */
+
+ if (certStatus.Status == CertStatus.Unrevoked
+ && !reasonsMask.IsAllReasons)
+ {
+ try
+ {
+ /*
+ * assume a DP with both the reasons and the cRLIssuer
+ * fields omitted and a distribution point name of the
+ * certificate issuer.
+ */
+ Asn1Object issuer = null;
+ try
+ {
+ issuer = new Asn1InputStream(
+ attrCert.Issuer.GetPrincipals()[0].GetEncoded()).ReadObject();
+ }
+ catch (Exception e)
+ {
+ throw new Exception(
+ "Issuer from certificate for CRL could not be reencoded.",
+ e);
+ }
+ DistributionPoint dp = new DistributionPoint(
+ new DistributionPointName(0, new GeneralNames(
+ new GeneralName(GeneralName.DirectoryName, issuer))), null, null);
+ PkixParameters paramsPKIXClone = (PkixParameters) paramsPKIX.Clone();
+ CheckCrl(dp, attrCert, paramsPKIXClone, validDate,
+ issuerCert, certStatus, reasonsMask, certPathCerts);
+ validCrlFound = true;
+ }
+ catch (Exception e)
+ {
+ lastException = new Exception(
+ "No valid CRL for distribution point found.", e);
+ }
+ }
+
+ if (!validCrlFound)
+ {
+ throw new PkixCertPathValidatorException(
+ "No valid CRL found.", lastException);
+ }
+ if (certStatus.Status != CertStatus.Unrevoked)
+ {
+ // This format is enforced by the NistCertPath tests
+ string formattedDate = certStatus.RevocationDate.Value.ToString(
+ "ddd MMM dd HH:mm:ss K yyyy");
+ string message = "Attribute certificate revocation after "
+ + formattedDate;
+ message += ", reason: "
+ + Rfc3280CertPathUtilities.CrlReasons[certStatus.Status];
+ throw new PkixCertPathValidatorException(message);
+ }
+ if (!reasonsMask.IsAllReasons
+ && certStatus.Status == CertStatus.Unrevoked)
+ {
+ certStatus.Status = CertStatus.Undetermined;
+ }
+ if (certStatus.Status == CertStatus.Undetermined)
+ {
+ throw new PkixCertPathValidatorException(
+ "Attribute certificate status could not be determined.");
+ }
+
+ }
+ else
+ {
+ if (attrCert.GetExtensionValue(X509Extensions.CrlDistributionPoints) != null
+ || attrCert.GetExtensionValue(X509Extensions.AuthorityInfoAccess) != null)
+ {
+ throw new PkixCertPathValidatorException(
+ "No rev avail extension is set, but also an AC revocation pointer.");
+ }
+ }
+ }
+ }
+
+ internal static void AdditionalChecks(
+ IX509AttributeCertificate attrCert,
+ PkixParameters pkixParams)
+ {
+ // 1
+ foreach (string oid in pkixParams.GetProhibitedACAttributes())
+ {
+ if (attrCert.GetAttributes(oid) != null)
+ {
+ throw new PkixCertPathValidatorException(
+ "Attribute certificate contains prohibited attribute: "
+ + oid + ".");
+ }
+ }
+ foreach (string oid in pkixParams.GetNecessaryACAttributes())
+ {
+ if (attrCert.GetAttributes(oid) == null)
+ {
+ throw new PkixCertPathValidatorException(
+ "Attribute certificate does not contain necessary attribute: "
+ + oid + ".");
+ }
+ }
+ }
+
+ internal static void ProcessAttrCert5(
+ IX509AttributeCertificate attrCert,
+ PkixParameters pkixParams)
+ {
+ try
+ {
+ attrCert.CheckValidity(PkixCertPathValidatorUtilities.GetValidDate(pkixParams));
+ }
+ catch (CertificateExpiredException e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Attribute certificate is not valid.", e);
+ }
+ catch (CertificateNotYetValidException e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Attribute certificate is not valid.", e);
+ }
+ }
+
+ internal static void ProcessAttrCert4(
+ X509Certificate acIssuerCert,
+ PkixParameters pkixParams)
+ {
+ ISet set = pkixParams.GetTrustedACIssuers();
+ bool trusted = false;
+ foreach (TrustAnchor anchor in set)
+ {
+ IDictionary symbols = X509Name.RFC2253Symbols;
+ if (acIssuerCert.SubjectDN.ToString(false, symbols).Equals(anchor.CAName)
+ || acIssuerCert.Equals(anchor.TrustedCert))
+ {
+ trusted = true;
+ }
+ }
+ if (!trusted)
+ {
+ throw new PkixCertPathValidatorException(
+ "Attribute certificate issuer is not directly trusted.");
+ }
+ }
+
+ internal static void ProcessAttrCert3(
+ X509Certificate acIssuerCert,
+ PkixParameters pkixParams)
+ {
+ if (acIssuerCert.GetKeyUsage() != null
+ && (!acIssuerCert.GetKeyUsage()[0] && !acIssuerCert.GetKeyUsage()[1]))
+ {
+ throw new PkixCertPathValidatorException(
+ "Attribute certificate issuer public key cannot be used to validate digital signatures.");
+ }
+ if (acIssuerCert.GetBasicConstraints() != -1)
+ {
+ throw new PkixCertPathValidatorException(
+ "Attribute certificate issuer is also a public key certificate issuer.");
+ }
+ }
+
+ internal static PkixCertPathValidatorResult ProcessAttrCert2(
+ PkixCertPath certPath,
+ PkixParameters pkixParams)
+ {
+ PkixCertPathValidator validator = new PkixCertPathValidator();
+
+ try
+ {
+ return validator.Validate(certPath, pkixParams);
+ }
+ catch (PkixCertPathValidatorException e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Certification path for issuer certificate of attribute certificate could not be validated.",
+ e);
+ }
+ }
+
+ /**
+ * Searches for a holder public key certificate and verifies its
+ * certification path.
+ *
+ * @param attrCert the attribute certificate.
+ * @param pkixParams The PKIX parameters.
+ * @return The certificate path of the holder certificate.
+ * @throws Exception if
+ *
+ * no public key certificate can be found although holder
+ * information is given by an entity name or a base certificate
+ * ID
+ * support classes cannot be created
+ * no certification path for the public key certificate can
+ * be built
+ *
+ */
+ internal static PkixCertPath ProcessAttrCert1(
+ IX509AttributeCertificate attrCert,
+ PkixParameters pkixParams)
+ {
+ PkixCertPathBuilderResult result = null;
+ // find holder PKCs
+ ISet holderPKCs = new HashSet();
+ if (attrCert.Holder.GetIssuer() != null)
+ {
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ selector.SerialNumber = attrCert.Holder.SerialNumber;
+ X509Name[] principals = attrCert.Holder.GetIssuer();
+ for (int i = 0; i < principals.Length; i++)
+ {
+ try
+ {
+// if (principals[i] is X500Principal)
+ {
+ selector.Issuer = principals[i];
+ }
+ holderPKCs.AddAll(PkixCertPathValidatorUtilities
+ .FindCertificates(selector, pkixParams.GetStores()));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Public key certificate for attribute certificate cannot be searched.",
+ e);
+ }
+ }
+ if (holderPKCs.IsEmpty)
+ {
+ throw new PkixCertPathValidatorException(
+ "Public key certificate specified in base certificate ID for attribute certificate cannot be found.");
+ }
+ }
+ if (attrCert.Holder.GetEntityNames() != null)
+ {
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ X509Name[] principals = attrCert.Holder.GetEntityNames();
+ for (int i = 0; i < principals.Length; i++)
+ {
+ try
+ {
+// if (principals[i] is X500Principal)
+ {
+ selector.Issuer = principals[i];
+ }
+ holderPKCs.AddAll(PkixCertPathValidatorUtilities
+ .FindCertificates(selector, pkixParams.GetStores()));
+ }
+ catch (Exception e)
+ {
+ throw new PkixCertPathValidatorException(
+ "Public key certificate for attribute certificate cannot be searched.",
+ e);
+ }
+ }
+ if (holderPKCs.IsEmpty)
+ {
+ throw new PkixCertPathValidatorException(
+ "Public key certificate specified in entity name for attribute certificate cannot be found.");
+ }
+ }
+
+ // verify cert paths for PKCs
+ PkixBuilderParameters parameters = (PkixBuilderParameters)
+ PkixBuilderParameters.GetInstance(pkixParams);
+
+ PkixCertPathValidatorException lastException = null;
+ foreach (X509Certificate cert in holderPKCs)
+ {
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ selector.Certificate = cert;
+ parameters.SetTargetConstraints(selector);
+
+ PkixCertPathBuilder builder = new PkixCertPathBuilder();
+
+ try
+ {
+ result = builder.Build(PkixBuilderParameters.GetInstance(parameters));
+ }
+ catch (PkixCertPathBuilderException e)
+ {
+ lastException = new PkixCertPathValidatorException(
+ "Certification path for public key certificate of attribute certificate could not be build.",
+ e);
+ }
+ }
+ if (lastException != null)
+ {
+ throw lastException;
+ }
+ return result.CertPath;
+ }
+
+ /**
+ *
+ * Checks a distribution point for revocation information for the
+ * certificate attrCert
.
+ *
+ * @param dp The distribution point to consider.
+ * @param attrCert The attribute certificate which should be checked.
+ * @param paramsPKIX PKIX parameters.
+ * @param validDate The date when the certificate revocation status should
+ * be checked.
+ * @param issuerCert Certificate to check if it is revoked.
+ * @param reasonMask The reasons mask which is already checked.
+ * @param certPathCerts The certificates of the certification path to be
+ * checked.
+ * @throws Exception if the certificate is revoked or the status
+ * cannot be checked or some error occurs.
+ */
+ private static void CheckCrl(
+ DistributionPoint dp,
+ IX509AttributeCertificate attrCert,
+ PkixParameters paramsPKIX,
+ DateTime validDate,
+ X509Certificate issuerCert,
+ CertStatus certStatus,
+ ReasonsMask reasonMask,
+ IList certPathCerts)
+ {
+ /*
+ * 4.3.6 No Revocation Available
+ *
+ * The noRevAvail extension, defined in [X.509-2000], allows an AC
+ * issuer to indicate that no revocation information will be made
+ * available for this AC.
+ */
+ if (attrCert.GetExtensionValue(X509Extensions.NoRevAvail) != null)
+ {
+ return;
+ }
+
+ DateTime currentDate = DateTime.UtcNow;
+ if (validDate.CompareTo(currentDate) > 0)
+ {
+ throw new Exception("Validation time is in future.");
+ }
+
+ // (a)
+ /*
+ * We always get timely valid CRLs, so there is no step (a) (1).
+ * "locally cached" CRLs are assumed to be in getStore(), additional
+ * CRLs must be enabled in the ExtendedPkixParameters and are in
+ * getAdditionalStore()
+ */
+ ISet crls = PkixCertPathValidatorUtilities.GetCompleteCrls(dp, attrCert,
+ currentDate, paramsPKIX);
+ bool validCrlFound = false;
+ Exception lastException = null;
+
+ IEnumerator crl_iter = crls.GetEnumerator();
+
+ while (crl_iter.MoveNext()
+ && certStatus.Status == CertStatus.Unrevoked
+ && !reasonMask.IsAllReasons)
+ {
+ try
+ {
+ X509Crl crl = (X509Crl) crl_iter.Current;
+
+ // (d)
+ ReasonsMask interimReasonsMask = Rfc3280CertPathUtilities.ProcessCrlD(crl, dp);
+
+ // (e)
+ /*
+ * The reasons mask is updated at the end, so only valid CRLs
+ * can update it. If this CRL does not contain new reasons it
+ * must be ignored.
+ */
+ if (!interimReasonsMask.HasNewReasons(reasonMask))
+ {
+ continue;
+ }
+
+ // (f)
+ ISet keys = Rfc3280CertPathUtilities.ProcessCrlF(crl, attrCert,
+ null, null, paramsPKIX, certPathCerts);
+ // (g)
+ AsymmetricKeyParameter pubKey = Rfc3280CertPathUtilities.ProcessCrlG(crl, keys);
+
+ X509Crl deltaCRL = null;
+
+ if (paramsPKIX.IsUseDeltasEnabled)
+ {
+ // get delta CRLs
+ ISet deltaCRLs = PkixCertPathValidatorUtilities.GetDeltaCrls(
+ currentDate, paramsPKIX, crl);
+ // we only want one valid delta CRL
+ // (h)
+ deltaCRL = Rfc3280CertPathUtilities.ProcessCrlH(deltaCRLs, pubKey);
+ }
+
+ /*
+ * CRL must be be valid at the current time, not the validation
+ * time. If a certificate is revoked with reason keyCompromise,
+ * cACompromise, it can be used for forgery, also for the past.
+ * This reason may not be contained in older CRLs.
+ */
+
+ /*
+ * in the chain model signatures stay valid also after the
+ * certificate has been expired, so they do not have to be in
+ * the CRL vality time
+ */
+ if (paramsPKIX.ValidityModel != PkixParameters.ChainValidityModel)
+ {
+ /*
+ * if a certificate has expired, but was revoked, it is not
+ * more in the CRL, so it would be regarded as valid if the
+ * first check is not done
+ */
+ if (attrCert.NotAfter.CompareTo(crl.ThisUpdate) < 0)
+ {
+ throw new Exception(
+ "No valid CRL for current time found.");
+ }
+ }
+
+ Rfc3280CertPathUtilities.ProcessCrlB1(dp, attrCert, crl);
+
+ // (b) (2)
+ Rfc3280CertPathUtilities.ProcessCrlB2(dp, attrCert, crl);
+
+ // (c)
+ Rfc3280CertPathUtilities.ProcessCrlC(deltaCRL, crl, paramsPKIX);
+
+ // (i)
+ Rfc3280CertPathUtilities.ProcessCrlI(validDate, deltaCRL,
+ attrCert, certStatus, paramsPKIX);
+
+ // (j)
+ Rfc3280CertPathUtilities.ProcessCrlJ(validDate, crl, attrCert,
+ certStatus);
+
+ // (k)
+ if (certStatus.Status == CrlReason.RemoveFromCrl)
+ {
+ certStatus.Status = CertStatus.Unrevoked;
+ }
+
+ // update reasons mask
+ reasonMask.AddReasons(interimReasonsMask);
+ validCrlFound = true;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+ if (!validCrlFound)
+ {
+ throw lastException;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/pkix/TrustAnchor.cs b/bc-sharp-crypto/src/pkix/TrustAnchor.cs
new file mode 100644
index 0000000000000000000000000000000000000000..22078baf20330b988025729132c534db0c24aa66
--- /dev/null
+++ b/bc-sharp-crypto/src/pkix/TrustAnchor.cs
@@ -0,0 +1,259 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Pkix
+{
+ ///
+ /// A trust anchor or most-trusted Certification Authority (CA).
+ ///
+ /// This class represents a "most-trusted CA", which is used as a trust anchor
+ /// for validating X.509 certification paths. A most-trusted CA includes the
+ /// public key of the CA, the CA's name, and any constraints upon the set of
+ /// paths which may be validated using this key. These parameters can be
+ /// specified in the form of a trusted X509Certificate or as individual
+ /// parameters.
+ ///
+ public class TrustAnchor
+ {
+ private readonly AsymmetricKeyParameter pubKey;
+ private readonly string caName;
+ private readonly X509Name caPrincipal;
+ private readonly X509Certificate trustedCert;
+ private byte[] ncBytes;
+ private NameConstraints nc;
+
+ ///
+ /// Creates an instance of TrustAnchor with the specified X509Certificate and
+ /// optional name constraints, which are intended to be used as additional
+ /// constraints when validating an X.509 certification path.
+ /// The name constraints are specified as a byte array. This byte array
+ /// should contain the DER encoded form of the name constraints, as they
+ /// would appear in the NameConstraints structure defined in RFC 2459 and
+ /// X.509. The ASN.1 definition of this structure appears below.
+ ///
+ ///
+ /// NameConstraints ::= SEQUENCE {
+ /// permittedSubtrees [0] GeneralSubtrees OPTIONAL,
+ /// excludedSubtrees [1] GeneralSubtrees OPTIONAL }
+ ///
+ /// GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+ ///
+ /// GeneralSubtree ::= SEQUENCE {
+ /// base GeneralName,
+ /// minimum [0] BaseDistance DEFAULT 0,
+ /// maximum [1] BaseDistance OPTIONAL }
+ ///
+ /// BaseDistance ::= INTEGER (0..MAX)
+ ///
+ /// GeneralName ::= CHOICE {
+ /// otherName [0] OtherName,
+ /// rfc822Name [1] IA5String,
+ /// dNSName [2] IA5String,
+ /// x400Address [3] ORAddress,
+ /// directoryName [4] Name,
+ /// ediPartyName [5] EDIPartyName,
+ /// uniformResourceIdentifier [6] IA5String,
+ /// iPAddress [7] OCTET STRING,
+ /// registeredID [8] OBJECT IDENTIFIER}
+ ///
+ ///
+ /// Note that the name constraints byte array supplied is cloned to protect
+ /// against subsequent modifications.
+ ///
+ /// a trusted X509Certificate
+ /// a byte array containing the ASN.1 DER encoding of a
+ /// NameConstraints extension to be used for checking name
+ /// constraints. Only the value of the extension is included, not
+ /// the OID or criticality flag. Specify null to omit the
+ /// parameter.
+ /// if the specified X509Certificate is null
+ public TrustAnchor(
+ X509Certificate trustedCert,
+ byte[] nameConstraints)
+ {
+ if (trustedCert == null)
+ throw new ArgumentNullException("trustedCert");
+
+ this.trustedCert = trustedCert;
+ this.pubKey = null;
+ this.caName = null;
+ this.caPrincipal = null;
+ setNameConstraints(nameConstraints);
+ }
+
+ ///
+ /// Creates an instance of TrustAnchor where the
+ /// most-trusted CA is specified as an X500Principal and public key.
+ ///
+ ///
+ ///
+ /// Name constraints are an optional parameter, and are intended to be used
+ /// as additional constraints when validating an X.509 certification path.
+ ///
+ /// The name constraints are specified as a byte array. This byte array
+ /// contains the DER encoded form of the name constraints, as they
+ /// would appear in the NameConstraints structure defined in RFC 2459
+ /// and X.509. The ASN.1 notation for this structure is supplied in the
+ /// documentation for the other constructors.
+ ///
+ /// Note that the name constraints byte array supplied here is cloned to
+ /// protect against subsequent modifications.
+ ///
+ ///
+ /// the name of the most-trusted CA as X509Name
+ /// the public key of the most-trusted CA
+ ///
+ /// a byte array containing the ASN.1 DER encoding of a NameConstraints extension to
+ /// be used for checking name constraints. Only the value of the extension is included,
+ /// not the OID or criticality flag. Specify null to omit the parameter.
+ ///
+ ///
+ /// if caPrincipal or pubKey is null
+ ///
+ public TrustAnchor(
+ X509Name caPrincipal,
+ AsymmetricKeyParameter pubKey,
+ byte[] nameConstraints)
+ {
+ if (caPrincipal == null)
+ throw new ArgumentNullException("caPrincipal");
+ if (pubKey == null)
+ throw new ArgumentNullException("pubKey");
+
+ this.trustedCert = null;
+ this.caPrincipal = caPrincipal;
+ this.caName = caPrincipal.ToString();
+ this.pubKey = pubKey;
+ setNameConstraints(nameConstraints);
+ }
+
+ ///
+ /// Creates an instance of TrustAnchor
where the most-trusted
+ /// CA is specified as a distinguished name and public key. Name constraints
+ /// are an optional parameter, and are intended to be used as additional
+ /// constraints when validating an X.509 certification path.
+ ///
+ /// The name constraints are specified as a byte array. This byte array
+ /// contains the DER encoded form of the name constraints, as they would
+ /// appear in the NameConstraints structure defined in RFC 2459 and X.509.
+ ///
+ /// the X.500 distinguished name of the most-trusted CA in RFC
+ /// 2253 string format
+ /// the public key of the most-trusted CA
+ /// a byte array containing the ASN.1 DER encoding of a
+ /// NameConstraints extension to be used for checking name
+ /// constraints. Only the value of the extension is included, not
+ /// the OID or criticality flag. Specify null to omit the
+ /// parameter.
+ /// throws NullPointerException, IllegalArgumentException
+ public TrustAnchor(
+ string caName,
+ AsymmetricKeyParameter pubKey,
+ byte[] nameConstraints)
+ {
+ if (caName == null)
+ throw new ArgumentNullException("caName");
+ if (pubKey == null)
+ throw new ArgumentNullException("pubKey");
+ if (caName.Length == 0)
+ throw new ArgumentException("caName can not be an empty string");
+
+ this.caPrincipal = new X509Name(caName);
+ this.pubKey = pubKey;
+ this.caName = caName;
+ this.trustedCert = null;
+ setNameConstraints(nameConstraints);
+ }
+
+ ///
+ /// Returns the most-trusted CA certificate.
+ ///
+ public X509Certificate TrustedCert
+ {
+ get { return this.trustedCert; }
+ }
+
+ ///
+ /// Returns the name of the most-trusted CA as an X509Name.
+ ///
+ public X509Name CA
+ {
+ get { return this.caPrincipal; }
+ }
+
+ ///
+ /// Returns the name of the most-trusted CA in RFC 2253 string format.
+ ///
+ public string CAName
+ {
+ get { return this.caName; }
+ }
+
+ ///
+ /// Returns the public key of the most-trusted CA.
+ ///
+ public AsymmetricKeyParameter CAPublicKey
+ {
+ get { return this.pubKey; }
+ }
+
+ ///
+ /// Decode the name constraints and clone them if not null.
+ ///
+ private void setNameConstraints(
+ byte[] bytes)
+ {
+ if (bytes == null)
+ {
+ ncBytes = null;
+ nc = null;
+ }
+ else
+ {
+ ncBytes = (byte[]) bytes.Clone();
+ // validate DER encoding
+ //nc = new NameConstraintsExtension(Boolean.FALSE, bytes);
+ nc = NameConstraints.GetInstance(Asn1Object.FromByteArray(bytes));
+ }
+ }
+
+ public byte[] GetNameConstraints
+ {
+ get { return Arrays.Clone(ncBytes); }
+ }
+
+ ///
+ /// Returns a formatted string describing the TrustAnchor
.
+ ///
+ /// a formatted string describing the TrustAnchor
+ public override string ToString()
+ {
+ // TODO Some of the sub-objects might not implement ToString() properly
+ string nl = Platform.NewLine;
+ StringBuilder sb = new StringBuilder();
+ sb.Append("[");
+ sb.Append(nl);
+ if (this.pubKey != null)
+ {
+ sb.Append(" Trusted CA Public Key: ").Append(this.pubKey).Append(nl);
+ sb.Append(" Trusted CA Issuer Name: ").Append(this.caName).Append(nl);
+ }
+ else
+ {
+ sb.Append(" Trusted CA cert: ").Append(this.TrustedCert).Append(nl);
+ }
+ if (nc != null)
+ {
+ sb.Append(" Name Constraints: ").Append(nc).Append(nl);
+ }
+ return sb.ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/security/AgreementUtilities.cs b/bc-sharp-crypto/src/security/AgreementUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..12d427c8ce6cf0c632c523afd1db9ca0877007fe
--- /dev/null
+++ b/bc-sharp-crypto/src/security/AgreementUtilities.cs
@@ -0,0 +1,105 @@
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Agreement.Kdf;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Security
+{
+ ///
+ /// Utility class for creating IBasicAgreement objects from their names/Oids
+ ///
+ public sealed class AgreementUtilities
+ {
+ private AgreementUtilities()
+ {
+ }
+
+ private static readonly IDictionary algorithms = Platform.CreateHashtable();
+ //private static readonly IDictionary oids = Platform.CreateHashtable();
+
+ static AgreementUtilities()
+ {
+ algorithms[X9ObjectIdentifiers.DHSinglePassCofactorDHSha1KdfScheme.Id] = "ECCDHWITHSHA1KDF";
+ algorithms[X9ObjectIdentifiers.DHSinglePassStdDHSha1KdfScheme.Id] = "ECDHWITHSHA1KDF";
+ algorithms[X9ObjectIdentifiers.MqvSinglePassSha1KdfScheme.Id] = "ECMQVWITHSHA1KDF";
+ }
+
+ public static IBasicAgreement GetBasicAgreement(
+ DerObjectIdentifier oid)
+ {
+ return GetBasicAgreement(oid.Id);
+ }
+
+ public static IBasicAgreement GetBasicAgreement(
+ string algorithm)
+ {
+ string upper = Platform.ToUpperInvariant(algorithm);
+ string mechanism = (string) algorithms[upper];
+
+ if (mechanism == null)
+ {
+ mechanism = upper;
+ }
+
+ if (mechanism == "DH" || mechanism == "DIFFIEHELLMAN")
+ return new DHBasicAgreement();
+
+ if (mechanism == "ECDH")
+ return new ECDHBasicAgreement();
+
+ if (mechanism == "ECDHC" || mechanism == "ECCDH")
+ return new ECDHCBasicAgreement();
+
+ if (mechanism == "ECMQV")
+ return new ECMqvBasicAgreement();
+
+ throw new SecurityUtilityException("Basic Agreement " + algorithm + " not recognised.");
+ }
+
+ public static IBasicAgreement GetBasicAgreementWithKdf(
+ DerObjectIdentifier oid,
+ string wrapAlgorithm)
+ {
+ return GetBasicAgreementWithKdf(oid.Id, wrapAlgorithm);
+ }
+
+ public static IBasicAgreement GetBasicAgreementWithKdf(
+ string agreeAlgorithm,
+ string wrapAlgorithm)
+ {
+ string upper = Platform.ToUpperInvariant(agreeAlgorithm);
+ string mechanism = (string) algorithms[upper];
+
+ if (mechanism == null)
+ {
+ mechanism = upper;
+ }
+
+ // 'DHWITHSHA1KDF' retained for backward compatibility
+ if (mechanism == "DHWITHSHA1KDF" || mechanism == "ECDHWITHSHA1KDF")
+ return new ECDHWithKdfBasicAgreement(
+ wrapAlgorithm,
+ new ECDHKekGenerator(
+ new Sha1Digest()));
+
+ if (mechanism == "ECMQVWITHSHA1KDF")
+ return new ECMqvWithKdfBasicAgreement(
+ wrapAlgorithm,
+ new ECDHKekGenerator(
+ new Sha1Digest()));
+
+ throw new SecurityUtilityException("Basic Agreement (with KDF) " + agreeAlgorithm + " not recognised.");
+ }
+
+ public static string GetAlgorithmName(
+ DerObjectIdentifier oid)
+ {
+ return (string) algorithms[oid.Id];
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/CipherUtilities.cs b/bc-sharp-crypto/src/security/CipherUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..de05bc9efc11aeda38e2c2f87e90df1f199df9f3
--- /dev/null
+++ b/bc-sharp-crypto/src/security/CipherUtilities.cs
@@ -0,0 +1,755 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Kisa;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Ntt;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Security
+{
+ ///
+ /// Cipher Utility class contains methods that can not be specifically grouped into other classes.
+ ///
+ public sealed class CipherUtilities
+ {
+ private enum CipherAlgorithm {
+ AES,
+ ARC4,
+ BLOWFISH,
+ CAMELLIA,
+ CAST5,
+ CAST6,
+ DES,
+ DESEDE,
+ ELGAMAL,
+ GOST28147,
+ HC128,
+ HC256,
+ IDEA,
+ NOEKEON,
+ PBEWITHSHAAND128BITRC4,
+ PBEWITHSHAAND40BITRC4,
+ RC2,
+ RC5,
+ RC5_64,
+ RC6,
+ RIJNDAEL,
+ RSA,
+ SALSA20,
+ SEED,
+ SERPENT,
+ SKIPJACK,
+ TEA,
+ THREEFISH_256,
+ THREEFISH_512,
+ THREEFISH_1024,
+ TNEPRES,
+ TWOFISH,
+ VMPC,
+ VMPC_KSA3,
+ XTEA,
+ };
+
+ private enum CipherMode { ECB, NONE, CBC, CCM, CFB, CTR, CTS, EAX, GCM, GOFB, OCB, OFB, OPENPGPCFB, SIC };
+ private enum CipherPadding
+ {
+ NOPADDING,
+ RAW,
+ ISO10126PADDING,
+ ISO10126D2PADDING,
+ ISO10126_2PADDING,
+ ISO7816_4PADDING,
+ ISO9797_1PADDING,
+ ISO9796_1,
+ ISO9796_1PADDING,
+ OAEP,
+ OAEPPADDING,
+ OAEPWITHMD5ANDMGF1PADDING,
+ OAEPWITHSHA1ANDMGF1PADDING,
+ OAEPWITHSHA_1ANDMGF1PADDING,
+ OAEPWITHSHA224ANDMGF1PADDING,
+ OAEPWITHSHA_224ANDMGF1PADDING,
+ OAEPWITHSHA256ANDMGF1PADDING,
+ OAEPWITHSHA_256ANDMGF1PADDING,
+ OAEPWITHSHA384ANDMGF1PADDING,
+ OAEPWITHSHA_384ANDMGF1PADDING,
+ OAEPWITHSHA512ANDMGF1PADDING,
+ OAEPWITHSHA_512ANDMGF1PADDING,
+ PKCS1,
+ PKCS1PADDING,
+ PKCS5,
+ PKCS5PADDING,
+ PKCS7,
+ PKCS7PADDING,
+ TBCPADDING,
+ WITHCTS,
+ X923PADDING,
+ ZEROBYTEPADDING,
+ };
+
+ private static readonly IDictionary algorithms = Platform.CreateHashtable();
+ private static readonly IDictionary oids = Platform.CreateHashtable();
+
+ static CipherUtilities()
+ {
+ // Signal to obfuscation tools not to change enum constants
+ ((CipherAlgorithm)Enums.GetArbitraryValue(typeof(CipherAlgorithm))).ToString();
+ ((CipherMode)Enums.GetArbitraryValue(typeof(CipherMode))).ToString();
+ ((CipherPadding)Enums.GetArbitraryValue(typeof(CipherPadding))).ToString();
+
+ // TODO Flesh out the list of aliases
+
+ algorithms[NistObjectIdentifiers.IdAes128Ecb.Id] = "AES/ECB/PKCS7PADDING";
+ algorithms[NistObjectIdentifiers.IdAes192Ecb.Id] = "AES/ECB/PKCS7PADDING";
+ algorithms[NistObjectIdentifiers.IdAes256Ecb.Id] = "AES/ECB/PKCS7PADDING";
+ algorithms["AES//PKCS7"] = "AES/ECB/PKCS7PADDING";
+ algorithms["AES//PKCS7PADDING"] = "AES/ECB/PKCS7PADDING";
+ algorithms["AES//PKCS5"] = "AES/ECB/PKCS7PADDING";
+ algorithms["AES//PKCS5PADDING"] = "AES/ECB/PKCS7PADDING";
+
+ algorithms[NistObjectIdentifiers.IdAes128Cbc.Id] = "AES/CBC/PKCS7PADDING";
+ algorithms[NistObjectIdentifiers.IdAes192Cbc.Id] = "AES/CBC/PKCS7PADDING";
+ algorithms[NistObjectIdentifiers.IdAes256Cbc.Id] = "AES/CBC/PKCS7PADDING";
+
+ algorithms[NistObjectIdentifiers.IdAes128Ofb.Id] = "AES/OFB/NOPADDING";
+ algorithms[NistObjectIdentifiers.IdAes192Ofb.Id] = "AES/OFB/NOPADDING";
+ algorithms[NistObjectIdentifiers.IdAes256Ofb.Id] = "AES/OFB/NOPADDING";
+
+ algorithms[NistObjectIdentifiers.IdAes128Cfb.Id] = "AES/CFB/NOPADDING";
+ algorithms[NistObjectIdentifiers.IdAes192Cfb.Id] = "AES/CFB/NOPADDING";
+ algorithms[NistObjectIdentifiers.IdAes256Cfb.Id] = "AES/CFB/NOPADDING";
+
+ algorithms["RSA/ECB/PKCS1"] = "RSA//PKCS1PADDING";
+ algorithms["RSA/ECB/PKCS1PADDING"] = "RSA//PKCS1PADDING";
+ algorithms[PkcsObjectIdentifiers.RsaEncryption.Id] = "RSA//PKCS1PADDING";
+ algorithms[PkcsObjectIdentifiers.IdRsaesOaep.Id] = "RSA//OAEPPADDING";
+
+ algorithms[OiwObjectIdentifiers.DesCbc.Id] = "DES/CBC";
+ algorithms[OiwObjectIdentifiers.DesCfb.Id] = "DES/CFB";
+ algorithms[OiwObjectIdentifiers.DesEcb.Id] = "DES/ECB";
+ algorithms[OiwObjectIdentifiers.DesOfb.Id] = "DES/OFB";
+ algorithms[OiwObjectIdentifiers.DesEde.Id] = "DESEDE";
+ algorithms["TDEA"] = "DESEDE";
+ algorithms[PkcsObjectIdentifiers.DesEde3Cbc.Id] = "DESEDE/CBC";
+ algorithms[PkcsObjectIdentifiers.RC2Cbc.Id] = "RC2/CBC";
+ algorithms["1.3.6.1.4.1.188.7.1.1.2"] = "IDEA/CBC";
+ algorithms["1.2.840.113533.7.66.10"] = "CAST5/CBC";
+
+ algorithms["RC4"] = "ARC4";
+ algorithms["ARCFOUR"] = "ARC4";
+ algorithms["1.2.840.113549.3.4"] = "ARC4";
+
+
+
+ algorithms["PBEWITHSHA1AND128BITRC4"] = "PBEWITHSHAAND128BITRC4";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC4.Id] = "PBEWITHSHAAND128BITRC4";
+ algorithms["PBEWITHSHA1AND40BITRC4"] = "PBEWITHSHAAND40BITRC4";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd40BitRC4.Id] = "PBEWITHSHAAND40BITRC4";
+
+ algorithms["PBEWITHSHA1ANDDES"] = "PBEWITHSHA1ANDDES-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithSha1AndDesCbc.Id] = "PBEWITHSHA1ANDDES-CBC";
+ algorithms["PBEWITHSHA1ANDRC2"] = "PBEWITHSHA1ANDRC2-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithSha1AndRC2Cbc.Id] = "PBEWITHSHA1ANDRC2-CBC";
+
+ algorithms["PBEWITHSHA1AND3-KEYTRIPLEDES-CBC"] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC";
+ algorithms["PBEWITHSHAAND3KEYTRIPLEDES"] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc.Id] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC";
+ algorithms["PBEWITHSHA1ANDDESEDE"] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC";
+
+ algorithms["PBEWITHSHA1AND2-KEYTRIPLEDES-CBC"] = "PBEWITHSHAAND2-KEYTRIPLEDES-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd2KeyTripleDesCbc.Id] = "PBEWITHSHAAND2-KEYTRIPLEDES-CBC";
+
+ algorithms["PBEWITHSHA1AND128BITRC2-CBC"] = "PBEWITHSHAAND128BITRC2-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC2Cbc.Id] = "PBEWITHSHAAND128BITRC2-CBC";
+
+ algorithms["PBEWITHSHA1AND40BITRC2-CBC"] = "PBEWITHSHAAND40BITRC2-CBC";
+ algorithms[PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc.Id] = "PBEWITHSHAAND40BITRC2-CBC";
+
+ algorithms["PBEWITHSHA1AND128BITAES-CBC-BC"] = "PBEWITHSHAAND128BITAES-CBC-BC";
+ algorithms["PBEWITHSHA-1AND128BITAES-CBC-BC"] = "PBEWITHSHAAND128BITAES-CBC-BC";
+
+ algorithms["PBEWITHSHA1AND192BITAES-CBC-BC"] = "PBEWITHSHAAND192BITAES-CBC-BC";
+ algorithms["PBEWITHSHA-1AND192BITAES-CBC-BC"] = "PBEWITHSHAAND192BITAES-CBC-BC";
+
+ algorithms["PBEWITHSHA1AND256BITAES-CBC-BC"] = "PBEWITHSHAAND256BITAES-CBC-BC";
+ algorithms["PBEWITHSHA-1AND256BITAES-CBC-BC"] = "PBEWITHSHAAND256BITAES-CBC-BC";
+
+ algorithms["PBEWITHSHA-256AND128BITAES-CBC-BC"] = "PBEWITHSHA256AND128BITAES-CBC-BC";
+ algorithms["PBEWITHSHA-256AND192BITAES-CBC-BC"] = "PBEWITHSHA256AND192BITAES-CBC-BC";
+ algorithms["PBEWITHSHA-256AND256BITAES-CBC-BC"] = "PBEWITHSHA256AND256BITAES-CBC-BC";
+
+
+ algorithms["GOST"] = "GOST28147";
+ algorithms["GOST-28147"] = "GOST28147";
+ algorithms[CryptoProObjectIdentifiers.GostR28147Cbc.Id] = "GOST28147/CBC/PKCS7PADDING";
+
+ algorithms["RC5-32"] = "RC5";
+
+ algorithms[NttObjectIdentifiers.IdCamellia128Cbc.Id] = "CAMELLIA/CBC/PKCS7PADDING";
+ algorithms[NttObjectIdentifiers.IdCamellia192Cbc.Id] = "CAMELLIA/CBC/PKCS7PADDING";
+ algorithms[NttObjectIdentifiers.IdCamellia256Cbc.Id] = "CAMELLIA/CBC/PKCS7PADDING";
+
+ algorithms[KisaObjectIdentifiers.IdSeedCbc.Id] = "SEED/CBC/PKCS7PADDING";
+
+ algorithms["1.3.6.1.4.1.3029.1.2"] = "BLOWFISH/CBC";
+ }
+
+ private CipherUtilities()
+ {
+ }
+
+ ///
+ /// Returns a ObjectIdentifier for a give encoding.
+ ///
+ /// A string representation of the encoding.
+ /// A DerObjectIdentifier, null if the Oid is not available.
+ // TODO Don't really want to support this
+ public static DerObjectIdentifier GetObjectIdentifier(
+ string mechanism)
+ {
+ if (mechanism == null)
+ throw new ArgumentNullException("mechanism");
+
+ mechanism = Platform.ToUpperInvariant(mechanism);
+ string aliased = (string) algorithms[mechanism];
+
+ if (aliased != null)
+ mechanism = aliased;
+
+ return (DerObjectIdentifier) oids[mechanism];
+ }
+
+ public static ICollection Algorithms
+ {
+ get { return oids.Keys; }
+ }
+
+ public static IBufferedCipher GetCipher(
+ DerObjectIdentifier oid)
+ {
+ return GetCipher(oid.Id);
+ }
+
+ public static IBufferedCipher GetCipher(
+ string algorithm)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+
+ algorithm = Platform.ToUpperInvariant(algorithm);
+
+ {
+ string aliased = (string) algorithms[algorithm];
+
+ if (aliased != null)
+ algorithm = aliased;
+ }
+
+ IBasicAgreement iesAgreement = null;
+ if (algorithm == "IES")
+ {
+ iesAgreement = new DHBasicAgreement();
+ }
+ else if (algorithm == "ECIES")
+ {
+ iesAgreement = new ECDHBasicAgreement();
+ }
+
+ if (iesAgreement != null)
+ {
+ return new BufferedIesCipher(
+ new IesEngine(
+ iesAgreement,
+ new Kdf2BytesGenerator(
+ new Sha1Digest()),
+ new HMac(
+ new Sha1Digest())));
+ }
+
+
+
+ if (Platform.StartsWith(algorithm, "PBE"))
+ {
+ if (Platform.EndsWith(algorithm, "-CBC"))
+ {
+ if (algorithm == "PBEWITHSHA1ANDDES-CBC")
+ {
+ return new PaddedBufferedBlockCipher(
+ new CbcBlockCipher(new DesEngine()));
+ }
+ else if (algorithm == "PBEWITHSHA1ANDRC2-CBC")
+ {
+ return new PaddedBufferedBlockCipher(
+ new CbcBlockCipher(new RC2Engine()));
+ }
+ else if (Strings.IsOneOf(algorithm,
+ "PBEWITHSHAAND2-KEYTRIPLEDES-CBC", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC"))
+ {
+ return new PaddedBufferedBlockCipher(
+ new CbcBlockCipher(new DesEdeEngine()));
+ }
+ else if (Strings.IsOneOf(algorithm,
+ "PBEWITHSHAAND128BITRC2-CBC", "PBEWITHSHAAND40BITRC2-CBC"))
+ {
+ return new PaddedBufferedBlockCipher(
+ new CbcBlockCipher(new RC2Engine()));
+ }
+ }
+ else if (Platform.EndsWith(algorithm, "-BC") || Platform.EndsWith(algorithm, "-OPENSSL"))
+ {
+ if (Strings.IsOneOf(algorithm,
+ "PBEWITHSHAAND128BITAES-CBC-BC",
+ "PBEWITHSHAAND192BITAES-CBC-BC",
+ "PBEWITHSHAAND256BITAES-CBC-BC",
+ "PBEWITHSHA256AND128BITAES-CBC-BC",
+ "PBEWITHSHA256AND192BITAES-CBC-BC",
+ "PBEWITHSHA256AND256BITAES-CBC-BC",
+ "PBEWITHMD5AND128BITAES-CBC-OPENSSL",
+ "PBEWITHMD5AND192BITAES-CBC-OPENSSL",
+ "PBEWITHMD5AND256BITAES-CBC-OPENSSL"))
+ {
+ return new PaddedBufferedBlockCipher(
+ new CbcBlockCipher(new AesEngine()));
+ }
+ }
+ }
+
+
+
+ string[] parts = algorithm.Split('/');
+
+ IBlockCipher blockCipher = null;
+ IAsymmetricBlockCipher asymBlockCipher = null;
+ IStreamCipher streamCipher = null;
+
+ string algorithmName = parts[0];
+
+ {
+ string aliased = (string)algorithms[algorithmName];
+
+ if (aliased != null)
+ algorithmName = aliased;
+ }
+
+ CipherAlgorithm cipherAlgorithm;
+ try
+ {
+ cipherAlgorithm = (CipherAlgorithm)Enums.GetEnumValue(typeof(CipherAlgorithm), algorithmName);
+ }
+ catch (ArgumentException)
+ {
+ throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
+ }
+
+ switch (cipherAlgorithm)
+ {
+ case CipherAlgorithm.AES:
+ blockCipher = new AesEngine();
+ break;
+ case CipherAlgorithm.ARC4:
+ streamCipher = new RC4Engine();
+ break;
+ case CipherAlgorithm.BLOWFISH:
+ blockCipher = new BlowfishEngine();
+ break;
+ case CipherAlgorithm.CAMELLIA:
+ blockCipher = new CamelliaEngine();
+ break;
+ case CipherAlgorithm.CAST5:
+ blockCipher = new Cast5Engine();
+ break;
+ case CipherAlgorithm.CAST6:
+ blockCipher = new Cast6Engine();
+ break;
+ case CipherAlgorithm.DES:
+ blockCipher = new DesEngine();
+ break;
+ case CipherAlgorithm.DESEDE:
+ blockCipher = new DesEdeEngine();
+ break;
+ case CipherAlgorithm.ELGAMAL:
+ asymBlockCipher = new ElGamalEngine();
+ break;
+ case CipherAlgorithm.GOST28147:
+ blockCipher = new Gost28147Engine();
+ break;
+ case CipherAlgorithm.HC128:
+ streamCipher = new HC128Engine();
+ break;
+ case CipherAlgorithm.HC256:
+ streamCipher = new HC256Engine();
+ break;
+ case CipherAlgorithm.IDEA:
+ blockCipher = new IdeaEngine();
+ break;
+ case CipherAlgorithm.NOEKEON:
+ blockCipher = new NoekeonEngine();
+ break;
+ case CipherAlgorithm.PBEWITHSHAAND128BITRC4:
+ case CipherAlgorithm.PBEWITHSHAAND40BITRC4:
+ streamCipher = new RC4Engine();
+ break;
+ case CipherAlgorithm.RC2:
+ blockCipher = new RC2Engine();
+ break;
+ case CipherAlgorithm.RC5:
+ blockCipher = new RC532Engine();
+ break;
+ case CipherAlgorithm.RC5_64:
+ blockCipher = new RC564Engine();
+ break;
+ case CipherAlgorithm.RC6:
+ blockCipher = new RC6Engine();
+ break;
+ case CipherAlgorithm.RIJNDAEL:
+ blockCipher = new RijndaelEngine();
+ break;
+ case CipherAlgorithm.RSA:
+ asymBlockCipher = new RsaBlindedEngine();
+ break;
+ case CipherAlgorithm.SALSA20:
+ streamCipher = new Salsa20Engine();
+ break;
+ case CipherAlgorithm.SEED:
+ blockCipher = new SeedEngine();
+ break;
+ case CipherAlgorithm.SERPENT:
+ blockCipher = new SerpentEngine();
+ break;
+ case CipherAlgorithm.SKIPJACK:
+ blockCipher = new SkipjackEngine();
+ break;
+ case CipherAlgorithm.TEA:
+ blockCipher = new TeaEngine();
+ break;
+ case CipherAlgorithm.THREEFISH_256:
+ blockCipher = new ThreefishEngine(ThreefishEngine.BLOCKSIZE_256);
+ break;
+ case CipherAlgorithm.THREEFISH_512:
+ blockCipher = new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512);
+ break;
+ case CipherAlgorithm.THREEFISH_1024:
+ blockCipher = new ThreefishEngine(ThreefishEngine.BLOCKSIZE_1024);
+ break;
+ case CipherAlgorithm.TNEPRES:
+ blockCipher = new TnepresEngine();
+ break;
+ case CipherAlgorithm.TWOFISH:
+ blockCipher = new TwofishEngine();
+ break;
+ case CipherAlgorithm.VMPC:
+ streamCipher = new VmpcEngine();
+ break;
+ case CipherAlgorithm.VMPC_KSA3:
+ streamCipher = new VmpcKsa3Engine();
+ break;
+ case CipherAlgorithm.XTEA:
+ blockCipher = new XteaEngine();
+ break;
+ default:
+ throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
+ }
+
+ if (streamCipher != null)
+ {
+ if (parts.Length > 1)
+ throw new ArgumentException("Modes and paddings not used for stream ciphers");
+
+ return new BufferedStreamCipher(streamCipher);
+ }
+
+
+ bool cts = false;
+ bool padded = true;
+ IBlockCipherPadding padding = null;
+ IAeadBlockCipher aeadBlockCipher = null;
+
+ if (parts.Length > 2)
+ {
+ if (streamCipher != null)
+ throw new ArgumentException("Paddings not used for stream ciphers");
+
+ string paddingName = parts[2];
+
+ CipherPadding cipherPadding;
+ if (paddingName == "")
+ {
+ cipherPadding = CipherPadding.RAW;
+ }
+ else if (paddingName == "X9.23PADDING")
+ {
+ cipherPadding = CipherPadding.X923PADDING;
+ }
+ else
+ {
+ try
+ {
+ cipherPadding = (CipherPadding)Enums.GetEnumValue(typeof(CipherPadding), paddingName);
+ }
+ catch (ArgumentException)
+ {
+ throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
+ }
+ }
+
+ switch (cipherPadding)
+ {
+ case CipherPadding.NOPADDING:
+ padded = false;
+ break;
+ case CipherPadding.RAW:
+ break;
+ case CipherPadding.ISO10126PADDING:
+ case CipherPadding.ISO10126D2PADDING:
+ case CipherPadding.ISO10126_2PADDING:
+ padding = new ISO10126d2Padding();
+ break;
+ case CipherPadding.ISO7816_4PADDING:
+ case CipherPadding.ISO9797_1PADDING:
+ padding = new ISO7816d4Padding();
+ break;
+ case CipherPadding.ISO9796_1:
+ case CipherPadding.ISO9796_1PADDING:
+ asymBlockCipher = new ISO9796d1Encoding(asymBlockCipher);
+ break;
+ case CipherPadding.OAEP:
+ case CipherPadding.OAEPPADDING:
+ asymBlockCipher = new OaepEncoding(asymBlockCipher);
+ break;
+ case CipherPadding.OAEPWITHMD5ANDMGF1PADDING:
+ asymBlockCipher = new OaepEncoding(asymBlockCipher, new MD5Digest());
+ break;
+ case CipherPadding.OAEPWITHSHA1ANDMGF1PADDING:
+ case CipherPadding.OAEPWITHSHA_1ANDMGF1PADDING:
+ asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha1Digest());
+ break;
+ case CipherPadding.OAEPWITHSHA224ANDMGF1PADDING:
+ case CipherPadding.OAEPWITHSHA_224ANDMGF1PADDING:
+ asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha224Digest());
+ break;
+ case CipherPadding.OAEPWITHSHA256ANDMGF1PADDING:
+ case CipherPadding.OAEPWITHSHA_256ANDMGF1PADDING:
+ asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha256Digest());
+ break;
+ case CipherPadding.OAEPWITHSHA384ANDMGF1PADDING:
+ case CipherPadding.OAEPWITHSHA_384ANDMGF1PADDING:
+ asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha384Digest());
+ break;
+ case CipherPadding.OAEPWITHSHA512ANDMGF1PADDING:
+ case CipherPadding.OAEPWITHSHA_512ANDMGF1PADDING:
+ asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha512Digest());
+ break;
+ case CipherPadding.PKCS1:
+ case CipherPadding.PKCS1PADDING:
+ asymBlockCipher = new Pkcs1Encoding(asymBlockCipher);
+ break;
+ case CipherPadding.PKCS5:
+ case CipherPadding.PKCS5PADDING:
+ case CipherPadding.PKCS7:
+ case CipherPadding.PKCS7PADDING:
+ padding = new Pkcs7Padding();
+ break;
+ case CipherPadding.TBCPADDING:
+ padding = new TbcPadding();
+ break;
+ case CipherPadding.WITHCTS:
+ cts = true;
+ break;
+ case CipherPadding.X923PADDING:
+ padding = new X923Padding();
+ break;
+ case CipherPadding.ZEROBYTEPADDING:
+ padding = new ZeroBytePadding();
+ break;
+ default:
+ throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
+ }
+ }
+
+ string mode = "";
+ if (parts.Length > 1)
+ {
+ mode = parts[1];
+
+ int di = GetDigitIndex(mode);
+ string modeName = di >= 0 ? mode.Substring(0, di) : mode;
+
+ try
+ {
+ CipherMode cipherMode = modeName == ""
+ ? CipherMode.NONE
+ : (CipherMode)Enums.GetEnumValue(typeof(CipherMode), modeName);
+
+ switch (cipherMode)
+ {
+ case CipherMode.ECB:
+ case CipherMode.NONE:
+ break;
+ case CipherMode.CBC:
+ blockCipher = new CbcBlockCipher(blockCipher);
+ break;
+ case CipherMode.CCM:
+ aeadBlockCipher = new CcmBlockCipher(blockCipher);
+ break;
+ case CipherMode.CFB:
+ {
+ int bits = (di < 0)
+ ? 8 * blockCipher.GetBlockSize()
+ : int.Parse(mode.Substring(di));
+
+ blockCipher = new CfbBlockCipher(blockCipher, bits);
+ break;
+ }
+ case CipherMode.CTR:
+ blockCipher = new SicBlockCipher(blockCipher);
+ break;
+ case CipherMode.CTS:
+ cts = true;
+ blockCipher = new CbcBlockCipher(blockCipher);
+ break;
+ case CipherMode.EAX:
+ aeadBlockCipher = new EaxBlockCipher(blockCipher);
+ break;
+ case CipherMode.GCM:
+ aeadBlockCipher = new GcmBlockCipher(blockCipher);
+ break;
+ case CipherMode.GOFB:
+ blockCipher = new GOfbBlockCipher(blockCipher);
+ break;
+ case CipherMode.OCB:
+ aeadBlockCipher = new OcbBlockCipher(blockCipher, CreateBlockCipher(cipherAlgorithm));
+ break;
+ case CipherMode.OFB:
+ {
+ int bits = (di < 0)
+ ? 8 * blockCipher.GetBlockSize()
+ : int.Parse(mode.Substring(di));
+
+ blockCipher = new OfbBlockCipher(blockCipher, bits);
+ break;
+ }
+ case CipherMode.OPENPGPCFB:
+ blockCipher = new OpenPgpCfbBlockCipher(blockCipher);
+ break;
+ case CipherMode.SIC:
+ if (blockCipher.GetBlockSize() < 16)
+ {
+ throw new ArgumentException("Warning: SIC-Mode can become a twotime-pad if the blocksize of the cipher is too small. Use a cipher with a block size of at least 128 bits (e.g. AES)");
+ }
+ blockCipher = new SicBlockCipher(blockCipher);
+ break;
+ default:
+ throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
+ }
+ }
+ catch (ArgumentException)
+ {
+ throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
+ }
+ }
+
+ if (aeadBlockCipher != null)
+ {
+ if (cts)
+ throw new SecurityUtilityException("CTS mode not valid for AEAD ciphers.");
+ if (padded && parts.Length > 2 && parts[2] != "")
+ throw new SecurityUtilityException("Bad padding specified for AEAD cipher.");
+
+ return new BufferedAeadBlockCipher(aeadBlockCipher);
+ }
+
+ if (blockCipher != null)
+ {
+ if (cts)
+ {
+ return new CtsBlockCipher(blockCipher);
+ }
+
+ if (padding != null)
+ {
+ return new PaddedBufferedBlockCipher(blockCipher, padding);
+ }
+
+ if (!padded || blockCipher.IsPartialBlockOkay)
+ {
+ return new BufferedBlockCipher(blockCipher);
+ }
+
+ return new PaddedBufferedBlockCipher(blockCipher);
+ }
+
+ if (asymBlockCipher != null)
+ {
+ return new BufferedAsymmetricBlockCipher(asymBlockCipher);
+ }
+
+ throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
+ }
+
+ public static string GetAlgorithmName(
+ DerObjectIdentifier oid)
+ {
+ return (string) algorithms[oid.Id];
+ }
+
+ private static int GetDigitIndex(
+ string s)
+ {
+ for (int i = 0; i < s.Length; ++i)
+ {
+ if (char.IsDigit(s[i]))
+ return i;
+ }
+
+ return -1;
+ }
+
+ private static IBlockCipher CreateBlockCipher(CipherAlgorithm cipherAlgorithm)
+ {
+ switch (cipherAlgorithm)
+ {
+ case CipherAlgorithm.AES: return new AesEngine();
+ case CipherAlgorithm.BLOWFISH: return new BlowfishEngine();
+ case CipherAlgorithm.CAMELLIA: return new CamelliaEngine();
+ case CipherAlgorithm.CAST5: return new Cast5Engine();
+ case CipherAlgorithm.CAST6: return new Cast6Engine();
+ case CipherAlgorithm.DES: return new DesEngine();
+ case CipherAlgorithm.DESEDE: return new DesEdeEngine();
+ case CipherAlgorithm.GOST28147: return new Gost28147Engine();
+ case CipherAlgorithm.IDEA: return new IdeaEngine();
+ case CipherAlgorithm.NOEKEON: return new NoekeonEngine();
+ case CipherAlgorithm.RC2: return new RC2Engine();
+ case CipherAlgorithm.RC5: return new RC532Engine();
+ case CipherAlgorithm.RC5_64: return new RC564Engine();
+ case CipherAlgorithm.RC6: return new RC6Engine();
+ case CipherAlgorithm.RIJNDAEL: return new RijndaelEngine();
+ case CipherAlgorithm.SEED: return new SeedEngine();
+ case CipherAlgorithm.SERPENT: return new SerpentEngine();
+ case CipherAlgorithm.SKIPJACK: return new SkipjackEngine();
+ case CipherAlgorithm.TEA: return new TeaEngine();
+ case CipherAlgorithm.THREEFISH_256: return new ThreefishEngine(ThreefishEngine.BLOCKSIZE_256);
+ case CipherAlgorithm.THREEFISH_512: return new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512);
+ case CipherAlgorithm.THREEFISH_1024: return new ThreefishEngine(ThreefishEngine.BLOCKSIZE_1024);
+ case CipherAlgorithm.TNEPRES: return new TnepresEngine();
+ case CipherAlgorithm.TWOFISH: return new TwofishEngine();
+ case CipherAlgorithm.XTEA: return new XteaEngine();
+ default:
+ throw new SecurityUtilityException("Cipher " + cipherAlgorithm + " not recognised or not a block cipher");
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/DigestUtilities.cs b/bc-sharp-crypto/src/security/DigestUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7ddf6c8e4aefaa9617de5acfb6ff197927708749
--- /dev/null
+++ b/bc-sharp-crypto/src/security/DigestUtilities.cs
@@ -0,0 +1,222 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Security
+{
+ ///
+ /// Utility class for creating IDigest objects from their names/Oids
+ ///
+ public sealed class DigestUtilities
+ {
+ private enum DigestAlgorithm {
+ GOST3411,
+ KECCAK_224, KECCAK_256, KECCAK_288, KECCAK_384, KECCAK_512,
+ MD2, MD4, MD5,
+ RIPEMD128, RIPEMD160, RIPEMD256, RIPEMD320,
+ SHA_1, SHA_224, SHA_256, SHA_384, SHA_512,
+ SHA_512_224, SHA_512_256,
+ SHA3_224, SHA3_256, SHA3_384, SHA3_512,
+ SHAKE128, SHAKE256,
+ TIGER,
+ WHIRLPOOL,
+ };
+
+ private DigestUtilities()
+ {
+ }
+
+ private static readonly IDictionary algorithms = Platform.CreateHashtable();
+ private static readonly IDictionary oids = Platform.CreateHashtable();
+
+ static DigestUtilities()
+ {
+ // Signal to obfuscation tools not to change enum constants
+ ((DigestAlgorithm)Enums.GetArbitraryValue(typeof(DigestAlgorithm))).ToString();
+
+ algorithms[PkcsObjectIdentifiers.MD2.Id] = "MD2";
+ algorithms[PkcsObjectIdentifiers.MD4.Id] = "MD4";
+ algorithms[PkcsObjectIdentifiers.MD5.Id] = "MD5";
+
+ algorithms["SHA1"] = "SHA-1";
+ algorithms[OiwObjectIdentifiers.IdSha1.Id] = "SHA-1";
+ algorithms["SHA224"] = "SHA-224";
+ algorithms[NistObjectIdentifiers.IdSha224.Id] = "SHA-224";
+ algorithms["SHA256"] = "SHA-256";
+ algorithms[NistObjectIdentifiers.IdSha256.Id] = "SHA-256";
+ algorithms["SHA384"] = "SHA-384";
+ algorithms[NistObjectIdentifiers.IdSha384.Id] = "SHA-384";
+ algorithms["SHA512"] = "SHA-512";
+ algorithms[NistObjectIdentifiers.IdSha512.Id] = "SHA-512";
+ algorithms["SHA512/224"] = "SHA-512/224";
+ algorithms[NistObjectIdentifiers.IdSha512_224.Id] = "SHA-512/224";
+ algorithms["SHA512/256"] = "SHA-512/256";
+ algorithms[NistObjectIdentifiers.IdSha512_256.Id] = "SHA-512/256";
+
+ algorithms["RIPEMD-128"] = "RIPEMD128";
+ algorithms[TeleTrusTObjectIdentifiers.RipeMD128.Id] = "RIPEMD128";
+ algorithms["RIPEMD-160"] = "RIPEMD160";
+ algorithms[TeleTrusTObjectIdentifiers.RipeMD160.Id] = "RIPEMD160";
+ algorithms["RIPEMD-256"] = "RIPEMD256";
+ algorithms[TeleTrusTObjectIdentifiers.RipeMD256.Id] = "RIPEMD256";
+ algorithms["RIPEMD-320"] = "RIPEMD320";
+// algorithms[TeleTrusTObjectIdentifiers.RipeMD320.Id] = "RIPEMD320";
+
+ algorithms[CryptoProObjectIdentifiers.GostR3411.Id] = "GOST3411";
+
+ algorithms[NistObjectIdentifiers.IdSha3_224.Id] = "SHA3-224";
+ algorithms[NistObjectIdentifiers.IdSha3_256.Id] = "SHA3-256";
+ algorithms[NistObjectIdentifiers.IdSha3_384.Id] = "SHA3-384";
+ algorithms[NistObjectIdentifiers.IdSha3_512.Id] = "SHA3-512";
+ algorithms[NistObjectIdentifiers.IdShake128.Id] = "SHAKE128";
+ algorithms[NistObjectIdentifiers.IdShake256.Id] = "SHAKE256";
+
+ oids["MD2"] = PkcsObjectIdentifiers.MD2;
+ oids["MD4"] = PkcsObjectIdentifiers.MD4;
+ oids["MD5"] = PkcsObjectIdentifiers.MD5;
+ oids["SHA-1"] = OiwObjectIdentifiers.IdSha1;
+ oids["SHA-224"] = NistObjectIdentifiers.IdSha224;
+ oids["SHA-256"] = NistObjectIdentifiers.IdSha256;
+ oids["SHA-384"] = NistObjectIdentifiers.IdSha384;
+ oids["SHA-512"] = NistObjectIdentifiers.IdSha512;
+ oids["SHA-512/224"] = NistObjectIdentifiers.IdSha512_224;
+ oids["SHA-512/256"] = NistObjectIdentifiers.IdSha512_256;
+ oids["SHA3-224"] = NistObjectIdentifiers.IdSha3_224;
+ oids["SHA3-256"] = NistObjectIdentifiers.IdSha3_256;
+ oids["SHA3-384"] = NistObjectIdentifiers.IdSha3_384;
+ oids["SHA3-512"] = NistObjectIdentifiers.IdSha3_512;
+ oids["SHAKE128"] = NistObjectIdentifiers.IdShake128;
+ oids["SHAKE256"] = NistObjectIdentifiers.IdShake256;
+ oids["RIPEMD128"] = TeleTrusTObjectIdentifiers.RipeMD128;
+ oids["RIPEMD160"] = TeleTrusTObjectIdentifiers.RipeMD160;
+ oids["RIPEMD256"] = TeleTrusTObjectIdentifiers.RipeMD256;
+ oids["GOST3411"] = CryptoProObjectIdentifiers.GostR3411;
+ }
+
+ ///
+ /// Returns a ObjectIdentifier for a given digest mechanism.
+ ///
+ /// A string representation of the digest meanism.
+ /// A DerObjectIdentifier, null if the Oid is not available.
+
+ public static DerObjectIdentifier GetObjectIdentifier(
+ string mechanism)
+ {
+ if (mechanism == null)
+ throw new System.ArgumentNullException("mechanism");
+
+ mechanism = Platform.ToUpperInvariant(mechanism);
+ string aliased = (string) algorithms[mechanism];
+
+ if (aliased != null)
+ mechanism = aliased;
+
+ return (DerObjectIdentifier) oids[mechanism];
+ }
+
+ public static ICollection Algorithms
+ {
+ get { return oids.Keys; }
+ }
+
+ public static IDigest GetDigest(
+ DerObjectIdentifier id)
+ {
+ return GetDigest(id.Id);
+ }
+
+ public static IDigest GetDigest(
+ string algorithm)
+ {
+ string upper = Platform.ToUpperInvariant(algorithm);
+ string mechanism = (string) algorithms[upper];
+
+ if (mechanism == null)
+ {
+ mechanism = upper;
+ }
+
+ try
+ {
+ DigestAlgorithm digestAlgorithm = (DigestAlgorithm)Enums.GetEnumValue(
+ typeof(DigestAlgorithm), mechanism);
+
+ switch (digestAlgorithm)
+ {
+ case DigestAlgorithm.GOST3411: return new Gost3411Digest();
+ case DigestAlgorithm.KECCAK_224: return new KeccakDigest(224);
+ case DigestAlgorithm.KECCAK_256: return new KeccakDigest(256);
+ case DigestAlgorithm.KECCAK_288: return new KeccakDigest(288);
+ case DigestAlgorithm.KECCAK_384: return new KeccakDigest(384);
+ case DigestAlgorithm.KECCAK_512: return new KeccakDigest(512);
+ case DigestAlgorithm.MD2: return new MD2Digest();
+ case DigestAlgorithm.MD4: return new MD4Digest();
+ case DigestAlgorithm.MD5: return new MD5Digest();
+ case DigestAlgorithm.RIPEMD128: return new RipeMD128Digest();
+ case DigestAlgorithm.RIPEMD160: return new RipeMD160Digest();
+ case DigestAlgorithm.RIPEMD256: return new RipeMD256Digest();
+ case DigestAlgorithm.RIPEMD320: return new RipeMD320Digest();
+ case DigestAlgorithm.SHA_1: return new Sha1Digest();
+ case DigestAlgorithm.SHA_224: return new Sha224Digest();
+ case DigestAlgorithm.SHA_256: return new Sha256Digest();
+ case DigestAlgorithm.SHA_384: return new Sha384Digest();
+ case DigestAlgorithm.SHA_512: return new Sha512Digest();
+ case DigestAlgorithm.SHA_512_224: return new Sha512tDigest(224);
+ case DigestAlgorithm.SHA_512_256: return new Sha512tDigest(256);
+ case DigestAlgorithm.SHA3_224: return new Sha3Digest(224);
+ case DigestAlgorithm.SHA3_256: return new Sha3Digest(256);
+ case DigestAlgorithm.SHA3_384: return new Sha3Digest(384);
+ case DigestAlgorithm.SHA3_512: return new Sha3Digest(512);
+ case DigestAlgorithm.SHAKE128: return new ShakeDigest(128);
+ case DigestAlgorithm.SHAKE256: return new ShakeDigest(256);
+ case DigestAlgorithm.TIGER: return new TigerDigest();
+ case DigestAlgorithm.WHIRLPOOL: return new WhirlpoolDigest();
+ }
+ }
+ catch (ArgumentException)
+ {
+ }
+
+ throw new SecurityUtilityException("Digest " + mechanism + " not recognised.");
+ }
+
+ public static string GetAlgorithmName(
+ DerObjectIdentifier oid)
+ {
+ return (string) algorithms[oid.Id];
+ }
+
+ public static byte[] CalculateDigest(string algorithm, byte[] input)
+ {
+ IDigest digest = GetDigest(algorithm);
+ digest.BlockUpdate(input, 0, input.Length);
+ return DoFinal(digest);
+ }
+
+ public static byte[] DoFinal(
+ IDigest digest)
+ {
+ byte[] b = new byte[digest.GetDigestSize()];
+ digest.DoFinal(b, 0);
+ return b;
+ }
+
+ public static byte[] DoFinal(
+ IDigest digest,
+ byte[] input)
+ {
+ digest.BlockUpdate(input, 0, input.Length);
+ return DoFinal(digest);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/DotNetUtilities.cs b/bc-sharp-crypto/src/security/DotNetUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..69322b54999a839f9fa461ccb9f02a0b22d66910
--- /dev/null
+++ b/bc-sharp-crypto/src/security/DotNetUtilities.cs
@@ -0,0 +1,245 @@
+#if !(NETCF_1_0 || SILVERLIGHT || PORTABLE)
+
+using System;
+using System.Security.Cryptography;
+using SystemX509 = System.Security.Cryptography.X509Certificates;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Security
+{
+ ///
+ /// A class containing methods to interface the BouncyCastle world to the .NET Crypto world.
+ ///
+ public sealed class DotNetUtilities
+ {
+ private DotNetUtilities()
+ {
+ }
+
+ ///
+ /// Create an System.Security.Cryptography.X509Certificate from an X509Certificate Structure.
+ ///
+ ///
+ /// A System.Security.Cryptography.X509Certificate.
+ public static SystemX509.X509Certificate ToX509Certificate(
+ X509CertificateStructure x509Struct)
+ {
+ return new SystemX509.X509Certificate(x509Struct.GetDerEncoded());
+ }
+
+ public static SystemX509.X509Certificate ToX509Certificate(
+ X509Certificate x509Cert)
+ {
+ return new SystemX509.X509Certificate(x509Cert.GetEncoded());
+ }
+
+ public static X509Certificate FromX509Certificate(
+ SystemX509.X509Certificate x509Cert)
+ {
+ return new X509CertificateParser().ReadCertificate(x509Cert.GetRawCertData());
+ }
+
+ public static AsymmetricCipherKeyPair GetDsaKeyPair(
+ DSA dsa)
+ {
+ return GetDsaKeyPair(dsa.ExportParameters(true));
+ }
+
+ public static AsymmetricCipherKeyPair GetDsaKeyPair(
+ DSAParameters dp)
+ {
+ DsaValidationParameters validationParameters = (dp.Seed != null)
+ ? new DsaValidationParameters(dp.Seed, dp.Counter)
+ : null;
+
+ DsaParameters parameters = new DsaParameters(
+ new BigInteger(1, dp.P),
+ new BigInteger(1, dp.Q),
+ new BigInteger(1, dp.G),
+ validationParameters);
+
+ DsaPublicKeyParameters pubKey = new DsaPublicKeyParameters(
+ new BigInteger(1, dp.Y),
+ parameters);
+
+ DsaPrivateKeyParameters privKey = new DsaPrivateKeyParameters(
+ new BigInteger(1, dp.X),
+ parameters);
+
+ return new AsymmetricCipherKeyPair(pubKey, privKey);
+ }
+
+ public static DsaPublicKeyParameters GetDsaPublicKey(
+ DSA dsa)
+ {
+ return GetDsaPublicKey(dsa.ExportParameters(false));
+ }
+
+ public static DsaPublicKeyParameters GetDsaPublicKey(
+ DSAParameters dp)
+ {
+ DsaValidationParameters validationParameters = (dp.Seed != null)
+ ? new DsaValidationParameters(dp.Seed, dp.Counter)
+ : null;
+
+ DsaParameters parameters = new DsaParameters(
+ new BigInteger(1, dp.P),
+ new BigInteger(1, dp.Q),
+ new BigInteger(1, dp.G),
+ validationParameters);
+
+ return new DsaPublicKeyParameters(
+ new BigInteger(1, dp.Y),
+ parameters);
+ }
+
+ public static AsymmetricCipherKeyPair GetRsaKeyPair(
+ RSA rsa)
+ {
+ return GetRsaKeyPair(rsa.ExportParameters(true));
+ }
+
+ public static AsymmetricCipherKeyPair GetRsaKeyPair(
+ RSAParameters rp)
+ {
+ BigInteger modulus = new BigInteger(1, rp.Modulus);
+ BigInteger pubExp = new BigInteger(1, rp.Exponent);
+
+ RsaKeyParameters pubKey = new RsaKeyParameters(
+ false,
+ modulus,
+ pubExp);
+
+ RsaPrivateCrtKeyParameters privKey = new RsaPrivateCrtKeyParameters(
+ modulus,
+ pubExp,
+ new BigInteger(1, rp.D),
+ new BigInteger(1, rp.P),
+ new BigInteger(1, rp.Q),
+ new BigInteger(1, rp.DP),
+ new BigInteger(1, rp.DQ),
+ new BigInteger(1, rp.InverseQ));
+
+ return new AsymmetricCipherKeyPair(pubKey, privKey);
+ }
+
+ public static RsaKeyParameters GetRsaPublicKey(
+ RSA rsa)
+ {
+ return GetRsaPublicKey(rsa.ExportParameters(false));
+ }
+
+ public static RsaKeyParameters GetRsaPublicKey(
+ RSAParameters rp)
+ {
+ return new RsaKeyParameters(
+ false,
+ new BigInteger(1, rp.Modulus),
+ new BigInteger(1, rp.Exponent));
+ }
+
+ public static AsymmetricCipherKeyPair GetKeyPair(AsymmetricAlgorithm privateKey)
+ {
+ if (privateKey is DSA)
+ {
+ return GetDsaKeyPair((DSA)privateKey);
+ }
+
+ if (privateKey is RSA)
+ {
+ return GetRsaKeyPair((RSA)privateKey);
+ }
+
+ throw new ArgumentException("Unsupported algorithm specified", "privateKey");
+ }
+
+ public static RSA ToRSA(RsaKeyParameters rsaKey)
+ {
+ // TODO This appears to not work for private keys (when no CRT info)
+ return CreateRSAProvider(ToRSAParameters(rsaKey));
+ }
+
+ public static RSA ToRSA(RsaPrivateCrtKeyParameters privKey)
+ {
+ return CreateRSAProvider(ToRSAParameters(privKey));
+ }
+
+ public static RSA ToRSA(RsaPrivateKeyStructure privKey)
+ {
+ return CreateRSAProvider(ToRSAParameters(privKey));
+ }
+
+ public static RSAParameters ToRSAParameters(RsaKeyParameters rsaKey)
+ {
+ RSAParameters rp = new RSAParameters();
+ rp.Modulus = rsaKey.Modulus.ToByteArrayUnsigned();
+ if (rsaKey.IsPrivate)
+ rp.D = ConvertRSAParametersField(rsaKey.Exponent, rp.Modulus.Length);
+ else
+ rp.Exponent = rsaKey.Exponent.ToByteArrayUnsigned();
+ return rp;
+ }
+
+ public static RSAParameters ToRSAParameters(RsaPrivateCrtKeyParameters privKey)
+ {
+ RSAParameters rp = new RSAParameters();
+ rp.Modulus = privKey.Modulus.ToByteArrayUnsigned();
+ rp.Exponent = privKey.PublicExponent.ToByteArrayUnsigned();
+ rp.P = privKey.P.ToByteArrayUnsigned();
+ rp.Q = privKey.Q.ToByteArrayUnsigned();
+ rp.D = ConvertRSAParametersField(privKey.Exponent, rp.Modulus.Length);
+ rp.DP = ConvertRSAParametersField(privKey.DP, rp.P.Length);
+ rp.DQ = ConvertRSAParametersField(privKey.DQ, rp.Q.Length);
+ rp.InverseQ = ConvertRSAParametersField(privKey.QInv, rp.Q.Length);
+ return rp;
+ }
+
+ public static RSAParameters ToRSAParameters(RsaPrivateKeyStructure privKey)
+ {
+ RSAParameters rp = new RSAParameters();
+ rp.Modulus = privKey.Modulus.ToByteArrayUnsigned();
+ rp.Exponent = privKey.PublicExponent.ToByteArrayUnsigned();
+ rp.P = privKey.Prime1.ToByteArrayUnsigned();
+ rp.Q = privKey.Prime2.ToByteArrayUnsigned();
+ rp.D = ConvertRSAParametersField(privKey.PrivateExponent, rp.Modulus.Length);
+ rp.DP = ConvertRSAParametersField(privKey.Exponent1, rp.P.Length);
+ rp.DQ = ConvertRSAParametersField(privKey.Exponent2, rp.Q.Length);
+ rp.InverseQ = ConvertRSAParametersField(privKey.Coefficient, rp.Q.Length);
+ return rp;
+ }
+
+ // TODO Move functionality to more general class
+ private static byte[] ConvertRSAParametersField(BigInteger n, int size)
+ {
+ byte[] bs = n.ToByteArrayUnsigned();
+
+ if (bs.Length == size)
+ return bs;
+
+ if (bs.Length > size)
+ throw new ArgumentException("Specified size too small", "size");
+
+ byte[] padded = new byte[size];
+ Array.Copy(bs, 0, padded, size - bs.Length, bs.Length);
+ return padded;
+ }
+
+ private static RSA CreateRSAProvider(RSAParameters rp)
+ {
+ CspParameters csp = new CspParameters();
+ csp.KeyContainerName = string.Format("BouncyCastle-{0}", Guid.NewGuid());
+ RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider(csp);
+ rsaCsp.ImportParameters(rp);
+ return rsaCsp;
+ }
+ }
+}
+
+#endif
diff --git a/bc-sharp-crypto/src/security/GeneralSecurityException.cs b/bc-sharp-crypto/src/security/GeneralSecurityException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d4ab38caef4a311e4f87a717ecb4b4f92b1755e2
--- /dev/null
+++ b/bc-sharp-crypto/src/security/GeneralSecurityException.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class GeneralSecurityException
+ : Exception
+ {
+ public GeneralSecurityException()
+ : base()
+ {
+ }
+
+ public GeneralSecurityException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public GeneralSecurityException(
+ string message,
+ Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/GeneratorUtilities.cs b/bc-sharp-crypto/src/security/GeneratorUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3beebd05b638b005103764f816916e9ae9056398
--- /dev/null
+++ b/bc-sharp-crypto/src/security/GeneratorUtilities.cs
@@ -0,0 +1,352 @@
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Iana;
+using Org.BouncyCastle.Asn1.Kisa;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Ntt;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Security
+{
+ public sealed class GeneratorUtilities
+ {
+ private GeneratorUtilities()
+ {
+ }
+
+ private static readonly IDictionary kgAlgorithms = Platform.CreateHashtable();
+ private static readonly IDictionary kpgAlgorithms = Platform.CreateHashtable();
+ private static readonly IDictionary defaultKeySizes = Platform.CreateHashtable();
+
+ static GeneratorUtilities()
+ {
+ //
+ // key generators.
+ //
+ AddKgAlgorithm("AES",
+ "AESWRAP");
+ AddKgAlgorithm("AES128",
+ "2.16.840.1.101.3.4.2",
+ NistObjectIdentifiers.IdAes128Cbc,
+ NistObjectIdentifiers.IdAes128Cfb,
+ NistObjectIdentifiers.IdAes128Ecb,
+ NistObjectIdentifiers.IdAes128Ofb,
+ NistObjectIdentifiers.IdAes128Wrap);
+ AddKgAlgorithm("AES192",
+ "2.16.840.1.101.3.4.22",
+ NistObjectIdentifiers.IdAes192Cbc,
+ NistObjectIdentifiers.IdAes192Cfb,
+ NistObjectIdentifiers.IdAes192Ecb,
+ NistObjectIdentifiers.IdAes192Ofb,
+ NistObjectIdentifiers.IdAes192Wrap);
+ AddKgAlgorithm("AES256",
+ "2.16.840.1.101.3.4.42",
+ NistObjectIdentifiers.IdAes256Cbc,
+ NistObjectIdentifiers.IdAes256Cfb,
+ NistObjectIdentifiers.IdAes256Ecb,
+ NistObjectIdentifiers.IdAes256Ofb,
+ NistObjectIdentifiers.IdAes256Wrap);
+ AddKgAlgorithm("BLOWFISH",
+ "1.3.6.1.4.1.3029.1.2");
+ AddKgAlgorithm("CAMELLIA",
+ "CAMELLIAWRAP");
+ AddKgAlgorithm("CAMELLIA128",
+ NttObjectIdentifiers.IdCamellia128Cbc,
+ NttObjectIdentifiers.IdCamellia128Wrap);
+ AddKgAlgorithm("CAMELLIA192",
+ NttObjectIdentifiers.IdCamellia192Cbc,
+ NttObjectIdentifiers.IdCamellia192Wrap);
+ AddKgAlgorithm("CAMELLIA256",
+ NttObjectIdentifiers.IdCamellia256Cbc,
+ NttObjectIdentifiers.IdCamellia256Wrap);
+ AddKgAlgorithm("CAST5",
+ "1.2.840.113533.7.66.10");
+ AddKgAlgorithm("CAST6");
+ AddKgAlgorithm("DES",
+ OiwObjectIdentifiers.DesCbc,
+ OiwObjectIdentifiers.DesCfb,
+ OiwObjectIdentifiers.DesEcb,
+ OiwObjectIdentifiers.DesOfb);
+ AddKgAlgorithm("DESEDE",
+ "DESEDEWRAP",
+ "TDEA",
+ OiwObjectIdentifiers.DesEde);
+ AddKgAlgorithm("DESEDE3",
+ PkcsObjectIdentifiers.DesEde3Cbc,
+ PkcsObjectIdentifiers.IdAlgCms3DesWrap);
+ AddKgAlgorithm("GOST28147",
+ "GOST",
+ "GOST-28147",
+ CryptoProObjectIdentifiers.GostR28147Cbc);
+ AddKgAlgorithm("HC128");
+ AddKgAlgorithm("HC256");
+ AddKgAlgorithm("IDEA",
+ "1.3.6.1.4.1.188.7.1.1.2");
+ AddKgAlgorithm("NOEKEON");
+ AddKgAlgorithm("RC2",
+ PkcsObjectIdentifiers.RC2Cbc,
+ PkcsObjectIdentifiers.IdAlgCmsRC2Wrap);
+ AddKgAlgorithm("RC4",
+ "ARC4",
+ "1.2.840.113549.3.4");
+ AddKgAlgorithm("RC5",
+ "RC5-32");
+ AddKgAlgorithm("RC5-64");
+ AddKgAlgorithm("RC6");
+ AddKgAlgorithm("RIJNDAEL");
+ AddKgAlgorithm("SALSA20");
+ AddKgAlgorithm("SEED",
+ KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap,
+ KisaObjectIdentifiers.IdSeedCbc);
+ AddKgAlgorithm("SERPENT");
+ AddKgAlgorithm("SKIPJACK");
+ AddKgAlgorithm("TEA");
+ AddKgAlgorithm("THREEFISH-256");
+ AddKgAlgorithm("THREEFISH-512");
+ AddKgAlgorithm("THREEFISH-1024");
+ AddKgAlgorithm("TNEPRES");
+ AddKgAlgorithm("TWOFISH");
+ AddKgAlgorithm("VMPC");
+ AddKgAlgorithm("VMPC-KSA3");
+ AddKgAlgorithm("XTEA");
+
+ //
+ // HMac key generators
+ //
+ AddHMacKeyGenerator("MD2");
+ AddHMacKeyGenerator("MD4");
+ AddHMacKeyGenerator("MD5",
+ IanaObjectIdentifiers.HmacMD5);
+ AddHMacKeyGenerator("SHA1",
+ PkcsObjectIdentifiers.IdHmacWithSha1,
+ IanaObjectIdentifiers.HmacSha1);
+ AddHMacKeyGenerator("SHA224",
+ PkcsObjectIdentifiers.IdHmacWithSha224);
+ AddHMacKeyGenerator("SHA256",
+ PkcsObjectIdentifiers.IdHmacWithSha256);
+ AddHMacKeyGenerator("SHA384",
+ PkcsObjectIdentifiers.IdHmacWithSha384);
+ AddHMacKeyGenerator("SHA512",
+ PkcsObjectIdentifiers.IdHmacWithSha512);
+ AddHMacKeyGenerator("SHA512/224");
+ AddHMacKeyGenerator("SHA512/256");
+ AddHMacKeyGenerator("SHA3-224");
+ AddHMacKeyGenerator("SHA3-256");
+ AddHMacKeyGenerator("SHA3-384");
+ AddHMacKeyGenerator("SHA3-512");
+ AddHMacKeyGenerator("RIPEMD128");
+ AddHMacKeyGenerator("RIPEMD160",
+ IanaObjectIdentifiers.HmacRipeMD160);
+ AddHMacKeyGenerator("TIGER",
+ IanaObjectIdentifiers.HmacTiger);
+
+
+
+ //
+ // key pair generators.
+ //
+ AddKpgAlgorithm("DH",
+ "DIFFIEHELLMAN");
+ AddKpgAlgorithm("DSA");
+ AddKpgAlgorithm("EC",
+ // TODO Should this be an alias for ECDH?
+ X9ObjectIdentifiers.DHSinglePassStdDHSha1KdfScheme);
+ AddKpgAlgorithm("ECDH",
+ "ECIES");
+ AddKpgAlgorithm("ECDHC");
+ AddKpgAlgorithm("ECMQV",
+ X9ObjectIdentifiers.MqvSinglePassSha1KdfScheme);
+ AddKpgAlgorithm("ECDSA");
+ AddKpgAlgorithm("ECGOST3410",
+ "ECGOST-3410",
+ "GOST-3410-2001");
+ AddKpgAlgorithm("ELGAMAL");
+ AddKpgAlgorithm("GOST3410",
+ "GOST-3410",
+ "GOST-3410-94");
+ AddKpgAlgorithm("RSA",
+ "1.2.840.113549.1.1.1");
+
+ AddDefaultKeySizeEntries(64, "DES");
+ AddDefaultKeySizeEntries(80, "SKIPJACK");
+ AddDefaultKeySizeEntries(128, "AES128", "BLOWFISH", "CAMELLIA128", "CAST5", "DESEDE",
+ "HC128", "HMACMD2", "HMACMD4", "HMACMD5", "HMACRIPEMD128", "IDEA", "NOEKEON",
+ "RC2", "RC4", "RC5", "SALSA20", "SEED", "TEA", "XTEA", "VMPC", "VMPC-KSA3");
+ AddDefaultKeySizeEntries(160, "HMACRIPEMD160", "HMACSHA1");
+ AddDefaultKeySizeEntries(192, "AES", "AES192", "CAMELLIA192", "DESEDE3", "HMACTIGER",
+ "RIJNDAEL", "SERPENT", "TNEPRES");
+ AddDefaultKeySizeEntries(224, "HMACSHA224", "HMACSHA512/224");
+ AddDefaultKeySizeEntries(256, "AES256", "CAMELLIA", "CAMELLIA256", "CAST6", "GOST28147",
+ "HC256", "HMACSHA256", "HMACSHA512/256", "RC5-64", "RC6", "THREEFISH-256", "TWOFISH");
+ AddDefaultKeySizeEntries(384, "HMACSHA384");
+ AddDefaultKeySizeEntries(512, "HMACSHA512", "THREEFISH-512");
+ AddDefaultKeySizeEntries(1024, "THREEFISH-1024");
+ }
+
+ private static void AddDefaultKeySizeEntries(int size, params string[] algorithms)
+ {
+ foreach (string algorithm in algorithms)
+ {
+ defaultKeySizes.Add(algorithm, size);
+ }
+ }
+
+ private static void AddKgAlgorithm(
+ string canonicalName,
+ params object[] aliases)
+ {
+ kgAlgorithms[canonicalName] = canonicalName;
+
+ foreach (object alias in aliases)
+ {
+ kgAlgorithms[alias.ToString()] = canonicalName;
+ }
+ }
+
+ private static void AddKpgAlgorithm(
+ string canonicalName,
+ params object[] aliases)
+ {
+ kpgAlgorithms[canonicalName] = canonicalName;
+
+ foreach (object alias in aliases)
+ {
+ kpgAlgorithms[alias.ToString()] = canonicalName;
+ }
+ }
+
+ private static void AddHMacKeyGenerator(
+ string algorithm,
+ params object[] aliases)
+ {
+ string mainName = "HMAC" + algorithm;
+
+ kgAlgorithms[mainName] = mainName;
+ kgAlgorithms["HMAC-" + algorithm] = mainName;
+ kgAlgorithms["HMAC/" + algorithm] = mainName;
+
+ foreach (object alias in aliases)
+ {
+ kgAlgorithms[alias.ToString()] = mainName;
+ }
+ }
+
+ // TODO Consider making this public
+ internal static string GetCanonicalKeyGeneratorAlgorithm(
+ string algorithm)
+ {
+ return (string) kgAlgorithms[Platform.ToUpperInvariant(algorithm)];
+ }
+
+ // TODO Consider making this public
+ internal static string GetCanonicalKeyPairGeneratorAlgorithm(
+ string algorithm)
+ {
+ return (string)kpgAlgorithms[Platform.ToUpperInvariant(algorithm)];
+ }
+
+ public static CipherKeyGenerator GetKeyGenerator(
+ DerObjectIdentifier oid)
+ {
+ return GetKeyGenerator(oid.Id);
+ }
+
+ public static CipherKeyGenerator GetKeyGenerator(
+ string algorithm)
+ {
+ string canonicalName = GetCanonicalKeyGeneratorAlgorithm(algorithm);
+
+ if (canonicalName == null)
+ throw new SecurityUtilityException("KeyGenerator " + algorithm + " not recognised.");
+
+ int defaultKeySize = FindDefaultKeySize(canonicalName);
+ if (defaultKeySize == -1)
+ throw new SecurityUtilityException("KeyGenerator " + algorithm
+ + " (" + canonicalName + ") not supported.");
+
+ if (canonicalName == "DES")
+ return new DesKeyGenerator(defaultKeySize);
+
+ if (canonicalName == "DESEDE" || canonicalName == "DESEDE3")
+ return new DesEdeKeyGenerator(defaultKeySize);
+
+ return new CipherKeyGenerator(defaultKeySize);
+ }
+
+ public static IAsymmetricCipherKeyPairGenerator GetKeyPairGenerator(
+ DerObjectIdentifier oid)
+ {
+ return GetKeyPairGenerator(oid.Id);
+ }
+
+ public static IAsymmetricCipherKeyPairGenerator GetKeyPairGenerator(
+ string algorithm)
+ {
+ string canonicalName = GetCanonicalKeyPairGeneratorAlgorithm(algorithm);
+
+ if (canonicalName == null)
+ throw new SecurityUtilityException("KeyPairGenerator " + algorithm + " not recognised.");
+
+ if (canonicalName == "DH")
+ return new DHKeyPairGenerator();
+
+ if (canonicalName == "DSA")
+ return new DsaKeyPairGenerator();
+
+ // "EC", "ECDH", "ECDHC", "ECDSA", "ECGOST3410", "ECMQV"
+ if (Platform.StartsWith(canonicalName, "EC"))
+ return new ECKeyPairGenerator(canonicalName);
+
+ if (canonicalName == "ELGAMAL")
+ return new ElGamalKeyPairGenerator();
+
+ if (canonicalName == "GOST3410")
+ return new Gost3410KeyPairGenerator();
+
+ if (canonicalName == "RSA")
+ return new RsaKeyPairGenerator();
+
+ throw new SecurityUtilityException("KeyPairGenerator " + algorithm
+ + " (" + canonicalName + ") not supported.");
+ }
+
+ internal static int GetDefaultKeySize(
+ DerObjectIdentifier oid)
+ {
+ return GetDefaultKeySize(oid.Id);
+ }
+
+ internal static int GetDefaultKeySize(
+ string algorithm)
+ {
+ string canonicalName = GetCanonicalKeyGeneratorAlgorithm(algorithm);
+
+ if (canonicalName == null)
+ throw new SecurityUtilityException("KeyGenerator " + algorithm + " not recognised.");
+
+ int defaultKeySize = FindDefaultKeySize(canonicalName);
+ if (defaultKeySize == -1)
+ throw new SecurityUtilityException("KeyGenerator " + algorithm
+ + " (" + canonicalName + ") not supported.");
+
+ return defaultKeySize;
+ }
+
+ private static int FindDefaultKeySize(
+ string canonicalName)
+ {
+ if (!defaultKeySizes.Contains(canonicalName))
+ return -1;
+
+ return (int)defaultKeySizes[canonicalName];
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/InvalidKeyException.cs b/bc-sharp-crypto/src/security/InvalidKeyException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ebad9e32f3d1a13da520282827489cee5fd0c417
--- /dev/null
+++ b/bc-sharp-crypto/src/security/InvalidKeyException.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class InvalidKeyException : KeyException
+ {
+ public InvalidKeyException() : base() { }
+ public InvalidKeyException(string message) : base(message) { }
+ public InvalidKeyException(string message, Exception exception) : base(message, exception) { }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/InvalidParameterException.cs b/bc-sharp-crypto/src/security/InvalidParameterException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..48172f470dafbd9e25501ae70c0c79bd23d5cd1e
--- /dev/null
+++ b/bc-sharp-crypto/src/security/InvalidParameterException.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class InvalidParameterException : KeyException
+ {
+ public InvalidParameterException() : base() { }
+ public InvalidParameterException(string message) : base(message) { }
+ public InvalidParameterException(string message, Exception exception) : base(message, exception) { }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/KeyException.cs b/bc-sharp-crypto/src/security/KeyException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e19fa8961121ee43e3801387008bd8c810d61a5b
--- /dev/null
+++ b/bc-sharp-crypto/src/security/KeyException.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class KeyException : GeneralSecurityException
+ {
+ public KeyException() : base() { }
+ public KeyException(string message) : base(message) { }
+ public KeyException(string message, Exception exception) : base(message, exception) { }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/MacUtilities.cs b/bc-sharp-crypto/src/security/MacUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..278f3bec1c9dc6c847e5230729d923da9ed860b7
--- /dev/null
+++ b/bc-sharp-crypto/src/security/MacUtilities.cs
@@ -0,0 +1,256 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Iana;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Security
+{
+ ///
+ /// Utility class for creating HMac object from their names/Oids
+ ///
+ public sealed class MacUtilities
+ {
+ private MacUtilities()
+ {
+ }
+
+ private static readonly IDictionary algorithms = Platform.CreateHashtable();
+ //private static readonly IDictionary oids = Platform.CreateHashtable();
+
+ static MacUtilities()
+ {
+ algorithms[IanaObjectIdentifiers.HmacMD5.Id] = "HMAC-MD5";
+ algorithms[IanaObjectIdentifiers.HmacRipeMD160.Id] = "HMAC-RIPEMD160";
+ algorithms[IanaObjectIdentifiers.HmacSha1.Id] = "HMAC-SHA1";
+ algorithms[IanaObjectIdentifiers.HmacTiger.Id] = "HMAC-TIGER";
+
+ algorithms[PkcsObjectIdentifiers.IdHmacWithSha1.Id] = "HMAC-SHA1";
+ algorithms[PkcsObjectIdentifiers.IdHmacWithSha224.Id] = "HMAC-SHA224";
+ algorithms[PkcsObjectIdentifiers.IdHmacWithSha256.Id] = "HMAC-SHA256";
+ algorithms[PkcsObjectIdentifiers.IdHmacWithSha384.Id] = "HMAC-SHA384";
+ algorithms[PkcsObjectIdentifiers.IdHmacWithSha512.Id] = "HMAC-SHA512";
+
+ // TODO AESMAC?
+
+ algorithms["DES"] = "DESMAC";
+ algorithms["DES/CFB8"] = "DESMAC/CFB8";
+ algorithms["DES64"] = "DESMAC64";
+ algorithms["DESEDE"] = "DESEDEMAC";
+ algorithms[PkcsObjectIdentifiers.DesEde3Cbc.Id] = "DESEDEMAC";
+ algorithms["DESEDE/CFB8"] = "DESEDEMAC/CFB8";
+ algorithms["DESISO9797MAC"] = "DESWITHISO9797";
+ algorithms["DESEDE64"] = "DESEDEMAC64";
+
+ algorithms["DESEDE64WITHISO7816-4PADDING"] = "DESEDEMAC64WITHISO7816-4PADDING";
+ algorithms["DESEDEISO9797ALG1MACWITHISO7816-4PADDING"] = "DESEDEMAC64WITHISO7816-4PADDING";
+ algorithms["DESEDEISO9797ALG1WITHISO7816-4PADDING"] = "DESEDEMAC64WITHISO7816-4PADDING";
+
+ algorithms["ISO9797ALG3"] = "ISO9797ALG3MAC";
+ algorithms["ISO9797ALG3MACWITHISO7816-4PADDING"] = "ISO9797ALG3WITHISO7816-4PADDING";
+
+ algorithms["SKIPJACK"] = "SKIPJACKMAC";
+ algorithms["SKIPJACK/CFB8"] = "SKIPJACKMAC/CFB8";
+ algorithms["IDEA"] = "IDEAMAC";
+ algorithms["IDEA/CFB8"] = "IDEAMAC/CFB8";
+ algorithms["RC2"] = "RC2MAC";
+ algorithms["RC2/CFB8"] = "RC2MAC/CFB8";
+ algorithms["RC5"] = "RC5MAC";
+ algorithms["RC5/CFB8"] = "RC5MAC/CFB8";
+ algorithms["GOST28147"] = "GOST28147MAC";
+ algorithms["VMPC"] = "VMPCMAC";
+ algorithms["VMPC-MAC"] = "VMPCMAC";
+ algorithms["SIPHASH"] = "SIPHASH-2-4";
+
+ algorithms["PBEWITHHMACSHA"] = "PBEWITHHMACSHA1";
+ algorithms["1.3.14.3.2.26"] = "PBEWITHHMACSHA1";
+ }
+
+// ///
+// /// Returns a ObjectIdentifier for a given digest mechanism.
+// ///
+// /// A string representation of the digest meanism.
+// /// A DerObjectIdentifier, null if the Oid is not available.
+// public static DerObjectIdentifier GetObjectIdentifier(
+// string mechanism)
+// {
+// mechanism = (string) algorithms[Platform.ToUpperInvariant(mechanism)];
+//
+// if (mechanism != null)
+// {
+// return (DerObjectIdentifier)oids[mechanism];
+// }
+//
+// return null;
+// }
+
+// public static ICollection Algorithms
+// {
+// get { return oids.Keys; }
+// }
+
+ public static IMac GetMac(
+ DerObjectIdentifier id)
+ {
+ return GetMac(id.Id);
+ }
+
+ public static IMac GetMac(
+ string algorithm)
+ {
+ string upper = Platform.ToUpperInvariant(algorithm);
+
+ string mechanism = (string) algorithms[upper];
+
+ if (mechanism == null)
+ {
+ mechanism = upper;
+ }
+
+ if (Platform.StartsWith(mechanism, "PBEWITH"))
+ {
+ mechanism = mechanism.Substring("PBEWITH".Length);
+ }
+
+ if (Platform.StartsWith(mechanism, "HMAC"))
+ {
+ string digestName;
+ if (Platform.StartsWith(mechanism, "HMAC-") || Platform.StartsWith(mechanism, "HMAC/"))
+ {
+ digestName = mechanism.Substring(5);
+ }
+ else
+ {
+ digestName = mechanism.Substring(4);
+ }
+
+ return new HMac(DigestUtilities.GetDigest(digestName));
+ }
+
+ if (mechanism == "AESCMAC")
+ {
+ return new CMac(new AesEngine());
+ }
+ if (mechanism == "DESMAC")
+ {
+ return new CbcBlockCipherMac(new DesEngine());
+ }
+ if (mechanism == "DESMAC/CFB8")
+ {
+ return new CfbBlockCipherMac(new DesEngine());
+ }
+ if (mechanism == "DESMAC64")
+ {
+ return new CbcBlockCipherMac(new DesEngine(), 64);
+ }
+ if (mechanism == "DESEDECMAC")
+ {
+ return new CMac(new DesEdeEngine());
+ }
+ if (mechanism == "DESEDEMAC")
+ {
+ return new CbcBlockCipherMac(new DesEdeEngine());
+ }
+ if (mechanism == "DESEDEMAC/CFB8")
+ {
+ return new CfbBlockCipherMac(new DesEdeEngine());
+ }
+ if (mechanism == "DESEDEMAC64")
+ {
+ return new CbcBlockCipherMac(new DesEdeEngine(), 64);
+ }
+ if (mechanism == "DESEDEMAC64WITHISO7816-4PADDING")
+ {
+ return new CbcBlockCipherMac(new DesEdeEngine(), 64, new ISO7816d4Padding());
+ }
+ if (mechanism == "DESWITHISO9797"
+ || mechanism == "ISO9797ALG3MAC")
+ {
+ return new ISO9797Alg3Mac(new DesEngine());
+ }
+ if (mechanism == "ISO9797ALG3WITHISO7816-4PADDING")
+ {
+ return new ISO9797Alg3Mac(new DesEngine(), new ISO7816d4Padding());
+ }
+ if (mechanism == "SKIPJACKMAC")
+ {
+ return new CbcBlockCipherMac(new SkipjackEngine());
+ }
+ if (mechanism == "SKIPJACKMAC/CFB8")
+ {
+ return new CfbBlockCipherMac(new SkipjackEngine());
+ }
+ if (mechanism == "IDEAMAC")
+ {
+ return new CbcBlockCipherMac(new IdeaEngine());
+ }
+ if (mechanism == "IDEAMAC/CFB8")
+ {
+ return new CfbBlockCipherMac(new IdeaEngine());
+ }
+ if (mechanism == "RC2MAC")
+ {
+ return new CbcBlockCipherMac(new RC2Engine());
+ }
+ if (mechanism == "RC2MAC/CFB8")
+ {
+ return new CfbBlockCipherMac(new RC2Engine());
+ }
+ if (mechanism == "RC5MAC")
+ {
+ return new CbcBlockCipherMac(new RC532Engine());
+ }
+ if (mechanism == "RC5MAC/CFB8")
+ {
+ return new CfbBlockCipherMac(new RC532Engine());
+ }
+ if (mechanism == "GOST28147MAC")
+ {
+ return new Gost28147Mac();
+ }
+ if (mechanism == "VMPCMAC")
+ {
+ return new VmpcMac();
+ }
+ if (mechanism == "SIPHASH-2-4")
+ {
+ return new SipHash();
+ }
+ throw new SecurityUtilityException("Mac " + mechanism + " not recognised.");
+ }
+
+ public static string GetAlgorithmName(
+ DerObjectIdentifier oid)
+ {
+ return (string) algorithms[oid.Id];
+ }
+
+ public static byte[] CalculateMac(string algorithm, ICipherParameters cp, byte[] input)
+ {
+ IMac mac = GetMac(algorithm);
+ mac.Init(cp);
+ mac.BlockUpdate(input, 0, input.Length);
+ return DoFinal(mac);
+ }
+
+ public static byte[] DoFinal(IMac mac)
+ {
+ byte[] b = new byte[mac.GetMacSize()];
+ mac.DoFinal(b, 0);
+ return b;
+ }
+
+ public static byte[] DoFinal(IMac mac, byte[] input)
+ {
+ mac.BlockUpdate(input, 0, input.Length);
+ return DoFinal(mac);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/NoSuchAlgorithmException.cs b/bc-sharp-crypto/src/security/NoSuchAlgorithmException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c56ec651e20606ec0863356e1727a9ec5b5f1340
--- /dev/null
+++ b/bc-sharp-crypto/src/security/NoSuchAlgorithmException.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+ [Obsolete("Never thrown")]
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class NoSuchAlgorithmException : GeneralSecurityException
+ {
+ public NoSuchAlgorithmException() : base() {}
+ public NoSuchAlgorithmException(string message) : base(message) {}
+ public NoSuchAlgorithmException(string message, Exception exception) : base(message, exception) {}
+ }
+}
diff --git a/bc-sharp-crypto/src/security/ParameterUtilities.cs b/bc-sharp-crypto/src/security/ParameterUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c12155878890d6e32f4e45ba48837f98dcc531dc
--- /dev/null
+++ b/bc-sharp-crypto/src/security/ParameterUtilities.cs
@@ -0,0 +1,325 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Kisa;
+using Org.BouncyCastle.Asn1.Misc;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Ntt;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Security
+{
+ public sealed class ParameterUtilities
+ {
+ private ParameterUtilities()
+ {
+ }
+
+ private static readonly IDictionary algorithms = Platform.CreateHashtable();
+ private static readonly IDictionary basicIVSizes = Platform.CreateHashtable();
+
+ static ParameterUtilities()
+ {
+ AddAlgorithm("AES",
+ "AESWRAP");
+ AddAlgorithm("AES128",
+ "2.16.840.1.101.3.4.2",
+ NistObjectIdentifiers.IdAes128Cbc,
+ NistObjectIdentifiers.IdAes128Cfb,
+ NistObjectIdentifiers.IdAes128Ecb,
+ NistObjectIdentifiers.IdAes128Ofb,
+ NistObjectIdentifiers.IdAes128Wrap);
+ AddAlgorithm("AES192",
+ "2.16.840.1.101.3.4.22",
+ NistObjectIdentifiers.IdAes192Cbc,
+ NistObjectIdentifiers.IdAes192Cfb,
+ NistObjectIdentifiers.IdAes192Ecb,
+ NistObjectIdentifiers.IdAes192Ofb,
+ NistObjectIdentifiers.IdAes192Wrap);
+ AddAlgorithm("AES256",
+ "2.16.840.1.101.3.4.42",
+ NistObjectIdentifiers.IdAes256Cbc,
+ NistObjectIdentifiers.IdAes256Cfb,
+ NistObjectIdentifiers.IdAes256Ecb,
+ NistObjectIdentifiers.IdAes256Ofb,
+ NistObjectIdentifiers.IdAes256Wrap);
+ AddAlgorithm("BLOWFISH",
+ "1.3.6.1.4.1.3029.1.2");
+ AddAlgorithm("CAMELLIA",
+ "CAMELLIAWRAP");
+ AddAlgorithm("CAMELLIA128",
+ NttObjectIdentifiers.IdCamellia128Cbc,
+ NttObjectIdentifiers.IdCamellia128Wrap);
+ AddAlgorithm("CAMELLIA192",
+ NttObjectIdentifiers.IdCamellia192Cbc,
+ NttObjectIdentifiers.IdCamellia192Wrap);
+ AddAlgorithm("CAMELLIA256",
+ NttObjectIdentifiers.IdCamellia256Cbc,
+ NttObjectIdentifiers.IdCamellia256Wrap);
+ AddAlgorithm("CAST5",
+ "1.2.840.113533.7.66.10");
+ AddAlgorithm("CAST6");
+ AddAlgorithm("DES",
+ OiwObjectIdentifiers.DesCbc,
+ OiwObjectIdentifiers.DesCfb,
+ OiwObjectIdentifiers.DesEcb,
+ OiwObjectIdentifiers.DesOfb);
+ AddAlgorithm("DESEDE",
+ "DESEDEWRAP",
+ "TDEA",
+ OiwObjectIdentifiers.DesEde,
+ PkcsObjectIdentifiers.IdAlgCms3DesWrap);
+ AddAlgorithm("DESEDE3",
+ PkcsObjectIdentifiers.DesEde3Cbc);
+ AddAlgorithm("GOST28147",
+ "GOST",
+ "GOST-28147",
+ CryptoProObjectIdentifiers.GostR28147Cbc);
+ AddAlgorithm("HC128");
+ AddAlgorithm("HC256");
+ AddAlgorithm("IDEA",
+ "1.3.6.1.4.1.188.7.1.1.2");
+ AddAlgorithm("NOEKEON");
+ AddAlgorithm("RC2",
+ PkcsObjectIdentifiers.RC2Cbc,
+ PkcsObjectIdentifiers.IdAlgCmsRC2Wrap);
+ AddAlgorithm("RC4",
+ "ARC4",
+ "1.2.840.113549.3.4");
+ AddAlgorithm("RC5",
+ "RC5-32");
+ AddAlgorithm("RC5-64");
+ AddAlgorithm("RC6");
+ AddAlgorithm("RIJNDAEL");
+ AddAlgorithm("SALSA20");
+ AddAlgorithm("SEED",
+ KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap,
+ KisaObjectIdentifiers.IdSeedCbc);
+ AddAlgorithm("SERPENT");
+ AddAlgorithm("SKIPJACK");
+ AddAlgorithm("TEA");
+ AddAlgorithm("THREEFISH-256");
+ AddAlgorithm("THREEFISH-512");
+ AddAlgorithm("THREEFISH-1024");
+ AddAlgorithm("TNEPRES");
+ AddAlgorithm("TWOFISH");
+ AddAlgorithm("VMPC");
+ AddAlgorithm("VMPC-KSA3");
+ AddAlgorithm("XTEA");
+
+ AddBasicIVSizeEntries(8, "BLOWFISH", "DES", "DESEDE", "DESEDE3");
+ AddBasicIVSizeEntries(16, "AES", "AES128", "AES192", "AES256",
+ "CAMELLIA", "CAMELLIA128", "CAMELLIA192", "CAMELLIA256", "NOEKEON", "SEED");
+
+ // TODO These algorithms support an IV
+ // but JCE doesn't seem to provide an AlgorithmParametersGenerator for them
+ // "RIJNDAEL", "SKIPJACK", "TWOFISH"
+ }
+
+ private static void AddAlgorithm(
+ string canonicalName,
+ params object[] aliases)
+ {
+ algorithms[canonicalName] = canonicalName;
+
+ foreach (object alias in aliases)
+ {
+ algorithms[alias.ToString()] = canonicalName;
+ }
+ }
+
+ private static void AddBasicIVSizeEntries(int size, params string[] algorithms)
+ {
+ foreach (string algorithm in algorithms)
+ {
+ basicIVSizes.Add(algorithm, size);
+ }
+ }
+
+ public static string GetCanonicalAlgorithmName(
+ string algorithm)
+ {
+ return (string) algorithms[Platform.ToUpperInvariant(algorithm)];
+ }
+
+ public static KeyParameter CreateKeyParameter(
+ DerObjectIdentifier algOid,
+ byte[] keyBytes)
+ {
+ return CreateKeyParameter(algOid.Id, keyBytes, 0, keyBytes.Length);
+ }
+
+ public static KeyParameter CreateKeyParameter(
+ string algorithm,
+ byte[] keyBytes)
+ {
+ return CreateKeyParameter(algorithm, keyBytes, 0, keyBytes.Length);
+ }
+
+ public static KeyParameter CreateKeyParameter(
+ DerObjectIdentifier algOid,
+ byte[] keyBytes,
+ int offset,
+ int length)
+ {
+ return CreateKeyParameter(algOid.Id, keyBytes, offset, length);
+ }
+
+ public static KeyParameter CreateKeyParameter(
+ string algorithm,
+ byte[] keyBytes,
+ int offset,
+ int length)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+
+ string canonical = GetCanonicalAlgorithmName(algorithm);
+
+ if (canonical == null)
+ throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
+
+ if (canonical == "DES")
+ return new DesParameters(keyBytes, offset, length);
+
+ if (canonical == "DESEDE" || canonical =="DESEDE3")
+ return new DesEdeParameters(keyBytes, offset, length);
+
+ if (canonical == "RC2")
+ return new RC2Parameters(keyBytes, offset, length);
+
+ return new KeyParameter(keyBytes, offset, length);
+ }
+
+ public static ICipherParameters GetCipherParameters(
+ DerObjectIdentifier algOid,
+ ICipherParameters key,
+ Asn1Object asn1Params)
+ {
+ return GetCipherParameters(algOid.Id, key, asn1Params);
+ }
+
+ public static ICipherParameters GetCipherParameters(
+ string algorithm,
+ ICipherParameters key,
+ Asn1Object asn1Params)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+
+ string canonical = GetCanonicalAlgorithmName(algorithm);
+
+ if (canonical == null)
+ throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
+
+ byte[] iv = null;
+
+ try
+ {
+ // TODO These algorithms support an IV
+ // but JCE doesn't seem to provide an AlgorithmParametersGenerator for them
+ // "RIJNDAEL", "SKIPJACK", "TWOFISH"
+
+ int basicIVKeySize = FindBasicIVSize(canonical);
+ if (basicIVKeySize != -1
+ || canonical == "RIJNDAEL" || canonical == "SKIPJACK" || canonical == "TWOFISH")
+ {
+ iv = ((Asn1OctetString) asn1Params).GetOctets();
+ }
+ else if (canonical == "CAST5")
+ {
+ iv = Cast5CbcParameters.GetInstance(asn1Params).GetIV();
+ }
+ else if (canonical == "IDEA")
+ {
+ iv = IdeaCbcPar.GetInstance(asn1Params).GetIV();
+ }
+ else if (canonical == "RC2")
+ {
+ iv = RC2CbcParameter.GetInstance(asn1Params).GetIV();
+ }
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("Could not process ASN.1 parameters", e);
+ }
+
+ if (iv != null)
+ {
+ return new ParametersWithIV(key, iv);
+ }
+
+ throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
+ }
+
+ public static Asn1Encodable GenerateParameters(
+ DerObjectIdentifier algID,
+ SecureRandom random)
+ {
+ return GenerateParameters(algID.Id, random);
+ }
+
+ public static Asn1Encodable GenerateParameters(
+ string algorithm,
+ SecureRandom random)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+
+ string canonical = GetCanonicalAlgorithmName(algorithm);
+
+ if (canonical == null)
+ throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
+
+ // TODO These algorithms support an IV
+ // but JCE doesn't seem to provide an AlgorithmParametersGenerator for them
+ // "RIJNDAEL", "SKIPJACK", "TWOFISH"
+
+ int basicIVKeySize = FindBasicIVSize(canonical);
+ if (basicIVKeySize != -1)
+ return CreateIVOctetString(random, basicIVKeySize);
+
+ if (canonical == "CAST5")
+ return new Cast5CbcParameters(CreateIV(random, 8), 128);
+
+ if (canonical == "IDEA")
+ return new IdeaCbcPar(CreateIV(random, 8));
+
+ if (canonical == "RC2")
+ return new RC2CbcParameter(CreateIV(random, 8));
+
+ throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
+ }
+
+ private static Asn1OctetString CreateIVOctetString(
+ SecureRandom random,
+ int ivLength)
+ {
+ return new DerOctetString(CreateIV(random, ivLength));
+ }
+
+ private static byte[] CreateIV(
+ SecureRandom random,
+ int ivLength)
+ {
+ byte[] iv = new byte[ivLength];
+ random.NextBytes(iv);
+ return iv;
+ }
+
+ private static int FindBasicIVSize(
+ string canonicalName)
+ {
+ if (!basicIVSizes.Contains(canonicalName))
+ return -1;
+
+ return (int)basicIVSizes[canonicalName];
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/PbeUtilities.cs b/bc-sharp-crypto/src/security/PbeUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..33f31e5b4892cb6f6822b6419e308a198d4a2f33
--- /dev/null
+++ b/bc-sharp-crypto/src/security/PbeUtilities.cs
@@ -0,0 +1,663 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.BC;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Security
+{
+ ///
+ ///
+ ///
+ public sealed class PbeUtilities
+ {
+ private PbeUtilities()
+ {
+ }
+
+ const string Pkcs5S1 = "Pkcs5S1";
+ const string Pkcs5S2 = "Pkcs5S2";
+ const string Pkcs12 = "Pkcs12";
+ const string OpenSsl = "OpenSsl";
+
+ private static readonly IDictionary algorithms = Platform.CreateHashtable();
+ private static readonly IDictionary algorithmType = Platform.CreateHashtable();
+ private static readonly IDictionary oids = Platform.CreateHashtable();
+
+ static PbeUtilities()
+ {
+ algorithms["PKCS5SCHEME1"] = "Pkcs5scheme1";
+ algorithms["PKCS5SCHEME2"] = "Pkcs5scheme2";
+ algorithms[PkcsObjectIdentifiers.IdPbeS2.Id] = "Pkcs5scheme2";
+// algorithms[PkcsObjectIdentifiers.IdPbkdf2.Id] = "Pkcs5scheme2";
+
+ // FIXME Add support for these? (see Pkcs8Generator)
+// algorithms[PkcsObjectIdentifiers.DesEde3Cbc.Id] = "Pkcs5scheme2";
+// algorithms[NistObjectIdentifiers.IdAes128Cbc.Id] = "Pkcs5scheme2";
+// algorithms[NistObjectIdentifiers.IdAes192Cbc.Id] = "Pkcs5scheme2";
+// algorithms[NistObjectIdentifiers.IdAes256Cbc.Id] = "Pkcs5scheme2";
+
+ algorithms["PBEWITHMD2ANDDES-CBC"] = "PBEwithMD2andDES-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithMD2AndDesCbc.Id] = "PBEwithMD2andDES-CBC";
+ algorithms["PBEWITHMD2ANDRC2-CBC"] = "PBEwithMD2andRC2-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithMD2AndRC2Cbc.Id] = "PBEwithMD2andRC2-CBC";
+ algorithms["PBEWITHMD5ANDDES-CBC"] = "PBEwithMD5andDES-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithMD5AndDesCbc.Id] = "PBEwithMD5andDES-CBC";
+ algorithms["PBEWITHMD5ANDRC2-CBC"] = "PBEwithMD5andRC2-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithMD5AndRC2Cbc.Id] = "PBEwithMD5andRC2-CBC";
+ algorithms["PBEWITHSHA1ANDDES"] = "PBEwithSHA-1andDES-CBC";
+ algorithms["PBEWITHSHA-1ANDDES"] = "PBEwithSHA-1andDES-CBC";
+ algorithms["PBEWITHSHA1ANDDES-CBC"] = "PBEwithSHA-1andDES-CBC";
+ algorithms["PBEWITHSHA-1ANDDES-CBC"] = "PBEwithSHA-1andDES-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithSha1AndDesCbc.Id] = "PBEwithSHA-1andDES-CBC";
+ algorithms["PBEWITHSHA1ANDRC2"] = "PBEwithSHA-1andRC2-CBC";
+ algorithms["PBEWITHSHA-1ANDRC2"] = "PBEwithSHA-1andRC2-CBC";
+ algorithms["PBEWITHSHA1ANDRC2-CBC"] = "PBEwithSHA-1andRC2-CBC";
+ algorithms["PBEWITHSHA-1ANDRC2-CBC"] = "PBEwithSHA-1andRC2-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithSha1AndRC2Cbc.Id] = "PBEwithSHA-1andRC2-CBC";
+ algorithms["PKCS12"] = "Pkcs12";
+ algorithms[BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.Id] = "PBEwithSHA-1and128bitAES-CBC-BC";
+ algorithms[BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.Id] = "PBEwithSHA-1and192bitAES-CBC-BC";
+ algorithms[BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc.Id] = "PBEwithSHA-1and256bitAES-CBC-BC";
+ algorithms[BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.Id] = "PBEwithSHA-256and128bitAES-CBC-BC";
+ algorithms[BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.Id] = "PBEwithSHA-256and192bitAES-CBC-BC";
+ algorithms[BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.Id] = "PBEwithSHA-256and256bitAES-CBC-BC";
+ algorithms["PBEWITHSHAAND128BITRC4"] = "PBEwithSHA-1and128bitRC4";
+ algorithms["PBEWITHSHA1AND128BITRC4"] = "PBEwithSHA-1and128bitRC4";
+ algorithms["PBEWITHSHA-1AND128BITRC4"] = "PBEwithSHA-1and128bitRC4";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC4.Id] = "PBEwithSHA-1and128bitRC4";
+ algorithms["PBEWITHSHAAND40BITRC4"] = "PBEwithSHA-1and40bitRC4";
+ algorithms["PBEWITHSHA1AND40BITRC4"] = "PBEwithSHA-1and40bitRC4";
+ algorithms["PBEWITHSHA-1AND40BITRC4"] = "PBEwithSHA-1and40bitRC4";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd40BitRC4.Id] = "PBEwithSHA-1and40bitRC4";
+ algorithms["PBEWITHSHAAND3-KEYDESEDE-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+ algorithms["PBEWITHSHAAND3-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+ algorithms["PBEWITHSHA1AND3-KEYDESEDE-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+ algorithms["PBEWITHSHA1AND3-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+ algorithms["PBEWITHSHA-1AND3-KEYDESEDE-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+ algorithms["PBEWITHSHA-1AND3-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc.Id] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+ algorithms["PBEWITHSHAAND2-KEYDESEDE-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+ algorithms["PBEWITHSHAAND2-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+ algorithms["PBEWITHSHA1AND2-KEYDESEDE-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+ algorithms["PBEWITHSHA1AND2-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+ algorithms["PBEWITHSHA-1AND2-KEYDESEDE-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+ algorithms["PBEWITHSHA-1AND2-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd2KeyTripleDesCbc.Id] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+ algorithms["PBEWITHSHAAND128BITRC2-CBC"] = "PBEwithSHA-1and128bitRC2-CBC";
+ algorithms["PBEWITHSHA1AND128BITRC2-CBC"] = "PBEwithSHA-1and128bitRC2-CBC";
+ algorithms["PBEWITHSHA-1AND128BITRC2-CBC"] = "PBEwithSHA-1and128bitRC2-CBC";
+ algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC2Cbc.Id] = "PBEwithSHA-1and128bitRC2-CBC";
+ algorithms["PBEWITHSHAAND40BITRC2-CBC"] = "PBEwithSHA-1and40bitRC2-CBC";
+ algorithms["PBEWITHSHA1AND40BITRC2-CBC"] = "PBEwithSHA-1and40bitRC2-CBC";
+ algorithms["PBEWITHSHA-1AND40BITRC2-CBC"] = "PBEwithSHA-1and40bitRC2-CBC";
+ algorithms[PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc.Id] = "PBEwithSHA-1and40bitRC2-CBC";
+ algorithms["PBEWITHSHAAND128BITAES-CBC-BC"] = "PBEwithSHA-1and128bitAES-CBC-BC";
+ algorithms["PBEWITHSHA1AND128BITAES-CBC-BC"] = "PBEwithSHA-1and128bitAES-CBC-BC";
+ algorithms["PBEWITHSHA-1AND128BITAES-CBC-BC"] = "PBEwithSHA-1and128bitAES-CBC-BC";
+ algorithms["PBEWITHSHAAND192BITAES-CBC-BC"] = "PBEwithSHA-1and192bitAES-CBC-BC";
+ algorithms["PBEWITHSHA1AND192BITAES-CBC-BC"] = "PBEwithSHA-1and192bitAES-CBC-BC";
+ algorithms["PBEWITHSHA-1AND192BITAES-CBC-BC"] = "PBEwithSHA-1and192bitAES-CBC-BC";
+ algorithms["PBEWITHSHAAND256BITAES-CBC-BC"] = "PBEwithSHA-1and256bitAES-CBC-BC";
+ algorithms["PBEWITHSHA1AND256BITAES-CBC-BC"] = "PBEwithSHA-1and256bitAES-CBC-BC";
+ algorithms["PBEWITHSHA-1AND256BITAES-CBC-BC"] = "PBEwithSHA-1and256bitAES-CBC-BC";
+ algorithms["PBEWITHSHA256AND128BITAES-CBC-BC"] = "PBEwithSHA-256and128bitAES-CBC-BC";
+ algorithms["PBEWITHSHA-256AND128BITAES-CBC-BC"] = "PBEwithSHA-256and128bitAES-CBC-BC";
+ algorithms["PBEWITHSHA256AND192BITAES-CBC-BC"] = "PBEwithSHA-256and192bitAES-CBC-BC";
+ algorithms["PBEWITHSHA-256AND192BITAES-CBC-BC"] = "PBEwithSHA-256and192bitAES-CBC-BC";
+ algorithms["PBEWITHSHA256AND256BITAES-CBC-BC"] = "PBEwithSHA-256and256bitAES-CBC-BC";
+ algorithms["PBEWITHSHA-256AND256BITAES-CBC-BC"] = "PBEwithSHA-256and256bitAES-CBC-BC";
+ algorithms["PBEWITHSHAANDIDEA"] = "PBEwithSHA-1andIDEA-CBC";
+ algorithms["PBEWITHSHAANDIDEA-CBC"] = "PBEwithSHA-1andIDEA-CBC";
+ algorithms["PBEWITHSHAANDTWOFISH"] = "PBEwithSHA-1andTWOFISH-CBC";
+ algorithms["PBEWITHSHAANDTWOFISH-CBC"] = "PBEwithSHA-1andTWOFISH-CBC";
+ algorithms["PBEWITHHMACSHA1"] = "PBEwithHmacSHA-1";
+ algorithms["PBEWITHHMACSHA-1"] = "PBEwithHmacSHA-1";
+ algorithms[OiwObjectIdentifiers.IdSha1.Id] = "PBEwithHmacSHA-1";
+ algorithms["PBEWITHHMACSHA224"] = "PBEwithHmacSHA-224";
+ algorithms["PBEWITHHMACSHA-224"] = "PBEwithHmacSHA-224";
+ algorithms[NistObjectIdentifiers.IdSha224.Id] = "PBEwithHmacSHA-224";
+ algorithms["PBEWITHHMACSHA256"] = "PBEwithHmacSHA-256";
+ algorithms["PBEWITHHMACSHA-256"] = "PBEwithHmacSHA-256";
+ algorithms[NistObjectIdentifiers.IdSha256.Id] = "PBEwithHmacSHA-256";
+ algorithms["PBEWITHHMACRIPEMD128"] = "PBEwithHmacRipeMD128";
+ algorithms[TeleTrusTObjectIdentifiers.RipeMD128.Id] = "PBEwithHmacRipeMD128";
+ algorithms["PBEWITHHMACRIPEMD160"] = "PBEwithHmacRipeMD160";
+ algorithms[TeleTrusTObjectIdentifiers.RipeMD160.Id] = "PBEwithHmacRipeMD160";
+ algorithms["PBEWITHHMACRIPEMD256"] = "PBEwithHmacRipeMD256";
+ algorithms[TeleTrusTObjectIdentifiers.RipeMD256.Id] = "PBEwithHmacRipeMD256";
+ algorithms["PBEWITHHMACTIGER"] = "PBEwithHmacTiger";
+
+ algorithms["PBEWITHMD5AND128BITAES-CBC-OPENSSL"] = "PBEwithMD5and128bitAES-CBC-OpenSSL";
+ algorithms["PBEWITHMD5AND192BITAES-CBC-OPENSSL"] = "PBEwithMD5and192bitAES-CBC-OpenSSL";
+ algorithms["PBEWITHMD5AND256BITAES-CBC-OPENSSL"] = "PBEwithMD5and256bitAES-CBC-OpenSSL";
+
+ algorithmType["Pkcs5scheme1"] = Pkcs5S1;
+ algorithmType["Pkcs5scheme2"] = Pkcs5S2;
+ algorithmType["PBEwithMD2andDES-CBC"] = Pkcs5S1;
+ algorithmType["PBEwithMD2andRC2-CBC"] = Pkcs5S1;
+ algorithmType["PBEwithMD5andDES-CBC"] = Pkcs5S1;
+ algorithmType["PBEwithMD5andRC2-CBC"] = Pkcs5S1;
+ algorithmType["PBEwithSHA-1andDES-CBC"] = Pkcs5S1;
+ algorithmType["PBEwithSHA-1andRC2-CBC"] = Pkcs5S1;
+ algorithmType["Pkcs12"] = Pkcs12;
+ algorithmType["PBEwithSHA-1and128bitRC4"] = Pkcs12;
+ algorithmType["PBEwithSHA-1and40bitRC4"] = Pkcs12;
+ algorithmType["PBEwithSHA-1and3-keyDESEDE-CBC"] = Pkcs12;
+ algorithmType["PBEwithSHA-1and2-keyDESEDE-CBC"] = Pkcs12;
+ algorithmType["PBEwithSHA-1and128bitRC2-CBC"] = Pkcs12;
+ algorithmType["PBEwithSHA-1and40bitRC2-CBC"] = Pkcs12;
+ algorithmType["PBEwithSHA-1and128bitAES-CBC-BC"] = Pkcs12;
+ algorithmType["PBEwithSHA-1and192bitAES-CBC-BC"] = Pkcs12;
+ algorithmType["PBEwithSHA-1and256bitAES-CBC-BC"] = Pkcs12;
+ algorithmType["PBEwithSHA-256and128bitAES-CBC-BC"] = Pkcs12;
+ algorithmType["PBEwithSHA-256and192bitAES-CBC-BC"] = Pkcs12;
+ algorithmType["PBEwithSHA-256and256bitAES-CBC-BC"] = Pkcs12;
+ algorithmType["PBEwithSHA-1andIDEA-CBC"] = Pkcs12;
+ algorithmType["PBEwithSHA-1andTWOFISH-CBC"] = Pkcs12;
+ algorithmType["PBEwithHmacSHA-1"] = Pkcs12;
+ algorithmType["PBEwithHmacSHA-224"] = Pkcs12;
+ algorithmType["PBEwithHmacSHA-256"] = Pkcs12;
+ algorithmType["PBEwithHmacRipeMD128"] = Pkcs12;
+ algorithmType["PBEwithHmacRipeMD160"] = Pkcs12;
+ algorithmType["PBEwithHmacRipeMD256"] = Pkcs12;
+ algorithmType["PBEwithHmacTiger"] = Pkcs12;
+
+ algorithmType["PBEwithMD5and128bitAES-CBC-OpenSSL"] = OpenSsl;
+ algorithmType["PBEwithMD5and192bitAES-CBC-OpenSSL"] = OpenSsl;
+ algorithmType["PBEwithMD5and256bitAES-CBC-OpenSSL"] = OpenSsl;
+
+ oids["PBEwithMD2andDES-CBC"] = PkcsObjectIdentifiers.PbeWithMD2AndDesCbc;
+ oids["PBEwithMD2andRC2-CBC"] = PkcsObjectIdentifiers.PbeWithMD2AndRC2Cbc;
+ oids["PBEwithMD5andDES-CBC"] = PkcsObjectIdentifiers.PbeWithMD5AndDesCbc;
+ oids["PBEwithMD5andRC2-CBC"] = PkcsObjectIdentifiers.PbeWithMD5AndRC2Cbc;
+ oids["PBEwithSHA-1andDES-CBC"] = PkcsObjectIdentifiers.PbeWithSha1AndDesCbc;
+ oids["PBEwithSHA-1andRC2-CBC"] = PkcsObjectIdentifiers.PbeWithSha1AndRC2Cbc;
+ oids["PBEwithSHA-1and128bitRC4"] = PkcsObjectIdentifiers.PbeWithShaAnd128BitRC4;
+ oids["PBEwithSHA-1and40bitRC4"] = PkcsObjectIdentifiers.PbeWithShaAnd40BitRC4;
+ oids["PBEwithSHA-1and3-keyDESEDE-CBC"] = PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc;
+ oids["PBEwithSHA-1and2-keyDESEDE-CBC"] = PkcsObjectIdentifiers.PbeWithShaAnd2KeyTripleDesCbc;
+ oids["PBEwithSHA-1and128bitRC2-CBC"] = PkcsObjectIdentifiers.PbeWithShaAnd128BitRC2Cbc;
+ oids["PBEwithSHA-1and40bitRC2-CBC"] = PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc;
+ oids["PBEwithHmacSHA-1"] = OiwObjectIdentifiers.IdSha1;
+ oids["PBEwithHmacSHA-224"] = NistObjectIdentifiers.IdSha224;
+ oids["PBEwithHmacSHA-256"] = NistObjectIdentifiers.IdSha256;
+ oids["PBEwithHmacRipeMD128"] = TeleTrusTObjectIdentifiers.RipeMD128;
+ oids["PBEwithHmacRipeMD160"] = TeleTrusTObjectIdentifiers.RipeMD160;
+ oids["PBEwithHmacRipeMD256"] = TeleTrusTObjectIdentifiers.RipeMD256;
+ oids["Pkcs5scheme2"] = PkcsObjectIdentifiers.IdPbeS2;
+ }
+
+ static PbeParametersGenerator MakePbeGenerator(
+ string type,
+ IDigest digest,
+ byte[] key,
+ byte[] salt,
+ int iterationCount)
+ {
+ PbeParametersGenerator generator;
+
+ if (type.Equals(Pkcs5S1))
+ {
+ generator = new Pkcs5S1ParametersGenerator(digest);
+ }
+ else if (type.Equals(Pkcs5S2))
+ {
+ generator = new Pkcs5S2ParametersGenerator();
+ }
+ else if (type.Equals(Pkcs12))
+ {
+ generator = new Pkcs12ParametersGenerator(digest);
+ }
+ else if (type.Equals(OpenSsl))
+ {
+ generator = new OpenSslPbeParametersGenerator();
+ }
+ else
+ {
+ throw new ArgumentException("Unknown PBE type: " + type, "type");
+ }
+
+ generator.Init(key, salt, iterationCount);
+ return generator;
+ }
+
+ ///
+ /// Returns a ObjectIdentifier for a give encoding.
+ ///
+ /// A string representation of the encoding.
+ /// A DerObjectIdentifier, null if the Oid is not available.
+ public static DerObjectIdentifier GetObjectIdentifier(
+ string mechanism)
+ {
+ mechanism = (string) algorithms[Platform.ToUpperInvariant(mechanism)];
+ if (mechanism != null)
+ {
+ return (DerObjectIdentifier)oids[mechanism];
+ }
+ return null;
+ }
+
+ public static ICollection Algorithms
+ {
+ get { return oids.Keys; }
+ }
+
+ public static bool IsPkcs12(
+ string algorithm)
+ {
+ string mechanism = (string)algorithms[Platform.ToUpperInvariant(algorithm)];
+
+ return mechanism != null && Pkcs12.Equals(algorithmType[mechanism]);
+ }
+
+ public static bool IsPkcs5Scheme1(
+ string algorithm)
+ {
+ string mechanism = (string)algorithms[Platform.ToUpperInvariant(algorithm)];
+
+ return mechanism != null && Pkcs5S1.Equals(algorithmType[mechanism]);
+ }
+
+ public static bool IsPkcs5Scheme2(
+ string algorithm)
+ {
+ string mechanism = (string)algorithms[Platform.ToUpperInvariant(algorithm)];
+
+ return mechanism != null && Pkcs5S2.Equals(algorithmType[mechanism]);
+ }
+
+ public static bool IsOpenSsl(
+ string algorithm)
+ {
+ string mechanism = (string)algorithms[Platform.ToUpperInvariant(algorithm)];
+
+ return mechanism != null && OpenSsl.Equals(algorithmType[mechanism]);
+ }
+
+ public static bool IsPbeAlgorithm(
+ string algorithm)
+ {
+ string mechanism = (string)algorithms[Platform.ToUpperInvariant(algorithm)];
+
+ return mechanism != null && algorithmType[mechanism] != null;
+ }
+
+ public static Asn1Encodable GenerateAlgorithmParameters(
+ DerObjectIdentifier algorithmOid,
+ byte[] salt,
+ int iterationCount)
+ {
+ return GenerateAlgorithmParameters(algorithmOid.Id, salt, iterationCount);
+ }
+
+ public static Asn1Encodable GenerateAlgorithmParameters(
+ string algorithm,
+ byte[] salt,
+ int iterationCount)
+ {
+ if (IsPkcs12(algorithm))
+ {
+ return new Pkcs12PbeParams(salt, iterationCount);
+ }
+ else if (IsPkcs5Scheme2(algorithm))
+ {
+ return new Pbkdf2Params(salt, iterationCount);
+ }
+ else
+ {
+ return new PbeParameter(salt, iterationCount);
+ }
+ }
+
+ public static ICipherParameters GenerateCipherParameters(
+ DerObjectIdentifier algorithmOid,
+ char[] password,
+ Asn1Encodable pbeParameters)
+ {
+ return GenerateCipherParameters(algorithmOid.Id, password, false, pbeParameters);
+ }
+
+ public static ICipherParameters GenerateCipherParameters(
+ DerObjectIdentifier algorithmOid,
+ char[] password,
+ bool wrongPkcs12Zero,
+ Asn1Encodable pbeParameters)
+ {
+ return GenerateCipherParameters(algorithmOid.Id, password, wrongPkcs12Zero, pbeParameters);
+ }
+
+ public static ICipherParameters GenerateCipherParameters(
+ AlgorithmIdentifier algID,
+ char[] password)
+ {
+ return GenerateCipherParameters(algID.Algorithm.Id, password, false, algID.Parameters);
+ }
+
+ public static ICipherParameters GenerateCipherParameters(
+ AlgorithmIdentifier algID,
+ char[] password,
+ bool wrongPkcs12Zero)
+ {
+ return GenerateCipherParameters(algID.Algorithm.Id, password, wrongPkcs12Zero, algID.Parameters);
+ }
+
+ public static ICipherParameters GenerateCipherParameters(
+ string algorithm,
+ char[] password,
+ Asn1Encodable pbeParameters)
+ {
+ return GenerateCipherParameters(algorithm, password, false, pbeParameters);
+ }
+
+ public static ICipherParameters GenerateCipherParameters(
+ string algorithm,
+ char[] password,
+ bool wrongPkcs12Zero,
+ Asn1Encodable pbeParameters)
+ {
+ string mechanism = (string)algorithms[Platform.ToUpperInvariant(algorithm)];
+
+ byte[] keyBytes = null;
+ byte[] salt = null;
+ int iterationCount = 0;
+
+ if (IsPkcs12(mechanism))
+ {
+ Pkcs12PbeParams pbeParams = Pkcs12PbeParams.GetInstance(pbeParameters);
+ salt = pbeParams.GetIV();
+ iterationCount = pbeParams.Iterations.IntValue;
+ keyBytes = PbeParametersGenerator.Pkcs12PasswordToBytes(password, wrongPkcs12Zero);
+ }
+ else if (IsPkcs5Scheme2(mechanism))
+ {
+ // See below
+ }
+ else
+ {
+ PbeParameter pbeParams = PbeParameter.GetInstance(pbeParameters);
+ salt = pbeParams.GetSalt();
+ iterationCount = pbeParams.IterationCount.IntValue;
+ keyBytes = PbeParametersGenerator.Pkcs5PasswordToBytes(password);
+ }
+
+ ICipherParameters parameters = null;
+
+ if (IsPkcs5Scheme2(mechanism))
+ {
+ PbeS2Parameters s2p = PbeS2Parameters.GetInstance(pbeParameters.ToAsn1Object());
+ AlgorithmIdentifier encScheme = s2p.EncryptionScheme;
+ DerObjectIdentifier encOid = encScheme.Algorithm;
+ Asn1Object encParams = encScheme.Parameters.ToAsn1Object();
+
+ // TODO What about s2p.KeyDerivationFunc.Algorithm?
+ Pbkdf2Params pbeParams = Pbkdf2Params.GetInstance(s2p.KeyDerivationFunc.Parameters.ToAsn1Object());
+
+ byte[] iv;
+ if (encOid.Equals(PkcsObjectIdentifiers.RC2Cbc)) // PKCS5.B.2.3
+ {
+ RC2CbcParameter rc2Params = RC2CbcParameter.GetInstance(encParams);
+ iv = rc2Params.GetIV();
+ }
+ else
+ {
+ iv = Asn1OctetString.GetInstance(encParams).GetOctets();
+ }
+
+ salt = pbeParams.GetSalt();
+ iterationCount = pbeParams.IterationCount.IntValue;
+ keyBytes = PbeParametersGenerator.Pkcs5PasswordToBytes(password);
+
+ int keyLength = pbeParams.KeyLength != null
+ ? pbeParams.KeyLength.IntValue * 8
+ : GeneratorUtilities.GetDefaultKeySize(encOid);
+
+ PbeParametersGenerator gen = MakePbeGenerator(
+ (string)algorithmType[mechanism], null, keyBytes, salt, iterationCount);
+
+ parameters = gen.GenerateDerivedParameters(encOid.Id, keyLength);
+
+ if (iv != null)
+ {
+ // FIXME? OpenSSL weirdness with IV of zeros (for ECB keys?)
+ if (Arrays.AreEqual(iv, new byte[iv.Length]))
+ {
+ //Console.Error.Write("***** IV all 0 (length " + iv.Length + ") *****");
+ }
+ else
+ {
+ parameters = new ParametersWithIV(parameters, iv);
+ }
+ }
+ }
+ else if (Platform.StartsWith(mechanism, "PBEwithSHA-1"))
+ {
+ PbeParametersGenerator generator = MakePbeGenerator(
+ (string) algorithmType[mechanism], new Sha1Digest(), keyBytes, salt, iterationCount);
+
+ if (mechanism.Equals("PBEwithSHA-1and128bitAES-CBC-BC"))
+ {
+ parameters = generator.GenerateDerivedParameters("AES", 128, 128);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1and192bitAES-CBC-BC"))
+ {
+ parameters = generator.GenerateDerivedParameters("AES", 192, 128);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1and256bitAES-CBC-BC"))
+ {
+ parameters = generator.GenerateDerivedParameters("AES", 256, 128);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1and128bitRC4"))
+ {
+ parameters = generator.GenerateDerivedParameters("RC4", 128);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1and40bitRC4"))
+ {
+ parameters = generator.GenerateDerivedParameters("RC4", 40);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1and3-keyDESEDE-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("DESEDE", 192, 64);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1and2-keyDESEDE-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("DESEDE", 128, 64);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1and128bitRC2-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("RC2", 128, 64);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1and40bitRC2-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("RC2", 40, 64);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1andDES-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("DES", 64, 64);
+ }
+ else if (mechanism.Equals("PBEwithSHA-1andRC2-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("RC2", 64, 64);
+ }
+ }
+ else if (Platform.StartsWith(mechanism, "PBEwithSHA-256"))
+ {
+ PbeParametersGenerator generator = MakePbeGenerator(
+ (string) algorithmType[mechanism], new Sha256Digest(), keyBytes, salt, iterationCount);
+
+ if (mechanism.Equals("PBEwithSHA-256and128bitAES-CBC-BC"))
+ {
+ parameters = generator.GenerateDerivedParameters("AES", 128, 128);
+ }
+ else if (mechanism.Equals("PBEwithSHA-256and192bitAES-CBC-BC"))
+ {
+ parameters = generator.GenerateDerivedParameters("AES", 192, 128);
+ }
+ else if (mechanism.Equals("PBEwithSHA-256and256bitAES-CBC-BC"))
+ {
+ parameters = generator.GenerateDerivedParameters("AES", 256, 128);
+ }
+ }
+ else if (Platform.StartsWith(mechanism, "PBEwithMD5"))
+ {
+ PbeParametersGenerator generator = MakePbeGenerator(
+ (string)algorithmType[mechanism], new MD5Digest(), keyBytes, salt, iterationCount);
+
+ if (mechanism.Equals("PBEwithMD5andDES-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("DES", 64, 64);
+ }
+ else if (mechanism.Equals("PBEwithMD5andRC2-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("RC2", 64, 64);
+ }
+ else if (mechanism.Equals("PBEwithMD5and128bitAES-CBC-OpenSSL"))
+ {
+ parameters = generator.GenerateDerivedParameters("AES", 128, 128);
+ }
+ else if (mechanism.Equals("PBEwithMD5and192bitAES-CBC-OpenSSL"))
+ {
+ parameters = generator.GenerateDerivedParameters("AES", 192, 128);
+ }
+ else if (mechanism.Equals("PBEwithMD5and256bitAES-CBC-OpenSSL"))
+ {
+ parameters = generator.GenerateDerivedParameters("AES", 256, 128);
+ }
+ }
+ else if (Platform.StartsWith(mechanism, "PBEwithMD2"))
+ {
+ PbeParametersGenerator generator = MakePbeGenerator(
+ (string)algorithmType[mechanism], new MD2Digest(), keyBytes, salt, iterationCount);
+ if (mechanism.Equals("PBEwithMD2andDES-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("DES", 64, 64);
+ }
+ else if (mechanism.Equals("PBEwithMD2andRC2-CBC"))
+ {
+ parameters = generator.GenerateDerivedParameters("RC2", 64, 64);
+ }
+ }
+ else if (Platform.StartsWith(mechanism, "PBEwithHmac"))
+ {
+ string digestName = mechanism.Substring("PBEwithHmac".Length);
+ IDigest digest = DigestUtilities.GetDigest(digestName);
+
+ PbeParametersGenerator generator = MakePbeGenerator(
+ (string) algorithmType[mechanism], digest, keyBytes, salt, iterationCount);
+
+ int bitLen = digest.GetDigestSize() * 8;
+ parameters = generator.GenerateDerivedMacParameters(bitLen);
+ }
+
+ Array.Clear(keyBytes, 0, keyBytes.Length);
+
+ return FixDesParity(mechanism, parameters);
+ }
+
+ public static object CreateEngine(
+ DerObjectIdentifier algorithmOid)
+ {
+ return CreateEngine(algorithmOid.Id);
+ }
+
+ public static object CreateEngine(
+ AlgorithmIdentifier algID)
+ {
+ string algorithm = algID.Algorithm.Id;
+
+ if (IsPkcs5Scheme2(algorithm))
+ {
+ PbeS2Parameters s2p = PbeS2Parameters.GetInstance(algID.Parameters.ToAsn1Object());
+ AlgorithmIdentifier encScheme = s2p.EncryptionScheme;
+ return CipherUtilities.GetCipher(encScheme.Algorithm);
+ }
+
+ return CreateEngine(algorithm);
+ }
+
+ public static object CreateEngine(
+ string algorithm)
+ {
+ string mechanism = (string)algorithms[Platform.ToUpperInvariant(algorithm)];
+
+ if (Platform.StartsWith(mechanism, "PBEwithHmac"))
+ {
+ string digestName = mechanism.Substring("PBEwithHmac".Length);
+
+ return MacUtilities.GetMac("HMAC/" + digestName);
+ }
+
+ if (Platform.StartsWith(mechanism, "PBEwithMD2")
+ || Platform.StartsWith(mechanism, "PBEwithMD5")
+ || Platform.StartsWith(mechanism, "PBEwithSHA-1")
+ || Platform.StartsWith(mechanism, "PBEwithSHA-256"))
+ {
+ if (Platform.EndsWith(mechanism, "AES-CBC-BC") || Platform.EndsWith(mechanism, "AES-CBC-OPENSSL"))
+ {
+ return CipherUtilities.GetCipher("AES/CBC");
+ }
+
+ if (Platform.EndsWith(mechanism, "DES-CBC"))
+ {
+ return CipherUtilities.GetCipher("DES/CBC");
+ }
+
+ if (Platform.EndsWith(mechanism, "DESEDE-CBC"))
+ {
+ return CipherUtilities.GetCipher("DESEDE/CBC");
+ }
+
+ if (Platform.EndsWith(mechanism, "RC2-CBC"))
+ {
+ return CipherUtilities.GetCipher("RC2/CBC");
+ }
+
+ if (Platform.EndsWith(mechanism, "RC4"))
+ {
+ return CipherUtilities.GetCipher("RC4");
+ }
+ }
+
+ return null;
+ }
+
+ public static string GetEncodingName(
+ DerObjectIdentifier oid)
+ {
+ return (string) algorithms[oid.Id];
+ }
+
+ private static ICipherParameters FixDesParity(string mechanism, ICipherParameters parameters)
+ {
+ if (!Platform.EndsWith(mechanism, "DES-CBC") && !Platform.EndsWith(mechanism, "DESEDE-CBC"))
+ {
+ return parameters;
+ }
+
+ if (parameters is ParametersWithIV)
+ {
+ ParametersWithIV ivParams = (ParametersWithIV)parameters;
+ return new ParametersWithIV(FixDesParity(mechanism, ivParams.Parameters), ivParams.GetIV());
+ }
+
+ KeyParameter kParam = (KeyParameter)parameters;
+ byte[] keyBytes = kParam.GetKey();
+ DesParameters.SetOddParity(keyBytes);
+ return new KeyParameter(keyBytes);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/PrivateKeyFactory.cs b/bc-sharp-crypto/src/security/PrivateKeyFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8c2ecfdb0cb9b127c3c43560162f455cb6124e7c
--- /dev/null
+++ b/bc-sharp-crypto/src/security/PrivateKeyFactory.cs
@@ -0,0 +1,222 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Security
+{
+ public sealed class PrivateKeyFactory
+ {
+ private PrivateKeyFactory()
+ {
+ }
+
+ public static AsymmetricKeyParameter CreateKey(
+ byte[] privateKeyInfoData)
+ {
+ return CreateKey(
+ PrivateKeyInfo.GetInstance(
+ Asn1Object.FromByteArray(privateKeyInfoData)));
+ }
+
+ public static AsymmetricKeyParameter CreateKey(
+ Stream inStr)
+ {
+ return CreateKey(
+ PrivateKeyInfo.GetInstance(
+ Asn1Object.FromStream(inStr)));
+ }
+
+ public static AsymmetricKeyParameter CreateKey(
+ PrivateKeyInfo keyInfo)
+ {
+ AlgorithmIdentifier algID = keyInfo.PrivateKeyAlgorithm;
+ DerObjectIdentifier algOid = algID.Algorithm;
+
+ // TODO See RSAUtil.isRsaOid in Java build
+ if (algOid.Equals(PkcsObjectIdentifiers.RsaEncryption)
+ || algOid.Equals(X509ObjectIdentifiers.IdEARsa)
+ || algOid.Equals(PkcsObjectIdentifiers.IdRsassaPss)
+ || algOid.Equals(PkcsObjectIdentifiers.IdRsaesOaep))
+ {
+ RsaPrivateKeyStructure keyStructure = RsaPrivateKeyStructure.GetInstance(keyInfo.ParsePrivateKey());
+
+ return new RsaPrivateCrtKeyParameters(
+ keyStructure.Modulus,
+ keyStructure.PublicExponent,
+ keyStructure.PrivateExponent,
+ keyStructure.Prime1,
+ keyStructure.Prime2,
+ keyStructure.Exponent1,
+ keyStructure.Exponent2,
+ keyStructure.Coefficient);
+ }
+ // TODO?
+// else if (algOid.Equals(X9ObjectIdentifiers.DHPublicNumber))
+ else if (algOid.Equals(PkcsObjectIdentifiers.DhKeyAgreement))
+ {
+ DHParameter para = new DHParameter(
+ Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
+ DerInteger derX = (DerInteger)keyInfo.ParsePrivateKey();
+
+ BigInteger lVal = para.L;
+ int l = lVal == null ? 0 : lVal.IntValue;
+ DHParameters dhParams = new DHParameters(para.P, para.G, null, l);
+
+ return new DHPrivateKeyParameters(derX.Value, dhParams, algOid);
+ }
+ else if (algOid.Equals(OiwObjectIdentifiers.ElGamalAlgorithm))
+ {
+ ElGamalParameter para = new ElGamalParameter(
+ Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
+ DerInteger derX = (DerInteger)keyInfo.ParsePrivateKey();
+
+ return new ElGamalPrivateKeyParameters(
+ derX.Value,
+ new ElGamalParameters(para.P, para.G));
+ }
+ else if (algOid.Equals(X9ObjectIdentifiers.IdDsa))
+ {
+ DerInteger derX = (DerInteger)keyInfo.ParsePrivateKey();
+ Asn1Encodable ae = algID.Parameters;
+
+ DsaParameters parameters = null;
+ if (ae != null)
+ {
+ DsaParameter para = DsaParameter.GetInstance(ae.ToAsn1Object());
+ parameters = new DsaParameters(para.P, para.Q, para.G);
+ }
+
+ return new DsaPrivateKeyParameters(derX.Value, parameters);
+ }
+ else if (algOid.Equals(X9ObjectIdentifiers.IdECPublicKey))
+ {
+ X962Parameters para = new X962Parameters(algID.Parameters.ToAsn1Object());
+
+ X9ECParameters x9;
+ if (para.IsNamedCurve)
+ {
+ x9 = ECKeyPairGenerator.FindECCurveByOid((DerObjectIdentifier)para.Parameters);
+ }
+ else
+ {
+ x9 = new X9ECParameters((Asn1Sequence)para.Parameters);
+ }
+
+ ECPrivateKeyStructure ec = ECPrivateKeyStructure.GetInstance(keyInfo.ParsePrivateKey());
+ BigInteger d = ec.GetKey();
+
+ if (para.IsNamedCurve)
+ {
+ return new ECPrivateKeyParameters("EC", d, (DerObjectIdentifier)para.Parameters);
+ }
+
+ ECDomainParameters dParams = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H, x9.GetSeed());
+ return new ECPrivateKeyParameters(d, dParams);
+ }
+ else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x2001))
+ {
+ Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
+ Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
+
+ ECDomainParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet);
+
+ if (ecP == null)
+ throw new ArgumentException("Unrecognized curve OID for GostR3410x2001 private key");
+
+ Asn1Object privKey = keyInfo.ParsePrivateKey();
+ ECPrivateKeyStructure ec;
+
+ if (privKey is DerInteger)
+ {
+ // TODO Do we need to pass any parameters here?
+ ec = new ECPrivateKeyStructure(ecP.N.BitLength, ((DerInteger)privKey).Value);
+ }
+ else
+ {
+ ec = ECPrivateKeyStructure.GetInstance(privKey);
+ }
+
+ return new ECPrivateKeyParameters("ECGOST3410", ec.GetKey(), gostParams.PublicKeyParamSet);
+ }
+ else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x94))
+ {
+ Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
+ Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
+
+ DerOctetString derX = (DerOctetString)keyInfo.ParsePrivateKey();
+ BigInteger x = new BigInteger(1, Arrays.Reverse(derX.GetOctets()));
+
+ return new Gost3410PrivateKeyParameters(x, gostParams.PublicKeyParamSet);
+ }
+ else
+ {
+ throw new SecurityUtilityException("algorithm identifier in key not recognised");
+ }
+ }
+
+ public static AsymmetricKeyParameter DecryptKey(
+ char[] passPhrase,
+ EncryptedPrivateKeyInfo encInfo)
+ {
+ return CreateKey(PrivateKeyInfoFactory.CreatePrivateKeyInfo(passPhrase, encInfo));
+ }
+
+ public static AsymmetricKeyParameter DecryptKey(
+ char[] passPhrase,
+ byte[] encryptedPrivateKeyInfoData)
+ {
+ return DecryptKey(passPhrase, Asn1Object.FromByteArray(encryptedPrivateKeyInfoData));
+ }
+
+ public static AsymmetricKeyParameter DecryptKey(
+ char[] passPhrase,
+ Stream encryptedPrivateKeyInfoStream)
+ {
+ return DecryptKey(passPhrase, Asn1Object.FromStream(encryptedPrivateKeyInfoStream));
+ }
+
+ private static AsymmetricKeyParameter DecryptKey(
+ char[] passPhrase,
+ Asn1Object asn1Object)
+ {
+ return DecryptKey(passPhrase, EncryptedPrivateKeyInfo.GetInstance(asn1Object));
+ }
+
+ public static byte[] EncryptKey(
+ DerObjectIdentifier algorithm,
+ char[] passPhrase,
+ byte[] salt,
+ int iterationCount,
+ AsymmetricKeyParameter key)
+ {
+ return EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
+ algorithm, passPhrase, salt, iterationCount, key).GetEncoded();
+ }
+
+ public static byte[] EncryptKey(
+ string algorithm,
+ char[] passPhrase,
+ byte[] salt,
+ int iterationCount,
+ AsymmetricKeyParameter key)
+ {
+ return EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
+ algorithm, passPhrase, salt, iterationCount, key).GetEncoded();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/PublicKeyFactory.cs b/bc-sharp-crypto/src/security/PublicKeyFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f1b28b774ca440fe117efed13f4a42f4498af0c3
--- /dev/null
+++ b/bc-sharp-crypto/src/security/PublicKeyFactory.cs
@@ -0,0 +1,253 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Security
+{
+ public sealed class PublicKeyFactory
+ {
+ private PublicKeyFactory()
+ {
+ }
+
+ public static AsymmetricKeyParameter CreateKey(
+ byte[] keyInfoData)
+ {
+ return CreateKey(
+ SubjectPublicKeyInfo.GetInstance(
+ Asn1Object.FromByteArray(keyInfoData)));
+ }
+
+ public static AsymmetricKeyParameter CreateKey(
+ Stream inStr)
+ {
+ return CreateKey(
+ SubjectPublicKeyInfo.GetInstance(
+ Asn1Object.FromStream(inStr)));
+ }
+
+ public static AsymmetricKeyParameter CreateKey(
+ SubjectPublicKeyInfo keyInfo)
+ {
+ AlgorithmIdentifier algID = keyInfo.AlgorithmID;
+ DerObjectIdentifier algOid = algID.Algorithm;
+
+ // TODO See RSAUtil.isRsaOid in Java build
+ if (algOid.Equals(PkcsObjectIdentifiers.RsaEncryption)
+ || algOid.Equals(X509ObjectIdentifiers.IdEARsa)
+ || algOid.Equals(PkcsObjectIdentifiers.IdRsassaPss)
+ || algOid.Equals(PkcsObjectIdentifiers.IdRsaesOaep))
+ {
+ RsaPublicKeyStructure pubKey = RsaPublicKeyStructure.GetInstance(
+ keyInfo.GetPublicKey());
+
+ return new RsaKeyParameters(false, pubKey.Modulus, pubKey.PublicExponent);
+ }
+ else if (algOid.Equals(X9ObjectIdentifiers.DHPublicNumber))
+ {
+ Asn1Sequence seq = Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object());
+
+ DHPublicKey dhPublicKey = DHPublicKey.GetInstance(keyInfo.GetPublicKey());
+
+ BigInteger y = dhPublicKey.Y.Value;
+
+ if (IsPkcsDHParam(seq))
+ return ReadPkcsDHParam(algOid, y, seq);
+
+ DHDomainParameters dhParams = DHDomainParameters.GetInstance(seq);
+
+ BigInteger p = dhParams.P.Value;
+ BigInteger g = dhParams.G.Value;
+ BigInteger q = dhParams.Q.Value;
+
+ BigInteger j = null;
+ if (dhParams.J != null)
+ {
+ j = dhParams.J.Value;
+ }
+
+ DHValidationParameters validation = null;
+ DHValidationParms dhValidationParms = dhParams.ValidationParms;
+ if (dhValidationParms != null)
+ {
+ byte[] seed = dhValidationParms.Seed.GetBytes();
+ BigInteger pgenCounter = dhValidationParms.PgenCounter.Value;
+
+ // TODO Check pgenCounter size?
+
+ validation = new DHValidationParameters(seed, pgenCounter.IntValue);
+ }
+
+ return new DHPublicKeyParameters(y, new DHParameters(p, g, q, j, validation));
+ }
+ else if (algOid.Equals(PkcsObjectIdentifiers.DhKeyAgreement))
+ {
+ Asn1Sequence seq = Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object());
+
+ DerInteger derY = (DerInteger) keyInfo.GetPublicKey();
+
+ return ReadPkcsDHParam(algOid, derY.Value, seq);
+ }
+ else if (algOid.Equals(OiwObjectIdentifiers.ElGamalAlgorithm))
+ {
+ ElGamalParameter para = new ElGamalParameter(
+ Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
+ DerInteger derY = (DerInteger) keyInfo.GetPublicKey();
+
+ return new ElGamalPublicKeyParameters(
+ derY.Value,
+ new ElGamalParameters(para.P, para.G));
+ }
+ else if (algOid.Equals(X9ObjectIdentifiers.IdDsa)
+ || algOid.Equals(OiwObjectIdentifiers.DsaWithSha1))
+ {
+ DerInteger derY = (DerInteger) keyInfo.GetPublicKey();
+ Asn1Encodable ae = algID.Parameters;
+
+ DsaParameters parameters = null;
+ if (ae != null)
+ {
+ DsaParameter para = DsaParameter.GetInstance(ae.ToAsn1Object());
+ parameters = new DsaParameters(para.P, para.Q, para.G);
+ }
+
+ return new DsaPublicKeyParameters(derY.Value, parameters);
+ }
+ else if (algOid.Equals(X9ObjectIdentifiers.IdECPublicKey))
+ {
+ X962Parameters para = new X962Parameters(algID.Parameters.ToAsn1Object());
+
+ X9ECParameters x9;
+ if (para.IsNamedCurve)
+ {
+ x9 = ECKeyPairGenerator.FindECCurveByOid((DerObjectIdentifier)para.Parameters);
+ }
+ else
+ {
+ x9 = new X9ECParameters((Asn1Sequence)para.Parameters);
+ }
+
+ Asn1OctetString key = new DerOctetString(keyInfo.PublicKeyData.GetBytes());
+ X9ECPoint derQ = new X9ECPoint(x9.Curve, key);
+ ECPoint q = derQ.Point;
+
+ if (para.IsNamedCurve)
+ {
+ return new ECPublicKeyParameters("EC", q, (DerObjectIdentifier)para.Parameters);
+ }
+
+ ECDomainParameters dParams = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H, x9.GetSeed());
+ return new ECPublicKeyParameters(q, dParams);
+ }
+ else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x2001))
+ {
+ Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
+ (Asn1Sequence) algID.Parameters);
+
+ Asn1OctetString key;
+ try
+ {
+ key = (Asn1OctetString) keyInfo.GetPublicKey();
+ }
+ catch (IOException)
+ {
+ throw new ArgumentException("invalid info structure in GOST3410 public key");
+ }
+
+ byte[] keyEnc = key.GetOctets();
+ byte[] x = new byte[32];
+ byte[] y = new byte[32];
+
+ for (int i = 0; i != y.Length; i++)
+ {
+ x[i] = keyEnc[32 - 1 - i];
+ }
+
+ for (int i = 0; i != x.Length; i++)
+ {
+ y[i] = keyEnc[64 - 1 - i];
+ }
+
+ ECDomainParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet);
+
+ if (ecP == null)
+ return null;
+
+ ECPoint q = ecP.Curve.CreatePoint(new BigInteger(1, x), new BigInteger(1, y));
+
+ return new ECPublicKeyParameters("ECGOST3410", q, gostParams.PublicKeyParamSet);
+ }
+ else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x94))
+ {
+ Gost3410PublicKeyAlgParameters algParams = new Gost3410PublicKeyAlgParameters(
+ (Asn1Sequence) algID.Parameters);
+
+ DerOctetString derY;
+ try
+ {
+ derY = (DerOctetString) keyInfo.GetPublicKey();
+ }
+ catch (IOException)
+ {
+ throw new ArgumentException("invalid info structure in GOST3410 public key");
+ }
+
+ byte[] keyEnc = derY.GetOctets();
+ byte[] keyBytes = new byte[keyEnc.Length];
+
+ for (int i = 0; i != keyEnc.Length; i++)
+ {
+ keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // was little endian
+ }
+
+ BigInteger y = new BigInteger(1, keyBytes);
+
+ return new Gost3410PublicKeyParameters(y, algParams.PublicKeyParamSet);
+ }
+ else
+ {
+ throw new SecurityUtilityException("algorithm identifier in key not recognised: " + algOid);
+ }
+ }
+
+ private static bool IsPkcsDHParam(Asn1Sequence seq)
+ {
+ if (seq.Count == 2)
+ return true;
+
+ if (seq.Count > 3)
+ return false;
+
+ DerInteger l = DerInteger.GetInstance(seq[2]);
+ DerInteger p = DerInteger.GetInstance(seq[0]);
+
+ return l.Value.CompareTo(BigInteger.ValueOf(p.Value.BitLength)) <= 0;
+ }
+
+ private static DHPublicKeyParameters ReadPkcsDHParam(DerObjectIdentifier algOid,
+ BigInteger y, Asn1Sequence seq)
+ {
+ DHParameter para = new DHParameter(seq);
+
+ BigInteger lVal = para.L;
+ int l = lVal == null ? 0 : lVal.IntValue;
+ DHParameters dhParams = new DHParameters(para.P, para.G, null, l);
+
+ return new DHPublicKeyParameters(y, dhParams, algOid);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/SecureRandom.cs b/bc-sharp-crypto/src/security/SecureRandom.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bd639a33648663c78f7504a881640488047a37da
--- /dev/null
+++ b/bc-sharp-crypto/src/security/SecureRandom.cs
@@ -0,0 +1,262 @@
+using System;
+using System.Threading;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Prng;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Security
+{
+ public class SecureRandom
+ : Random
+ {
+ private static long counter = Times.NanoTime();
+
+#if NETCF_1_0 || PORTABLE
+ private static object counterLock = new object();
+ private static long NextCounterValue()
+ {
+ lock (counterLock)
+ {
+ return ++counter;
+ }
+ }
+
+ private static readonly SecureRandom[] master = { null };
+ private static SecureRandom Master
+ {
+ get
+ {
+ lock (master)
+ {
+ if (master[0] == null)
+ {
+ SecureRandom sr = master[0] = GetInstance("SHA256PRNG", false);
+
+ // Even though Ticks has at most 8 or 14 bits of entropy, there's no harm in adding it.
+ sr.SetSeed(DateTime.Now.Ticks);
+
+ // 32 will be enough when ThreadedSeedGenerator is fixed. Until then, ThreadedSeedGenerator returns low
+ // entropy, and this is not sufficient to be secure. http://www.bouncycastle.org/csharpdevmailarchive/msg00814.html
+ sr.SetSeed(new ThreadedSeedGenerator().GenerateSeed(32, true));
+ }
+
+ return master[0];
+ }
+ }
+ }
+#else
+ private static long NextCounterValue()
+ {
+ return Interlocked.Increment(ref counter);
+ }
+
+ private static readonly SecureRandom master = new SecureRandom(new CryptoApiRandomGenerator());
+ private static SecureRandom Master
+ {
+ get { return master; }
+ }
+#endif
+
+ private static DigestRandomGenerator CreatePrng(string digestName, bool autoSeed)
+ {
+ IDigest digest = DigestUtilities.GetDigest(digestName);
+ if (digest == null)
+ return null;
+ DigestRandomGenerator prng = new DigestRandomGenerator(digest);
+ if (autoSeed)
+ {
+ prng.AddSeedMaterial(NextCounterValue());
+ prng.AddSeedMaterial(GetNextBytes(Master, digest.GetDigestSize()));
+ }
+ return prng;
+ }
+
+ public static byte[] GetNextBytes(SecureRandom secureRandom, int length)
+ {
+ byte[] result = new byte[length];
+ secureRandom.NextBytes(result);
+ return result;
+ }
+
+ ///
+ /// Create and auto-seed an instance based on the given algorithm.
+ ///
+ /// Equivalent to GetInstance(algorithm, true)
+ /// e.g. "SHA256PRNG"
+ public static SecureRandom GetInstance(string algorithm)
+ {
+ return GetInstance(algorithm, true);
+ }
+
+ ///
+ /// Create an instance based on the given algorithm, with optional auto-seeding
+ ///
+ /// e.g. "SHA256PRNG"
+ /// If true, the instance will be auto-seeded.
+ public static SecureRandom GetInstance(string algorithm, bool autoSeed)
+ {
+ string upper = Platform.ToUpperInvariant(algorithm);
+ if (Platform.EndsWith(upper, "PRNG"))
+ {
+ string digestName = upper.Substring(0, upper.Length - "PRNG".Length);
+ DigestRandomGenerator prng = CreatePrng(digestName, autoSeed);
+ if (prng != null)
+ {
+ return new SecureRandom(prng);
+ }
+ }
+
+ throw new ArgumentException("Unrecognised PRNG algorithm: " + algorithm, "algorithm");
+ }
+
+ [Obsolete("Call GenerateSeed() on a SecureRandom instance instead")]
+ public static byte[] GetSeed(int length)
+ {
+ return GetNextBytes(Master, length);
+ }
+
+ protected readonly IRandomGenerator generator;
+
+ public SecureRandom()
+ : this(CreatePrng("SHA256", true))
+ {
+ }
+
+ ///
+ /// To replicate existing predictable output, replace with GetInstance("SHA1PRNG", false), followed by SetSeed(seed)
+ ///
+ [Obsolete("Use GetInstance/SetSeed instead")]
+ public SecureRandom(byte[] seed)
+ : this(CreatePrng("SHA1", false))
+ {
+ SetSeed(seed);
+ }
+
+ /// Use the specified instance of IRandomGenerator as random source.
+ ///
+ /// This constructor performs no seeding of either the IRandomGenerator or the
+ /// constructed SecureRandom . It is the responsibility of the client to provide
+ /// proper seed material as necessary/appropriate for the given IRandomGenerator
+ /// implementation.
+ ///
+ /// The source to generate all random bytes from.
+ public SecureRandom(IRandomGenerator generator)
+ : base(0)
+ {
+ this.generator = generator;
+ }
+
+ public virtual byte[] GenerateSeed(int length)
+ {
+ return GetNextBytes(Master, length);
+ }
+
+ public virtual void SetSeed(byte[] seed)
+ {
+ generator.AddSeedMaterial(seed);
+ }
+
+ public virtual void SetSeed(long seed)
+ {
+ generator.AddSeedMaterial(seed);
+ }
+
+ public override int Next()
+ {
+ return NextInt() & int.MaxValue;
+ }
+
+ public override int Next(int maxValue)
+ {
+
+ if (maxValue < 2)
+ {
+ if (maxValue < 0)
+ throw new ArgumentOutOfRangeException("maxValue", "cannot be negative");
+
+ return 0;
+ }
+
+ int bits;
+
+ // Test whether maxValue is a power of 2
+ if ((maxValue & (maxValue - 1)) == 0)
+ {
+ bits = NextInt() & int.MaxValue;
+ return (int)(((long)bits * maxValue) >> 31);
+ }
+
+ int result;
+ do
+ {
+ bits = NextInt() & int.MaxValue;
+ result = bits % maxValue;
+ }
+ while (bits - result + (maxValue - 1) < 0); // Ignore results near overflow
+
+ return result;
+ }
+
+ public override int Next(int minValue, int maxValue)
+ {
+ if (maxValue <= minValue)
+ {
+ if (maxValue == minValue)
+ return minValue;
+
+ throw new ArgumentException("maxValue cannot be less than minValue");
+ }
+
+ int diff = maxValue - minValue;
+ if (diff > 0)
+ return minValue + Next(diff);
+
+ for (;;)
+ {
+ int i = NextInt();
+
+ if (i >= minValue && i < maxValue)
+ return i;
+ }
+ }
+
+ public override void NextBytes(byte[] buf)
+ {
+ generator.NextBytes(buf);
+ }
+
+ public virtual void NextBytes(byte[] buf, int off, int len)
+ {
+ generator.NextBytes(buf, off, len);
+ }
+
+ private static readonly double DoubleScale = System.Math.Pow(2.0, 64.0);
+
+ public override double NextDouble()
+ {
+ return Convert.ToDouble((ulong) NextLong()) / DoubleScale;
+ }
+
+ public virtual int NextInt()
+ {
+ byte[] bytes = new byte[4];
+ NextBytes(bytes);
+
+ uint result = bytes[0];
+ result <<= 8;
+ result |= bytes[1];
+ result <<= 8;
+ result |= bytes[2];
+ result <<= 8;
+ result |= bytes[3];
+ return (int)result;
+ }
+
+ public virtual long NextLong()
+ {
+ return ((long)(uint) NextInt() << 32) | (long)(uint) NextInt();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/SecurityUtilityException.cs b/bc-sharp-crypto/src/security/SecurityUtilityException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8a19530083045e90cd2eca95435c987a72e1f442
--- /dev/null
+++ b/bc-sharp-crypto/src/security/SecurityUtilityException.cs
@@ -0,0 +1,36 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class SecurityUtilityException
+ : Exception
+ {
+ /**
+ * base constructor.
+ */
+ public SecurityUtilityException()
+ {
+ }
+
+ /**
+ * create a SecurityUtilityException with the given message.
+ *
+ * @param message the message to be carried with the exception.
+ */
+ public SecurityUtilityException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public SecurityUtilityException(
+ string message,
+ Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/SignatureException.cs b/bc-sharp-crypto/src/security/SignatureException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3ad617dfd78ea110f12bbbab0609ae2223f8295e
--- /dev/null
+++ b/bc-sharp-crypto/src/security/SignatureException.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class SignatureException : GeneralSecurityException
+ {
+ public SignatureException() : base() { }
+ public SignatureException(string message) : base(message) { }
+ public SignatureException(string message, Exception exception) : base(message, exception) { }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/SignerUtilities.cs b/bc-sharp-crypto/src/security/SignerUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9a4915b4632374592fe5c6bf822530ba86ee52f2
--- /dev/null
+++ b/bc-sharp-crypto/src/security/SignerUtilities.cs
@@ -0,0 +1,566 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Security
+{
+ ///
+ /// Signer Utility class contains methods that can not be specifically grouped into other classes.
+ ///
+ public sealed class SignerUtilities
+ {
+ private SignerUtilities()
+ {
+ }
+
+ internal static readonly IDictionary algorithms = Platform.CreateHashtable();
+ internal static readonly IDictionary oids = Platform.CreateHashtable();
+
+ static SignerUtilities()
+ {
+ algorithms["MD2WITHRSA"] = "MD2withRSA";
+ algorithms["MD2WITHRSAENCRYPTION"] = "MD2withRSA";
+ algorithms[PkcsObjectIdentifiers.MD2WithRsaEncryption.Id] = "MD2withRSA";
+
+ algorithms["MD4WITHRSA"] = "MD4withRSA";
+ algorithms["MD4WITHRSAENCRYPTION"] = "MD4withRSA";
+ algorithms[PkcsObjectIdentifiers.MD4WithRsaEncryption.Id] = "MD4withRSA";
+
+ algorithms["MD5WITHRSA"] = "MD5withRSA";
+ algorithms["MD5WITHRSAENCRYPTION"] = "MD5withRSA";
+ algorithms[PkcsObjectIdentifiers.MD5WithRsaEncryption.Id] = "MD5withRSA";
+
+ algorithms["SHA1WITHRSA"] = "SHA-1withRSA";
+ algorithms["SHA1WITHRSAENCRYPTION"] = "SHA-1withRSA";
+ algorithms[PkcsObjectIdentifiers.Sha1WithRsaEncryption.Id] = "SHA-1withRSA";
+ algorithms["SHA-1WITHRSA"] = "SHA-1withRSA";
+
+ algorithms["SHA224WITHRSA"] = "SHA-224withRSA";
+ algorithms["SHA224WITHRSAENCRYPTION"] = "SHA-224withRSA";
+ algorithms[PkcsObjectIdentifiers.Sha224WithRsaEncryption.Id] = "SHA-224withRSA";
+ algorithms["SHA-224WITHRSA"] = "SHA-224withRSA";
+
+ algorithms["SHA256WITHRSA"] = "SHA-256withRSA";
+ algorithms["SHA256WITHRSAENCRYPTION"] = "SHA-256withRSA";
+ algorithms[PkcsObjectIdentifiers.Sha256WithRsaEncryption.Id] = "SHA-256withRSA";
+ algorithms["SHA-256WITHRSA"] = "SHA-256withRSA";
+
+ algorithms["SHA384WITHRSA"] = "SHA-384withRSA";
+ algorithms["SHA384WITHRSAENCRYPTION"] = "SHA-384withRSA";
+ algorithms[PkcsObjectIdentifiers.Sha384WithRsaEncryption.Id] = "SHA-384withRSA";
+ algorithms["SHA-384WITHRSA"] = "SHA-384withRSA";
+
+ algorithms["SHA512WITHRSA"] = "SHA-512withRSA";
+ algorithms["SHA512WITHRSAENCRYPTION"] = "SHA-512withRSA";
+ algorithms[PkcsObjectIdentifiers.Sha512WithRsaEncryption.Id] = "SHA-512withRSA";
+ algorithms["SHA-512WITHRSA"] = "SHA-512withRSA";
+
+ algorithms["PSSWITHRSA"] = "PSSwithRSA";
+ algorithms["RSASSA-PSS"] = "PSSwithRSA";
+ algorithms[PkcsObjectIdentifiers.IdRsassaPss.Id] = "PSSwithRSA";
+ algorithms["RSAPSS"] = "PSSwithRSA";
+
+ algorithms["SHA1WITHRSAANDMGF1"] = "SHA-1withRSAandMGF1";
+ algorithms["SHA-1WITHRSAANDMGF1"] = "SHA-1withRSAandMGF1";
+ algorithms["SHA1WITHRSA/PSS"] = "SHA-1withRSAandMGF1";
+ algorithms["SHA-1WITHRSA/PSS"] = "SHA-1withRSAandMGF1";
+
+ algorithms["SHA224WITHRSAANDMGF1"] = "SHA-224withRSAandMGF1";
+ algorithms["SHA-224WITHRSAANDMGF1"] = "SHA-224withRSAandMGF1";
+ algorithms["SHA224WITHRSA/PSS"] = "SHA-224withRSAandMGF1";
+ algorithms["SHA-224WITHRSA/PSS"] = "SHA-224withRSAandMGF1";
+
+ algorithms["SHA256WITHRSAANDMGF1"] = "SHA-256withRSAandMGF1";
+ algorithms["SHA-256WITHRSAANDMGF1"] = "SHA-256withRSAandMGF1";
+ algorithms["SHA256WITHRSA/PSS"] = "SHA-256withRSAandMGF1";
+ algorithms["SHA-256WITHRSA/PSS"] = "SHA-256withRSAandMGF1";
+
+ algorithms["SHA384WITHRSAANDMGF1"] = "SHA-384withRSAandMGF1";
+ algorithms["SHA-384WITHRSAANDMGF1"] = "SHA-384withRSAandMGF1";
+ algorithms["SHA384WITHRSA/PSS"] = "SHA-384withRSAandMGF1";
+ algorithms["SHA-384WITHRSA/PSS"] = "SHA-384withRSAandMGF1";
+
+ algorithms["SHA512WITHRSAANDMGF1"] = "SHA-512withRSAandMGF1";
+ algorithms["SHA-512WITHRSAANDMGF1"] = "SHA-512withRSAandMGF1";
+ algorithms["SHA512WITHRSA/PSS"] = "SHA-512withRSAandMGF1";
+ algorithms["SHA-512WITHRSA/PSS"] = "SHA-512withRSAandMGF1";
+
+ algorithms["RIPEMD128WITHRSA"] = "RIPEMD128withRSA";
+ algorithms["RIPEMD128WITHRSAENCRYPTION"] = "RIPEMD128withRSA";
+ algorithms[TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128.Id] = "RIPEMD128withRSA";
+
+ algorithms["RIPEMD160WITHRSA"] = "RIPEMD160withRSA";
+ algorithms["RIPEMD160WITHRSAENCRYPTION"] = "RIPEMD160withRSA";
+ algorithms[TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160.Id] = "RIPEMD160withRSA";
+
+ algorithms["RIPEMD256WITHRSA"] = "RIPEMD256withRSA";
+ algorithms["RIPEMD256WITHRSAENCRYPTION"] = "RIPEMD256withRSA";
+ algorithms[TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256.Id] = "RIPEMD256withRSA";
+
+ algorithms["NONEWITHRSA"] = "RSA";
+ algorithms["RSAWITHNONE"] = "RSA";
+ algorithms["RAWRSA"] = "RSA";
+
+ algorithms["RAWRSAPSS"] = "RAWRSASSA-PSS";
+ algorithms["NONEWITHRSAPSS"] = "RAWRSASSA-PSS";
+ algorithms["NONEWITHRSASSA-PSS"] = "RAWRSASSA-PSS";
+
+ algorithms["NONEWITHDSA"] = "NONEwithDSA";
+ algorithms["DSAWITHNONE"] = "NONEwithDSA";
+ algorithms["RAWDSA"] = "NONEwithDSA";
+
+ algorithms["DSA"] = "SHA-1withDSA";
+ algorithms["DSAWITHSHA1"] = "SHA-1withDSA";
+ algorithms["DSAWITHSHA-1"] = "SHA-1withDSA";
+ algorithms["SHA/DSA"] = "SHA-1withDSA";
+ algorithms["SHA1/DSA"] = "SHA-1withDSA";
+ algorithms["SHA-1/DSA"] = "SHA-1withDSA";
+ algorithms["SHA1WITHDSA"] = "SHA-1withDSA";
+ algorithms["SHA-1WITHDSA"] = "SHA-1withDSA";
+ algorithms[X9ObjectIdentifiers.IdDsaWithSha1.Id] = "SHA-1withDSA";
+
+ algorithms["DSAWITHSHA224"] = "SHA-224withDSA";
+ algorithms["DSAWITHSHA-224"] = "SHA-224withDSA";
+ algorithms["SHA224/DSA"] = "SHA-224withDSA";
+ algorithms["SHA-224/DSA"] = "SHA-224withDSA";
+ algorithms["SHA224WITHDSA"] = "SHA-224withDSA";
+ algorithms["SHA-224WITHDSA"] = "SHA-224withDSA";
+ algorithms[NistObjectIdentifiers.DsaWithSha224.Id] = "SHA-224withDSA";
+
+ algorithms["DSAWITHSHA256"] = "SHA-256withDSA";
+ algorithms["DSAWITHSHA-256"] = "SHA-256withDSA";
+ algorithms["SHA256/DSA"] = "SHA-256withDSA";
+ algorithms["SHA-256/DSA"] = "SHA-256withDSA";
+ algorithms["SHA256WITHDSA"] = "SHA-256withDSA";
+ algorithms["SHA-256WITHDSA"] = "SHA-256withDSA";
+ algorithms[NistObjectIdentifiers.DsaWithSha256.Id] = "SHA-256withDSA";
+
+ algorithms["DSAWITHSHA384"] = "SHA-384withDSA";
+ algorithms["DSAWITHSHA-384"] = "SHA-384withDSA";
+ algorithms["SHA384/DSA"] = "SHA-384withDSA";
+ algorithms["SHA-384/DSA"] = "SHA-384withDSA";
+ algorithms["SHA384WITHDSA"] = "SHA-384withDSA";
+ algorithms["SHA-384WITHDSA"] = "SHA-384withDSA";
+ algorithms[NistObjectIdentifiers.DsaWithSha384.Id] = "SHA-384withDSA";
+
+ algorithms["DSAWITHSHA512"] = "SHA-512withDSA";
+ algorithms["DSAWITHSHA-512"] = "SHA-512withDSA";
+ algorithms["SHA512/DSA"] = "SHA-512withDSA";
+ algorithms["SHA-512/DSA"] = "SHA-512withDSA";
+ algorithms["SHA512WITHDSA"] = "SHA-512withDSA";
+ algorithms["SHA-512WITHDSA"] = "SHA-512withDSA";
+ algorithms[NistObjectIdentifiers.DsaWithSha512.Id] = "SHA-512withDSA";
+
+ algorithms["NONEWITHECDSA"] = "NONEwithECDSA";
+ algorithms["ECDSAWITHNONE"] = "NONEwithECDSA";
+
+ algorithms["ECDSA"] = "SHA-1withECDSA";
+ algorithms["SHA1/ECDSA"] = "SHA-1withECDSA";
+ algorithms["SHA-1/ECDSA"] = "SHA-1withECDSA";
+ algorithms["ECDSAWITHSHA1"] = "SHA-1withECDSA";
+ algorithms["ECDSAWITHSHA-1"] = "SHA-1withECDSA";
+ algorithms["SHA1WITHECDSA"] = "SHA-1withECDSA";
+ algorithms["SHA-1WITHECDSA"] = "SHA-1withECDSA";
+ algorithms[X9ObjectIdentifiers.ECDsaWithSha1.Id] = "SHA-1withECDSA";
+ algorithms[TeleTrusTObjectIdentifiers.ECSignWithSha1.Id] = "SHA-1withECDSA";
+
+ algorithms["SHA224/ECDSA"] = "SHA-224withECDSA";
+ algorithms["SHA-224/ECDSA"] = "SHA-224withECDSA";
+ algorithms["ECDSAWITHSHA224"] = "SHA-224withECDSA";
+ algorithms["ECDSAWITHSHA-224"] = "SHA-224withECDSA";
+ algorithms["SHA224WITHECDSA"] = "SHA-224withECDSA";
+ algorithms["SHA-224WITHECDSA"] = "SHA-224withECDSA";
+ algorithms[X9ObjectIdentifiers.ECDsaWithSha224.Id] = "SHA-224withECDSA";
+
+ algorithms["SHA256/ECDSA"] = "SHA-256withECDSA";
+ algorithms["SHA-256/ECDSA"] = "SHA-256withECDSA";
+ algorithms["ECDSAWITHSHA256"] = "SHA-256withECDSA";
+ algorithms["ECDSAWITHSHA-256"] = "SHA-256withECDSA";
+ algorithms["SHA256WITHECDSA"] = "SHA-256withECDSA";
+ algorithms["SHA-256WITHECDSA"] = "SHA-256withECDSA";
+ algorithms[X9ObjectIdentifiers.ECDsaWithSha256.Id] = "SHA-256withECDSA";
+
+ algorithms["SHA384/ECDSA"] = "SHA-384withECDSA";
+ algorithms["SHA-384/ECDSA"] = "SHA-384withECDSA";
+ algorithms["ECDSAWITHSHA384"] = "SHA-384withECDSA";
+ algorithms["ECDSAWITHSHA-384"] = "SHA-384withECDSA";
+ algorithms["SHA384WITHECDSA"] = "SHA-384withECDSA";
+ algorithms["SHA-384WITHECDSA"] = "SHA-384withECDSA";
+ algorithms[X9ObjectIdentifiers.ECDsaWithSha384.Id] = "SHA-384withECDSA";
+
+ algorithms["SHA512/ECDSA"] = "SHA-512withECDSA";
+ algorithms["SHA-512/ECDSA"] = "SHA-512withECDSA";
+ algorithms["ECDSAWITHSHA512"] = "SHA-512withECDSA";
+ algorithms["ECDSAWITHSHA-512"] = "SHA-512withECDSA";
+ algorithms["SHA512WITHECDSA"] = "SHA-512withECDSA";
+ algorithms["SHA-512WITHECDSA"] = "SHA-512withECDSA";
+ algorithms[X9ObjectIdentifiers.ECDsaWithSha512.Id] = "SHA-512withECDSA";
+
+ algorithms["RIPEMD160/ECDSA"] = "RIPEMD160withECDSA";
+ algorithms["ECDSAWITHRIPEMD160"] = "RIPEMD160withECDSA";
+ algorithms["RIPEMD160WITHECDSA"] = "RIPEMD160withECDSA";
+ algorithms[TeleTrusTObjectIdentifiers.ECSignWithRipeMD160.Id] = "RIPEMD160withECDSA";
+
+ algorithms["GOST-3410"] = "GOST3410";
+ algorithms["GOST-3410-94"] = "GOST3410";
+ algorithms["GOST3411WITHGOST3410"] = "GOST3410";
+ algorithms[CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94.Id] = "GOST3410";
+
+ algorithms["ECGOST-3410"] = "ECGOST3410";
+ algorithms["ECGOST-3410-2001"] = "ECGOST3410";
+ algorithms["GOST3411WITHECGOST3410"] = "ECGOST3410";
+ algorithms[CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001.Id] = "ECGOST3410";
+
+
+
+ oids["MD2withRSA"] = PkcsObjectIdentifiers.MD2WithRsaEncryption;
+ oids["MD4withRSA"] = PkcsObjectIdentifiers.MD4WithRsaEncryption;
+ oids["MD5withRSA"] = PkcsObjectIdentifiers.MD5WithRsaEncryption;
+
+ oids["SHA-1withRSA"] = PkcsObjectIdentifiers.Sha1WithRsaEncryption;
+ oids["SHA-224withRSA"] = PkcsObjectIdentifiers.Sha224WithRsaEncryption;
+ oids["SHA-256withRSA"] = PkcsObjectIdentifiers.Sha256WithRsaEncryption;
+ oids["SHA-384withRSA"] = PkcsObjectIdentifiers.Sha384WithRsaEncryption;
+ oids["SHA-512withRSA"] = PkcsObjectIdentifiers.Sha512WithRsaEncryption;
+
+ oids["PSSwithRSA"] = PkcsObjectIdentifiers.IdRsassaPss;
+ oids["SHA-1withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+ oids["SHA-224withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+ oids["SHA-256withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+ oids["SHA-384withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+ oids["SHA-512withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+
+ oids["RIPEMD128withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128;
+ oids["RIPEMD160withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160;
+ oids["RIPEMD256withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256;
+
+ oids["SHA-1withDSA"] = X9ObjectIdentifiers.IdDsaWithSha1;
+
+ oids["SHA-1withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha1;
+ oids["SHA-224withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha224;
+ oids["SHA-256withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha256;
+ oids["SHA-384withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha384;
+ oids["SHA-512withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha512;
+
+ oids["GOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94;
+ oids["ECGOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001;
+ }
+
+ ///
+ /// Returns an ObjectIdentifier for a given encoding.
+ ///
+ /// A string representation of the encoding.
+ /// A DerObjectIdentifier, null if the OID is not available.
+ // TODO Don't really want to support this
+ public static DerObjectIdentifier GetObjectIdentifier(
+ string mechanism)
+ {
+ if (mechanism == null)
+ throw new ArgumentNullException("mechanism");
+
+ mechanism = Platform.ToUpperInvariant(mechanism);
+ string aliased = (string) algorithms[mechanism];
+
+ if (aliased != null)
+ mechanism = aliased;
+
+ return (DerObjectIdentifier) oids[mechanism];
+ }
+
+ public static ICollection Algorithms
+ {
+ get { return oids.Keys; }
+ }
+
+ public static Asn1Encodable GetDefaultX509Parameters(
+ DerObjectIdentifier id)
+ {
+ return GetDefaultX509Parameters(id.Id);
+ }
+
+ public static Asn1Encodable GetDefaultX509Parameters(
+ string algorithm)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+
+ algorithm = Platform.ToUpperInvariant(algorithm);
+
+ string mechanism = (string) algorithms[algorithm];
+
+ if (mechanism == null)
+ mechanism = algorithm;
+
+ if (mechanism == "PSSwithRSA")
+ {
+ // TODO The Sha1Digest here is a default. In JCE version, the actual digest
+ // to be used can be overridden by subsequent parameter settings.
+ return GetPssX509Parameters("SHA-1");
+ }
+
+ if (Platform.EndsWith(mechanism, "withRSAandMGF1"))
+ {
+ string digestName = mechanism.Substring(0, mechanism.Length - "withRSAandMGF1".Length);
+ return GetPssX509Parameters(digestName);
+ }
+
+ return DerNull.Instance;
+ }
+
+ private static Asn1Encodable GetPssX509Parameters(
+ string digestName)
+ {
+ AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
+ DigestUtilities.GetObjectIdentifier(digestName), DerNull.Instance);
+
+ // TODO Is it possible for the MGF hash alg to be different from the PSS one?
+ AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
+ PkcsObjectIdentifiers.IdMgf1, hashAlgorithm);
+
+ int saltLen = DigestUtilities.GetDigest(digestName).GetDigestSize();
+ return new RsassaPssParameters(hashAlgorithm, maskGenAlgorithm,
+ new DerInteger(saltLen), new DerInteger(1));
+ }
+
+ public static ISigner GetSigner(
+ DerObjectIdentifier id)
+ {
+ return GetSigner(id.Id);
+ }
+
+ public static ISigner GetSigner(
+ string algorithm)
+ {
+ if (algorithm == null)
+ throw new ArgumentNullException("algorithm");
+
+ algorithm = Platform.ToUpperInvariant(algorithm);
+
+ string mechanism = (string) algorithms[algorithm];
+
+ if (mechanism == null)
+ mechanism = algorithm;
+
+ if (mechanism.Equals("RSA"))
+ {
+ return (new RsaDigestSigner(new NullDigest(), (AlgorithmIdentifier)null));
+ }
+ if (mechanism.Equals("MD2withRSA"))
+ {
+ return (new RsaDigestSigner(new MD2Digest()));
+ }
+ if (mechanism.Equals("MD4withRSA"))
+ {
+ return (new RsaDigestSigner(new MD4Digest()));
+ }
+ if (mechanism.Equals("MD5withRSA"))
+ {
+ return (new RsaDigestSigner(new MD5Digest()));
+ }
+ if (mechanism.Equals("SHA-1withRSA"))
+ {
+ return (new RsaDigestSigner(new Sha1Digest()));
+ }
+ if (mechanism.Equals("SHA-224withRSA"))
+ {
+ return (new RsaDigestSigner(new Sha224Digest()));
+ }
+ if (mechanism.Equals("SHA-256withRSA"))
+ {
+ return (new RsaDigestSigner(new Sha256Digest()));
+ }
+ if (mechanism.Equals("SHA-384withRSA"))
+ {
+ return (new RsaDigestSigner(new Sha384Digest()));
+ }
+ if (mechanism.Equals("SHA-512withRSA"))
+ {
+ return (new RsaDigestSigner(new Sha512Digest()));
+ }
+ if (mechanism.Equals("RIPEMD128withRSA"))
+ {
+ return (new RsaDigestSigner(new RipeMD128Digest()));
+ }
+ if (mechanism.Equals("RIPEMD160withRSA"))
+ {
+ return (new RsaDigestSigner(new RipeMD160Digest()));
+ }
+ if (mechanism.Equals("RIPEMD256withRSA"))
+ {
+ return (new RsaDigestSigner(new RipeMD256Digest()));
+ }
+
+ if (mechanism.Equals("RAWRSASSA-PSS"))
+ {
+ // TODO Add support for other parameter settings
+ return PssSigner.CreateRawSigner(new RsaBlindedEngine(), new Sha1Digest());
+ }
+ if (mechanism.Equals("PSSwithRSA"))
+ {
+ // TODO The Sha1Digest here is a default. In JCE version, the actual digest
+ // to be used can be overridden by subsequent parameter settings.
+ return (new PssSigner(new RsaBlindedEngine(), new Sha1Digest()));
+ }
+ if (mechanism.Equals("SHA-1withRSAandMGF1"))
+ {
+ return (new PssSigner(new RsaBlindedEngine(), new Sha1Digest()));
+ }
+ if (mechanism.Equals("SHA-224withRSAandMGF1"))
+ {
+ return (new PssSigner(new RsaBlindedEngine(), new Sha224Digest()));
+ }
+ if (mechanism.Equals("SHA-256withRSAandMGF1"))
+ {
+ return (new PssSigner(new RsaBlindedEngine(), new Sha256Digest()));
+ }
+ if (mechanism.Equals("SHA-384withRSAandMGF1"))
+ {
+ return (new PssSigner(new RsaBlindedEngine(), new Sha384Digest()));
+ }
+ if (mechanism.Equals("SHA-512withRSAandMGF1"))
+ {
+ return (new PssSigner(new RsaBlindedEngine(), new Sha512Digest()));
+ }
+
+ if (mechanism.Equals("NONEwithDSA"))
+ {
+ return (new DsaDigestSigner(new DsaSigner(), new NullDigest()));
+ }
+ if (mechanism.Equals("SHA-1withDSA"))
+ {
+ return (new DsaDigestSigner(new DsaSigner(), new Sha1Digest()));
+ }
+ if (mechanism.Equals("SHA-224withDSA"))
+ {
+ return (new DsaDigestSigner(new DsaSigner(), new Sha224Digest()));
+ }
+ if (mechanism.Equals("SHA-256withDSA"))
+ {
+ return (new DsaDigestSigner(new DsaSigner(), new Sha256Digest()));
+ }
+ if (mechanism.Equals("SHA-384withDSA"))
+ {
+ return (new DsaDigestSigner(new DsaSigner(), new Sha384Digest()));
+ }
+ if (mechanism.Equals("SHA-512withDSA"))
+ {
+ return (new DsaDigestSigner(new DsaSigner(), new Sha512Digest()));
+ }
+
+ if (mechanism.Equals("NONEwithECDSA"))
+ {
+ return (new DsaDigestSigner(new ECDsaSigner(), new NullDigest()));
+ }
+ if (mechanism.Equals("SHA-1withECDSA"))
+ {
+ return (new DsaDigestSigner(new ECDsaSigner(), new Sha1Digest()));
+ }
+ if (mechanism.Equals("SHA-224withECDSA"))
+ {
+ return (new DsaDigestSigner(new ECDsaSigner(), new Sha224Digest()));
+ }
+ if (mechanism.Equals("SHA-256withECDSA"))
+ {
+ return (new DsaDigestSigner(new ECDsaSigner(), new Sha256Digest()));
+ }
+ if (mechanism.Equals("SHA-384withECDSA"))
+ {
+ return (new DsaDigestSigner(new ECDsaSigner(), new Sha384Digest()));
+ }
+ if (mechanism.Equals("SHA-512withECDSA"))
+ {
+ return (new DsaDigestSigner(new ECDsaSigner(), new Sha512Digest()));
+ }
+
+ if (mechanism.Equals("RIPEMD160withECDSA"))
+ {
+ return (new DsaDigestSigner(new ECDsaSigner(), new RipeMD160Digest()));
+ }
+
+ if (mechanism.Equals("SHA1WITHECNR"))
+ {
+ return (new DsaDigestSigner(new ECNRSigner(), new Sha1Digest()));
+ }
+ if (mechanism.Equals("SHA224WITHECNR"))
+ {
+ return (new DsaDigestSigner(new ECNRSigner(), new Sha224Digest()));
+ }
+ if (mechanism.Equals("SHA256WITHECNR"))
+ {
+ return (new DsaDigestSigner(new ECNRSigner(), new Sha256Digest()));
+ }
+ if (mechanism.Equals("SHA384WITHECNR"))
+ {
+ return (new DsaDigestSigner(new ECNRSigner(), new Sha384Digest()));
+ }
+ if (mechanism.Equals("SHA512WITHECNR"))
+ {
+ return (new DsaDigestSigner(new ECNRSigner(), new Sha512Digest()));
+ }
+
+ if (mechanism.Equals("GOST3410"))
+ {
+ return new Gost3410DigestSigner(new Gost3410Signer(), new Gost3411Digest());
+ }
+ if (mechanism.Equals("ECGOST3410"))
+ {
+ return new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411Digest());
+ }
+
+ if (mechanism.Equals("SHA1WITHRSA/ISO9796-2"))
+ {
+ return new Iso9796d2Signer(new RsaBlindedEngine(), new Sha1Digest(), true);
+ }
+ if (mechanism.Equals("MD5WITHRSA/ISO9796-2"))
+ {
+ return new Iso9796d2Signer(new RsaBlindedEngine(), new MD5Digest(), true);
+ }
+ if (mechanism.Equals("RIPEMD160WITHRSA/ISO9796-2"))
+ {
+ return new Iso9796d2Signer(new RsaBlindedEngine(), new RipeMD160Digest(), true);
+ }
+
+ if (Platform.EndsWith(mechanism, "/X9.31"))
+ {
+ string x931 = mechanism.Substring(0, mechanism.Length - "/X9.31".Length);
+ int withPos = Platform.IndexOf(x931, "WITH");
+ if (withPos > 0)
+ {
+ int endPos = withPos + "WITH".Length;
+
+ string digestName = x931.Substring(0, withPos);
+ IDigest digest = DigestUtilities.GetDigest(digestName);
+
+ string cipherName = x931.Substring(endPos, x931.Length - endPos);
+ if (cipherName.Equals("RSA"))
+ {
+ IAsymmetricBlockCipher cipher = new RsaBlindedEngine();
+ return new X931Signer(cipher, digest);
+ }
+ }
+ }
+
+ throw new SecurityUtilityException("Signer " + algorithm + " not recognised.");
+ }
+
+ public static string GetEncodingName(
+ DerObjectIdentifier oid)
+ {
+ return (string) algorithms[oid.Id];
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/WrapperUtilities.cs b/bc-sharp-crypto/src/security/WrapperUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c57632081d9f427fe7898cbbd556aa508ab29bd0
--- /dev/null
+++ b/bc-sharp-crypto/src/security/WrapperUtilities.cs
@@ -0,0 +1,153 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Kisa;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Ntt;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Security
+{
+ ///
+ /// Utility class for creating IWrapper objects from their names/Oids
+ ///
+ public sealed class WrapperUtilities
+ {
+ private enum WrapAlgorithm { AESWRAP, CAMELLIAWRAP, DESEDEWRAP, RC2WRAP, SEEDWRAP,
+ DESEDERFC3211WRAP, AESRFC3211WRAP, CAMELLIARFC3211WRAP };
+
+ private WrapperUtilities()
+ {
+ }
+
+ private static readonly IDictionary algorithms = Platform.CreateHashtable();
+ //private static readonly IDictionary oids = Platform.CreateHashtable();
+
+ static WrapperUtilities()
+ {
+ // Signal to obfuscation tools not to change enum constants
+ ((WrapAlgorithm)Enums.GetArbitraryValue(typeof(WrapAlgorithm))).ToString();
+
+ algorithms[NistObjectIdentifiers.IdAes128Wrap.Id] = "AESWRAP";
+ algorithms[NistObjectIdentifiers.IdAes192Wrap.Id] = "AESWRAP";
+ algorithms[NistObjectIdentifiers.IdAes256Wrap.Id] = "AESWRAP";
+
+ algorithms[NttObjectIdentifiers.IdCamellia128Wrap.Id] = "CAMELLIAWRAP";
+ algorithms[NttObjectIdentifiers.IdCamellia192Wrap.Id] = "CAMELLIAWRAP";
+ algorithms[NttObjectIdentifiers.IdCamellia256Wrap.Id] = "CAMELLIAWRAP";
+
+ algorithms[PkcsObjectIdentifiers.IdAlgCms3DesWrap.Id] = "DESEDEWRAP";
+ algorithms["TDEAWRAP"] = "DESEDEWRAP";
+
+ algorithms[PkcsObjectIdentifiers.IdAlgCmsRC2Wrap.Id] = "RC2WRAP";
+
+ algorithms[KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap.Id] = "SEEDWRAP";
+ }
+
+ public static IWrapper GetWrapper(
+ DerObjectIdentifier oid)
+ {
+ return GetWrapper(oid.Id);
+ }
+
+ public static IWrapper GetWrapper(
+ string algorithm)
+ {
+ string upper = Platform.ToUpperInvariant(algorithm);
+ string mechanism = (string)algorithms[upper];
+
+ if (mechanism == null)
+ {
+ mechanism = upper;
+ }
+
+ try
+ {
+ WrapAlgorithm wrapAlgorithm = (WrapAlgorithm)Enums.GetEnumValue(
+ typeof(WrapAlgorithm), mechanism);
+
+ switch (wrapAlgorithm)
+ {
+ case WrapAlgorithm.AESWRAP: return new AesWrapEngine();
+ case WrapAlgorithm.CAMELLIAWRAP: return new CamelliaWrapEngine();
+ case WrapAlgorithm.DESEDEWRAP: return new DesEdeWrapEngine();
+ case WrapAlgorithm.RC2WRAP: return new RC2WrapEngine();
+ case WrapAlgorithm.SEEDWRAP: return new SeedWrapEngine();
+ case WrapAlgorithm.DESEDERFC3211WRAP: return new Rfc3211WrapEngine(new DesEdeEngine());
+ case WrapAlgorithm.AESRFC3211WRAP: return new Rfc3211WrapEngine(new AesEngine());
+ case WrapAlgorithm.CAMELLIARFC3211WRAP: return new Rfc3211WrapEngine(new CamelliaEngine());
+ }
+ }
+ catch (ArgumentException)
+ {
+ }
+
+ // Create an IBufferedCipher and use it as IWrapper (via BufferedCipherWrapper)
+ IBufferedCipher blockCipher = CipherUtilities.GetCipher(algorithm);
+
+ if (blockCipher != null)
+ return new BufferedCipherWrapper(blockCipher);
+
+ throw new SecurityUtilityException("Wrapper " + algorithm + " not recognised.");
+ }
+
+ public static string GetAlgorithmName(
+ DerObjectIdentifier oid)
+ {
+ return (string) algorithms[oid.Id];
+ }
+
+ private class BufferedCipherWrapper
+ : IWrapper
+ {
+ private readonly IBufferedCipher cipher;
+ private bool forWrapping;
+
+ public BufferedCipherWrapper(
+ IBufferedCipher cipher)
+ {
+ this.cipher = cipher;
+ }
+
+ public string AlgorithmName
+ {
+ get { return cipher.AlgorithmName; }
+ }
+
+ public void Init(
+ bool forWrapping,
+ ICipherParameters parameters)
+ {
+ this.forWrapping = forWrapping;
+
+ cipher.Init(forWrapping, parameters);
+ }
+
+ public byte[] Wrap(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (!forWrapping)
+ throw new InvalidOperationException("Not initialised for wrapping");
+
+ return cipher.DoFinal(input, inOff, length);
+ }
+
+ public byte[] Unwrap(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ if (forWrapping)
+ throw new InvalidOperationException("Not initialised for unwrapping");
+
+ return cipher.DoFinal(input, inOff, length);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/cert/CertificateEncodingException.cs b/bc-sharp-crypto/src/security/cert/CertificateEncodingException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ab9024fc768d83c743ba6311b493e2566e409975
--- /dev/null
+++ b/bc-sharp-crypto/src/security/cert/CertificateEncodingException.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Org.BouncyCastle.Security.Certificates
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class CertificateEncodingException : CertificateException
+ {
+ public CertificateEncodingException() : base() { }
+ public CertificateEncodingException(string msg) : base(msg) { }
+ public CertificateEncodingException(string msg, Exception e) : base(msg, e) { }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/cert/CertificateException.cs b/bc-sharp-crypto/src/security/cert/CertificateException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4bbaccfc15d145bc70321fbe3da86e9e40f8f832
--- /dev/null
+++ b/bc-sharp-crypto/src/security/cert/CertificateException.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Org.BouncyCastle.Security.Certificates
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class CertificateException : GeneralSecurityException
+ {
+ public CertificateException() : base() { }
+ public CertificateException(string message) : base(message) { }
+ public CertificateException(string message, Exception exception) : base(message, exception) { }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/cert/CertificateExpiredException.cs b/bc-sharp-crypto/src/security/cert/CertificateExpiredException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..864fb85c1394c38305563b8ca09c414455eec3f5
--- /dev/null
+++ b/bc-sharp-crypto/src/security/cert/CertificateExpiredException.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Org.BouncyCastle.Security.Certificates
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class CertificateExpiredException : CertificateException
+ {
+ public CertificateExpiredException() : base() { }
+ public CertificateExpiredException(string message) : base(message) { }
+ public CertificateExpiredException(string message, Exception exception) : base(message, exception) { }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/cert/CertificateNotYetValidException.cs b/bc-sharp-crypto/src/security/cert/CertificateNotYetValidException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..02112be98cadf4656285a04b16195aed04571b01
--- /dev/null
+++ b/bc-sharp-crypto/src/security/cert/CertificateNotYetValidException.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Org.BouncyCastle.Security.Certificates
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class CertificateNotYetValidException : CertificateException
+ {
+ public CertificateNotYetValidException() : base() { }
+ public CertificateNotYetValidException(string message) : base(message) { }
+ public CertificateNotYetValidException(string message, Exception exception) : base(message, exception) { }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/cert/CertificateParsingException.cs b/bc-sharp-crypto/src/security/cert/CertificateParsingException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ae909ca40e7fbb2f9c1dfcafafd41b02549ee1f5
--- /dev/null
+++ b/bc-sharp-crypto/src/security/cert/CertificateParsingException.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Org.BouncyCastle.Security.Certificates
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class CertificateParsingException : CertificateException
+ {
+ public CertificateParsingException() : base() { }
+ public CertificateParsingException(string message) : base(message) { }
+ public CertificateParsingException(string message, Exception exception) : base(message, exception) { }
+ }
+}
diff --git a/bc-sharp-crypto/src/security/cert/CrlException.cs b/bc-sharp-crypto/src/security/cert/CrlException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fe9807e7911a658245882dbc0fae2d7ce824ff75
--- /dev/null
+++ b/bc-sharp-crypto/src/security/cert/CrlException.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Org.BouncyCastle.Security.Certificates
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class CrlException : GeneralSecurityException
+ {
+ public CrlException() : base() { }
+ public CrlException(string msg) : base(msg) {}
+ public CrlException(string msg, Exception e) : base(msg, e) {}
+ }
+}
diff --git a/bc-sharp-crypto/src/tsp/GenTimeAccuracy.cs b/bc-sharp-crypto/src/tsp/GenTimeAccuracy.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8a2f2998970ab70718eab94e85c426403082f325
--- /dev/null
+++ b/bc-sharp-crypto/src/tsp/GenTimeAccuracy.cs
@@ -0,0 +1,33 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Tsp;
+
+namespace Org.BouncyCastle.Tsp
+{
+ public class GenTimeAccuracy
+ {
+ private Accuracy accuracy;
+
+ public GenTimeAccuracy(
+ Accuracy accuracy)
+ {
+ this.accuracy = accuracy;
+ }
+
+ public int Seconds { get { return GetTimeComponent(accuracy.Seconds); } }
+
+ public int Millis { get { return GetTimeComponent(accuracy.Millis); } }
+
+ public int Micros { get { return GetTimeComponent(accuracy.Micros); } }
+
+ private int GetTimeComponent(
+ DerInteger time)
+ {
+ return time == null ? 0 : time.Value.IntValue;
+ }
+
+ public override string ToString()
+ {
+ return Seconds + "." + Millis.ToString("000") + Micros.ToString("000");
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/tsp/TSPAlgorithms.cs b/bc-sharp-crypto/src/tsp/TSPAlgorithms.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e3dfc7916f2d09e38a73f37d01e369af480a2438
--- /dev/null
+++ b/bc-sharp-crypto/src/tsp/TSPAlgorithms.cs
@@ -0,0 +1,48 @@
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Tsp
+{
+ /**
+ * Recognised hash algorithms for the time stamp protocol.
+ */
+ public abstract class TspAlgorithms
+ {
+ public static readonly string MD5 = PkcsObjectIdentifiers.MD5.Id;
+
+ public static readonly string Sha1 = OiwObjectIdentifiers.IdSha1.Id;
+
+ public static readonly string Sha224 = NistObjectIdentifiers.IdSha224.Id;
+ public static readonly string Sha256 = NistObjectIdentifiers.IdSha256.Id;
+ public static readonly string Sha384 = NistObjectIdentifiers.IdSha384.Id;
+ public static readonly string Sha512 = NistObjectIdentifiers.IdSha512.Id;
+
+ public static readonly string RipeMD128 = TeleTrusTObjectIdentifiers.RipeMD128.Id;
+ public static readonly string RipeMD160 = TeleTrusTObjectIdentifiers.RipeMD160.Id;
+ public static readonly string RipeMD256 = TeleTrusTObjectIdentifiers.RipeMD256.Id;
+
+ public static readonly string Gost3411 = CryptoProObjectIdentifiers.GostR3411.Id;
+
+ public static readonly IList Allowed;
+
+ static TspAlgorithms()
+ {
+ string[] algs = new string[]
+ {
+ Gost3411, MD5, Sha1, Sha224, Sha256, Sha384, Sha512, RipeMD128, RipeMD160, RipeMD256
+ };
+
+ Allowed = Platform.CreateArrayList();
+ foreach (string alg in algs)
+ {
+ Allowed.Add(alg);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/tsp/TSPException.cs b/bc-sharp-crypto/src/tsp/TSPException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0f29b12990230690ca065d4fdee7c8e539cacd42
--- /dev/null
+++ b/bc-sharp-crypto/src/tsp/TSPException.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Org.BouncyCastle.Tsp
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class TspException
+ : Exception
+ {
+ public TspException()
+ {
+ }
+
+ public TspException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public TspException(
+ string message,
+ Exception e)
+ : base(message, e)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/tsp/TSPUtil.cs b/bc-sharp-crypto/src/tsp/TSPUtil.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1026914f473238c70f6897ff051b26b326ed6801
--- /dev/null
+++ b/bc-sharp-crypto/src/tsp/TSPUtil.cs
@@ -0,0 +1,202 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Tsp
+{
+ public class TspUtil
+ {
+ private static ISet EmptySet = CollectionUtilities.ReadOnly(new HashSet());
+ private static IList EmptyList = CollectionUtilities.ReadOnly(Platform.CreateArrayList());
+
+ private static readonly IDictionary digestLengths = Platform.CreateHashtable();
+ private static readonly IDictionary digestNames = Platform.CreateHashtable();
+
+ static TspUtil()
+ {
+ digestLengths.Add(PkcsObjectIdentifiers.MD5.Id, 16);
+ digestLengths.Add(OiwObjectIdentifiers.IdSha1.Id, 20);
+ digestLengths.Add(NistObjectIdentifiers.IdSha224.Id, 28);
+ digestLengths.Add(NistObjectIdentifiers.IdSha256.Id, 32);
+ digestLengths.Add(NistObjectIdentifiers.IdSha384.Id, 48);
+ digestLengths.Add(NistObjectIdentifiers.IdSha512.Id, 64);
+ digestLengths.Add(TeleTrusTObjectIdentifiers.RipeMD128.Id, 16);
+ digestLengths.Add(TeleTrusTObjectIdentifiers.RipeMD160.Id, 20);
+ digestLengths.Add(TeleTrusTObjectIdentifiers.RipeMD256.Id, 32);
+ digestLengths.Add(CryptoProObjectIdentifiers.GostR3411.Id, 32);
+
+ digestNames.Add(PkcsObjectIdentifiers.MD5.Id, "MD5");
+ digestNames.Add(OiwObjectIdentifiers.IdSha1.Id, "SHA1");
+ digestNames.Add(NistObjectIdentifiers.IdSha224.Id, "SHA224");
+ digestNames.Add(NistObjectIdentifiers.IdSha256.Id, "SHA256");
+ digestNames.Add(NistObjectIdentifiers.IdSha384.Id, "SHA384");
+ digestNames.Add(NistObjectIdentifiers.IdSha512.Id, "SHA512");
+ digestNames.Add(PkcsObjectIdentifiers.Sha1WithRsaEncryption.Id, "SHA1");
+ digestNames.Add(PkcsObjectIdentifiers.Sha224WithRsaEncryption.Id, "SHA224");
+ digestNames.Add(PkcsObjectIdentifiers.Sha256WithRsaEncryption.Id, "SHA256");
+ digestNames.Add(PkcsObjectIdentifiers.Sha384WithRsaEncryption.Id, "SHA384");
+ digestNames.Add(PkcsObjectIdentifiers.Sha512WithRsaEncryption.Id, "SHA512");
+ digestNames.Add(TeleTrusTObjectIdentifiers.RipeMD128.Id, "RIPEMD128");
+ digestNames.Add(TeleTrusTObjectIdentifiers.RipeMD160.Id, "RIPEMD160");
+ digestNames.Add(TeleTrusTObjectIdentifiers.RipeMD256.Id, "RIPEMD256");
+ digestNames.Add(CryptoProObjectIdentifiers.GostR3411.Id, "GOST3411");
+ }
+
+
+ /**
+ * Fetches the signature time-stamp attributes from a SignerInformation object.
+ * Checks that the MessageImprint for each time-stamp matches the signature field.
+ * (see RFC 3161 Appendix A).
+ *
+ * @param signerInfo a SignerInformation to search for time-stamps
+ * @return a collection of TimeStampToken objects
+ * @throws TSPValidationException
+ */
+ public static ICollection GetSignatureTimestamps(
+ SignerInformation signerInfo)
+ {
+ IList timestamps = Platform.CreateArrayList();
+
+ Asn1.Cms.AttributeTable unsignedAttrs = signerInfo.UnsignedAttributes;
+ if (unsignedAttrs != null)
+ {
+ foreach (Asn1.Cms.Attribute tsAttr in unsignedAttrs.GetAll(
+ PkcsObjectIdentifiers.IdAASignatureTimeStampToken))
+ {
+ foreach (Asn1Encodable asn1 in tsAttr.AttrValues)
+ {
+ try
+ {
+ Asn1.Cms.ContentInfo contentInfo = Asn1.Cms.ContentInfo.GetInstance(
+ asn1.ToAsn1Object());
+ TimeStampToken timeStampToken = new TimeStampToken(contentInfo);
+ TimeStampTokenInfo tstInfo = timeStampToken.TimeStampInfo;
+
+ byte[] expectedDigest = DigestUtilities.CalculateDigest(
+ GetDigestAlgName(tstInfo.MessageImprintAlgOid),
+ signerInfo.GetSignature());
+
+ if (!Arrays.ConstantTimeAreEqual(expectedDigest, tstInfo.GetMessageImprintDigest()))
+ throw new TspValidationException("Incorrect digest in message imprint");
+
+ timestamps.Add(timeStampToken);
+ }
+ catch (SecurityUtilityException)
+ {
+ throw new TspValidationException("Unknown hash algorithm specified in timestamp");
+ }
+ catch (Exception)
+ {
+ throw new TspValidationException("Timestamp could not be parsed");
+ }
+ }
+ }
+ }
+
+ return timestamps;
+ }
+
+ /**
+ * Validate the passed in certificate as being of the correct type to be used
+ * for time stamping. To be valid it must have an ExtendedKeyUsage extension
+ * which has a key purpose identifier of id-kp-timeStamping.
+ *
+ * @param cert the certificate of interest.
+ * @throws TspValidationException if the certicate fails on one of the check points.
+ */
+ public static void ValidateCertificate(
+ X509Certificate cert)
+ {
+ if (cert.Version != 3)
+ throw new ArgumentException("Certificate must have an ExtendedKeyUsage extension.");
+
+ Asn1OctetString ext = cert.GetExtensionValue(X509Extensions.ExtendedKeyUsage);
+ if (ext == null)
+ throw new TspValidationException("Certificate must have an ExtendedKeyUsage extension.");
+
+ if (!cert.GetCriticalExtensionOids().Contains(X509Extensions.ExtendedKeyUsage.Id))
+ throw new TspValidationException("Certificate must have an ExtendedKeyUsage extension marked as critical.");
+
+ try
+ {
+ ExtendedKeyUsage extKey = ExtendedKeyUsage.GetInstance(
+ Asn1Object.FromByteArray(ext.GetOctets()));
+
+ if (!extKey.HasKeyPurposeId(KeyPurposeID.IdKPTimeStamping) || extKey.Count != 1)
+ throw new TspValidationException("ExtendedKeyUsage not solely time stamping.");
+ }
+ catch (IOException)
+ {
+ throw new TspValidationException("cannot process ExtendedKeyUsage extension");
+ }
+ }
+
+ ///
+ /// Return the digest algorithm using one of the standard JCA string
+ /// representations rather than the algorithm identifier (if possible).
+ ///
+ internal static string GetDigestAlgName(
+ string digestAlgOID)
+ {
+ string digestName = (string) digestNames[digestAlgOID];
+
+ return digestName != null ? digestName : digestAlgOID;
+ }
+
+ internal static int GetDigestLength(
+ string digestAlgOID)
+ {
+ if (!digestLengths.Contains(digestAlgOID))
+ throw new TspException("digest algorithm cannot be found.");
+
+ return (int)digestLengths[digestAlgOID];
+ }
+
+ internal static IDigest CreateDigestInstance(
+ String digestAlgOID)
+ {
+ string digestName = GetDigestAlgName(digestAlgOID);
+
+ return DigestUtilities.GetDigest(digestName);
+ }
+
+ internal static ISet GetCriticalExtensionOids(X509Extensions extensions)
+ {
+ if (extensions == null)
+ return EmptySet;
+
+ return CollectionUtilities.ReadOnly(new HashSet(extensions.GetCriticalExtensionOids()));
+ }
+
+ internal static ISet GetNonCriticalExtensionOids(X509Extensions extensions)
+ {
+ if (extensions == null)
+ return EmptySet;
+
+ // TODO: should probably produce a set that imposes correct ordering
+ return CollectionUtilities.ReadOnly(new HashSet(extensions.GetNonCriticalExtensionOids()));
+ }
+
+ internal static IList GetExtensionOids(X509Extensions extensions)
+ {
+ if (extensions == null)
+ return EmptyList;
+
+ return CollectionUtilities.ReadOnly(Platform.CreateArrayList(extensions.GetExtensionOids()));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/tsp/TSPValidationException.cs b/bc-sharp-crypto/src/tsp/TSPValidationException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..80f64203bd466f81038877c03c33ce997ebc84af
--- /dev/null
+++ b/bc-sharp-crypto/src/tsp/TSPValidationException.cs
@@ -0,0 +1,44 @@
+using System;
+
+namespace Org.BouncyCastle.Tsp
+{
+ /**
+ * Exception thrown if a TSP request or response fails to validate.
+ *
+ * If a failure code is associated with the exception it can be retrieved using
+ * the getFailureCode() method.
+ */
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class TspValidationException
+ : TspException
+ {
+ private int failureCode;
+
+ public TspValidationException(
+ string message)
+ : base(message)
+ {
+ this.failureCode = -1;
+ }
+
+ public TspValidationException(
+ string message,
+ int failureCode)
+ : base(message)
+ {
+ this.failureCode = failureCode;
+ }
+
+ /**
+ * Return the failure code associated with this exception - if one is set.
+ *
+ * @return the failure code if set, -1 otherwise.
+ */
+ public int FailureCode
+ {
+ get { return failureCode; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/tsp/TimeStampRequest.cs b/bc-sharp-crypto/src/tsp/TimeStampRequest.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0b41adef7940cc6f638d4c1c3c340bec385a1db5
--- /dev/null
+++ b/bc-sharp-crypto/src/tsp/TimeStampRequest.cs
@@ -0,0 +1,186 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Tsp
+{
+ /**
+ * Base class for an RFC 3161 Time Stamp Request.
+ */
+ public class TimeStampRequest
+ : X509ExtensionBase
+ {
+ private TimeStampReq req;
+ private X509Extensions extensions;
+
+ public TimeStampRequest(
+ TimeStampReq req)
+ {
+ this.req = req;
+ this.extensions = req.Extensions;
+ }
+
+ /**
+ * Create a TimeStampRequest from the past in byte array.
+ *
+ * @param req byte array containing the request.
+ * @throws IOException if the request is malformed.
+ */
+ public TimeStampRequest(
+ byte[] req)
+ : this(new Asn1InputStream(req))
+ {
+ }
+
+ /**
+ * Create a TimeStampRequest from the past in input stream.
+ *
+ * @param in input stream containing the request.
+ * @throws IOException if the request is malformed.
+ */
+ public TimeStampRequest(
+ Stream input)
+ : this(new Asn1InputStream(input))
+ {
+ }
+
+ private TimeStampRequest(
+ Asn1InputStream str)
+ {
+ try
+ {
+ this.req = TimeStampReq.GetInstance(str.ReadObject());
+ }
+ catch (InvalidCastException e)
+ {
+ throw new IOException("malformed request: " + e);
+ }
+ catch (ArgumentException e)
+ {
+ throw new IOException("malformed request: " + e);
+ }
+ }
+
+ public int Version
+ {
+ get { return req.Version.Value.IntValue; }
+ }
+
+ public string MessageImprintAlgOid
+ {
+ get { return req.MessageImprint.HashAlgorithm.Algorithm.Id; }
+ }
+
+ public byte[] GetMessageImprintDigest()
+ {
+ return req.MessageImprint.GetHashedMessage();
+ }
+
+ public string ReqPolicy
+ {
+ get
+ {
+ return req.ReqPolicy == null
+ ? null
+ : req.ReqPolicy.Id;
+ }
+ }
+
+ public BigInteger Nonce
+ {
+ get
+ {
+ return req.Nonce == null
+ ? null
+ : req.Nonce.Value;
+ }
+ }
+
+ public bool CertReq
+ {
+ get
+ {
+ return req.CertReq == null
+ ? false
+ : req.CertReq.IsTrue;
+ }
+ }
+
+ /**
+ * Validate the timestamp request, checking the digest to see if it is of an
+ * accepted type and whether it is of the correct length for the algorithm specified.
+ *
+ * @param algorithms a set of string OIDS giving accepted algorithms.
+ * @param policies if non-null a set of policies we are willing to sign under.
+ * @param extensions if non-null a set of extensions we are willing to accept.
+ * @throws TspException if the request is invalid, or processing fails.
+ */
+ public void Validate(
+ IList algorithms,
+ IList policies,
+ IList extensions)
+ {
+ if (!algorithms.Contains(this.MessageImprintAlgOid))
+ throw new TspValidationException("request contains unknown algorithm", PkiFailureInfo.BadAlg);
+
+ if (policies != null && this.ReqPolicy != null && !policies.Contains(this.ReqPolicy))
+ throw new TspValidationException("request contains unknown policy", PkiFailureInfo.UnacceptedPolicy);
+
+ if (this.Extensions != null && extensions != null)
+ {
+ foreach (DerObjectIdentifier oid in this.Extensions.ExtensionOids)
+ {
+ if (!extensions.Contains(oid.Id))
+ throw new TspValidationException("request contains unknown extension", PkiFailureInfo.UnacceptedExtension);
+ }
+ }
+
+ int digestLength = TspUtil.GetDigestLength(this.MessageImprintAlgOid);
+
+ if (digestLength != this.GetMessageImprintDigest().Length)
+ throw new TspValidationException("imprint digest the wrong length", PkiFailureInfo.BadDataFormat);
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] GetEncoded()
+ {
+ return req.GetEncoded();
+ }
+
+ internal X509Extensions Extensions
+ {
+ get { return req.Extensions; }
+ }
+
+ public virtual bool HasExtensions
+ {
+ get { return extensions != null; }
+ }
+
+ public virtual X509Extension GetExtension(DerObjectIdentifier oid)
+ {
+ return extensions == null ? null : extensions.GetExtension(oid);
+ }
+
+ public virtual IList GetExtensionOids()
+ {
+ return TspUtil.GetExtensionOids(extensions);
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return Extensions;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/tsp/TimeStampRequestGenerator.cs b/bc-sharp-crypto/src/tsp/TimeStampRequestGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2c698e47627213bbd3bb57b70d85ff30adc68ebd
--- /dev/null
+++ b/bc-sharp-crypto/src/tsp/TimeStampRequestGenerator.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Tsp
+{
+ /**
+ * Generator for RFC 3161 Time Stamp Request objects.
+ */
+ public class TimeStampRequestGenerator
+ {
+ private DerObjectIdentifier reqPolicy;
+
+ private DerBoolean certReq;
+
+ private IDictionary extensions = Platform.CreateHashtable();
+ private IList extOrdering = Platform.CreateArrayList();
+
+ public void SetReqPolicy(
+ string reqPolicy)
+ {
+ this.reqPolicy = new DerObjectIdentifier(reqPolicy);
+ }
+
+ public void SetCertReq(
+ bool certReq)
+ {
+ this.certReq = DerBoolean.GetInstance(certReq);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * @throws IOException
+ */
+ [Obsolete("Use method taking DerObjectIdentifier")]
+ public void AddExtension(
+ string oid,
+ bool critical,
+ Asn1Encodable value)
+ {
+ this.AddExtension(oid, critical, value.GetEncoded());
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag
+ * The value parameter becomes the contents of the octet string associated
+ * with the extension.
+ */
+ [Obsolete("Use method taking DerObjectIdentifier")]
+ public void AddExtension(
+ string oid,
+ bool critical,
+ byte[] value)
+ {
+ DerObjectIdentifier derOid = new DerObjectIdentifier(oid);
+ extensions[derOid] = new X509Extension(critical, new DerOctetString(value));
+ extOrdering.Add(derOid);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * @throws IOException
+ */
+ public virtual void AddExtension(
+ DerObjectIdentifier oid,
+ bool critical,
+ Asn1Encodable extValue)
+ {
+ this.AddExtension(oid, critical, extValue.GetEncoded());
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag
+ * The value parameter becomes the contents of the octet string associated
+ * with the extension.
+ */
+ public virtual void AddExtension(
+ DerObjectIdentifier oid,
+ bool critical,
+ byte[] extValue)
+ {
+ extensions.Add(oid, new X509Extension(critical, new DerOctetString(extValue)));
+ extOrdering.Add(oid);
+ }
+
+ public TimeStampRequest Generate(
+ string digestAlgorithm,
+ byte[] digest)
+ {
+ return this.Generate(digestAlgorithm, digest, null);
+ }
+
+ public TimeStampRequest Generate(
+ string digestAlgorithmOid,
+ byte[] digest,
+ BigInteger nonce)
+ {
+ if (digestAlgorithmOid == null)
+ {
+ throw new ArgumentException("No digest algorithm specified");
+ }
+
+ DerObjectIdentifier digestAlgOid = new DerObjectIdentifier(digestAlgorithmOid);
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOid, DerNull.Instance);
+ MessageImprint messageImprint = new MessageImprint(algID, digest);
+
+ X509Extensions ext = null;
+
+ if (extOrdering.Count != 0)
+ {
+ ext = new X509Extensions(extOrdering, extensions);
+ }
+
+ DerInteger derNonce = nonce == null
+ ? null
+ : new DerInteger(nonce);
+
+ return new TimeStampRequest(
+ new TimeStampReq(messageImprint, reqPolicy, derNonce, certReq, ext));
+ }
+
+ public virtual TimeStampRequest Generate(DerObjectIdentifier digestAlgorithm, byte[] digest)
+ {
+ return Generate(digestAlgorithm.Id, digest);
+ }
+
+ public virtual TimeStampRequest Generate(DerObjectIdentifier digestAlgorithm, byte[] digest, BigInteger nonce)
+ {
+ return Generate(digestAlgorithm.Id, digest, nonce);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/tsp/TimeStampResponse.cs b/bc-sharp-crypto/src/tsp/TimeStampResponse.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0695211114da1d77a15b3ac98984aca4dd48fb7a
--- /dev/null
+++ b/bc-sharp-crypto/src/tsp/TimeStampResponse.cs
@@ -0,0 +1,184 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Tsp
+{
+ /**
+ * Base class for an RFC 3161 Time Stamp Response object.
+ */
+ public class TimeStampResponse
+ {
+ private TimeStampResp resp;
+ private TimeStampToken timeStampToken;
+
+ public TimeStampResponse(
+ TimeStampResp resp)
+ {
+ this.resp = resp;
+
+ if (resp.TimeStampToken != null)
+ {
+ timeStampToken = new TimeStampToken(resp.TimeStampToken);
+ }
+ }
+
+ /**
+ * Create a TimeStampResponse from a byte array containing an ASN.1 encoding.
+ *
+ * @param resp the byte array containing the encoded response.
+ * @throws TspException if the response is malformed.
+ * @throws IOException if the byte array doesn't represent an ASN.1 encoding.
+ */
+ public TimeStampResponse(
+ byte[] resp)
+ : this(readTimeStampResp(new Asn1InputStream(resp)))
+ {
+ }
+
+ /**
+ * Create a TimeStampResponse from an input stream containing an ASN.1 encoding.
+ *
+ * @param input the input stream containing the encoded response.
+ * @throws TspException if the response is malformed.
+ * @throws IOException if the stream doesn't represent an ASN.1 encoding.
+ */
+ public TimeStampResponse(
+ Stream input)
+ : this(readTimeStampResp(new Asn1InputStream(input)))
+ {
+ }
+
+ private static TimeStampResp readTimeStampResp(
+ Asn1InputStream input)
+ {
+ try
+ {
+ return TimeStampResp.GetInstance(input.ReadObject());
+ }
+ catch (ArgumentException e)
+ {
+ throw new TspException("malformed timestamp response: " + e, e);
+ }
+ catch (InvalidCastException e)
+ {
+ throw new TspException("malformed timestamp response: " + e, e);
+ }
+ }
+
+ public int Status
+ {
+ get { return resp.Status.Status.IntValue; }
+ }
+
+ public string GetStatusString()
+ {
+ if (resp.Status.StatusString == null)
+ {
+ return null;
+ }
+
+ StringBuilder statusStringBuf = new StringBuilder();
+ PkiFreeText text = resp.Status.StatusString;
+ for (int i = 0; i != text.Count; i++)
+ {
+ statusStringBuf.Append(text[i].GetString());
+ }
+
+ return statusStringBuf.ToString();
+ }
+
+ public PkiFailureInfo GetFailInfo()
+ {
+ if (resp.Status.FailInfo == null)
+ {
+ return null;
+ }
+
+ return new PkiFailureInfo(resp.Status.FailInfo);
+ }
+
+ public TimeStampToken TimeStampToken
+ {
+ get { return timeStampToken; }
+ }
+
+ /**
+ * Check this response against to see if it a well formed response for
+ * the passed in request. Validation will include checking the time stamp
+ * token if the response status is GRANTED or GRANTED_WITH_MODS.
+ *
+ * @param request the request to be checked against
+ * @throws TspException if the request can not match this response.
+ */
+ public void Validate(
+ TimeStampRequest request)
+ {
+ TimeStampToken tok = this.TimeStampToken;
+
+ if (tok != null)
+ {
+ TimeStampTokenInfo tstInfo = tok.TimeStampInfo;
+
+ if (request.Nonce != null && !request.Nonce.Equals(tstInfo.Nonce))
+ {
+ throw new TspValidationException("response contains wrong nonce value.");
+ }
+
+ if (this.Status != (int) PkiStatus.Granted && this.Status != (int) PkiStatus.GrantedWithMods)
+ {
+ throw new TspValidationException("time stamp token found in failed request.");
+ }
+
+ if (!Arrays.ConstantTimeAreEqual(request.GetMessageImprintDigest(), tstInfo.GetMessageImprintDigest()))
+ {
+ throw new TspValidationException("response for different message imprint digest.");
+ }
+
+ if (!tstInfo.MessageImprintAlgOid.Equals(request.MessageImprintAlgOid))
+ {
+ throw new TspValidationException("response for different message imprint algorithm.");
+ }
+
+ Asn1.Cms.Attribute scV1 = tok.SignedAttributes[PkcsObjectIdentifiers.IdAASigningCertificate];
+ Asn1.Cms.Attribute scV2 = tok.SignedAttributes[PkcsObjectIdentifiers.IdAASigningCertificateV2];
+
+ if (scV1 == null && scV2 == null)
+ {
+ throw new TspValidationException("no signing certificate attribute present.");
+ }
+
+ if (scV1 != null && scV2 != null)
+ {
+ /*
+ * RFC 5035 5.4. If both attributes exist in a single message,
+ * they are independently evaluated.
+ */
+ }
+
+ if (request.ReqPolicy != null && !request.ReqPolicy.Equals(tstInfo.Policy))
+ {
+ throw new TspValidationException("TSA policy wrong for request.");
+ }
+ }
+ else if (this.Status == (int) PkiStatus.Granted || this.Status == (int) PkiStatus.GrantedWithMods)
+ {
+ throw new TspValidationException("no time stamp token found and one expected.");
+ }
+ }
+
+ /**
+ * return the ASN.1 encoded representation of this object.
+ */
+ public byte[] GetEncoded()
+ {
+ return resp.GetEncoded();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/tsp/TimeStampResponseGenerator.cs b/bc-sharp-crypto/src/tsp/TimeStampResponseGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b596f8d9701dc1ac3fe916adc1638f072d4ee96b
--- /dev/null
+++ b/bc-sharp-crypto/src/tsp/TimeStampResponseGenerator.cs
@@ -0,0 +1,209 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Tsp
+{
+ /**
+ * Generator for RFC 3161 Time Stamp Responses.
+ */
+ public class TimeStampResponseGenerator
+ {
+ private PkiStatus status;
+
+ private Asn1EncodableVector statusStrings;
+
+ private int failInfo;
+ private TimeStampTokenGenerator tokenGenerator;
+ private IList acceptedAlgorithms;
+ private IList acceptedPolicies;
+ private IList acceptedExtensions;
+
+ public TimeStampResponseGenerator(
+ TimeStampTokenGenerator tokenGenerator,
+ IList acceptedAlgorithms)
+ : this(tokenGenerator, acceptedAlgorithms, null, null)
+ {
+ }
+
+ public TimeStampResponseGenerator(
+ TimeStampTokenGenerator tokenGenerator,
+ IList acceptedAlgorithms,
+ IList acceptedPolicy)
+ : this(tokenGenerator, acceptedAlgorithms, acceptedPolicy, null)
+ {
+ }
+
+ public TimeStampResponseGenerator(
+ TimeStampTokenGenerator tokenGenerator,
+ IList acceptedAlgorithms,
+ IList acceptedPolicies,
+ IList acceptedExtensions)
+ {
+ this.tokenGenerator = tokenGenerator;
+ this.acceptedAlgorithms = acceptedAlgorithms;
+ this.acceptedPolicies = acceptedPolicies;
+ this.acceptedExtensions = acceptedExtensions;
+
+ statusStrings = new Asn1EncodableVector();
+ }
+
+ private void AddStatusString(string statusString)
+ {
+ statusStrings.Add(new DerUtf8String(statusString));
+ }
+
+ private void SetFailInfoField(int field)
+ {
+ failInfo |= field;
+ }
+
+ private PkiStatusInfo GetPkiStatusInfo()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ new DerInteger((int)status));
+
+ if (statusStrings.Count > 0)
+ {
+ v.Add(new PkiFreeText(new DerSequence(statusStrings)));
+ }
+
+ if (failInfo != 0)
+ {
+ v.Add(new FailInfo(failInfo));
+ }
+
+ return new PkiStatusInfo(new DerSequence(v));
+ }
+
+ public TimeStampResponse Generate(
+ TimeStampRequest request,
+ BigInteger serialNumber,
+ DateTime genTime)
+ {
+ return Generate(request, serialNumber, new DateTimeObject(genTime));
+ }
+
+ /**
+ * Return an appropriate TimeStampResponse.
+ *
+ * If genTime is null a timeNotAvailable error response will be returned.
+ *
+ * @param request the request this response is for.
+ * @param serialNumber serial number for the response token.
+ * @param genTime generation time for the response token.
+ * @param provider provider to use for signature calculation.
+ * @return
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchProviderException
+ * @throws TSPException
+ *
+ */
+ public TimeStampResponse Generate(
+ TimeStampRequest request,
+ BigInteger serialNumber,
+ DateTimeObject genTime)
+ {
+ TimeStampResp resp;
+
+ try
+ {
+ if (genTime == null)
+ throw new TspValidationException("The time source is not available.",
+ PkiFailureInfo.TimeNotAvailable);
+
+ request.Validate(acceptedAlgorithms, acceptedPolicies, acceptedExtensions);
+
+ this.status = PkiStatus.Granted;
+ this.AddStatusString("Operation Okay");
+
+ PkiStatusInfo pkiStatusInfo = GetPkiStatusInfo();
+
+ ContentInfo tstTokenContentInfo;
+ try
+ {
+ TimeStampToken token = tokenGenerator.Generate(request, serialNumber, genTime.Value);
+ byte[] encoded = token.ToCmsSignedData().GetEncoded();
+
+ tstTokenContentInfo = ContentInfo.GetInstance(Asn1Object.FromByteArray(encoded));
+ }
+ catch (IOException e)
+ {
+ throw new TspException("Timestamp token received cannot be converted to ContentInfo", e);
+ }
+
+ resp = new TimeStampResp(pkiStatusInfo, tstTokenContentInfo);
+ }
+ catch (TspValidationException e)
+ {
+ status = PkiStatus.Rejection;
+
+ this.SetFailInfoField(e.FailureCode);
+ this.AddStatusString(e.Message);
+
+ PkiStatusInfo pkiStatusInfo = GetPkiStatusInfo();
+
+ resp = new TimeStampResp(pkiStatusInfo, null);
+ }
+
+ try
+ {
+ return new TimeStampResponse(resp);
+ }
+ catch (IOException e)
+ {
+ throw new TspException("created badly formatted response!", e);
+ }
+ }
+
+ class FailInfo
+ : DerBitString
+ {
+ internal FailInfo(int failInfoValue)
+ : base(failInfoValue)
+ {
+ }
+ }
+
+ /**
+ * Generate a TimeStampResponse with chosen status and FailInfoField.
+ *
+ * @param status the PKIStatus to set.
+ * @param failInfoField the FailInfoField to set.
+ * @param statusString an optional string describing the failure.
+ * @return a TimeStampResponse with a failInfoField and optional statusString
+ * @throws TSPException in case the response could not be created
+ */
+ public TimeStampResponse GenerateFailResponse(PkiStatus status, int failInfoField, string statusString)
+ {
+ this.status = status;
+
+ this.SetFailInfoField(failInfoField);
+
+ if (statusString != null)
+ {
+ this.AddStatusString(statusString);
+ }
+
+ PkiStatusInfo pkiStatusInfo = GetPkiStatusInfo();
+
+ TimeStampResp resp = new TimeStampResp(pkiStatusInfo, null);
+
+ try
+ {
+ return new TimeStampResponse(resp);
+ }
+ catch (IOException e)
+ {
+ throw new TspException("created badly formatted response!", e);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/tsp/TimeStampToken.cs b/bc-sharp-crypto/src/tsp/TimeStampToken.cs
new file mode 100644
index 0000000000000000000000000000000000000000..105208a7df79a27be7b293704ec14d7bc5588fc8
--- /dev/null
+++ b/bc-sharp-crypto/src/tsp/TimeStampToken.cs
@@ -0,0 +1,305 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ess;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Tsp
+{
+ public class TimeStampToken
+ {
+ private readonly CmsSignedData tsToken;
+ private readonly SignerInformation tsaSignerInfo;
+// private readonly DateTime genTime;
+ private readonly TimeStampTokenInfo tstInfo;
+ private readonly CertID certID;
+
+ public TimeStampToken(
+ Asn1.Cms.ContentInfo contentInfo)
+ : this(new CmsSignedData(contentInfo))
+ {
+ }
+
+ public TimeStampToken(
+ CmsSignedData signedData)
+ {
+ this.tsToken = signedData;
+
+ if (!this.tsToken.SignedContentType.Equals(PkcsObjectIdentifiers.IdCTTstInfo))
+ {
+ throw new TspValidationException("ContentInfo object not for a time stamp.");
+ }
+
+ ICollection signers = tsToken.GetSignerInfos().GetSigners();
+
+ if (signers.Count != 1)
+ {
+ throw new ArgumentException("Time-stamp token signed by "
+ + signers.Count
+ + " signers, but it must contain just the TSA signature.");
+ }
+
+
+ IEnumerator signerEnum = signers.GetEnumerator();
+
+ signerEnum.MoveNext();
+ tsaSignerInfo = (SignerInformation) signerEnum.Current;
+
+ try
+ {
+ CmsProcessable content = tsToken.SignedContent;
+ MemoryStream bOut = new MemoryStream();
+
+ content.Write(bOut);
+
+ this.tstInfo = new TimeStampTokenInfo(
+ TstInfo.GetInstance(
+ Asn1Object.FromByteArray(bOut.ToArray())));
+
+ Asn1.Cms.Attribute attr = tsaSignerInfo.SignedAttributes[
+ PkcsObjectIdentifiers.IdAASigningCertificate];
+
+// if (attr == null)
+// {
+// throw new TspValidationException(
+// "no signing certificate attribute found, time stamp invalid.");
+// }
+//
+// SigningCertificate signCert = SigningCertificate.GetInstance(
+// attr.AttrValues[0]);
+//
+// this.certID = EssCertID.GetInstance(signCert.GetCerts()[0]);
+
+ if (attr != null)
+ {
+ SigningCertificate signCert = SigningCertificate.GetInstance(attr.AttrValues[0]);
+
+ this.certID = new CertID(EssCertID.GetInstance(signCert.GetCerts()[0]));
+ }
+ else
+ {
+ attr = tsaSignerInfo.SignedAttributes[PkcsObjectIdentifiers.IdAASigningCertificateV2];
+
+ if (attr == null)
+ throw new TspValidationException("no signing certificate attribute found, time stamp invalid.");
+
+ SigningCertificateV2 signCertV2 = SigningCertificateV2.GetInstance(attr.AttrValues[0]);
+
+ this.certID = new CertID(EssCertIDv2.GetInstance(signCertV2.GetCerts()[0]));
+ }
+ }
+ catch (CmsException e)
+ {
+ throw new TspException(e.Message, e.InnerException);
+ }
+ }
+
+ public TimeStampTokenInfo TimeStampInfo
+ {
+ get { return tstInfo; }
+ }
+
+ public SignerID SignerID
+ {
+ get { return tsaSignerInfo.SignerID; }
+ }
+
+ public Asn1.Cms.AttributeTable SignedAttributes
+ {
+ get { return tsaSignerInfo.SignedAttributes; }
+ }
+
+ public Asn1.Cms.AttributeTable UnsignedAttributes
+ {
+ get { return tsaSignerInfo.UnsignedAttributes; }
+ }
+
+ public IX509Store GetCertificates(
+ string type)
+ {
+ return tsToken.GetCertificates(type);
+ }
+
+ public IX509Store GetCrls(
+ string type)
+ {
+ return tsToken.GetCrls(type);
+ }
+
+ public IX509Store GetAttributeCertificates(
+ string type)
+ {
+ return tsToken.GetAttributeCertificates(type);
+ }
+
+ /**
+ * Validate the time stamp token.
+ *
+ * To be valid the token must be signed by the passed in certificate and
+ * the certificate must be the one referred to by the SigningCertificate
+ * attribute included in the hashed attributes of the token. The
+ * certificate must also have the ExtendedKeyUsageExtension with only
+ * KeyPurposeID.IdKPTimeStamping and have been valid at the time the
+ * timestamp was created.
+ *
+ *
+ * A successful call to validate means all the above are true.
+ *
+ */
+ public void Validate(
+ X509Certificate cert)
+ {
+ try
+ {
+ byte[] hash = DigestUtilities.CalculateDigest(
+ certID.GetHashAlgorithmName(), cert.GetEncoded());
+
+ if (!Arrays.ConstantTimeAreEqual(certID.GetCertHash(), hash))
+ {
+ throw new TspValidationException("certificate hash does not match certID hash.");
+ }
+
+ if (certID.IssuerSerial != null)
+ {
+ if (!certID.IssuerSerial.Serial.Value.Equals(cert.SerialNumber))
+ {
+ throw new TspValidationException("certificate serial number does not match certID for signature.");
+ }
+
+ GeneralName[] names = certID.IssuerSerial.Issuer.GetNames();
+ X509Name principal = PrincipalUtilities.GetIssuerX509Principal(cert);
+ bool found = false;
+
+ for (int i = 0; i != names.Length; i++)
+ {
+ if (names[i].TagNo == 4
+ && X509Name.GetInstance(names[i].Name).Equivalent(principal))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ throw new TspValidationException("certificate name does not match certID for signature. ");
+ }
+ }
+
+ TspUtil.ValidateCertificate(cert);
+
+ cert.CheckValidity(tstInfo.GenTime);
+
+ if (!tsaSignerInfo.Verify(cert))
+ {
+ throw new TspValidationException("signature not created by certificate.");
+ }
+ }
+ catch (CmsException e)
+ {
+ if (e.InnerException != null)
+ {
+ throw new TspException(e.Message, e.InnerException);
+ }
+
+ throw new TspException("CMS exception: " + e, e);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new TspException("problem processing certificate: " + e, e);
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw new TspException("cannot find algorithm: " + e.Message, e);
+ }
+ }
+
+ /**
+ * Return the underlying CmsSignedData object.
+ *
+ * @return the underlying CMS structure.
+ */
+ public CmsSignedData ToCmsSignedData()
+ {
+ return tsToken;
+ }
+
+ /**
+ * Return a ASN.1 encoded byte stream representing the encoded object.
+ *
+ * @throws IOException if encoding fails.
+ */
+ public byte[] GetEncoded()
+ {
+ return tsToken.GetEncoded();
+ }
+
+
+ // perhaps this should be done using an interface on the ASN.1 classes...
+ private class CertID
+ {
+ private EssCertID certID;
+ private EssCertIDv2 certIDv2;
+
+ internal CertID(EssCertID certID)
+ {
+ this.certID = certID;
+ this.certIDv2 = null;
+ }
+
+ internal CertID(EssCertIDv2 certID)
+ {
+ this.certIDv2 = certID;
+ this.certID = null;
+ }
+
+ public string GetHashAlgorithmName()
+ {
+ if (certID != null)
+ return "SHA-1";
+
+ if (NistObjectIdentifiers.IdSha256.Equals(certIDv2.HashAlgorithm.Algorithm))
+ return "SHA-256";
+
+ return certIDv2.HashAlgorithm.Algorithm.Id;
+ }
+
+ public AlgorithmIdentifier GetHashAlgorithm()
+ {
+ return (certID != null)
+ ? new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1)
+ : certIDv2.HashAlgorithm;
+ }
+
+ public byte[] GetCertHash()
+ {
+ return certID != null
+ ? certID.GetCertHash()
+ : certIDv2.GetCertHash();
+ }
+
+ public IssuerSerial IssuerSerial
+ {
+ get
+ {
+ return certID != null
+ ? certID.IssuerSerial
+ : certIDv2.IssuerSerial;
+ }
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/tsp/TimeStampTokenGenerator.cs b/bc-sharp-crypto/src/tsp/TimeStampTokenGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..07eddd4b9875ad898a26ef4ad0171cfc98cf9da2
--- /dev/null
+++ b/bc-sharp-crypto/src/tsp/TimeStampTokenGenerator.cs
@@ -0,0 +1,245 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ess;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Tsp
+{
+ public class TimeStampTokenGenerator
+ {
+ private int accuracySeconds = -1;
+ private int accuracyMillis = -1;
+ private int accuracyMicros = -1;
+ private bool ordering = false;
+ private GeneralName tsa = null;
+ private string tsaPolicyOID;
+
+ private AsymmetricKeyParameter key;
+ private X509Certificate cert;
+ private string digestOID;
+ private Asn1.Cms.AttributeTable signedAttr;
+ private Asn1.Cms.AttributeTable unsignedAttr;
+ private IX509Store x509Certs;
+ private IX509Store x509Crls;
+
+ /**
+ * basic creation - only the default attributes will be included here.
+ */
+ public TimeStampTokenGenerator(
+ AsymmetricKeyParameter key,
+ X509Certificate cert,
+ string digestOID,
+ string tsaPolicyOID)
+ : this(key, cert, digestOID, tsaPolicyOID, null, null)
+ {
+ }
+
+ /**
+ * create with a signer with extra signed/unsigned attributes.
+ */
+ public TimeStampTokenGenerator(
+ AsymmetricKeyParameter key,
+ X509Certificate cert,
+ string digestOID,
+ string tsaPolicyOID,
+ Asn1.Cms.AttributeTable signedAttr,
+ Asn1.Cms.AttributeTable unsignedAttr)
+ {
+ this.key = key;
+ this.cert = cert;
+ this.digestOID = digestOID;
+ this.tsaPolicyOID = tsaPolicyOID;
+ this.unsignedAttr = unsignedAttr;
+
+ TspUtil.ValidateCertificate(cert);
+
+ //
+ // Add the ESSCertID attribute
+ //
+ IDictionary signedAttrs;
+ if (signedAttr != null)
+ {
+ signedAttrs = signedAttr.ToDictionary();
+ }
+ else
+ {
+ signedAttrs = Platform.CreateHashtable();
+ }
+
+ try
+ {
+ byte[] hash = DigestUtilities.CalculateDigest("SHA-1", cert.GetEncoded());
+
+ EssCertID essCertid = new EssCertID(hash);
+
+ Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(
+ PkcsObjectIdentifiers.IdAASigningCertificate,
+ new DerSet(new SigningCertificate(essCertid)));
+
+ signedAttrs[attr.AttrType] = attr;
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new TspException("Exception processing certificate.", e);
+ }
+ catch (SecurityUtilityException e)
+ {
+ throw new TspException("Can't find a SHA-1 implementation.", e);
+ }
+
+ this.signedAttr = new Asn1.Cms.AttributeTable(signedAttrs);
+ }
+
+ public void SetCertificates(
+ IX509Store certificates)
+ {
+ this.x509Certs = certificates;
+ }
+
+ public void SetCrls(
+ IX509Store crls)
+ {
+ this.x509Crls = crls;
+ }
+
+ public void SetAccuracySeconds(
+ int accuracySeconds)
+ {
+ this.accuracySeconds = accuracySeconds;
+ }
+
+ public void SetAccuracyMillis(
+ int accuracyMillis)
+ {
+ this.accuracyMillis = accuracyMillis;
+ }
+
+ public void SetAccuracyMicros(
+ int accuracyMicros)
+ {
+ this.accuracyMicros = accuracyMicros;
+ }
+
+ public void SetOrdering(
+ bool ordering)
+ {
+ this.ordering = ordering;
+ }
+
+ public void SetTsa(
+ GeneralName tsa)
+ {
+ this.tsa = tsa;
+ }
+
+ //------------------------------------------------------------------------------
+
+ public TimeStampToken Generate(
+ TimeStampRequest request,
+ BigInteger serialNumber,
+ DateTime genTime)
+ {
+ DerObjectIdentifier digestAlgOID = new DerObjectIdentifier(request.MessageImprintAlgOid);
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOID, DerNull.Instance);
+ MessageImprint messageImprint = new MessageImprint(algID, request.GetMessageImprintDigest());
+
+ Accuracy accuracy = null;
+ if (accuracySeconds > 0 || accuracyMillis > 0 || accuracyMicros > 0)
+ {
+ DerInteger seconds = null;
+ if (accuracySeconds > 0)
+ {
+ seconds = new DerInteger(accuracySeconds);
+ }
+
+ DerInteger millis = null;
+ if (accuracyMillis > 0)
+ {
+ millis = new DerInteger(accuracyMillis);
+ }
+
+ DerInteger micros = null;
+ if (accuracyMicros > 0)
+ {
+ micros = new DerInteger(accuracyMicros);
+ }
+
+ accuracy = new Accuracy(seconds, millis, micros);
+ }
+
+ DerBoolean derOrdering = null;
+ if (ordering)
+ {
+ derOrdering = DerBoolean.GetInstance(ordering);
+ }
+
+ DerInteger nonce = null;
+ if (request.Nonce != null)
+ {
+ nonce = new DerInteger(request.Nonce);
+ }
+
+ DerObjectIdentifier tsaPolicy = new DerObjectIdentifier(tsaPolicyOID);
+ if (request.ReqPolicy != null)
+ {
+ tsaPolicy = new DerObjectIdentifier(request.ReqPolicy);
+ }
+
+ TstInfo tstInfo = new TstInfo(tsaPolicy, messageImprint,
+ new DerInteger(serialNumber), new DerGeneralizedTime(genTime), accuracy,
+ derOrdering, nonce, tsa, request.Extensions);
+
+ try
+ {
+ CmsSignedDataGenerator signedDataGenerator = new CmsSignedDataGenerator();
+
+ byte[] derEncodedTstInfo = tstInfo.GetDerEncoded();
+
+ if (request.CertReq)
+ {
+ signedDataGenerator.AddCertificates(x509Certs);
+ }
+
+ signedDataGenerator.AddCrls(x509Crls);
+ signedDataGenerator.AddSigner(key, cert, digestOID, signedAttr, unsignedAttr);
+
+ CmsSignedData signedData = signedDataGenerator.Generate(
+ PkcsObjectIdentifiers.IdCTTstInfo.Id,
+ new CmsProcessableByteArray(derEncodedTstInfo),
+ true);
+
+ return new TimeStampToken(signedData);
+ }
+ catch (CmsException cmsEx)
+ {
+ throw new TspException("Error generating time-stamp token", cmsEx);
+ }
+ catch (IOException e)
+ {
+ throw new TspException("Exception encoding info", e);
+ }
+ catch (X509StoreException e)
+ {
+ throw new TspException("Exception handling CertStore", e);
+ }
+// catch (InvalidAlgorithmParameterException e)
+// {
+// throw new TspException("Exception handling CertStore CRLs", e);
+// }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/tsp/TimeStampTokenInfo.cs b/bc-sharp-crypto/src/tsp/TimeStampTokenInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cdef826bc299718c5984463e972c39aed49951c6
--- /dev/null
+++ b/bc-sharp-crypto/src/tsp/TimeStampTokenInfo.cs
@@ -0,0 +1,107 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Tsp
+{
+ public class TimeStampTokenInfo
+ {
+ private TstInfo tstInfo;
+ private DateTime genTime;
+
+ public TimeStampTokenInfo(
+ TstInfo tstInfo)
+ {
+ this.tstInfo = tstInfo;
+
+ try
+ {
+ this.genTime = tstInfo.GenTime.ToDateTime();
+ }
+ catch (Exception e)
+ {
+ throw new TspException("unable to parse genTime field: " + e.Message);
+ }
+ }
+
+ public bool IsOrdered
+ {
+ get { return tstInfo.Ordering.IsTrue; }
+ }
+
+ public Accuracy Accuracy
+ {
+ get { return tstInfo.Accuracy; }
+ }
+
+ public DateTime GenTime
+ {
+ get { return genTime; }
+ }
+
+ public GenTimeAccuracy GenTimeAccuracy
+ {
+ get
+ {
+ return this.Accuracy == null
+ ? null
+ : new GenTimeAccuracy(this.Accuracy);
+ }
+ }
+
+ public string Policy
+ {
+ get { return tstInfo.Policy.Id; }
+ }
+
+ public BigInteger SerialNumber
+ {
+ get { return tstInfo.SerialNumber.Value; }
+ }
+
+ public GeneralName Tsa
+ {
+ get { return tstInfo.Tsa; }
+ }
+
+ /**
+ * @return the nonce value, null if there isn't one.
+ */
+ public BigInteger Nonce
+ {
+ get
+ {
+ return tstInfo.Nonce == null
+ ? null
+ : tstInfo.Nonce.Value;
+ }
+ }
+
+ public AlgorithmIdentifier HashAlgorithm
+ {
+ get { return tstInfo.MessageImprint.HashAlgorithm; }
+ }
+
+ public string MessageImprintAlgOid
+ {
+ get { return tstInfo.MessageImprint.HashAlgorithm.Algorithm.Id; }
+ }
+
+ public byte[] GetMessageImprintDigest()
+ {
+ return tstInfo.MessageImprint.GetHashedMessage();
+ }
+
+ public byte[] GetEncoded()
+ {
+ return tstInfo.GetEncoded();
+ }
+
+ public TstInfo TstInfo
+ {
+ get { return tstInfo; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/Arrays.cs b/bc-sharp-crypto/src/util/Arrays.cs
new file mode 100644
index 0000000000000000000000000000000000000000..df9b4e7eec1da7415fea2591229a9e8ab3def903
--- /dev/null
+++ b/bc-sharp-crypto/src/util/Arrays.cs
@@ -0,0 +1,704 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Utilities
+{
+ /// General array utilities.
+ public abstract class Arrays
+ {
+ public static bool AreEqual(
+ bool[] a,
+ bool[] b)
+ {
+ if (a == b)
+ return true;
+
+ if (a == null || b == null)
+ return false;
+
+ return HaveSameContents(a, b);
+ }
+
+ public static bool AreEqual(
+ char[] a,
+ char[] b)
+ {
+ if (a == b)
+ return true;
+
+ if (a == null || b == null)
+ return false;
+
+ return HaveSameContents(a, b);
+ }
+
+ ///
+ /// Are two arrays equal.
+ ///
+ /// Left side.
+ /// Right side.
+ /// True if equal.
+ public static bool AreEqual(
+ byte[] a,
+ byte[] b)
+ {
+ if (a == b)
+ return true;
+
+ if (a == null || b == null)
+ return false;
+
+ return HaveSameContents(a, b);
+ }
+
+ [Obsolete("Use 'AreEqual' method instead")]
+ public static bool AreSame(
+ byte[] a,
+ byte[] b)
+ {
+ return AreEqual(a, b);
+ }
+
+ ///
+ /// A constant time equals comparison - does not terminate early if
+ /// test will fail.
+ ///
+ /// first array
+ /// second array
+ /// true if arrays equal, false otherwise.
+ public static bool ConstantTimeAreEqual(
+ byte[] a,
+ byte[] b)
+ {
+ int i = a.Length;
+ if (i != b.Length)
+ return false;
+ int cmp = 0;
+ while (i != 0)
+ {
+ --i;
+ cmp |= (a[i] ^ b[i]);
+ }
+ return cmp == 0;
+ }
+
+ public static bool AreEqual(
+ int[] a,
+ int[] b)
+ {
+ if (a == b)
+ return true;
+
+ if (a == null || b == null)
+ return false;
+
+ return HaveSameContents(a, b);
+ }
+
+ [CLSCompliantAttribute(false)]
+ public static bool AreEqual(uint[] a, uint[] b)
+ {
+ if (a == b)
+ return true;
+
+ if (a == null || b == null)
+ return false;
+
+ return HaveSameContents(a, b);
+ }
+
+ private static bool HaveSameContents(
+ bool[] a,
+ bool[] b)
+ {
+ int i = a.Length;
+ if (i != b.Length)
+ return false;
+ while (i != 0)
+ {
+ --i;
+ if (a[i] != b[i])
+ return false;
+ }
+ return true;
+ }
+
+ private static bool HaveSameContents(
+ char[] a,
+ char[] b)
+ {
+ int i = a.Length;
+ if (i != b.Length)
+ return false;
+ while (i != 0)
+ {
+ --i;
+ if (a[i] != b[i])
+ return false;
+ }
+ return true;
+ }
+
+ private static bool HaveSameContents(
+ byte[] a,
+ byte[] b)
+ {
+ int i = a.Length;
+ if (i != b.Length)
+ return false;
+ while (i != 0)
+ {
+ --i;
+ if (a[i] != b[i])
+ return false;
+ }
+ return true;
+ }
+
+ private static bool HaveSameContents(
+ int[] a,
+ int[] b)
+ {
+ int i = a.Length;
+ if (i != b.Length)
+ return false;
+ while (i != 0)
+ {
+ --i;
+ if (a[i] != b[i])
+ return false;
+ }
+ return true;
+ }
+
+ private static bool HaveSameContents(uint[] a, uint[] b)
+ {
+ int i = a.Length;
+ if (i != b.Length)
+ return false;
+ while (i != 0)
+ {
+ --i;
+ if (a[i] != b[i])
+ return false;
+ }
+ return true;
+ }
+
+ public static string ToString(
+ object[] a)
+ {
+ StringBuilder sb = new StringBuilder('[');
+ if (a.Length > 0)
+ {
+ sb.Append(a[0]);
+ for (int index = 1; index < a.Length; ++index)
+ {
+ sb.Append(", ").Append(a[index]);
+ }
+ }
+ sb.Append(']');
+ return sb.ToString();
+ }
+
+ public static int GetHashCode(byte[] data)
+ {
+ if (data == null)
+ {
+ return 0;
+ }
+
+ int i = data.Length;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ hc *= 257;
+ hc ^= data[i];
+ }
+
+ return hc;
+ }
+
+ public static int GetHashCode(byte[] data, int off, int len)
+ {
+ if (data == null)
+ {
+ return 0;
+ }
+
+ int i = len;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ hc *= 257;
+ hc ^= data[off + i];
+ }
+
+ return hc;
+ }
+
+ public static int GetHashCode(int[] data)
+ {
+ if (data == null)
+ return 0;
+
+ int i = data.Length;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ hc *= 257;
+ hc ^= data[i];
+ }
+
+ return hc;
+ }
+
+ public static int GetHashCode(int[] data, int off, int len)
+ {
+ if (data == null)
+ return 0;
+
+ int i = len;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ hc *= 257;
+ hc ^= data[off + i];
+ }
+
+ return hc;
+ }
+
+ [CLSCompliantAttribute(false)]
+ public static int GetHashCode(uint[] data)
+ {
+ if (data == null)
+ return 0;
+
+ int i = data.Length;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ hc *= 257;
+ hc ^= (int)data[i];
+ }
+
+ return hc;
+ }
+
+ [CLSCompliantAttribute(false)]
+ public static int GetHashCode(uint[] data, int off, int len)
+ {
+ if (data == null)
+ return 0;
+
+ int i = len;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ hc *= 257;
+ hc ^= (int)data[off + i];
+ }
+
+ return hc;
+ }
+
+ [CLSCompliantAttribute(false)]
+ public static int GetHashCode(ulong[] data)
+ {
+ if (data == null)
+ return 0;
+
+ int i = data.Length;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ ulong di = data[i];
+ hc *= 257;
+ hc ^= (int)di;
+ hc *= 257;
+ hc ^= (int)(di >> 32);
+ }
+
+ return hc;
+ }
+
+ [CLSCompliantAttribute(false)]
+ public static int GetHashCode(ulong[] data, int off, int len)
+ {
+ if (data == null)
+ return 0;
+
+ int i = len;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ ulong di = data[off + i];
+ hc *= 257;
+ hc ^= (int)di;
+ hc *= 257;
+ hc ^= (int)(di >> 32);
+ }
+
+ return hc;
+ }
+
+ public static byte[] Clone(
+ byte[] data)
+ {
+ return data == null ? null : (byte[])data.Clone();
+ }
+
+ public static byte[] Clone(
+ byte[] data,
+ byte[] existing)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ if ((existing == null) || (existing.Length != data.Length))
+ {
+ return Clone(data);
+ }
+ Array.Copy(data, 0, existing, 0, existing.Length);
+ return existing;
+ }
+
+ public static int[] Clone(
+ int[] data)
+ {
+ return data == null ? null : (int[])data.Clone();
+ }
+
+ internal static uint[] Clone(uint[] data)
+ {
+ return data == null ? null : (uint[])data.Clone();
+ }
+
+ public static long[] Clone(long[] data)
+ {
+ return data == null ? null : (long[])data.Clone();
+ }
+
+ [CLSCompliantAttribute(false)]
+ public static ulong[] Clone(
+ ulong[] data)
+ {
+ return data == null ? null : (ulong[]) data.Clone();
+ }
+
+ [CLSCompliantAttribute(false)]
+ public static ulong[] Clone(
+ ulong[] data,
+ ulong[] existing)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ if ((existing == null) || (existing.Length != data.Length))
+ {
+ return Clone(data);
+ }
+ Array.Copy(data, 0, existing, 0, existing.Length);
+ return existing;
+ }
+
+ public static bool Contains(byte[] a, byte n)
+ {
+ for (int i = 0; i < a.Length; ++i)
+ {
+ if (a[i] == n)
+ return true;
+ }
+ return false;
+ }
+
+ public static bool Contains(short[] a, short n)
+ {
+ for (int i = 0; i < a.Length; ++i)
+ {
+ if (a[i] == n)
+ return true;
+ }
+ return false;
+ }
+
+ public static bool Contains(int[] a, int n)
+ {
+ for (int i = 0; i < a.Length; ++i)
+ {
+ if (a[i] == n)
+ return true;
+ }
+ return false;
+ }
+
+ public static void Fill(
+ byte[] buf,
+ byte b)
+ {
+ int i = buf.Length;
+ while (i > 0)
+ {
+ buf[--i] = b;
+ }
+ }
+
+ public static byte[] CopyOf(byte[] data, int newLength)
+ {
+ byte[] tmp = new byte[newLength];
+ Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length));
+ return tmp;
+ }
+
+ public static char[] CopyOf(char[] data, int newLength)
+ {
+ char[] tmp = new char[newLength];
+ Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length));
+ return tmp;
+ }
+
+ public static int[] CopyOf(int[] data, int newLength)
+ {
+ int[] tmp = new int[newLength];
+ Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length));
+ return tmp;
+ }
+
+ public static long[] CopyOf(long[] data, int newLength)
+ {
+ long[] tmp = new long[newLength];
+ Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length));
+ return tmp;
+ }
+
+ public static BigInteger[] CopyOf(BigInteger[] data, int newLength)
+ {
+ BigInteger[] tmp = new BigInteger[newLength];
+ Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length));
+ return tmp;
+ }
+
+ /**
+ * Make a copy of a range of bytes from the passed in data array. The range can
+ * extend beyond the end of the input array, in which case the return array will
+ * be padded with zeroes.
+ *
+ * @param data the array from which the data is to be copied.
+ * @param from the start index at which the copying should take place.
+ * @param to the final index of the range (exclusive).
+ *
+ * @return a new byte array containing the range given.
+ */
+ public static byte[] CopyOfRange(byte[] data, int from, int to)
+ {
+ int newLength = GetLength(from, to);
+ byte[] tmp = new byte[newLength];
+ Array.Copy(data, from, tmp, 0, System.Math.Min(newLength, data.Length - from));
+ return tmp;
+ }
+
+ public static int[] CopyOfRange(int[] data, int from, int to)
+ {
+ int newLength = GetLength(from, to);
+ int[] tmp = new int[newLength];
+ Array.Copy(data, from, tmp, 0, System.Math.Min(newLength, data.Length - from));
+ return tmp;
+ }
+
+ public static long[] CopyOfRange(long[] data, int from, int to)
+ {
+ int newLength = GetLength(from, to);
+ long[] tmp = new long[newLength];
+ Array.Copy(data, from, tmp, 0, System.Math.Min(newLength, data.Length - from));
+ return tmp;
+ }
+
+ public static BigInteger[] CopyOfRange(BigInteger[] data, int from, int to)
+ {
+ int newLength = GetLength(from, to);
+ BigInteger[] tmp = new BigInteger[newLength];
+ Array.Copy(data, from, tmp, 0, System.Math.Min(newLength, data.Length - from));
+ return tmp;
+ }
+
+ private static int GetLength(int from, int to)
+ {
+ int newLength = to - from;
+ if (newLength < 0)
+ throw new ArgumentException(from + " > " + to);
+ return newLength;
+ }
+
+ public static byte[] Append(byte[] a, byte b)
+ {
+ if (a == null)
+ return new byte[] { b };
+
+ int length = a.Length;
+ byte[] result = new byte[length + 1];
+ Array.Copy(a, 0, result, 0, length);
+ result[length] = b;
+ return result;
+ }
+
+ public static short[] Append(short[] a, short b)
+ {
+ if (a == null)
+ return new short[] { b };
+
+ int length = a.Length;
+ short[] result = new short[length + 1];
+ Array.Copy(a, 0, result, 0, length);
+ result[length] = b;
+ return result;
+ }
+
+ public static int[] Append(int[] a, int b)
+ {
+ if (a == null)
+ return new int[] { b };
+
+ int length = a.Length;
+ int[] result = new int[length + 1];
+ Array.Copy(a, 0, result, 0, length);
+ result[length] = b;
+ return result;
+ }
+
+ public static byte[] Concatenate(byte[] a, byte[] b)
+ {
+ if (a == null)
+ return Clone(b);
+ if (b == null)
+ return Clone(a);
+
+ byte[] rv = new byte[a.Length + b.Length];
+ Array.Copy(a, 0, rv, 0, a.Length);
+ Array.Copy(b, 0, rv, a.Length, b.Length);
+ return rv;
+ }
+
+ public static byte[] ConcatenateAll(params byte[][] vs)
+ {
+ byte[][] nonNull = new byte[vs.Length][];
+ int count = 0;
+ int totalLength = 0;
+
+ for (int i = 0; i < vs.Length; ++i)
+ {
+ byte[] v = vs[i];
+ if (v != null)
+ {
+ nonNull[count++] = v;
+ totalLength += v.Length;
+ }
+ }
+
+ byte[] result = new byte[totalLength];
+ int pos = 0;
+
+ for (int j = 0; j < count; ++j)
+ {
+ byte[] v = nonNull[j];
+ Array.Copy(v, 0, result, pos, v.Length);
+ pos += v.Length;
+ }
+
+ return result;
+ }
+
+ public static int[] Concatenate(int[] a, int[] b)
+ {
+ if (a == null)
+ return Clone(b);
+ if (b == null)
+ return Clone(a);
+
+ int[] rv = new int[a.Length + b.Length];
+ Array.Copy(a, 0, rv, 0, a.Length);
+ Array.Copy(b, 0, rv, a.Length, b.Length);
+ return rv;
+ }
+
+ public static byte[] Prepend(byte[] a, byte b)
+ {
+ if (a == null)
+ return new byte[] { b };
+
+ int length = a.Length;
+ byte[] result = new byte[length + 1];
+ Array.Copy(a, 0, result, 1, length);
+ result[0] = b;
+ return result;
+ }
+
+ public static short[] Prepend(short[] a, short b)
+ {
+ if (a == null)
+ return new short[] { b };
+
+ int length = a.Length;
+ short[] result = new short[length + 1];
+ Array.Copy(a, 0, result, 1, length);
+ result[0] = b;
+ return result;
+ }
+
+ public static int[] Prepend(int[] a, int b)
+ {
+ if (a == null)
+ return new int[] { b };
+
+ int length = a.Length;
+ int[] result = new int[length + 1];
+ Array.Copy(a, 0, result, 1, length);
+ result[0] = b;
+ return result;
+ }
+
+ public static byte[] Reverse(byte[] a)
+ {
+ if (a == null)
+ return null;
+
+ int p1 = 0, p2 = a.Length;
+ byte[] result = new byte[p2];
+
+ while (--p2 >= 0)
+ {
+ result[p2] = a[p1++];
+ }
+
+ return result;
+ }
+
+ public static int[] Reverse(int[] a)
+ {
+ if (a == null)
+ return null;
+
+ int p1 = 0, p2 = a.Length;
+ int[] result = new int[p2];
+
+ while (--p2 >= 0)
+ {
+ result[p2] = a[p1++];
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/BigIntegers.cs b/bc-sharp-crypto/src/util/BigIntegers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..f2d0425cc74de407fc3bcdee6730425bc3882828
--- /dev/null
+++ b/bc-sharp-crypto/src/util/BigIntegers.cs
@@ -0,0 +1,90 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Utilities
+{
+ /**
+ * BigInteger utilities.
+ */
+ public abstract class BigIntegers
+ {
+ private const int MaxIterations = 1000;
+
+ /**
+ * Return the passed in value as an unsigned byte array.
+ *
+ * @param value value to be converted.
+ * @return a byte array without a leading zero byte if present in the signed encoding.
+ */
+ public static byte[] AsUnsignedByteArray(
+ BigInteger n)
+ {
+ return n.ToByteArrayUnsigned();
+ }
+
+ /**
+ * Return the passed in value as an unsigned byte array of specified length, zero-extended as necessary.
+ *
+ * @param length desired length of result array.
+ * @param n value to be converted.
+ * @return a byte array of specified length, with leading zeroes as necessary given the size of n.
+ */
+ public static byte[] AsUnsignedByteArray(int length, BigInteger n)
+ {
+ byte[] bytes = n.ToByteArrayUnsigned();
+
+ if (bytes.Length > length)
+ throw new ArgumentException("standard length exceeded", "n");
+
+ if (bytes.Length == length)
+ return bytes;
+
+ byte[] tmp = new byte[length];
+ Array.Copy(bytes, 0, tmp, tmp.Length - bytes.Length, bytes.Length);
+ return tmp;
+ }
+
+ /**
+ * Return a random BigInteger not less than 'min' and not greater than 'max'
+ *
+ * @param min the least value that may be generated
+ * @param max the greatest value that may be generated
+ * @param random the source of randomness
+ * @return a random BigInteger value in the range [min,max]
+ */
+ public static BigInteger CreateRandomInRange(
+ BigInteger min,
+ BigInteger max,
+ // TODO Should have been just Random class
+ SecureRandom random)
+ {
+ int cmp = min.CompareTo(max);
+ if (cmp >= 0)
+ {
+ if (cmp > 0)
+ throw new ArgumentException("'min' may not be greater than 'max'");
+
+ return min;
+ }
+
+ if (min.BitLength > max.BitLength / 2)
+ {
+ return CreateRandomInRange(BigInteger.Zero, max.Subtract(min), random).Add(min);
+ }
+
+ for (int i = 0; i < MaxIterations; ++i)
+ {
+ BigInteger x = new BigInteger(max.BitLength, random);
+ if (x.CompareTo(min) >= 0 && x.CompareTo(max) <= 0)
+ {
+ return x;
+ }
+ }
+
+ // fall back to a faster (restricted) method
+ return new BigInteger(max.Subtract(min).BitLength - 1, random).Add(min);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/Enums.cs b/bc-sharp-crypto/src/util/Enums.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9e908c4c0adcc20831748d23fe3c3827a4b161d3
--- /dev/null
+++ b/bc-sharp-crypto/src/util/Enums.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Text;
+
+#if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE
+using System.Collections;
+using System.Reflection;
+#endif
+
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Utilities
+{
+ internal abstract class Enums
+ {
+ internal static Enum GetEnumValue(System.Type enumType, string s)
+ {
+ if (!IsEnumType(enumType))
+ throw new ArgumentException("Not an enumeration type", "enumType");
+
+ // We only want to parse single named constants
+ if (s.Length > 0 && char.IsLetter(s[0]) && s.IndexOf(',') < 0)
+ {
+ s = s.Replace('-', '_');
+ s = s.Replace('/', '_');
+
+#if NETCF_1_0
+ FieldInfo field = enumType.GetField(s, BindingFlags.Static | BindingFlags.Public);
+ if (field != null)
+ {
+ return (Enum)field.GetValue(null);
+ }
+#else
+ return (Enum)Enum.Parse(enumType, s, false);
+#endif
+ }
+
+ throw new ArgumentException();
+ }
+
+ internal static Array GetEnumValues(System.Type enumType)
+ {
+ if (!IsEnumType(enumType))
+ throw new ArgumentException("Not an enumeration type", "enumType");
+
+#if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT
+ IList result = Platform.CreateArrayList();
+ FieldInfo[] fields = enumType.GetFields(BindingFlags.Static | BindingFlags.Public);
+ foreach (FieldInfo field in fields)
+ {
+ // Note: Argument to GetValue() ignored since the fields are static,
+ // but Silverlight for Windows Phone throws exception if we pass null
+ result.Add(field.GetValue(enumType));
+ }
+ object[] arr = new object[result.Count];
+ result.CopyTo(arr, 0);
+ return arr;
+#else
+ return Enum.GetValues(enumType);
+#endif
+ }
+
+ internal static Enum GetArbitraryValue(System.Type enumType)
+ {
+ Array values = GetEnumValues(enumType);
+ int pos = (int)(DateTimeUtilities.CurrentUnixMs() & int.MaxValue) % values.Length;
+ return (Enum)values.GetValue(pos);
+ }
+
+ internal static bool IsEnumType(System.Type t)
+ {
+#if NEW_REFLECTION
+ return t.GetTypeInfo().IsEnum;
+#else
+ return t.IsEnum;
+#endif
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/IMemoable.cs b/bc-sharp-crypto/src/util/IMemoable.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cc8a2e55b0cbc3a56466a2d752b5a94d536fb7b1
--- /dev/null
+++ b/bc-sharp-crypto/src/util/IMemoable.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities
+{
+ public interface IMemoable
+ {
+ ///
+ /// Produce a copy of this object with its configuration and in its current state.
+ ///
+ ///
+ /// The returned object may be used simply to store the state, or may be used as a similar object
+ /// starting from the copied state.
+ ///
+ IMemoable Copy();
+
+ ///
+ /// Restore a copied object state into this object.
+ ///
+ ///
+ /// Implementations of this method should try to avoid or minimise memory allocation to perform the reset.
+ ///
+ /// an object originally {@link #copy() copied} from an object of the same type as this instance.
+ /// if the provided object is not of the correct type.
+ /// if the other parameter is in some other way invalid.
+ void Reset(IMemoable other);
+ }
+
+}
+
diff --git a/bc-sharp-crypto/src/util/Integers.cs b/bc-sharp-crypto/src/util/Integers.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ccbf872c49d99c2b0355e70531684bf3d384e44e
--- /dev/null
+++ b/bc-sharp-crypto/src/util/Integers.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities
+{
+ public abstract class Integers
+ {
+ public static int RotateLeft(int i, int distance)
+ {
+ return (i << distance) ^ (int)((uint)i >> -distance);
+ }
+
+ public static int RotateRight(int i, int distance)
+ {
+ return (int)((uint)i >> distance) ^ (i << -distance);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/MemoableResetException.cs b/bc-sharp-crypto/src/util/MemoableResetException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..99554f6c22acacd7a7ebe4dfa65788f61ac12570
--- /dev/null
+++ b/bc-sharp-crypto/src/util/MemoableResetException.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities
+{
+ /**
+ * Exception to be thrown on a failure to reset an object implementing Memoable.
+ *
+ * The exception extends InvalidCastException to enable users to have a single handling case,
+ * only introducing specific handling of this one if required.
+ *
+ */
+ public class MemoableResetException
+ : InvalidCastException
+ {
+ /**
+ * Basic Constructor.
+ *
+ * @param msg message to be associated with this exception.
+ */
+ public MemoableResetException(string msg)
+ : base(msg)
+ {
+ }
+ }
+
+}
+
diff --git a/bc-sharp-crypto/src/util/Platform.cs b/bc-sharp-crypto/src/util/Platform.cs
new file mode 100644
index 0000000000000000000000000000000000000000..86484854dd3fbf16dcfe815422e723fe3536c133
--- /dev/null
+++ b/bc-sharp-crypto/src/util/Platform.cs
@@ -0,0 +1,229 @@
+using System;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+#if SILVERLIGHT || PORTABLE
+using System.Collections.Generic;
+#else
+using System.Collections;
+#endif
+
+namespace Org.BouncyCastle.Utilities
+{
+ internal abstract class Platform
+ {
+ private static readonly CompareInfo InvariantCompareInfo = CultureInfo.InvariantCulture.CompareInfo;
+
+#if NETCF_1_0 || NETCF_2_0
+ private static string GetNewLine()
+ {
+ MemoryStream buf = new MemoryStream();
+ StreamWriter w = new StreamWriter(buf, Encoding.UTF8);
+ w.WriteLine();
+ Dispose(w);
+ byte[] bs = buf.ToArray();
+ return Encoding.UTF8.GetString(bs, 0, bs.Length);
+ }
+#else
+ private static string GetNewLine()
+ {
+ return Environment.NewLine;
+ }
+#endif
+
+ internal static bool EqualsIgnoreCase(string a, string b)
+ {
+#if PORTABLE
+ return String.Equals(a, b, StringComparison.OrdinalIgnoreCase);
+#else
+ return ToUpperInvariant(a) == ToUpperInvariant(b);
+#endif
+ }
+
+#if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE
+ internal static string GetEnvironmentVariable(
+ string variable)
+ {
+ return null;
+ }
+#else
+ internal static string GetEnvironmentVariable(
+ string variable)
+ {
+ try
+ {
+ return Environment.GetEnvironmentVariable(variable);
+ }
+ catch (System.Security.SecurityException)
+ {
+ // We don't have the required permission to read this environment variable,
+ // which is fine, just act as if it's not set
+ return null;
+ }
+ }
+#endif
+
+#if NETCF_1_0
+ internal static Exception CreateNotImplementedException(
+ string message)
+ {
+ return new Exception("Not implemented: " + message);
+ }
+
+ internal static bool Equals(
+ object a,
+ object b)
+ {
+ return a == b || (a != null && b != null && a.Equals(b));
+ }
+#else
+ internal static Exception CreateNotImplementedException(
+ string message)
+ {
+ return new NotImplementedException(message);
+ }
+#endif
+
+#if SILVERLIGHT || PORTABLE
+ internal static System.Collections.IList CreateArrayList()
+ {
+ return new List();
+ }
+ internal static System.Collections.IList CreateArrayList(int capacity)
+ {
+ return new List(capacity);
+ }
+ internal static System.Collections.IList CreateArrayList(System.Collections.ICollection collection)
+ {
+ System.Collections.IList result = new List(collection.Count);
+ foreach (object o in collection)
+ {
+ result.Add(o);
+ }
+ return result;
+ }
+ internal static System.Collections.IList CreateArrayList(System.Collections.IEnumerable collection)
+ {
+ System.Collections.IList result = new List();
+ foreach (object o in collection)
+ {
+ result.Add(o);
+ }
+ return result;
+ }
+ internal static System.Collections.IDictionary CreateHashtable()
+ {
+ return new Dictionary();
+ }
+ internal static System.Collections.IDictionary CreateHashtable(int capacity)
+ {
+ return new Dictionary(capacity);
+ }
+ internal static System.Collections.IDictionary CreateHashtable(System.Collections.IDictionary dictionary)
+ {
+ System.Collections.IDictionary result = new Dictionary(dictionary.Count);
+ foreach (System.Collections.DictionaryEntry entry in dictionary)
+ {
+ result.Add(entry.Key, entry.Value);
+ }
+ return result;
+ }
+#else
+ internal static System.Collections.IList CreateArrayList()
+ {
+ return new ArrayList();
+ }
+ internal static System.Collections.IList CreateArrayList(int capacity)
+ {
+ return new ArrayList(capacity);
+ }
+ internal static System.Collections.IList CreateArrayList(System.Collections.ICollection collection)
+ {
+ return new ArrayList(collection);
+ }
+ internal static System.Collections.IList CreateArrayList(System.Collections.IEnumerable collection)
+ {
+ ArrayList result = new ArrayList();
+ foreach (object o in collection)
+ {
+ result.Add(o);
+ }
+ return result;
+ }
+ internal static System.Collections.IDictionary CreateHashtable()
+ {
+ return new Hashtable();
+ }
+ internal static System.Collections.IDictionary CreateHashtable(int capacity)
+ {
+ return new Hashtable(capacity);
+ }
+ internal static System.Collections.IDictionary CreateHashtable(System.Collections.IDictionary dictionary)
+ {
+ return new Hashtable(dictionary);
+ }
+#endif
+
+ internal static string ToLowerInvariant(string s)
+ {
+#if PORTABLE
+ return s.ToLowerInvariant();
+#else
+ return s.ToLower(CultureInfo.InvariantCulture);
+#endif
+ }
+
+ internal static string ToUpperInvariant(string s)
+ {
+#if PORTABLE
+ return s.ToUpperInvariant();
+#else
+ return s.ToUpper(CultureInfo.InvariantCulture);
+#endif
+ }
+
+ internal static readonly string NewLine = GetNewLine();
+
+#if PORTABLE
+ internal static void Dispose(IDisposable d)
+ {
+ d.Dispose();
+ }
+#else
+ internal static void Dispose(Stream s)
+ {
+ s.Close();
+ }
+ internal static void Dispose(TextWriter t)
+ {
+ t.Close();
+ }
+#endif
+
+ internal static int IndexOf(string source, string value)
+ {
+ return InvariantCompareInfo.IndexOf(source, value, CompareOptions.Ordinal);
+ }
+
+ internal static int LastIndexOf(string source, string value)
+ {
+ return InvariantCompareInfo.LastIndexOf(source, value, CompareOptions.Ordinal);
+ }
+
+ internal static bool StartsWith(string source, string prefix)
+ {
+ return InvariantCompareInfo.IsPrefix(source, prefix, CompareOptions.Ordinal);
+ }
+
+ internal static bool EndsWith(string source, string suffix)
+ {
+ return InvariantCompareInfo.IsSuffix(source, suffix, CompareOptions.Ordinal);
+ }
+
+ internal static string GetTypeName(object obj)
+ {
+ return obj.GetType().FullName;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/Strings.cs b/bc-sharp-crypto/src/util/Strings.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3937a087fd4b53c302e91bfb3d55af3e44eeff7e
--- /dev/null
+++ b/bc-sharp-crypto/src/util/Strings.cs
@@ -0,0 +1,103 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Utilities
+{
+ /// General string utilities.
+ public abstract class Strings
+ {
+ internal static bool IsOneOf(string s, params string[] candidates)
+ {
+ foreach (string candidate in candidates)
+ {
+ if (s == candidate)
+ return true;
+ }
+ return false;
+ }
+
+ public static string FromByteArray(
+ byte[] bs)
+ {
+ char[] cs = new char[bs.Length];
+ for (int i = 0; i < cs.Length; ++i)
+ {
+ cs[i] = Convert.ToChar(bs[i]);
+ }
+ return new string(cs);
+ }
+
+ public static byte[] ToByteArray(
+ char[] cs)
+ {
+ byte[] bs = new byte[cs.Length];
+ for (int i = 0; i < bs.Length; ++i)
+ {
+ bs[i] = Convert.ToByte(cs[i]);
+ }
+ return bs;
+ }
+
+ public static byte[] ToByteArray(
+ string s)
+ {
+ byte[] bs = new byte[s.Length];
+ for (int i = 0; i < bs.Length; ++i)
+ {
+ bs[i] = Convert.ToByte(s[i]);
+ }
+ return bs;
+ }
+
+ public static string FromAsciiByteArray(
+ byte[] bytes)
+ {
+#if SILVERLIGHT || PORTABLE
+ // TODO Check for non-ASCII bytes in input?
+ return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
+#else
+ return Encoding.ASCII.GetString(bytes, 0, bytes.Length);
+#endif
+ }
+
+ public static byte[] ToAsciiByteArray(
+ char[] cs)
+ {
+#if SILVERLIGHT || PORTABLE
+ // TODO Check for non-ASCII characters in input?
+ return Encoding.UTF8.GetBytes(cs);
+#else
+ return Encoding.ASCII.GetBytes(cs);
+#endif
+ }
+
+ public static byte[] ToAsciiByteArray(
+ string s)
+ {
+#if SILVERLIGHT || PORTABLE
+ // TODO Check for non-ASCII characters in input?
+ return Encoding.UTF8.GetBytes(s);
+#else
+ return Encoding.ASCII.GetBytes(s);
+#endif
+ }
+
+ public static string FromUtf8ByteArray(
+ byte[] bytes)
+ {
+ return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
+ }
+
+ public static byte[] ToUtf8ByteArray(
+ char[] cs)
+ {
+ return Encoding.UTF8.GetBytes(cs);
+ }
+
+ public static byte[] ToUtf8ByteArray(
+ string s)
+ {
+ return Encoding.UTF8.GetBytes(s);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/Times.cs b/bc-sharp-crypto/src/util/Times.cs
new file mode 100644
index 0000000000000000000000000000000000000000..99a78d21a14517adee07b83880504e22791c19ce
--- /dev/null
+++ b/bc-sharp-crypto/src/util/Times.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities
+{
+ public sealed class Times
+ {
+ private static long NanosecondsPerTick = 100L;
+
+ public static long NanoTime()
+ {
+ return DateTime.UtcNow.Ticks * NanosecondsPerTick;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/TypeExtensions.cs b/bc-sharp-crypto/src/util/TypeExtensions.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e2aeae4dc9bdb3b1bd95e6b47db75600498d99ee
--- /dev/null
+++ b/bc-sharp-crypto/src/util/TypeExtensions.cs
@@ -0,0 +1,17 @@
+#if NEW_REFLECTION
+
+using System;
+using System.Reflection;
+
+namespace Org.BouncyCastle
+{
+ internal static class TypeExtensions
+ {
+ public static bool IsInstanceOfType(this Type type, object instance)
+ {
+ return instance != null && type.GetTypeInfo().IsAssignableFrom(instance.GetType().GetTypeInfo());
+ }
+ }
+}
+
+#endif
diff --git a/bc-sharp-crypto/src/util/collections/CollectionUtilities.cs b/bc-sharp-crypto/src/util/collections/CollectionUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..18fcb6774dcd71308ef9908d60f04672f5e6b4cb
--- /dev/null
+++ b/bc-sharp-crypto/src/util/collections/CollectionUtilities.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections;
+using System.Text;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+ public abstract class CollectionUtilities
+ {
+ public static void AddRange(IList to, IEnumerable range)
+ {
+ foreach (object o in range)
+ {
+ to.Add(o);
+ }
+ }
+
+ public static bool CheckElementsAreOfType(IEnumerable e, Type t)
+ {
+ foreach (object o in e)
+ {
+ if (!t.IsInstanceOfType(o))
+ return false;
+ }
+ return true;
+ }
+
+ public static IDictionary ReadOnly(IDictionary d)
+ {
+ return new UnmodifiableDictionaryProxy(d);
+ }
+
+ public static IList ReadOnly(IList l)
+ {
+ return new UnmodifiableListProxy(l);
+ }
+
+ public static ISet ReadOnly(ISet s)
+ {
+ return new UnmodifiableSetProxy(s);
+ }
+
+ public static string ToString(IEnumerable c)
+ {
+ StringBuilder sb = new StringBuilder("[");
+
+ IEnumerator e = c.GetEnumerator();
+
+ if (e.MoveNext())
+ {
+ sb.Append(e.Current.ToString());
+
+ while (e.MoveNext())
+ {
+ sb.Append(", ");
+ sb.Append(e.Current.ToString());
+ }
+ }
+
+ sb.Append(']');
+
+ return sb.ToString();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/collections/EmptyEnumerable.cs b/bc-sharp-crypto/src/util/collections/EmptyEnumerable.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a61a0789a32c7a0eadcdc4dec51bcb89e461bda7
--- /dev/null
+++ b/bc-sharp-crypto/src/util/collections/EmptyEnumerable.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+ public sealed class EmptyEnumerable
+ : IEnumerable
+ {
+ public static readonly IEnumerable Instance = new EmptyEnumerable();
+
+ private EmptyEnumerable()
+ {
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return EmptyEnumerator.Instance;
+ }
+ }
+
+ public sealed class EmptyEnumerator
+ : IEnumerator
+ {
+ public static readonly IEnumerator Instance = new EmptyEnumerator();
+
+ private EmptyEnumerator()
+ {
+ }
+
+ public bool MoveNext()
+ {
+ return false;
+ }
+
+ public void Reset()
+ {
+ }
+
+ public object Current
+ {
+ get { throw new InvalidOperationException("No elements"); }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/collections/EnumerableProxy.cs b/bc-sharp-crypto/src/util/collections/EnumerableProxy.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9eec4af21386e0e4111523b91426679ec8dbf82e
--- /dev/null
+++ b/bc-sharp-crypto/src/util/collections/EnumerableProxy.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+ public sealed class EnumerableProxy
+ : IEnumerable
+ {
+ private readonly IEnumerable inner;
+
+ public EnumerableProxy(
+ IEnumerable inner)
+ {
+ if (inner == null)
+ throw new ArgumentNullException("inner");
+
+ this.inner = inner;
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return inner.GetEnumerator();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/collections/HashSet.cs b/bc-sharp-crypto/src/util/collections/HashSet.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1facb58e3a551be182951d0411274297fa098805
--- /dev/null
+++ b/bc-sharp-crypto/src/util/collections/HashSet.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+ public class HashSet
+ : ISet
+ {
+ private readonly IDictionary impl = Platform.CreateHashtable();
+
+ public HashSet()
+ {
+ }
+
+ public HashSet(IEnumerable s)
+ {
+ foreach (object o in s)
+ {
+ Add(o);
+ }
+ }
+
+ public virtual void Add(object o)
+ {
+ impl[o] = null;
+ }
+
+ public virtual void AddAll(IEnumerable e)
+ {
+ foreach (object o in e)
+ {
+ Add(o);
+ }
+ }
+
+ public virtual void Clear()
+ {
+ impl.Clear();
+ }
+
+ public virtual bool Contains(object o)
+ {
+ return impl.Contains(o);
+ }
+
+ public virtual void CopyTo(Array array, int index)
+ {
+ impl.Keys.CopyTo(array, index);
+ }
+
+ public virtual int Count
+ {
+ get { return impl.Count; }
+ }
+
+ public virtual IEnumerator GetEnumerator()
+ {
+ return impl.Keys.GetEnumerator();
+ }
+
+ public virtual bool IsEmpty
+ {
+ get { return impl.Count == 0; }
+ }
+
+ public virtual bool IsFixedSize
+ {
+ get { return impl.IsFixedSize; }
+ }
+
+ public virtual bool IsReadOnly
+ {
+ get { return impl.IsReadOnly; }
+ }
+
+ public virtual bool IsSynchronized
+ {
+ get { return impl.IsSynchronized; }
+ }
+
+ public virtual void Remove(object o)
+ {
+ impl.Remove(o);
+ }
+
+ public virtual void RemoveAll(IEnumerable e)
+ {
+ foreach (object o in e)
+ {
+ Remove(o);
+ }
+ }
+
+ public virtual object SyncRoot
+ {
+ get { return impl.SyncRoot; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/collections/ISet.cs b/bc-sharp-crypto/src/util/collections/ISet.cs
new file mode 100644
index 0000000000000000000000000000000000000000..1f8edba40dbb17945e5abebcffb01377bb3a98e5
--- /dev/null
+++ b/bc-sharp-crypto/src/util/collections/ISet.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+ public interface ISet
+ : ICollection
+ {
+ void Add(object o);
+ void AddAll(IEnumerable e);
+ void Clear();
+ bool Contains(object o);
+ bool IsEmpty { get; }
+ bool IsFixedSize { get; }
+ bool IsReadOnly { get; }
+ void Remove(object o);
+ void RemoveAll(IEnumerable e);
+ }
+}
diff --git a/bc-sharp-crypto/src/util/collections/LinkedDictionary.cs b/bc-sharp-crypto/src/util/collections/LinkedDictionary.cs
new file mode 100644
index 0000000000000000000000000000000000000000..933d38ded495dfc18331d476b66866d3a2223a53
--- /dev/null
+++ b/bc-sharp-crypto/src/util/collections/LinkedDictionary.cs
@@ -0,0 +1,178 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+ public class LinkedDictionary
+ : IDictionary
+ {
+ internal readonly IDictionary hash = Platform.CreateHashtable();
+ internal readonly IList keys = Platform.CreateArrayList();
+
+ public LinkedDictionary()
+ {
+ }
+
+ public virtual void Add(object k, object v)
+ {
+ hash.Add(k, v);
+ keys.Add(k);
+ }
+
+ public virtual void Clear()
+ {
+ hash.Clear();
+ keys.Clear();
+ }
+
+ public virtual bool Contains(object k)
+ {
+ return hash.Contains(k);
+ }
+
+ public virtual void CopyTo(Array array, int index)
+ {
+ foreach (object k in keys)
+ {
+ array.SetValue(hash[k], index++);
+ }
+ }
+
+ public virtual int Count
+ {
+ get { return hash.Count; }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ public virtual IDictionaryEnumerator GetEnumerator()
+ {
+ return new LinkedDictionaryEnumerator(this);
+ }
+
+ public virtual void Remove(object k)
+ {
+ hash.Remove(k);
+ keys.Remove(k);
+ }
+
+ public virtual bool IsFixedSize
+ {
+ get { return false; }
+ }
+
+ public virtual bool IsReadOnly
+ {
+ get { return false; }
+ }
+
+ public virtual bool IsSynchronized
+ {
+ get { return false; }
+ }
+
+ public virtual object SyncRoot
+ {
+ get { return false; }
+ }
+
+ public virtual ICollection Keys
+ {
+ get { return Platform.CreateArrayList(keys); }
+ }
+
+ public virtual ICollection Values
+ {
+ // NB: Order has to be the same as for Keys property
+ get
+ {
+ IList values = Platform.CreateArrayList(keys.Count);
+ foreach (object k in keys)
+ {
+ values.Add(hash[k]);
+ }
+ return values;
+ }
+ }
+
+ public virtual object this[object k]
+ {
+ get
+ {
+ return hash[k];
+ }
+ set
+ {
+ if (!hash.Contains(k))
+ keys.Add(k);
+ hash[k] = value;
+ }
+ }
+ }
+
+ internal class LinkedDictionaryEnumerator : IDictionaryEnumerator
+ {
+ private readonly LinkedDictionary parent;
+ private int pos = -1;
+
+ internal LinkedDictionaryEnumerator(LinkedDictionary parent)
+ {
+ this.parent = parent;
+ }
+
+ public virtual object Current
+ {
+ get { return Entry; }
+ }
+
+ public virtual DictionaryEntry Entry
+ {
+ get
+ {
+ object k = CurrentKey;
+ return new DictionaryEntry(k, parent.hash[k]);
+ }
+ }
+
+ public virtual object Key
+ {
+ get
+ {
+ return CurrentKey;
+ }
+ }
+
+ public virtual bool MoveNext()
+ {
+ if (pos >= parent.keys.Count)
+ return false;
+ return ++pos < parent.keys.Count;
+ }
+
+ public virtual void Reset()
+ {
+ this.pos = -1;
+ }
+
+ public virtual object Value
+ {
+ get
+ {
+ return parent.hash[CurrentKey];
+ }
+ }
+
+ private object CurrentKey
+ {
+ get
+ {
+ if (pos < 0 || pos >= parent.keys.Count)
+ throw new InvalidOperationException();
+ return parent.keys[pos];
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/collections/UnmodifiableDictionary.cs b/bc-sharp-crypto/src/util/collections/UnmodifiableDictionary.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0bdf70ad7954b09fa61f293735b43f4c25601b71
--- /dev/null
+++ b/bc-sharp-crypto/src/util/collections/UnmodifiableDictionary.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+ public abstract class UnmodifiableDictionary
+ : IDictionary
+ {
+ protected UnmodifiableDictionary()
+ {
+ }
+
+ public virtual void Add(object k, object v)
+ {
+ throw new NotSupportedException();
+ }
+
+ public virtual void Clear()
+ {
+ throw new NotSupportedException();
+ }
+
+ public abstract bool Contains(object k);
+
+ public abstract void CopyTo(Array array, int index);
+
+ public abstract int Count { get; }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ public abstract IDictionaryEnumerator GetEnumerator();
+
+ public virtual void Remove(object k)
+ {
+ throw new NotSupportedException();
+ }
+
+ public abstract bool IsFixedSize { get; }
+
+ public virtual bool IsReadOnly
+ {
+ get { return true; }
+ }
+
+ public abstract bool IsSynchronized { get; }
+
+ public abstract object SyncRoot { get; }
+
+ public abstract ICollection Keys { get; }
+
+ public abstract ICollection Values { get; }
+
+ public virtual object this[object k]
+ {
+ get { return GetValue(k); }
+ set { throw new NotSupportedException(); }
+ }
+
+ protected abstract object GetValue(object k);
+ }
+}
diff --git a/bc-sharp-crypto/src/util/collections/UnmodifiableDictionaryProxy.cs b/bc-sharp-crypto/src/util/collections/UnmodifiableDictionaryProxy.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0fca909a31e3d06246c13453bd9177e202e43f95
--- /dev/null
+++ b/bc-sharp-crypto/src/util/collections/UnmodifiableDictionaryProxy.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+ public class UnmodifiableDictionaryProxy
+ : UnmodifiableDictionary
+ {
+ private readonly IDictionary d;
+
+ public UnmodifiableDictionaryProxy(IDictionary d)
+ {
+ this.d = d;
+ }
+
+ public override bool Contains(object k)
+ {
+ return d.Contains(k);
+ }
+
+ public override void CopyTo(Array array, int index)
+ {
+ d.CopyTo(array, index);
+ }
+
+ public override int Count
+ {
+ get { return d.Count; }
+ }
+
+ public override IDictionaryEnumerator GetEnumerator()
+ {
+ return d.GetEnumerator();
+ }
+
+ public override bool IsFixedSize
+ {
+ get { return d.IsFixedSize; }
+ }
+
+ public override bool IsSynchronized
+ {
+ get { return d.IsSynchronized; }
+ }
+
+ public override object SyncRoot
+ {
+ get { return d.SyncRoot; }
+ }
+
+ public override ICollection Keys
+ {
+ get { return d.Keys; }
+ }
+
+ public override ICollection Values
+ {
+ get { return d.Values; }
+ }
+
+ protected override object GetValue(object k)
+ {
+ return d[k];
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/collections/UnmodifiableList.cs b/bc-sharp-crypto/src/util/collections/UnmodifiableList.cs
new file mode 100644
index 0000000000000000000000000000000000000000..28e49eac30fd55c48be03ebbb60e6d32033f6e41
--- /dev/null
+++ b/bc-sharp-crypto/src/util/collections/UnmodifiableList.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+ public abstract class UnmodifiableList
+ : IList
+ {
+ protected UnmodifiableList()
+ {
+ }
+
+ public virtual int Add(object o)
+ {
+ throw new NotSupportedException();
+ }
+
+ public virtual void Clear()
+ {
+ throw new NotSupportedException();
+ }
+
+ public abstract bool Contains(object o);
+
+ public abstract void CopyTo(Array array, int index);
+
+ public abstract int Count { get; }
+
+ public abstract IEnumerator GetEnumerator();
+
+ public abstract int IndexOf(object o);
+
+ public virtual void Insert(int i, object o)
+ {
+ throw new NotSupportedException();
+ }
+
+ public abstract bool IsFixedSize { get; }
+
+ public virtual bool IsReadOnly
+ {
+ get { return true; }
+ }
+
+ public abstract bool IsSynchronized { get; }
+
+ public virtual void Remove(object o)
+ {
+ throw new NotSupportedException();
+ }
+
+ public virtual void RemoveAt(int i)
+ {
+ throw new NotSupportedException();
+ }
+
+ public abstract object SyncRoot { get; }
+
+ public virtual object this[int i]
+ {
+ get { return GetValue(i); }
+ set { throw new NotSupportedException(); }
+ }
+
+ protected abstract object GetValue(int i);
+ }
+}
diff --git a/bc-sharp-crypto/src/util/collections/UnmodifiableListProxy.cs b/bc-sharp-crypto/src/util/collections/UnmodifiableListProxy.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9d00737ef6b2a969b4929da2d9d87957b9701a92
--- /dev/null
+++ b/bc-sharp-crypto/src/util/collections/UnmodifiableListProxy.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+ public class UnmodifiableListProxy
+ : UnmodifiableList
+ {
+ private readonly IList l;
+
+ public UnmodifiableListProxy(IList l)
+ {
+ this.l = l;
+ }
+
+ public override bool Contains(object o)
+ {
+ return l.Contains(o);
+ }
+
+ public override void CopyTo(Array array, int index)
+ {
+ l.CopyTo(array, index);
+ }
+
+ public override int Count
+ {
+ get { return l.Count; }
+ }
+
+ public override IEnumerator GetEnumerator()
+ {
+ return l.GetEnumerator();
+ }
+
+ public override int IndexOf(object o)
+ {
+ return l.IndexOf(o);
+ }
+
+ public override bool IsFixedSize
+ {
+ get { return l.IsFixedSize; }
+ }
+
+ public override bool IsSynchronized
+ {
+ get { return l.IsSynchronized; }
+ }
+
+ public override object SyncRoot
+ {
+ get { return l.SyncRoot; }
+ }
+
+ protected override object GetValue(int i)
+ {
+ return l[i];
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/collections/UnmodifiableSet.cs b/bc-sharp-crypto/src/util/collections/UnmodifiableSet.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8792815ac3d1466c11deabc07099a5d58eb9bc91
--- /dev/null
+++ b/bc-sharp-crypto/src/util/collections/UnmodifiableSet.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+ public abstract class UnmodifiableSet
+ : ISet
+ {
+ protected UnmodifiableSet()
+ {
+ }
+
+ public virtual void Add(object o)
+ {
+ throw new NotSupportedException();
+ }
+
+ public virtual void AddAll(IEnumerable e)
+ {
+ throw new NotSupportedException();
+ }
+
+ public virtual void Clear()
+ {
+ throw new NotSupportedException();
+ }
+
+ public abstract bool Contains(object o);
+
+ public abstract void CopyTo(Array array, int index);
+
+ public abstract int Count { get; }
+
+ public abstract IEnumerator GetEnumerator();
+
+ public abstract bool IsEmpty { get; }
+
+ public abstract bool IsFixedSize { get; }
+
+ public virtual bool IsReadOnly
+ {
+ get { return true; }
+ }
+
+ public abstract bool IsSynchronized { get; }
+
+ public abstract object SyncRoot { get; }
+
+ public virtual void Remove(object o)
+ {
+ throw new NotSupportedException();
+ }
+
+ public virtual void RemoveAll(IEnumerable e)
+ {
+ throw new NotSupportedException();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/collections/UnmodifiableSetProxy.cs b/bc-sharp-crypto/src/util/collections/UnmodifiableSetProxy.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e119e29578eb002a8c62f178d21e967be45476bb
--- /dev/null
+++ b/bc-sharp-crypto/src/util/collections/UnmodifiableSetProxy.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+ public class UnmodifiableSetProxy
+ : UnmodifiableSet
+ {
+ private readonly ISet s;
+
+ public UnmodifiableSetProxy (ISet s)
+ {
+ this.s = s;
+ }
+
+ public override bool Contains(object o)
+ {
+ return s.Contains(o);
+ }
+
+ public override void CopyTo(Array array, int index)
+ {
+ s.CopyTo(array, index);
+ }
+
+ public override int Count
+ {
+ get { return s.Count; }
+ }
+
+ public override IEnumerator GetEnumerator()
+ {
+ return s.GetEnumerator();
+ }
+
+ public override bool IsEmpty
+ {
+ get { return s.IsEmpty; }
+ }
+
+ public override bool IsFixedSize
+ {
+ get { return s.IsFixedSize; }
+ }
+
+ public override bool IsSynchronized
+ {
+ get { return s.IsSynchronized; }
+ }
+
+ public override object SyncRoot
+ {
+ get { return s.SyncRoot; }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/date/DateTimeObject.cs b/bc-sharp-crypto/src/util/date/DateTimeObject.cs
new file mode 100644
index 0000000000000000000000000000000000000000..793376b6dd461f3774c850782a0c5f877ed0d53e
--- /dev/null
+++ b/bc-sharp-crypto/src/util/date/DateTimeObject.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Date
+{
+ public sealed class DateTimeObject
+ {
+ private readonly DateTime dt;
+
+ public DateTimeObject(
+ DateTime dt)
+ {
+ this.dt = dt;
+ }
+
+ public DateTime Value
+ {
+ get { return dt; }
+ }
+
+ public override string ToString()
+ {
+ return dt.ToString();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/date/DateTimeUtilities.cs b/bc-sharp-crypto/src/util/date/DateTimeUtilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..311ad5d37a158f9c6f7503b257af24c3240907d6
--- /dev/null
+++ b/bc-sharp-crypto/src/util/date/DateTimeUtilities.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Date
+{
+ public class DateTimeUtilities
+ {
+ public static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1);
+
+ private DateTimeUtilities()
+ {
+ }
+
+ ///
+ /// Return the number of milliseconds since the Unix epoch (1 Jan., 1970 UTC) for a given DateTime value.
+ ///
+ /// A UTC DateTime value not before epoch.
+ /// Number of whole milliseconds after epoch.
+ /// 'dateTime' is before epoch.
+ public static long DateTimeToUnixMs(
+ DateTime dateTime)
+ {
+ if (dateTime.CompareTo(UnixEpoch) < 0)
+ throw new ArgumentException("DateTime value may not be before the epoch", "dateTime");
+
+ return (dateTime.Ticks - UnixEpoch.Ticks) / TimeSpan.TicksPerMillisecond;
+ }
+
+ ///
+ /// Create a DateTime value from the number of milliseconds since the Unix epoch (1 Jan., 1970 UTC).
+ ///
+ /// Number of milliseconds since the epoch.
+ /// A UTC DateTime value
+ public static DateTime UnixMsToDateTime(
+ long unixMs)
+ {
+ return new DateTime(unixMs * TimeSpan.TicksPerMillisecond + UnixEpoch.Ticks);
+ }
+
+ ///
+ /// Return the current number of milliseconds since the Unix epoch (1 Jan., 1970 UTC).
+ ///
+ public static long CurrentUnixMs()
+ {
+ return DateTimeToUnixMs(DateTime.UtcNow);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/encoders/Base64.cs b/bc-sharp-crypto/src/util/encoders/Base64.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ccecd8dc2975c0d0a7772fdab8bfc75345fa37a5
--- /dev/null
+++ b/bc-sharp-crypto/src/util/encoders/Base64.cs
@@ -0,0 +1,120 @@
+using System;
+using System.IO;
+using System.Text;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ public sealed class Base64
+ {
+ private Base64()
+ {
+ }
+
+ public static string ToBase64String(
+ byte[] data)
+ {
+ return Convert.ToBase64String(data, 0, data.Length);
+ }
+
+ public static string ToBase64String(
+ byte[] data,
+ int off,
+ int length)
+ {
+ return Convert.ToBase64String(data, off, length);
+ }
+
+ /**
+ * encode the input data producing a base 64 encoded byte array.
+ *
+ * @return a byte array containing the base 64 encoded data.
+ */
+ public static byte[] Encode(
+ byte[] data)
+ {
+ return Encode(data, 0, data.Length);
+ }
+
+ /**
+ * encode the input data producing a base 64 encoded byte array.
+ *
+ * @return a byte array containing the base 64 encoded data.
+ */
+ public static byte[] Encode(
+ byte[] data,
+ int off,
+ int length)
+ {
+ string s = Convert.ToBase64String(data, off, length);
+ return Strings.ToAsciiByteArray(s);
+ }
+
+ /**
+ * Encode the byte data to base 64 writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int Encode(
+ byte[] data,
+ Stream outStream)
+ {
+ byte[] encoded = Encode(data);
+ outStream.Write(encoded, 0, encoded.Length);
+ return encoded.Length;
+ }
+
+ /**
+ * Encode the byte data to base 64 writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int Encode(
+ byte[] data,
+ int off,
+ int length,
+ Stream outStream)
+ {
+ byte[] encoded = Encode(data, off, length);
+ outStream.Write(encoded, 0, encoded.Length);
+ return encoded.Length;
+ }
+
+ /**
+ * decode the base 64 encoded input data. It is assumed the input data is valid.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] Decode(
+ byte[] data)
+ {
+ string s = Strings.FromAsciiByteArray(data);
+ return Convert.FromBase64String(s);
+ }
+
+ /**
+ * decode the base 64 encoded string data - whitespace will be ignored.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] Decode(
+ string data)
+ {
+ return Convert.FromBase64String(data);
+ }
+
+ /**
+ * decode the base 64 encoded string data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int Decode(
+ string data,
+ Stream outStream)
+ {
+ byte[] decoded = Decode(data);
+ outStream.Write(decoded, 0, decoded.Length);
+ return decoded.Length;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/encoders/Base64Encoder.cs b/bc-sharp-crypto/src/util/encoders/Base64Encoder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7b53df25ae640890f9aa60d7aa6cc73535fdadd9
--- /dev/null
+++ b/bc-sharp-crypto/src/util/encoders/Base64Encoder.cs
@@ -0,0 +1,324 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ public class Base64Encoder
+ : IEncoder
+ {
+ protected readonly byte[] encodingTable =
+ {
+ (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
+ (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
+ (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
+ (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
+ (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
+ (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+ (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
+ (byte)'v',
+ (byte)'w', (byte)'x', (byte)'y', (byte)'z',
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6',
+ (byte)'7', (byte)'8', (byte)'9',
+ (byte)'+', (byte)'/'
+ };
+
+ protected byte padding = (byte)'=';
+
+ /*
+ * set up the decoding table.
+ */
+ protected readonly byte[] decodingTable = new byte[128];
+
+ protected void InitialiseDecodingTable()
+ {
+ Arrays.Fill(decodingTable, (byte)0xff);
+
+ for (int i = 0; i < encodingTable.Length; i++)
+ {
+ decodingTable[encodingTable[i]] = (byte)i;
+ }
+ }
+
+ public Base64Encoder()
+ {
+ InitialiseDecodingTable();
+ }
+
+ /**
+ * encode the input data producing a base 64 output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public int Encode(
+ byte[] data,
+ int off,
+ int length,
+ Stream outStream)
+ {
+ int modulus = length % 3;
+ int dataLength = (length - modulus);
+ int a1, a2, a3;
+
+ for (int i = off; i < off + dataLength; i += 3)
+ {
+ a1 = data[i] & 0xff;
+ a2 = data[i + 1] & 0xff;
+ a3 = data[i + 2] & 0xff;
+
+ outStream.WriteByte(encodingTable[(int) ((uint) a1 >> 2) & 0x3f]);
+ outStream.WriteByte(encodingTable[((a1 << 4) | (int) ((uint) a2 >> 4)) & 0x3f]);
+ outStream.WriteByte(encodingTable[((a2 << 2) | (int) ((uint) a3 >> 6)) & 0x3f]);
+ outStream.WriteByte(encodingTable[a3 & 0x3f]);
+ }
+
+ /*
+ * process the tail end.
+ */
+ int b1, b2, b3;
+ int d1, d2;
+
+ switch (modulus)
+ {
+ case 0: /* nothing left to do */
+ break;
+ case 1:
+ d1 = data[off + dataLength] & 0xff;
+ b1 = (d1 >> 2) & 0x3f;
+ b2 = (d1 << 4) & 0x3f;
+
+ outStream.WriteByte(encodingTable[b1]);
+ outStream.WriteByte(encodingTable[b2]);
+ outStream.WriteByte(padding);
+ outStream.WriteByte(padding);
+ break;
+ case 2:
+ d1 = data[off + dataLength] & 0xff;
+ d2 = data[off + dataLength + 1] & 0xff;
+
+ b1 = (d1 >> 2) & 0x3f;
+ b2 = ((d1 << 4) | (d2 >> 4)) & 0x3f;
+ b3 = (d2 << 2) & 0x3f;
+
+ outStream.WriteByte(encodingTable[b1]);
+ outStream.WriteByte(encodingTable[b2]);
+ outStream.WriteByte(encodingTable[b3]);
+ outStream.WriteByte(padding);
+ break;
+ }
+
+ return (dataLength / 3) * 4 + ((modulus == 0) ? 0 : 4);
+ }
+
+ private bool ignore(
+ char c)
+ {
+ return (c == '\n' || c =='\r' || c == '\t' || c == ' ');
+ }
+
+ /**
+ * decode the base 64 encoded byte data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public int Decode(
+ byte[] data,
+ int off,
+ int length,
+ Stream outStream)
+ {
+ byte b1, b2, b3, b4;
+ int outLen = 0;
+
+ int end = off + length;
+
+ while (end > off)
+ {
+ if (!ignore((char)data[end - 1]))
+ {
+ break;
+ }
+
+ end--;
+ }
+
+ int i = off;
+ int finish = end - 4;
+
+ i = nextI(data, i, finish);
+
+ while (i < finish)
+ {
+ b1 = decodingTable[data[i++]];
+
+ i = nextI(data, i, finish);
+
+ b2 = decodingTable[data[i++]];
+
+ i = nextI(data, i, finish);
+
+ b3 = decodingTable[data[i++]];
+
+ i = nextI(data, i, finish);
+
+ b4 = decodingTable[data[i++]];
+
+ if ((b1 | b2 | b3 | b4) >= 0x80)
+ throw new IOException("invalid characters encountered in base64 data");
+
+ outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
+ outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
+ outStream.WriteByte((byte)((b3 << 6) | b4));
+
+ outLen += 3;
+
+ i = nextI(data, i, finish);
+ }
+
+ outLen += decodeLastBlock(outStream, (char)data[end - 4], (char)data[end - 3], (char)data[end - 2], (char)data[end - 1]);
+
+ return outLen;
+ }
+
+ private int nextI(
+ byte[] data,
+ int i,
+ int finish)
+ {
+ while ((i < finish) && ignore((char)data[i]))
+ {
+ i++;
+ }
+ return i;
+ }
+
+ /**
+ * decode the base 64 encoded string data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public int DecodeString(
+ string data,
+ Stream outStream)
+ {
+ // Platform Implementation
+// byte[] bytes = Convert.FromBase64String(data);
+// outStream.Write(bytes, 0, bytes.Length);
+// return bytes.Length;
+
+ byte b1, b2, b3, b4;
+ int length = 0;
+
+ int end = data.Length;
+
+ while (end > 0)
+ {
+ if (!ignore(data[end - 1]))
+ {
+ break;
+ }
+
+ end--;
+ }
+
+ int i = 0;
+ int finish = end - 4;
+
+ i = nextI(data, i, finish);
+
+ while (i < finish)
+ {
+ b1 = decodingTable[data[i++]];
+
+ i = nextI(data, i, finish);
+
+ b2 = decodingTable[data[i++]];
+
+ i = nextI(data, i, finish);
+
+ b3 = decodingTable[data[i++]];
+
+ i = nextI(data, i, finish);
+
+ b4 = decodingTable[data[i++]];
+
+ if ((b1 | b2 | b3 | b4) >= 0x80)
+ throw new IOException("invalid characters encountered in base64 data");
+
+ outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
+ outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
+ outStream.WriteByte((byte)((b3 << 6) | b4));
+
+ length += 3;
+
+ i = nextI(data, i, finish);
+ }
+
+ length += decodeLastBlock(outStream, data[end - 4], data[end - 3], data[end - 2], data[end - 1]);
+
+ return length;
+ }
+
+ private int decodeLastBlock(
+ Stream outStream,
+ char c1,
+ char c2,
+ char c3,
+ char c4)
+ {
+ if (c3 == padding)
+ {
+ byte b1 = decodingTable[c1];
+ byte b2 = decodingTable[c2];
+
+ if ((b1 | b2) >= 0x80)
+ throw new IOException("invalid characters encountered at end of base64 data");
+
+ outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
+
+ return 1;
+ }
+
+ if (c4 == padding)
+ {
+ byte b1 = decodingTable[c1];
+ byte b2 = decodingTable[c2];
+ byte b3 = decodingTable[c3];
+
+ if ((b1 | b2 | b3) >= 0x80)
+ throw new IOException("invalid characters encountered at end of base64 data");
+
+ outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
+ outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
+
+ return 2;
+ }
+
+ {
+ byte b1 = decodingTable[c1];
+ byte b2 = decodingTable[c2];
+ byte b3 = decodingTable[c3];
+ byte b4 = decodingTable[c4];
+
+ if ((b1 | b2 | b3 | b4) >= 0x80)
+ throw new IOException("invalid characters encountered at end of base64 data");
+
+ outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
+ outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
+ outStream.WriteByte((byte)((b3 << 6) | b4));
+
+ return 3;
+ }
+ }
+
+ private int nextI(string data, int i, int finish)
+ {
+ while ((i < finish) && ignore(data[i]))
+ {
+ i++;
+ }
+ return i;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/encoders/BufferedDecoder.cs b/bc-sharp-crypto/src/util/encoders/BufferedDecoder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..633cf1e971e10c2623cd874fa34cde0148eff1f1
--- /dev/null
+++ b/bc-sharp-crypto/src/util/encoders/BufferedDecoder.cs
@@ -0,0 +1,117 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ ///
+ /// A buffering class to allow translation from one format to another to
+ /// be done in discrete chunks.
+ ///
+ public class BufferedDecoder
+ {
+ internal byte[] buffer;
+ internal int bufOff;
+
+ internal ITranslator translator;
+
+ ///
+ /// Create a buffered Decoder.
+ ///
+ /// The translater to use.
+ /// The size of the buffer.
+ public BufferedDecoder(
+ ITranslator translator,
+ int bufferSize)
+ {
+ this.translator = translator;
+
+ if ((bufferSize % translator.GetEncodedBlockSize()) != 0)
+ {
+ throw new ArgumentException("buffer size not multiple of input block size");
+ }
+
+ buffer = new byte[bufferSize];
+// bufOff = 0;
+ }
+
+ ///
+ /// Process one byte of data.
+ ///
+ /// Data in.
+ /// Byte array for the output.
+ /// The offset in the output byte array to start writing from.
+ /// The amount of output bytes.
+ public int ProcessByte(
+ byte input,
+ byte[] output,
+ int outOff)
+ {
+ int resultLen = 0;
+
+ buffer[bufOff++] = input;
+
+ if (bufOff == buffer.Length)
+ {
+ resultLen = translator.Decode(buffer, 0, buffer.Length, output, outOff);
+ bufOff = 0;
+ }
+
+ return resultLen;
+ }
+
+
+ ///
+ /// Process data from a byte array.
+ ///
+ /// The input data.
+ /// Start position within input data array.
+ /// Amount of data to process from input data array.
+ /// Array to store output.
+ /// Position in output array to start writing from.
+ /// The amount of output bytes.
+ public int ProcessBytes(
+ byte[] input,
+ int inOff,
+ int len,
+ byte[] outBytes,
+ int outOff)
+ {
+ if (len < 0)
+ {
+ throw new ArgumentException("Can't have a negative input length!");
+ }
+
+ int resultLen = 0;
+ int gapLen = buffer.Length - bufOff;
+
+ if (len > gapLen)
+ {
+ Array.Copy(input, inOff, buffer, bufOff, gapLen);
+
+ resultLen += translator.Decode(buffer, 0, buffer.Length, outBytes, outOff);
+
+ bufOff = 0;
+
+ len -= gapLen;
+ inOff += gapLen;
+ outOff += resultLen;
+
+ int chunkSize = len - (len % buffer.Length);
+
+ resultLen += translator.Decode(input, inOff, chunkSize, outBytes, outOff);
+
+ len -= chunkSize;
+ inOff += chunkSize;
+ }
+
+ if (len != 0)
+ {
+ Array.Copy(input, inOff, buffer, bufOff, len);
+
+ bufOff += len;
+ }
+
+ return resultLen;
+ }
+ }
+
+}
diff --git a/bc-sharp-crypto/src/util/encoders/BufferedEncoder.cs b/bc-sharp-crypto/src/util/encoders/BufferedEncoder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5c3b1ab46172470639d0b7dc16ce8fcd9a1899f7
--- /dev/null
+++ b/bc-sharp-crypto/src/util/encoders/BufferedEncoder.cs
@@ -0,0 +1,117 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ ///
+ /// A class that allows encoding of data using a specific encoder to be processed in chunks.
+ ///
+ public class BufferedEncoder
+ {
+ internal byte[] Buffer;
+ internal int bufOff;
+
+ internal ITranslator translator;
+
+
+ ///
+ /// Create.
+ ///
+ /// The translator to use.
+ /// Size of the chunks.
+ public BufferedEncoder(
+ ITranslator translator,
+ int bufferSize)
+ {
+ this.translator = translator;
+
+ if ((bufferSize % translator.GetEncodedBlockSize()) != 0)
+ {
+ throw new ArgumentException("buffer size not multiple of input block size");
+ }
+
+ Buffer = new byte[bufferSize];
+// bufOff = 0;
+ }
+
+
+ ///
+ /// Process one byte of data.
+ ///
+ /// The byte.
+ /// An array to store output in.
+ /// Offset within output array to start writing from.
+ ///
+ public int ProcessByte(
+ byte input,
+ byte[] outBytes,
+ int outOff)
+ {
+ int resultLen = 0;
+
+ Buffer[bufOff++] = input;
+
+ if (bufOff == Buffer.Length)
+ {
+ resultLen = translator.Encode(Buffer, 0, Buffer.Length, outBytes, outOff);
+ bufOff = 0;
+ }
+
+ return resultLen;
+ }
+
+ ///
+ /// Process data from a byte array.
+ ///
+ /// Input data Byte array containing data to be processed.
+ /// Start position within input data array.
+ /// Amount of input data to be processed.
+ /// Output data array.
+ /// Offset within output data array to start writing to.
+ /// The amount of data written.
+ public int ProcessBytes(
+ byte[] input,
+ int inOff,
+ int len,
+ byte[] outBytes,
+ int outOff)
+ {
+ if (len < 0)
+ {
+ throw new ArgumentException("Can't have a negative input length!");
+ }
+
+ int resultLen = 0;
+ int gapLen = Buffer.Length - bufOff;
+
+ if (len > gapLen)
+ {
+ Array.Copy(input, inOff, Buffer, bufOff, gapLen);
+
+ resultLen += translator.Encode(Buffer, 0, Buffer.Length, outBytes, outOff);
+
+ bufOff = 0;
+
+ len -= gapLen;
+ inOff += gapLen;
+ outOff += resultLen;
+
+ int chunkSize = len - (len % Buffer.Length);
+
+ resultLen += translator.Encode(input, inOff, chunkSize, outBytes, outOff);
+
+ len -= chunkSize;
+ inOff += chunkSize;
+ }
+
+ if (len != 0)
+ {
+ Array.Copy(input, inOff, Buffer, bufOff, len);
+
+ bufOff += len;
+ }
+
+ return resultLen;
+ }
+ }
+
+}
diff --git a/bc-sharp-crypto/src/util/encoders/Hex.cs b/bc-sharp-crypto/src/util/encoders/Hex.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3540a9d1e0eda163dd0cf04eae23380bad1488fa
--- /dev/null
+++ b/bc-sharp-crypto/src/util/encoders/Hex.cs
@@ -0,0 +1,130 @@
+using System;
+using System.IO;
+using System.Text;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ ///
+ /// Class to decode and encode Hex.
+ ///
+ public sealed class Hex
+ {
+ private static readonly IEncoder encoder = new HexEncoder();
+
+ private Hex()
+ {
+ }
+
+ public static string ToHexString(
+ byte[] data)
+ {
+ return ToHexString(data, 0, data.Length);
+ }
+
+ public static string ToHexString(
+ byte[] data,
+ int off,
+ int length)
+ {
+ byte[] hex = Encode(data, off, length);
+ return Strings.FromAsciiByteArray(hex);
+ }
+
+ /**
+ * encode the input data producing a Hex encoded byte array.
+ *
+ * @return a byte array containing the Hex encoded data.
+ */
+ public static byte[] Encode(
+ byte[] data)
+ {
+ return Encode(data, 0, data.Length);
+ }
+
+ /**
+ * encode the input data producing a Hex encoded byte array.
+ *
+ * @return a byte array containing the Hex encoded data.
+ */
+ public static byte[] Encode(
+ byte[] data,
+ int off,
+ int length)
+ {
+ MemoryStream bOut = new MemoryStream(length * 2);
+
+ encoder.Encode(data, off, length, bOut);
+
+ return bOut.ToArray();
+ }
+
+ /**
+ * Hex encode the byte data writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int Encode(
+ byte[] data,
+ Stream outStream)
+ {
+ return encoder.Encode(data, 0, data.Length, outStream);
+ }
+
+ /**
+ * Hex encode the byte data writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int Encode(
+ byte[] data,
+ int off,
+ int length,
+ Stream outStream)
+ {
+ return encoder.Encode(data, off, length, outStream);
+ }
+
+ /**
+ * decode the Hex encoded input data. It is assumed the input data is valid.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] Decode(
+ byte[] data)
+ {
+ MemoryStream bOut = new MemoryStream((data.Length + 1) / 2);
+
+ encoder.Decode(data, 0, data.Length, bOut);
+
+ return bOut.ToArray();
+ }
+
+ /**
+ * decode the Hex encoded string data - whitespace will be ignored.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] Decode(
+ string data)
+ {
+ MemoryStream bOut = new MemoryStream((data.Length + 1) / 2);
+
+ encoder.DecodeString(data, bOut);
+
+ return bOut.ToArray();
+ }
+
+ /**
+ * decode the Hex encoded string data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int Decode(
+ string data,
+ Stream outStream)
+ {
+ return encoder.DecodeString(data, outStream);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/encoders/HexEncoder.cs b/bc-sharp-crypto/src/util/encoders/HexEncoder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..af526e0daa30b105a246131f13a2fd6e16b9ac24
--- /dev/null
+++ b/bc-sharp-crypto/src/util/encoders/HexEncoder.cs
@@ -0,0 +1,176 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ public class HexEncoder
+ : IEncoder
+ {
+ protected readonly byte[] encodingTable =
+ {
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
+ (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'
+ };
+
+ /*
+ * set up the decoding table.
+ */
+ protected readonly byte[] decodingTable = new byte[128];
+
+ protected void InitialiseDecodingTable()
+ {
+ Arrays.Fill(decodingTable, (byte)0xff);
+
+ for (int i = 0; i < encodingTable.Length; i++)
+ {
+ decodingTable[encodingTable[i]] = (byte)i;
+ }
+
+ decodingTable['A'] = decodingTable['a'];
+ decodingTable['B'] = decodingTable['b'];
+ decodingTable['C'] = decodingTable['c'];
+ decodingTable['D'] = decodingTable['d'];
+ decodingTable['E'] = decodingTable['e'];
+ decodingTable['F'] = decodingTable['f'];
+ }
+
+ public HexEncoder()
+ {
+ InitialiseDecodingTable();
+ }
+
+ /**
+ * encode the input data producing a Hex output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public int Encode(
+ byte[] data,
+ int off,
+ int length,
+ Stream outStream)
+ {
+ for (int i = off; i < (off + length); i++)
+ {
+ int v = data[i];
+
+ outStream.WriteByte(encodingTable[v >> 4]);
+ outStream.WriteByte(encodingTable[v & 0xf]);
+ }
+
+ return length * 2;
+ }
+
+ private static bool Ignore(char c)
+ {
+ return c == '\n' || c =='\r' || c == '\t' || c == ' ';
+ }
+
+ /**
+ * decode the Hex encoded byte data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public int Decode(
+ byte[] data,
+ int off,
+ int length,
+ Stream outStream)
+ {
+ byte b1, b2;
+ int outLen = 0;
+ int end = off + length;
+
+ while (end > off)
+ {
+ if (!Ignore((char)data[end - 1]))
+ {
+ break;
+ }
+
+ end--;
+ }
+
+ int i = off;
+ while (i < end)
+ {
+ while (i < end && Ignore((char)data[i]))
+ {
+ i++;
+ }
+
+ b1 = decodingTable[data[i++]];
+
+ while (i < end && Ignore((char)data[i]))
+ {
+ i++;
+ }
+
+ b2 = decodingTable[data[i++]];
+
+ if ((b1 | b2) >= 0x80)
+ throw new IOException("invalid characters encountered in Hex data");
+
+ outStream.WriteByte((byte)((b1 << 4) | b2));
+
+ outLen++;
+ }
+
+ return outLen;
+ }
+
+ /**
+ * decode the Hex encoded string data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public int DecodeString(
+ string data,
+ Stream outStream)
+ {
+ byte b1, b2;
+ int length = 0;
+
+ int end = data.Length;
+
+ while (end > 0)
+ {
+ if (!Ignore(data[end - 1]))
+ {
+ break;
+ }
+
+ end--;
+ }
+
+ int i = 0;
+ while (i < end)
+ {
+ while (i < end && Ignore(data[i]))
+ {
+ i++;
+ }
+
+ b1 = decodingTable[data[i++]];
+
+ while (i < end && Ignore(data[i]))
+ {
+ i++;
+ }
+
+ b2 = decodingTable[data[i++]];
+
+ if ((b1 | b2) >= 0x80)
+ throw new IOException("invalid characters encountered in Hex data");
+
+ outStream.WriteByte((byte)((b1 << 4) | b2));
+
+ length++;
+ }
+
+ return length;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/encoders/HexTranslator.cs b/bc-sharp-crypto/src/util/encoders/HexTranslator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9775b6948dba2b48f831fba7029e71a268843440
--- /dev/null
+++ b/bc-sharp-crypto/src/util/encoders/HexTranslator.cs
@@ -0,0 +1,108 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ ///
+ /// A hex translator.
+ ///
+ public class HexTranslator : ITranslator
+ {
+ private static readonly byte[] hexTable =
+ {
+ (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
+ (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'
+ };
+
+ ///
+ /// Return encoded block size.
+ ///
+ /// 2
+ public int GetEncodedBlockSize()
+ {
+ return 2;
+ }
+
+ ///
+ /// Encode some data.
+ ///
+ /// Input data array.
+ /// Start position within input data array.
+ /// The amount of data to process.
+ /// The output data array.
+ /// The offset within the output data array to start writing from.
+ /// Amount of data encoded.
+ public int Encode(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] outBytes,
+ int outOff)
+ {
+ for (int i = 0, j = 0; i < length; i++, j += 2)
+ {
+ outBytes[outOff + j] = hexTable[(input[inOff] >> 4) & 0x0f];
+ outBytes[outOff + j + 1] = hexTable[input[inOff] & 0x0f];
+
+ inOff++;
+ }
+
+ return length * 2;
+ }
+
+ ///
+ /// Returns the decoded block size.
+ ///
+ /// 1
+ public int GetDecodedBlockSize()
+ {
+ return 1;
+ }
+
+ ///
+ /// Decode data from a byte array.
+ ///
+ /// The input data array.
+ /// Start position within input data array.
+ /// The amounty of data to process.
+ /// The output data array.
+ /// The position within the output data array to start writing from.
+ /// The amount of data written.
+ public int Decode(
+ byte[] input,
+ int inOff,
+ int length,
+ byte[] outBytes,
+ int outOff)
+ {
+ int halfLength = length / 2;
+ byte left, right;
+ for (int i = 0; i < halfLength; i++)
+ {
+ left = input[inOff + i * 2];
+ right = input[inOff + i * 2 + 1];
+
+ if (left < (byte)'a')
+ {
+ outBytes[outOff] = (byte)((left - '0') << 4);
+ }
+ else
+ {
+ outBytes[outOff] = (byte)((left - 'a' + 10) << 4);
+ }
+ if (right < (byte)'a')
+ {
+ outBytes[outOff] += (byte)(right - '0');
+ }
+ else
+ {
+ outBytes[outOff] += (byte)(right - 'a' + 10);
+ }
+
+ outOff++;
+ }
+
+ return halfLength;
+ }
+ }
+
+}
diff --git a/bc-sharp-crypto/src/util/encoders/IEncoder.cs b/bc-sharp-crypto/src/util/encoders/IEncoder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5887d5daa513a9621f4d5a32b8bc9d650d17ae15
--- /dev/null
+++ b/bc-sharp-crypto/src/util/encoders/IEncoder.cs
@@ -0,0 +1,18 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ /**
+ * Encode and decode byte arrays (typically from binary to 7-bit ASCII
+ * encodings).
+ */
+ public interface IEncoder
+ {
+ int Encode(byte[] data, int off, int length, Stream outStream);
+
+ int Decode(byte[] data, int off, int length, Stream outStream);
+
+ int DecodeString(string data, Stream outStream);
+ }
+}
diff --git a/bc-sharp-crypto/src/util/encoders/Translator.cs b/bc-sharp-crypto/src/util/encoders/Translator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..10bd24b63177aed7e71151bfb7fd759ec7fa3c81
--- /dev/null
+++ b/bc-sharp-crypto/src/util/encoders/Translator.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ ///
+ /// Translator interface.
+ ///
+ public interface ITranslator
+ {
+ int GetEncodedBlockSize();
+
+ int Encode(byte[] input, int inOff, int length, byte[] outBytes, int outOff);
+
+ int GetDecodedBlockSize();
+
+ int Decode(byte[] input, int inOff, int length, byte[] outBytes, int outOff);
+ }
+
+}
diff --git a/bc-sharp-crypto/src/util/encoders/UrlBase64.cs b/bc-sharp-crypto/src/util/encoders/UrlBase64.cs
new file mode 100644
index 0000000000000000000000000000000000000000..94195ef5eddec94a459bbafbe25c0a4161eef8b5
--- /dev/null
+++ b/bc-sharp-crypto/src/util/encoders/UrlBase64.cs
@@ -0,0 +1,127 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ /**
+ * Convert binary data to and from UrlBase64 encoding. This is identical to
+ * Base64 encoding, except that the padding character is "." and the other
+ * non-alphanumeric characters are "-" and "_" instead of "+" and "/".
+ *
+ * The purpose of UrlBase64 encoding is to provide a compact encoding of binary
+ * data that is safe for use as an URL parameter. Base64 encoding does not
+ * produce encoded values that are safe for use in URLs, since "/" can be
+ * interpreted as a path delimiter; "+" is the encoded form of a space; and
+ * "=" is used to separate a name from the corresponding value in an URL
+ * parameter.
+ *
+ */
+ public class UrlBase64
+ {
+ private static readonly IEncoder encoder = new UrlBase64Encoder();
+
+ /**
+ * Encode the input data producing a URL safe base 64 encoded byte array.
+ *
+ * @return a byte array containing the URL safe base 64 encoded data.
+ */
+ public static byte[] Encode(
+ byte[] data)
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ try
+ {
+ encoder.Encode(data, 0, data.Length, bOut);
+ }
+ catch (IOException e)
+ {
+ throw new Exception("exception encoding URL safe base64 string: " + e.Message, e);
+ }
+
+ return bOut.ToArray();
+ }
+
+ /**
+ * Encode the byte data writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int Encode(
+ byte[] data,
+ Stream outStr)
+ {
+ return encoder.Encode(data, 0, data.Length, outStr);
+ }
+
+ /**
+ * Decode the URL safe base 64 encoded input data - white space will be ignored.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] Decode(
+ byte[] data)
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ try
+ {
+ encoder.Decode(data, 0, data.Length, bOut);
+ }
+ catch (IOException e)
+ {
+ throw new Exception("exception decoding URL safe base64 string: " + e.Message, e);
+ }
+
+ return bOut.ToArray();
+ }
+
+ /**
+ * decode the URL safe base 64 encoded byte data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int Decode(
+ byte[] data,
+ Stream outStr)
+ {
+ return encoder.Decode(data, 0, data.Length, outStr);
+ }
+
+ /**
+ * decode the URL safe base 64 encoded string data - whitespace will be ignored.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] Decode(
+ string data)
+ {
+ MemoryStream bOut = new MemoryStream();
+
+ try
+ {
+ encoder.DecodeString(data, bOut);
+ }
+ catch (IOException e)
+ {
+ throw new Exception("exception decoding URL safe base64 string: " + e.Message, e);
+ }
+
+ return bOut.ToArray();
+ }
+
+ /**
+ * Decode the URL safe base 64 encoded string data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int Decode(
+ string data,
+ Stream outStr)
+ {
+ return encoder.DecodeString(data, outStr);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/encoders/UrlBase64Encoder.cs b/bc-sharp-crypto/src/util/encoders/UrlBase64Encoder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5611a831cf8f863babcb44450a1f2391fb5c3c60
--- /dev/null
+++ b/bc-sharp-crypto/src/util/encoders/UrlBase64Encoder.cs
@@ -0,0 +1,31 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+ /**
+ * Convert binary data to and from UrlBase64 encoding. This is identical to
+ * Base64 encoding, except that the padding character is "." and the other
+ * non-alphanumeric characters are "-" and "_" instead of "+" and "/".
+ *
+ * The purpose of UrlBase64 encoding is to provide a compact encoding of binary
+ * data that is safe for use as an URL parameter. Base64 encoding does not
+ * produce encoded values that are safe for use in URLs, since "/" can be
+ * interpreted as a path delimiter; "+" is the encoded form of a space; and
+ * "=" is used to separate a name from the corresponding value in an URL
+ * parameter.
+ *
+ */
+ public class UrlBase64Encoder
+ : Base64Encoder
+ {
+ public UrlBase64Encoder()
+ {
+ encodingTable[encodingTable.Length - 2] = (byte) '-';
+ encodingTable[encodingTable.Length - 1] = (byte) '_';
+ padding = (byte) '.';
+ // we must re-create the decoding table with the new encoded values.
+ InitialiseDecodingTable();
+ }
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/util/io/BaseInputStream.cs b/bc-sharp-crypto/src/util/io/BaseInputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a5613d8019a3b607cf406e7fdc89a291e0fb2628
--- /dev/null
+++ b/bc-sharp-crypto/src/util/io/BaseInputStream.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+ public abstract class BaseInputStream : Stream
+ {
+ private bool closed;
+
+ public sealed override bool CanRead { get { return !closed; } }
+ public sealed override bool CanSeek { get { return false; } }
+ public sealed override bool CanWrite { get { return false; } }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ closed = true;
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ closed = true;
+ base.Close();
+ }
+#endif
+
+ public sealed override void Flush() {}
+ public sealed override long Length { get { throw new NotSupportedException(); } }
+ public sealed override long Position
+ {
+ get { throw new NotSupportedException(); }
+ set { throw new NotSupportedException(); }
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ int pos = offset;
+ try
+ {
+ int end = offset + count;
+ while (pos < end)
+ {
+ int b = ReadByte();
+ if (b == -1) break;
+ buffer[pos++] = (byte) b;
+ }
+ }
+ catch (IOException)
+ {
+ if (pos == offset) throw;
+ }
+ return pos - offset;
+ }
+
+ public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
+ public sealed override void SetLength(long value) { throw new NotSupportedException(); }
+ public sealed override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/io/BaseOutputStream.cs b/bc-sharp-crypto/src/util/io/BaseOutputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0dbe821defe63578e693a5a71ac2ab6868f26961
--- /dev/null
+++ b/bc-sharp-crypto/src/util/io/BaseOutputStream.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+ public abstract class BaseOutputStream : Stream
+ {
+ private bool closed;
+
+ public sealed override bool CanRead { get { return false; } }
+ public sealed override bool CanSeek { get { return false; } }
+ public sealed override bool CanWrite { get { return !closed; } }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ closed = true;
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ closed = true;
+ base.Close();
+ }
+#endif
+
+ public override void Flush() { }
+ public sealed override long Length { get { throw new NotSupportedException(); } }
+ public sealed override long Position
+ {
+ get { throw new NotSupportedException(); }
+ set { throw new NotSupportedException(); }
+ }
+ public sealed override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
+ public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
+ public sealed override void SetLength(long value) { throw new NotSupportedException(); }
+
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ Debug.Assert(buffer != null);
+ Debug.Assert(0 <= offset && offset <= buffer.Length);
+ Debug.Assert(count >= 0);
+
+ int end = offset + count;
+
+ Debug.Assert(0 <= end && end <= buffer.Length);
+
+ for (int i = offset; i < end; ++i)
+ {
+ this.WriteByte(buffer[i]);
+ }
+ }
+
+ public virtual void Write(params byte[] buffer)
+ {
+ Write(buffer, 0, buffer.Length);
+ }
+
+ public override void WriteByte(byte b)
+ {
+ Write(new byte[]{ b }, 0, 1);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/io/FilterStream.cs b/bc-sharp-crypto/src/util/io/FilterStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a92dee3e550b440a7eeb1367898fd477548edd1c
--- /dev/null
+++ b/bc-sharp-crypto/src/util/io/FilterStream.cs
@@ -0,0 +1,78 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+ public class FilterStream : Stream
+ {
+ public FilterStream(Stream s)
+ {
+ this.s = s;
+ }
+ public override bool CanRead
+ {
+ get { return s.CanRead; }
+ }
+ public override bool CanSeek
+ {
+ get { return s.CanSeek; }
+ }
+ public override bool CanWrite
+ {
+ get { return s.CanWrite; }
+ }
+ public override long Length
+ {
+ get { return s.Length; }
+ }
+ public override long Position
+ {
+ get { return s.Position; }
+ set { s.Position = value; }
+ }
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Platform.Dispose(s);
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ Platform.Dispose(s);
+ base.Close();
+ }
+#endif
+ public override void Flush()
+ {
+ s.Flush();
+ }
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ return s.Seek(offset, origin);
+ }
+ public override void SetLength(long value)
+ {
+ s.SetLength(value);
+ }
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ return s.Read(buffer, offset, count);
+ }
+ public override int ReadByte()
+ {
+ return s.ReadByte();
+ }
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ s.Write(buffer, offset, count);
+ }
+ public override void WriteByte(byte value)
+ {
+ s.WriteByte(value);
+ }
+ protected readonly Stream s;
+ }
+}
diff --git a/bc-sharp-crypto/src/util/io/NullOutputStream.cs b/bc-sharp-crypto/src/util/io/NullOutputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..13877fa139fd1bcbf9f5668de55e13e3aac9fa54
--- /dev/null
+++ b/bc-sharp-crypto/src/util/io/NullOutputStream.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+ internal class NullOutputStream
+ : BaseOutputStream
+ {
+ public override void WriteByte(byte b)
+ {
+ // do nothing
+ }
+
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ // do nothing
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/io/PushbackStream.cs b/bc-sharp-crypto/src/util/io/PushbackStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..95469425963a3e3dff5bee564f2bcf0fd1c14d01
--- /dev/null
+++ b/bc-sharp-crypto/src/util/io/PushbackStream.cs
@@ -0,0 +1,52 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.Utilities;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+ public class PushbackStream
+ : FilterStream
+ {
+ private int buf = -1;
+
+ public PushbackStream(
+ Stream s)
+ : base(s)
+ {
+ }
+
+ public override int ReadByte()
+ {
+ if (buf != -1)
+ {
+ int tmp = buf;
+ buf = -1;
+ return tmp;
+ }
+
+ return base.ReadByte();
+ }
+
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ if (buf != -1 && count > 0)
+ {
+ // TODO Can this case be made more efficient?
+ buffer[offset] = (byte) buf;
+ buf = -1;
+ return 1;
+ }
+
+ return base.Read(buffer, offset, count);
+ }
+
+ public virtual void Unread(int b)
+ {
+ if (buf != -1)
+ throw new InvalidOperationException("Can only push back one byte");
+
+ buf = b & 0xFF;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/io/StreamOverflowException.cs b/bc-sharp-crypto/src/util/io/StreamOverflowException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..36d21e23e92ea0ce6e6bf7a3656e4281e71623b3
--- /dev/null
+++ b/bc-sharp-crypto/src/util/io/StreamOverflowException.cs
@@ -0,0 +1,30 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class StreamOverflowException
+ : IOException
+ {
+ public StreamOverflowException()
+ : base()
+ {
+ }
+
+ public StreamOverflowException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public StreamOverflowException(
+ string message,
+ Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/io/Streams.cs b/bc-sharp-crypto/src/util/io/Streams.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cc7fa924c2511ebed45b02902d9b25c9f7e8f01b
--- /dev/null
+++ b/bc-sharp-crypto/src/util/io/Streams.cs
@@ -0,0 +1,100 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+ public sealed class Streams
+ {
+ private const int BufferSize = 512;
+
+ private Streams()
+ {
+ }
+
+ public static void Drain(Stream inStr)
+ {
+ byte[] bs = new byte[BufferSize];
+ while (inStr.Read(bs, 0, bs.Length) > 0)
+ {
+ }
+ }
+
+ public static byte[] ReadAll(Stream inStr)
+ {
+ MemoryStream buf = new MemoryStream();
+ PipeAll(inStr, buf);
+ return buf.ToArray();
+ }
+
+ public static byte[] ReadAllLimited(Stream inStr, int limit)
+ {
+ MemoryStream buf = new MemoryStream();
+ PipeAllLimited(inStr, limit, buf);
+ return buf.ToArray();
+ }
+
+ public static int ReadFully(Stream inStr, byte[] buf)
+ {
+ return ReadFully(inStr, buf, 0, buf.Length);
+ }
+
+ public static int ReadFully(Stream inStr, byte[] buf, int off, int len)
+ {
+ int totalRead = 0;
+ while (totalRead < len)
+ {
+ int numRead = inStr.Read(buf, off + totalRead, len - totalRead);
+ if (numRead < 1)
+ break;
+ totalRead += numRead;
+ }
+ return totalRead;
+ }
+
+ public static void PipeAll(Stream inStr, Stream outStr)
+ {
+ byte[] bs = new byte[BufferSize];
+ int numRead;
+ while ((numRead = inStr.Read(bs, 0, bs.Length)) > 0)
+ {
+ outStr.Write(bs, 0, numRead);
+ }
+ }
+
+ ///
+ /// Pipe all bytes from inStr to outStr , throwing StreamFlowException if greater
+ /// than limit bytes in inStr .
+ ///
+ ///
+ /// A
+ ///
+ ///
+ /// A
+ ///
+ ///
+ /// A
+ ///
+ /// The number of bytes actually transferred, if not greater than limit
+ ///
+ public static long PipeAllLimited(Stream inStr, long limit, Stream outStr)
+ {
+ byte[] bs = new byte[BufferSize];
+ long total = 0;
+ int numRead;
+ while ((numRead = inStr.Read(bs, 0, bs.Length)) > 0)
+ {
+ if ((limit - total) < numRead)
+ throw new StreamOverflowException("Data Overflow");
+ total += numRead;
+ outStr.Write(bs, 0, numRead);
+ }
+ return total;
+ }
+
+ ///
+ public static void WriteBufTo(MemoryStream buf, Stream output)
+ {
+ buf.WriteTo(output);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/io/TeeInputStream.cs b/bc-sharp-crypto/src/util/io/TeeInputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6996f3fbb744c34c84e24f6be2a8718db8ea278e
--- /dev/null
+++ b/bc-sharp-crypto/src/util/io/TeeInputStream.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+ public class TeeInputStream
+ : BaseInputStream
+ {
+ private readonly Stream input, tee;
+
+ public TeeInputStream(Stream input, Stream tee)
+ {
+ Debug.Assert(input.CanRead);
+ Debug.Assert(tee.CanWrite);
+
+ this.input = input;
+ this.tee = tee;
+ }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Platform.Dispose(input);
+ Platform.Dispose(tee);
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ Platform.Dispose(input);
+ Platform.Dispose(tee);
+ base.Close();
+ }
+#endif
+
+ public override int Read(byte[] buf, int off, int len)
+ {
+ int i = input.Read(buf, off, len);
+
+ if (i > 0)
+ {
+ tee.Write(buf, off, i);
+ }
+
+ return i;
+ }
+
+ public override int ReadByte()
+ {
+ int i = input.ReadByte();
+
+ if (i >= 0)
+ {
+ tee.WriteByte((byte)i);
+ }
+
+ return i;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/io/TeeOutputStream.cs b/bc-sharp-crypto/src/util/io/TeeOutputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a6c7fd5b5920b6441070b6fa22194ea3ddbf960c
--- /dev/null
+++ b/bc-sharp-crypto/src/util/io/TeeOutputStream.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+ public class TeeOutputStream
+ : BaseOutputStream
+ {
+ private readonly Stream output, tee;
+
+ public TeeOutputStream(Stream output, Stream tee)
+ {
+ Debug.Assert(output.CanWrite);
+ Debug.Assert(tee.CanWrite);
+
+ this.output = output;
+ this.tee = tee;
+ }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ Platform.Dispose(output);
+ Platform.Dispose(tee);
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close()
+ {
+ Platform.Dispose(output);
+ Platform.Dispose(tee);
+ base.Close();
+ }
+#endif
+
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ output.Write(buffer, offset, count);
+ tee.Write(buffer, offset, count);
+ }
+
+ public override void WriteByte(byte b)
+ {
+ output.WriteByte(b);
+ tee.WriteByte(b);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/io/pem/PemGenerationException.cs b/bc-sharp-crypto/src/util/io/pem/PemGenerationException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6b395857767dc1caa1fe181c24814f40473d2ee5
--- /dev/null
+++ b/bc-sharp-crypto/src/util/io/pem/PemGenerationException.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.IO.Pem
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class PemGenerationException
+ : Exception
+ {
+ public PemGenerationException()
+ : base()
+ {
+ }
+
+ public PemGenerationException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public PemGenerationException(
+ string message,
+ Exception exception)
+ : base(message, exception)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/io/pem/PemHeader.cs b/bc-sharp-crypto/src/util/io/pem/PemHeader.cs
new file mode 100644
index 0000000000000000000000000000000000000000..72da8a4f7df5ac74c795c9735387c655ebbc904a
--- /dev/null
+++ b/bc-sharp-crypto/src/util/io/pem/PemHeader.cs
@@ -0,0 +1,55 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.IO.Pem
+{
+ public class PemHeader
+ {
+ private string name;
+ private string val;
+
+ public PemHeader(string name, string val)
+ {
+ this.name = name;
+ this.val = val;
+ }
+
+ public virtual string Name
+ {
+ get { return name; }
+ }
+
+ public virtual string Value
+ {
+ get { return val; }
+ }
+
+ public override int GetHashCode()
+ {
+ return GetHashCode(this.name) + 31 * GetHashCode(this.val);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj == this)
+ return true;
+
+ if (!(obj is PemHeader))
+ return false;
+
+ PemHeader other = (PemHeader)obj;
+
+ return Platform.Equals(this.name, other.name)
+ && Platform.Equals(this.val, other.val);
+ }
+
+ private int GetHashCode(string s)
+ {
+ if (s == null)
+ {
+ return 1;
+ }
+
+ return s.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/io/pem/PemObject.cs b/bc-sharp-crypto/src/util/io/pem/PemObject.cs
new file mode 100644
index 0000000000000000000000000000000000000000..41212f997b196f5659b7683ebcdf504c2641637d
--- /dev/null
+++ b/bc-sharp-crypto/src/util/io/pem/PemObject.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Utilities.IO.Pem
+{
+ public class PemObject
+ : PemObjectGenerator
+ {
+ private string type;
+ private IList headers;
+ private byte[] content;
+
+ public PemObject(string type, byte[] content)
+ : this(type, Platform.CreateArrayList(), content)
+ {
+ }
+
+ public PemObject(String type, IList headers, byte[] content)
+ {
+ this.type = type;
+ this.headers = Platform.CreateArrayList(headers);
+ this.content = content;
+ }
+
+ public string Type
+ {
+ get { return type; }
+ }
+
+ public IList Headers
+ {
+ get { return headers; }
+ }
+
+ public byte[] Content
+ {
+ get { return content; }
+ }
+
+ public PemObject Generate()
+ {
+ return this;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/io/pem/PemObjectGenerator.cs b/bc-sharp-crypto/src/util/io/pem/PemObjectGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6f9bfc19178e27db558d449f54cf6ba0a146eb45
--- /dev/null
+++ b/bc-sharp-crypto/src/util/io/pem/PemObjectGenerator.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.IO.Pem
+{
+ public interface PemObjectGenerator
+ {
+ ///
+ /// A
+ ///
+ ///
+ PemObject Generate();
+ }
+}
diff --git a/bc-sharp-crypto/src/util/io/pem/PemObjectParser.cs b/bc-sharp-crypto/src/util/io/pem/PemObjectParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..91d26dc3a040c5c08df6ce27b7484f610a6b3549
--- /dev/null
+++ b/bc-sharp-crypto/src/util/io/pem/PemObjectParser.cs
@@ -0,0 +1,17 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO.Pem
+{
+ public interface PemObjectParser
+ {
+ ///
+ /// A
+ ///
+ ///
+ /// A
+ ///
+ ///
+ object ParseObject(PemObject obj);
+ }
+}
diff --git a/bc-sharp-crypto/src/util/io/pem/PemReader.cs b/bc-sharp-crypto/src/util/io/pem/PemReader.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bf712b6dec3bd645a58ece803d3a901265f18ce1
--- /dev/null
+++ b/bc-sharp-crypto/src/util/io/pem/PemReader.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Utilities.IO.Pem
+{
+ public class PemReader
+ {
+ private const string BeginString = "-----BEGIN ";
+ private const string EndString = "-----END ";
+
+ private readonly TextReader reader;
+
+ public PemReader(TextReader reader)
+ {
+ if (reader == null)
+ throw new ArgumentNullException("reader");
+
+ this.reader = reader;
+ }
+
+ public TextReader Reader
+ {
+ get { return reader; }
+ }
+
+ ///
+ /// A
+ ///
+ ///
+ public PemObject ReadPemObject()
+ {
+ string line = reader.ReadLine();
+
+ if (line != null && Platform.StartsWith(line, BeginString))
+ {
+ line = line.Substring(BeginString.Length);
+ int index = line.IndexOf('-');
+ string type = line.Substring(0, index);
+
+ if (index > 0)
+ return LoadObject(type);
+ }
+
+ return null;
+ }
+
+ private PemObject LoadObject(string type)
+ {
+ string endMarker = EndString + type;
+ IList headers = Platform.CreateArrayList();
+ StringBuilder buf = new StringBuilder();
+
+ string line;
+ while ((line = reader.ReadLine()) != null
+ && Platform.IndexOf(line, endMarker) == -1)
+ {
+ int colonPos = line.IndexOf(':');
+
+ if (colonPos == -1)
+ {
+ buf.Append(line.Trim());
+ }
+ else
+ {
+ // Process field
+ string fieldName = line.Substring(0, colonPos).Trim();
+
+ if (Platform.StartsWith(fieldName, "X-"))
+ {
+ fieldName = fieldName.Substring(2);
+ }
+
+ string fieldValue = line.Substring(colonPos + 1).Trim();
+
+ headers.Add(new PemHeader(fieldName, fieldValue));
+ }
+ }
+
+ if (line == null)
+ {
+ throw new IOException(endMarker + " not found");
+ }
+
+ if (buf.Length % 4 != 0)
+ {
+ throw new IOException("base64 data appears to be truncated");
+ }
+
+ return new PemObject(type, headers, Base64.Decode(buf.ToString()));
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/io/pem/PemWriter.cs b/bc-sharp-crypto/src/util/io/pem/PemWriter.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e85b31543d7ac7b8cb2127635744029c1a9a9ab7
--- /dev/null
+++ b/bc-sharp-crypto/src/util/io/pem/PemWriter.cs
@@ -0,0 +1,120 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Utilities.IO.Pem
+{
+ /**
+ * A generic PEM writer, based on RFC 1421
+ */
+ public class PemWriter
+ {
+ private const int LineLength = 64;
+
+ private readonly TextWriter writer;
+ private readonly int nlLength;
+ private char[] buf = new char[LineLength];
+
+ /**
+ * Base constructor.
+ *
+ * @param out output stream to use.
+ */
+ public PemWriter(TextWriter writer)
+ {
+ if (writer == null)
+ throw new ArgumentNullException("writer");
+
+ this.writer = writer;
+ this.nlLength = Platform.NewLine.Length;
+ }
+
+ public TextWriter Writer
+ {
+ get { return writer; }
+ }
+
+ /**
+ * Return the number of bytes or characters required to contain the
+ * passed in object if it is PEM encoded.
+ *
+ * @param obj pem object to be output
+ * @return an estimate of the number of bytes
+ */
+ public int GetOutputSize(PemObject obj)
+ {
+ // BEGIN and END boundaries.
+ int size = (2 * (obj.Type.Length + 10 + nlLength)) + 6 + 4;
+
+ if (obj.Headers.Count > 0)
+ {
+ foreach (PemHeader header in obj.Headers)
+ {
+ size += header.Name.Length + ": ".Length + header.Value.Length + nlLength;
+ }
+
+ size += nlLength;
+ }
+
+ // base64 encoding
+ int dataLen = ((obj.Content.Length + 2) / 3) * 4;
+
+ size += dataLen + (((dataLen + LineLength - 1) / LineLength) * nlLength);
+
+ return size;
+ }
+
+ public void WriteObject(PemObjectGenerator objGen)
+ {
+ PemObject obj = objGen.Generate();
+
+ WritePreEncapsulationBoundary(obj.Type);
+
+ if (obj.Headers.Count > 0)
+ {
+ foreach (PemHeader header in obj.Headers)
+ {
+ writer.Write(header.Name);
+ writer.Write(": ");
+ writer.WriteLine(header.Value);
+ }
+
+ writer.WriteLine();
+ }
+
+ WriteEncoded(obj.Content);
+ WritePostEncapsulationBoundary(obj.Type);
+ }
+
+ private void WriteEncoded(byte[] bytes)
+ {
+ bytes = Base64.Encode(bytes);
+
+ for (int i = 0; i < bytes.Length; i += buf.Length)
+ {
+ int index = 0;
+ while (index != buf.Length)
+ {
+ if ((i + index) >= bytes.Length)
+ break;
+
+ buf[index] = (char)bytes[i + index];
+ index++;
+ }
+ writer.WriteLine(buf, 0, index);
+ }
+ }
+
+ private void WritePreEncapsulationBoundary(string type)
+ {
+ writer.WriteLine("-----BEGIN " + type + "-----");
+ }
+
+ private void WritePostEncapsulationBoundary(string type)
+ {
+ writer.WriteLine("-----END " + type + "-----");
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/net/IPAddress.cs b/bc-sharp-crypto/src/util/net/IPAddress.cs
new file mode 100644
index 0000000000000000000000000000000000000000..38c1245903934add4690cc8ac57826b9635de603
--- /dev/null
+++ b/bc-sharp-crypto/src/util/net/IPAddress.cs
@@ -0,0 +1,197 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Utilities.Net
+{
+ public class IPAddress
+ {
+ /**
+ * Validate the given IPv4 or IPv6 address.
+ *
+ * @param address the IP address as a string.
+ *
+ * @return true if a valid address, false otherwise
+ */
+ public static bool IsValid(
+ string address)
+ {
+ return IsValidIPv4(address) || IsValidIPv6(address);
+ }
+
+ /**
+ * Validate the given IPv4 or IPv6 address and netmask.
+ *
+ * @param address the IP address as a string.
+ *
+ * @return true if a valid address with netmask, false otherwise
+ */
+ public static bool IsValidWithNetMask(
+ string address)
+ {
+ return IsValidIPv4WithNetmask(address) || IsValidIPv6WithNetmask(address);
+ }
+
+ /**
+ * Validate the given IPv4 address.
+ *
+ * @param address the IP address as a string.
+ *
+ * @return true if a valid IPv4 address, false otherwise
+ */
+ public static bool IsValidIPv4(
+ string address)
+ {
+ try
+ {
+ return unsafeIsValidIPv4(address);
+ }
+ catch (FormatException) {}
+ catch (OverflowException) {}
+ return false;
+ }
+
+ private static bool unsafeIsValidIPv4(
+ string address)
+ {
+ if (address.Length == 0)
+ return false;
+
+ int octets = 0;
+ string temp = address + ".";
+
+ int pos;
+ int start = 0;
+ while (start < temp.Length
+ && (pos = temp.IndexOf('.', start)) > start)
+ {
+ if (octets == 4)
+ return false;
+
+ string octetStr = temp.Substring(start, pos - start);
+ int octet = Int32.Parse(octetStr);
+
+ if (octet < 0 || octet > 255)
+ return false;
+
+ start = pos + 1;
+ octets++;
+ }
+
+ return octets == 4;
+ }
+
+ public static bool IsValidIPv4WithNetmask(
+ string address)
+ {
+ int index = address.IndexOf('/');
+ string mask = address.Substring(index + 1);
+
+ return (index > 0) && IsValidIPv4(address.Substring(0, index))
+ && (IsValidIPv4(mask) || IsMaskValue(mask, 32));
+ }
+
+ public static bool IsValidIPv6WithNetmask(
+ string address)
+ {
+ int index = address.IndexOf('/');
+ string mask = address.Substring(index + 1);
+
+ return (index > 0) && (IsValidIPv6(address.Substring(0, index))
+ && (IsValidIPv6(mask) || IsMaskValue(mask, 128)));
+ }
+
+ private static bool IsMaskValue(
+ string component,
+ int size)
+ {
+ int val = Int32.Parse(component);
+ try
+ {
+ return val >= 0 && val <= size;
+ }
+ catch (FormatException) {}
+ catch (OverflowException) {}
+ return false;
+ }
+
+ /**
+ * Validate the given IPv6 address.
+ *
+ * @param address the IP address as a string.
+ *
+ * @return true if a valid IPv4 address, false otherwise
+ */
+ public static bool IsValidIPv6(
+ string address)
+ {
+ try
+ {
+ return unsafeIsValidIPv6(address);
+ }
+ catch (FormatException) {}
+ catch (OverflowException) {}
+ return false;
+ }
+
+ private static bool unsafeIsValidIPv6(
+ string address)
+ {
+ if (address.Length == 0)
+ {
+ return false;
+ }
+
+ int octets = 0;
+
+ string temp = address + ":";
+ bool doubleColonFound = false;
+ int pos;
+ int start = 0;
+ while (start < temp.Length
+ && (pos = temp.IndexOf(':', start)) >= start)
+ {
+ if (octets == 8)
+ {
+ return false;
+ }
+
+ if (start != pos)
+ {
+ string value = temp.Substring(start, pos - start);
+
+ if (pos == (temp.Length - 1) && value.IndexOf('.') > 0)
+ {
+ if (!IsValidIPv4(value))
+ {
+ return false;
+ }
+
+ octets++; // add an extra one as address covers 2 words.
+ }
+ else
+ {
+ string octetStr = temp.Substring(start, pos - start);
+ int octet = Int32.Parse(octetStr, NumberStyles.AllowHexSpecifier);
+
+ if (octet < 0 || octet > 0xffff)
+ return false;
+ }
+ }
+ else
+ {
+ if (pos != 1 && pos != temp.Length - 1 && doubleColonFound)
+ {
+ return false;
+ }
+ doubleColonFound = true;
+ }
+ start = pos + 1;
+ octets++;
+ }
+
+ return octets == 8 || doubleColonFound;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/zlib/Adler32.cs b/bc-sharp-crypto/src/util/zlib/Adler32.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c38258f2aa5beb8db08a55e028bcd0ca583474ed
--- /dev/null
+++ b/bc-sharp-crypto/src/util/zlib/Adler32.cs
@@ -0,0 +1,88 @@
+using System;
+/*
+ * $Id: Adler32.cs,v 1.1 2006-07-31 13:59:25 bouncy Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+ internal sealed class Adler32{
+
+ // largest prime smaller than 65536
+ private const int BASE=65521;
+ // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
+ private const int NMAX=5552;
+
+ internal long adler32(long adler, byte[] buf, int index, int len){
+ if(buf == null){ return 1L; }
+
+ long s1=adler&0xffff;
+ long s2=(adler>>16)&0xffff;
+ int k;
+
+ while(len > 0) {
+ k=len=16){
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ s1+=buf[index++]&0xff; s2+=s1;
+ k-=16;
+ }
+ if(k!=0){
+ do{
+ s1+=buf[index++]&0xff; s2+=s1;
+ }
+ while(--k!=0);
+ }
+ s1%=BASE;
+ s2%=BASE;
+ }
+ return (s2<<16)|s1;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/util/zlib/Deflate.cs b/bc-sharp-crypto/src/util/zlib/Deflate.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ca04309392fc67854a6ee0b144d25be40cfa730a
--- /dev/null
+++ b/bc-sharp-crypto/src/util/zlib/Deflate.cs
@@ -0,0 +1,1640 @@
+using System;
+/*
+ * $Id: Deflate.cs,v 1.2 2008-05-10 09:35:40 bouncy Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+ public sealed class Deflate{
+
+ private const int MAX_MEM_LEVEL=9;
+
+ private const int Z_DEFAULT_COMPRESSION=-1;
+
+ private const int MAX_WBITS=15; // 32K LZ77 window
+ private const int DEF_MEM_LEVEL=8;
+
+ internal class Config{
+ internal int good_length; // reduce lazy search above this match length
+ internal int max_lazy; // do not perform lazy search above this match length
+ internal int nice_length; // quit search above this match length
+ internal int max_chain;
+ internal int func;
+ internal Config(int good_length, int max_lazy,
+ int nice_length, int max_chain, int func){
+ this.good_length=good_length;
+ this.max_lazy=max_lazy;
+ this.nice_length=nice_length;
+ this.max_chain=max_chain;
+ this.func=func;
+ }
+ }
+
+ private const int STORED=0;
+ private const int FAST=1;
+ private const int SLOW=2;
+ private static readonly Config[] config_table;
+
+ static Deflate(){
+ config_table=new Config[10];
+ // good lazy nice chain
+ config_table[0]=new Config(0, 0, 0, 0, STORED);
+ config_table[1]=new Config(4, 4, 8, 4, FAST);
+ config_table[2]=new Config(4, 5, 16, 8, FAST);
+ config_table[3]=new Config(4, 6, 32, 32, FAST);
+
+ config_table[4]=new Config(4, 4, 16, 16, SLOW);
+ config_table[5]=new Config(8, 16, 32, 32, SLOW);
+ config_table[6]=new Config(8, 16, 128, 128, SLOW);
+ config_table[7]=new Config(8, 32, 128, 256, SLOW);
+ config_table[8]=new Config(32, 128, 258, 1024, SLOW);
+ config_table[9]=new Config(32, 258, 258, 4096, SLOW);
+ }
+
+ private static readonly String[] z_errmsg = {
+ "need dictionary", // Z_NEED_DICT 2
+ "stream end", // Z_STREAM_END 1
+ "", // Z_OK 0
+ "file error", // Z_ERRNO (-1)
+ "stream error", // Z_STREAM_ERROR (-2)
+ "data error", // Z_DATA_ERROR (-3)
+ "insufficient memory", // Z_MEM_ERROR (-4)
+ "buffer error", // Z_BUF_ERROR (-5)
+ "incompatible version",// Z_VERSION_ERROR (-6)
+ ""
+ };
+
+ // block not completed, need more input or more output
+ private const int NeedMore=0;
+
+ // block flush performed
+ private const int BlockDone=1;
+
+ // finish started, need only more output at next deflate
+ private const int FinishStarted=2;
+
+ // finish done, accept no more input or output
+ private const int FinishDone=3;
+
+ // preset dictionary flag in zlib header
+ private const int PRESET_DICT=0x20;
+
+ private const int Z_FILTERED=1;
+ private const int Z_HUFFMAN_ONLY=2;
+ private const int Z_DEFAULT_STRATEGY=0;
+
+ private const int Z_NO_FLUSH=0;
+ private const int Z_PARTIAL_FLUSH=1;
+ private const int Z_SYNC_FLUSH=2;
+ private const int Z_FULL_FLUSH=3;
+ private const int Z_FINISH=4;
+
+ private const int Z_OK=0;
+ private const int Z_STREAM_END=1;
+ private const int Z_NEED_DICT=2;
+ private const int Z_ERRNO=-1;
+ private const int Z_STREAM_ERROR=-2;
+ private const int Z_DATA_ERROR=-3;
+ private const int Z_MEM_ERROR=-4;
+ private const int Z_BUF_ERROR=-5;
+ private const int Z_VERSION_ERROR=-6;
+
+ private const int INIT_STATE=42;
+ private const int BUSY_STATE=113;
+ private const int FINISH_STATE=666;
+
+ // The deflate compression method
+ private const int Z_DEFLATED=8;
+
+ private const int STORED_BLOCK=0;
+ private const int STATIC_TREES=1;
+ private const int DYN_TREES=2;
+
+ // The three kinds of block type
+ private const int Z_BINARY=0;
+ private const int Z_ASCII=1;
+ private const int Z_UNKNOWN=2;
+
+ private const int Buf_size=8*2;
+
+ // repeat previous bit length 3-6 times (2 bits of repeat count)
+ private const int REP_3_6=16;
+
+ // repeat a zero length 3-10 times (3 bits of repeat count)
+ private const int REPZ_3_10=17;
+
+ // repeat a zero length 11-138 times (7 bits of repeat count)
+ private const int REPZ_11_138=18;
+
+ private const int MIN_MATCH=3;
+ private const int MAX_MATCH=258;
+ private const int MIN_LOOKAHEAD=(MAX_MATCH+MIN_MATCH+1);
+
+ private const int MAX_BITS=15;
+ private const int D_CODES=30;
+ private const int BL_CODES=19;
+ private const int LENGTH_CODES=29;
+ private const int LITERALS=256;
+ private const int L_CODES=(LITERALS+1+LENGTH_CODES);
+ private const int HEAP_SIZE=(2*L_CODES+1);
+
+ private const int END_BLOCK=256;
+
+ internal ZStream strm; // pointer back to this zlib stream
+ internal int status; // as the name implies
+ internal byte[] pending_buf; // output still pending
+ internal int pending_buf_size; // size of pending_buf
+ internal int pending_out; // next pending byte to output to the stream
+ internal int pending; // nb of bytes in the pending buffer
+ internal int noheader; // suppress zlib header and adler32
+ internal byte data_type; // UNKNOWN, BINARY or ASCII
+ internal byte method; // STORED (for zip only) or DEFLATED
+ internal int last_flush; // value of flush param for previous deflate call
+
+ internal int w_size; // LZ77 window size (32K by default)
+ internal int w_bits; // log2(w_size) (8..16)
+ internal int w_mask; // w_size - 1
+
+ internal byte[] window;
+ // Sliding window. Input bytes are read into the second half of the window,
+ // and move to the first half later to keep a dictionary of at least wSize
+ // bytes. With this organization, matches are limited to a distance of
+ // wSize-MAX_MATCH bytes, but this ensures that IO is always
+ // performed with a length multiple of the block size. Also, it limits
+ // the window size to 64K, which is quite useful on MSDOS.
+ // To do: use the user input buffer as sliding window.
+
+ internal int window_size;
+ // Actual size of window: 2*wSize, except when the user input buffer
+ // is directly used as sliding window.
+
+ internal short[] prev;
+ // Link to older string with same hash index. To limit the size of this
+ // array to 64K, this link is maintained only for the last 32K strings.
+ // An index in this array is thus a window index modulo 32K.
+
+ internal short[] head; // Heads of the hash chains or NIL.
+
+ internal int ins_h; // hash index of string to be inserted
+ internal int hash_size; // number of elements in hash table
+ internal int hash_bits; // log2(hash_size)
+ internal int hash_mask; // hash_size-1
+
+ // Number of bits by which ins_h must be shifted at each input
+ // step. It must be such that after MIN_MATCH steps, the oldest
+ // byte no longer takes part in the hash key, that is:
+ // hash_shift * MIN_MATCH >= hash_bits
+ internal int hash_shift;
+
+ // Window position at the beginning of the current output block. Gets
+ // negative when the window is moved backwards.
+
+ internal int block_start;
+
+ internal int match_length; // length of best match
+ internal int prev_match; // previous match
+ internal int match_available; // set if previous match exists
+ internal int strstart; // start of string to insert
+ internal int match_start; // start of matching string
+ internal int lookahead; // number of valid bytes ahead in window
+
+ // Length of the best match at previous step. Matches not greater than this
+ // are discarded. This is used in the lazy match evaluation.
+ internal int prev_length;
+
+ // To speed up deflation, hash chains are never searched beyond this
+ // length. A higher limit improves compression ratio but degrades the speed.
+ internal int max_chain_length;
+
+ // Attempt to find a better match only when the current match is strictly
+ // smaller than this value. This mechanism is used only for compression
+ // levels >= 4.
+ internal int max_lazy_match;
+
+ // Insert new strings in the hash table only if the match length is not
+ // greater than this length. This saves time but degrades compression.
+ // max_insert_length is used only for compression levels <= 3.
+
+ internal int level; // compression level (1..9)
+ internal int strategy; // favor or force Huffman coding
+
+ // Use a faster search when the previous match is longer than this
+ internal int good_match;
+
+ // Stop searching when current match exceeds this
+ internal int nice_match;
+
+ internal short[] dyn_ltree; // literal and length tree
+ internal short[] dyn_dtree; // distance tree
+ internal short[] bl_tree; // Huffman tree for bit lengths
+
+ internal Tree l_desc=new Tree(); // desc for literal tree
+ internal Tree d_desc=new Tree(); // desc for distance tree
+ internal Tree bl_desc=new Tree(); // desc for bit length tree
+
+ // number of codes at each bit length for an optimal tree
+ internal short[] bl_count=new short[MAX_BITS+1];
+
+ // heap used to build the Huffman trees
+ internal int[] heap=new int[2*L_CODES+1];
+
+ internal int heap_len; // number of elements in the heap
+ internal int heap_max; // element of largest frequency
+ // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ // The same heap array is used to build all trees.
+
+ // Depth of each subtree used as tie breaker for trees of equal frequency
+ internal byte[] depth=new byte[2*L_CODES+1];
+
+ internal int l_buf; // index for literals or lengths */
+
+ // Size of match buffer for literals/lengths. There are 4 reasons for
+ // limiting lit_bufsize to 64K:
+ // - frequencies can be kept in 16 bit counters
+ // - if compression is not successful for the first block, all input
+ // data is still in the window so we can still emit a stored block even
+ // when input comes from standard input. (This can also be done for
+ // all blocks if lit_bufsize is not greater than 32K.)
+ // - if compression is not successful for a file smaller than 64K, we can
+ // even emit a stored file instead of a stored block (saving 5 bytes).
+ // This is applicable only for zip (not gzip or zlib).
+ // - creating new Huffman trees less frequently may not provide fast
+ // adaptation to changes in the input data statistics. (Take for
+ // example a binary file with poorly compressible code followed by
+ // a highly compressible string table.) Smaller buffer sizes give
+ // fast adaptation but have of course the overhead of transmitting
+ // trees more frequently.
+ // - I can't count above 4
+ internal int lit_bufsize;
+
+ internal int last_lit; // running index in l_buf
+
+ // Buffer for distances. To simplify the code, d_buf and l_buf have
+ // the same number of elements. To use different lengths, an extra flag
+ // array would be necessary.
+
+ internal int d_buf; // index of pendig_buf
+
+ internal int opt_len; // bit length of current block with optimal trees
+ internal int static_len; // bit length of current block with static trees
+ internal int matches; // number of string matches in current block
+ internal int last_eob_len; // bit length of EOB code for last block
+
+ // Output buffer. bits are inserted starting at the bottom (least
+ // significant bits).
+ internal uint bi_buf;
+
+ // Number of valid bits in bi_buf. All bits above the last valid bit
+ // are always zero.
+ internal int bi_valid;
+
+ internal Deflate(){
+ dyn_ltree=new short[HEAP_SIZE*2];
+ dyn_dtree=new short[(2*D_CODES+1)*2]; // distance tree
+ bl_tree=new short[(2*BL_CODES+1)*2]; // Huffman tree for bit lengths
+ }
+
+ internal void lm_init() {
+ window_size=2*w_size;
+
+ head[hash_size-1]=0;
+ for(int i=0; i= 3; max_blindex--) {
+ if (bl_tree[Tree.bl_order[max_blindex]*2+1] != 0) break;
+ }
+ // Update opt_len to include the bit length tree and counts
+ opt_len += 3*(max_blindex+1) + 5+5+4;
+
+ return max_blindex;
+ }
+
+
+ // Send the header for a block using dynamic Huffman trees: the counts, the
+ // lengths of the bit length codes, the literal tree and the distance tree.
+ // IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ internal void send_all_trees(int lcodes, int dcodes, int blcodes){
+ int rank; // index in bl_order
+
+ send_bits(lcodes-257, 5); // not +255 as stated in appnote.txt
+ send_bits(dcodes-1, 5);
+ send_bits(blcodes-4, 4); // not -3 as stated in appnote.txt
+ for (rank = 0; rank < blcodes; rank++) {
+ send_bits(bl_tree[Tree.bl_order[rank]*2+1], 3);
+ }
+ send_tree(dyn_ltree, lcodes-1); // literal tree
+ send_tree(dyn_dtree, dcodes-1); // distance tree
+ }
+
+ // Send a literal or distance tree in compressed form, using the codes in
+ // bl_tree.
+ internal void send_tree (short[] tree,// the tree to be sent
+ int max_code // and its largest code of non zero frequency
+ ){
+ int n; // iterates over all tree elements
+ int prevlen = -1; // last emitted length
+ int curlen; // length of current code
+ int nextlen = tree[0*2+1]; // length of next code
+ int count = 0; // repeat count of the current code
+ int max_count = 7; // max repeat count
+ int min_count = 4; // min repeat count
+
+ if (nextlen == 0){ max_count = 138; min_count = 3; }
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[(n+1)*2+1];
+ if(++count < max_count && curlen == nextlen) {
+ continue;
+ }
+ else if(count < min_count) {
+ do { send_code(curlen, bl_tree); } while (--count != 0);
+ }
+ else if(curlen != 0){
+ if(curlen != prevlen){
+ send_code(curlen, bl_tree); count--;
+ }
+ send_code(REP_3_6, bl_tree);
+ send_bits(count-3, 2);
+ }
+ else if(count <= 10){
+ send_code(REPZ_3_10, bl_tree);
+ send_bits(count-3, 3);
+ }
+ else{
+ send_code(REPZ_11_138, bl_tree);
+ send_bits(count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if(nextlen == 0){
+ max_count = 138; min_count = 3;
+ }
+ else if(curlen == nextlen){
+ max_count = 6; min_count = 3;
+ }
+ else{
+ max_count = 7; min_count = 4;
+ }
+ }
+ }
+
+ // Output a byte on the stream.
+ // IN assertion: there is enough room in pending_buf.
+ internal void put_byte(byte[] p, int start, int len){
+ System.Array.Copy(p, start, pending_buf, pending, len);
+ pending+=len;
+ }
+
+ internal void put_byte(byte c){
+ pending_buf[pending++]=c;
+ }
+ internal void put_short(int w) {
+ pending_buf[pending++]=(byte)(w/*&0xff*/);
+ pending_buf[pending++]=(byte)(w>>8);
+ }
+ internal void putShortMSB(int b){
+ pending_buf[pending++]=(byte)(b>>8);
+ pending_buf[pending++]=(byte)(b/*&0xff*/);
+ }
+
+ internal void send_code(int c, short[] tree){
+ int c2=c*2;
+ send_bits((tree[c2]&0xffff), (tree[c2+1]&0xffff));
+ }
+
+ internal void send_bits(int val, int length){
+ if (bi_valid > Buf_size - length) {
+ bi_buf |= (uint)(val << bi_valid);
+ pending_buf[pending++]=(byte)(bi_buf/*&0xff*/);
+ pending_buf[pending++]=(byte)(bi_buf>>8);
+ bi_buf = ((uint)val) >> (Buf_size - bi_valid);
+ bi_valid += length - Buf_size;
+ } else {
+ bi_buf |= (uint)(val << bi_valid);
+ bi_valid += length;
+ }
+// int len = length;
+// if (bi_valid > (int)Buf_size - len) {
+// int val = value;
+// // bi_buf |= (val << bi_valid);
+// bi_buf = (short)((ushort)bi_buf | (ushort)((val << bi_valid)&0xffff));
+// put_short(bi_buf);
+// bi_buf = (short)(((uint)val) >> (Buf_size - bi_valid));
+// bi_valid += len - Buf_size;
+// } else {
+// // bi_buf |= (value) << bi_valid;
+// bi_buf = (short)((ushort)bi_buf | (ushort)(((value) << bi_valid)&0xffff));
+// bi_valid += len;
+// }
+ }
+
+ // Send one empty static block to give enough lookahead for inflate.
+ // This takes 10 bits, of which 7 may remain in the bit buffer.
+ // The current inflate code requires 9 bits of lookahead. If the
+ // last two codes for the previous block (real code plus EOB) were coded
+ // on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ // the last real code. In this case we send two empty static blocks instead
+ // of one. (There are no problems if the previous block is stored or fixed.)
+ // To simplify the code, we assume the worst case of last real code encoded
+ // on one bit only.
+ internal void _tr_align(){
+ send_bits(STATIC_TREES<<1, 3);
+ send_code(END_BLOCK, StaticTree.static_ltree);
+
+ bi_flush();
+
+ // Of the 10 bits for the empty block, we have already sent
+ // (10 - bi_valid) bits. The lookahead for the last real code (before
+ // the EOB of the previous block) was thus at least one plus the length
+ // of the EOB plus what we have just sent of the empty static block.
+ if (1 + last_eob_len + 10 - bi_valid < 9) {
+ send_bits(STATIC_TREES<<1, 3);
+ send_code(END_BLOCK, StaticTree.static_ltree);
+ bi_flush();
+ }
+ last_eob_len = 7;
+ }
+
+
+ // Save the match info and tally the frequency counts. Return true if
+ // the current block must be flushed.
+ internal bool _tr_tally (int dist, // distance of matched string
+ int lc // match length-MIN_MATCH or unmatched char (if dist==0)
+ ){
+
+ pending_buf[d_buf+last_lit*2] = (byte)(dist>>8);
+ pending_buf[d_buf+last_lit*2+1] = (byte)dist;
+
+ pending_buf[l_buf+last_lit] = (byte)lc; last_lit++;
+
+ if (dist == 0) {
+ // lc is the unmatched char
+ dyn_ltree[lc*2]++;
+ }
+ else {
+ matches++;
+ // Here, lc is the match length - MIN_MATCH
+ dist--; // dist = match distance - 1
+ dyn_ltree[(Tree._length_code[lc]+LITERALS+1)*2]++;
+ dyn_dtree[Tree.d_code(dist)*2]++;
+ }
+
+ if ((last_lit & 0x1fff) == 0 && level > 2) {
+ // Compute an upper bound for the compressed length
+ int out_length = last_lit*8;
+ int in_length = strstart - block_start;
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (int)((int)dyn_dtree[dcode*2] *
+ (5L+Tree.extra_dbits[dcode]));
+ }
+ out_length >>= 3;
+ if ((matches < (last_lit/2)) && out_length < in_length/2) return true;
+ }
+
+ return (last_lit == lit_bufsize-1);
+ // We avoid equality with lit_bufsize because of wraparound at 64K
+ // on 16 bit machines and because stored blocks are restricted to
+ // 64K-1 bytes.
+ }
+
+ // Send the block data compressed using the given Huffman trees
+ internal void compress_block(short[] ltree, short[] dtree){
+ int dist; // distance of matched string
+ int lc; // match length or unmatched char (if dist == 0)
+ int lx = 0; // running index in l_buf
+ int code; // the code to send
+ int extra; // number of extra bits to send
+
+ if (last_lit != 0){
+ do{
+ dist=((pending_buf[d_buf+lx*2]<<8)&0xff00)|
+ (pending_buf[d_buf+lx*2+1]&0xff);
+ lc=(pending_buf[l_buf+lx])&0xff; lx++;
+
+ if(dist == 0){
+ send_code(lc, ltree); // send a literal byte
+ }
+ else{
+ // Here, lc is the match length - MIN_MATCH
+ code = Tree._length_code[lc];
+
+ send_code(code+LITERALS+1, ltree); // send the length code
+ extra = Tree.extra_lbits[code];
+ if(extra != 0){
+ lc -= Tree.base_length[code];
+ send_bits(lc, extra); // send the extra length bits
+ }
+ dist--; // dist is now the match distance - 1
+ code = Tree.d_code(dist);
+
+ send_code(code, dtree); // send the distance code
+ extra = Tree.extra_dbits[code];
+ if (extra != 0) {
+ dist -= Tree.base_dist[code];
+ send_bits(dist, extra); // send the extra distance bits
+ }
+ } // literal or match pair ?
+
+ // Check that the overlay between pending_buf and d_buf+l_buf is ok:
+ }
+ while (lx < last_lit);
+ }
+
+ send_code(END_BLOCK, ltree);
+ last_eob_len = ltree[END_BLOCK*2+1];
+ }
+
+ // Set the data type to ASCII or BINARY, using a crude approximation:
+ // binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ // IN assertion: the fields freq of dyn_ltree are set and the total of all
+ // frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ internal void set_data_type(){
+ int n = 0;
+ int ascii_freq = 0;
+ int bin_freq = 0;
+ while(n<7){ bin_freq += dyn_ltree[n*2]; n++;}
+ while(n<128){ ascii_freq += dyn_ltree[n*2]; n++;}
+ while(n (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
+ }
+
+ // Flush the bit buffer, keeping at most 7 bits in it.
+ internal void bi_flush(){
+ if (bi_valid == 16) {
+ pending_buf[pending++]=(byte)(bi_buf/*&0xff*/);
+ pending_buf[pending++]=(byte)(bi_buf>>8);
+ bi_buf=0;
+ bi_valid=0;
+ }
+ else if (bi_valid >= 8) {
+ pending_buf[pending++]=(byte)(bi_buf);
+ bi_buf>>=8;
+ bi_buf &= 0x00ff;
+ bi_valid-=8;
+ }
+ }
+
+ // Flush the bit buffer and align the output on a byte boundary
+ internal void bi_windup(){
+ if (bi_valid > 8) {
+ pending_buf[pending++]=(byte)(bi_buf);
+ pending_buf[pending++]=(byte)(bi_buf>>8);
+ } else if (bi_valid > 0) {
+ pending_buf[pending++]=(byte)(bi_buf);
+ }
+ bi_buf = 0;
+ bi_valid = 0;
+ }
+
+ // Copy a stored block, storing first the length and its
+ // one's complement if requested.
+ internal void copy_block(int buf, // the input data
+ int len, // its length
+ bool header // true if block header must be written
+ ){
+ //int index=0;
+ bi_windup(); // align on byte boundary
+ last_eob_len = 8; // enough lookahead for inflate
+
+ if (header) {
+ put_short((short)len);
+ put_short((short)~len);
+ }
+
+ // while(len--!=0) {
+ // put_byte(window[buf+index]);
+ // index++;
+ // }
+ put_byte(window, buf, len);
+ }
+
+ internal void flush_block_only(bool eof){
+ _tr_flush_block(block_start>=0 ? block_start : -1,
+ strstart-block_start,
+ eof);
+ block_start=strstart;
+ strm.flush_pending();
+ }
+
+ // Copy without compression as much as possible from the input stream, return
+ // the current block state.
+ // This function does not insert new strings in the dictionary since
+ // uncompressible data is probably not useful. This function is used
+ // only for the level=0 compression option.
+ // NOTE: this function should be optimized to avoid extra copying from
+ // window to pending_buf.
+ internal int deflate_stored(int flush){
+ // Stored blocks are limited to 0xffff bytes, pending_buf is limited
+ // to pending_buf_size, and each stored block has a 5 byte header:
+
+ int max_block_size = 0xffff;
+ int max_start;
+
+ if(max_block_size > pending_buf_size - 5) {
+ max_block_size = pending_buf_size - 5;
+ }
+
+ // Copy as much as possible from input to output:
+ while(true){
+ // Fill the window as much as possible:
+ if(lookahead<=1){
+ fill_window();
+ if(lookahead==0 && flush==Z_NO_FLUSH) return NeedMore;
+ if(lookahead==0) break; // flush the current block
+ }
+
+ strstart+=lookahead;
+ lookahead=0;
+
+ // Emit a stored block if pending_buf will be full:
+ max_start=block_start+max_block_size;
+ if(strstart==0|| strstart>=max_start) {
+ // strstart == 0 is possible when wraparound on 16-bit machine
+ lookahead = (int)(strstart-max_start);
+ strstart = (int)max_start;
+
+ flush_block_only(false);
+ if(strm.avail_out==0) return NeedMore;
+
+ }
+
+ // Flush if we may have to slide, otherwise block_start may become
+ // negative and the data will be gone:
+ if(strstart-block_start >= w_size-MIN_LOOKAHEAD) {
+ flush_block_only(false);
+ if(strm.avail_out==0) return NeedMore;
+ }
+ }
+
+ flush_block_only(flush == Z_FINISH);
+ if(strm.avail_out==0)
+ return (flush == Z_FINISH) ? FinishStarted : NeedMore;
+
+ return flush == Z_FINISH ? FinishDone : BlockDone;
+ }
+
+ // Send a stored block
+ internal void _tr_stored_block(int buf, // input block
+ int stored_len, // length of input block
+ bool eof // true if this is the last block for a file
+ ){
+ send_bits((STORED_BLOCK<<1)+(eof?1:0), 3); // send block type
+ copy_block(buf, stored_len, true); // with header
+ }
+
+ // Determine the best encoding for the current block: dynamic trees, static
+ // trees or store, and output the encoded block to the zip file.
+ internal void _tr_flush_block(int buf, // input block, or NULL if too old
+ int stored_len, // length of input block
+ bool eof // true if this is the last block for a file
+ ) {
+ int opt_lenb, static_lenb;// opt_len and static_len in bytes
+ int max_blindex = 0; // index of last bit length code of non zero freq
+
+ // Build the Huffman trees unless a stored block is forced
+ if(level > 0) {
+ // Check if the file is ascii or binary
+ if(data_type == Z_UNKNOWN) set_data_type();
+
+ // Construct the literal and distance trees
+ l_desc.build_tree(this);
+
+ d_desc.build_tree(this);
+
+ // At this point, opt_len and static_len are the total bit lengths of
+ // the compressed block data, excluding the tree representations.
+
+ // Build the bit length tree for the above two trees, and get the index
+ // in bl_order of the last bit length code to send.
+ max_blindex=build_bl_tree();
+
+ // Determine the best encoding. Compute first the block length in bytes
+ opt_lenb=(opt_len+3+7)>>3;
+ static_lenb=(static_len+3+7)>>3;
+
+ if(static_lenb<=opt_lenb) opt_lenb=static_lenb;
+ }
+ else {
+ opt_lenb=static_lenb=stored_len+5; // force a stored block
+ }
+
+ if(stored_len+4<=opt_lenb && buf != -1){
+ // 4: two words for the lengths
+ // The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ // Otherwise we can't have processed more than WSIZE input bytes since
+ // the last block flush, because compression would have been
+ // successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ // transform a block into a stored block.
+ _tr_stored_block(buf, stored_len, eof);
+ }
+ else if(static_lenb == opt_lenb){
+ send_bits((STATIC_TREES<<1)+(eof?1:0), 3);
+ compress_block(StaticTree.static_ltree, StaticTree.static_dtree);
+ }
+ else{
+ send_bits((DYN_TREES<<1)+(eof?1:0), 3);
+ send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1);
+ compress_block(dyn_ltree, dyn_dtree);
+ }
+
+ // The above check is made mod 2^32, for files larger than 512 MB
+ // and uLong implemented on 32 bits.
+
+ init_block();
+
+ if(eof){
+ bi_windup();
+ }
+ }
+
+ // Fill the window when the lookahead becomes insufficient.
+ // Updates strstart and lookahead.
+ //
+ // IN assertion: lookahead < MIN_LOOKAHEAD
+ // OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ // At least one byte has been read, or avail_in == 0; reads are
+ // performed for at least two bytes (required for the zip translate_eol
+ // option -- not supported here).
+ internal void fill_window(){
+ int n, m;
+ int p;
+ int more; // Amount of free space at the end of the window.
+
+ do{
+ more = (window_size-lookahead-strstart);
+
+ // Deal with !@#$% 64K limit:
+ if(more==0 && strstart==0 && lookahead==0){
+ more = w_size;
+ }
+ else if(more==-1) {
+ // Very unlikely, but possible on 16 bit machine if strstart == 0
+ // and lookahead == 1 (input done one byte at time)
+ more--;
+
+ // If the window is almost full and there is insufficient lookahead,
+ // move the upper half to the lower one to make room in the upper half.
+ }
+ else if(strstart >= w_size+ w_size-MIN_LOOKAHEAD) {
+ System.Array.Copy(window, w_size, window, 0, w_size);
+ match_start-=w_size;
+ strstart-=w_size; // we now have strstart >= MAX_DIST
+ block_start-=w_size;
+
+ // Slide the hash table (could be avoided with 32 bit values
+ // at the expense of memory usage). We slide even when level == 0
+ // to keep the hash table consistent if we switch back to level > 0
+ // later. (Using level 0 permanently is not an optimal usage of
+ // zlib, so we don't care about this pathological case.)
+
+ n = hash_size;
+ p=n;
+ do {
+ m = (head[--p]&0xffff);
+ head[p]=(short)(m>=w_size ? (m-w_size) : 0);
+ }
+ while (--n != 0);
+
+ n = w_size;
+ p = n;
+ do {
+ m = (prev[--p]&0xffff);
+ prev[p] = (short)(m >= w_size ? (m-w_size) : 0);
+ // If n is not on any hash chain, prev[n] is garbage but
+ // its value will never be used.
+ }
+ while (--n!=0);
+ more += w_size;
+ }
+
+ if (strm.avail_in == 0) return;
+
+ // If there was no sliding:
+ // strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ // more == window_size - lookahead - strstart
+ // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ // => more >= window_size - 2*WSIZE + 2
+ // In the BIG_MEM or MMAP case (not yet supported),
+ // window_size == input_size + MIN_LOOKAHEAD &&
+ // strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ // Otherwise, window_size == 2*WSIZE so more >= 2.
+ // If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+
+ n = strm.read_buf(window, strstart + lookahead, more);
+ lookahead += n;
+
+ // Initialize the hash value now that we have some input:
+ if(lookahead >= MIN_MATCH) {
+ ins_h = window[strstart]&0xff;
+ ins_h=(((ins_h)<= MIN_MATCH){
+ ins_h=(((ins_h)<=MIN_MATCH){
+ // check_match(strstart, match_start, match_length);
+
+ bflush=_tr_tally(strstart-match_start, match_length-MIN_MATCH);
+
+ lookahead -= match_length;
+
+ // Insert new strings in the hash table only if the match length
+ // is not too large. This saves time but degrades compression.
+ if(match_length <= max_lazy_match &&
+ lookahead >= MIN_MATCH) {
+ match_length--; // string at strstart already in hash table
+ do{
+ strstart++;
+
+ ins_h=((ins_h<= MIN_MATCH) {
+ ins_h=(((ins_h)< 4096))) {
+
+ // If prev_match is also MIN_MATCH, match_start is garbage
+ // but we will ignore the current match anyway.
+ match_length = MIN_MATCH-1;
+ }
+ }
+
+ // If there was a match at the previous step and the current
+ // match is not better, output the previous match:
+ if(prev_length >= MIN_MATCH && match_length <= prev_length) {
+ int max_insert = strstart + lookahead - MIN_MATCH;
+ // Do not insert strings in hash table beyond this.
+
+ // check_match(strstart-1, prev_match, prev_length);
+
+ bflush=_tr_tally(strstart-1-prev_match, prev_length - MIN_MATCH);
+
+ // Insert in hash table all strings up to the end of the match.
+ // strstart-1 and strstart are already inserted. If there is not
+ // enough lookahead, the last two strings are not inserted in
+ // the hash table.
+ lookahead -= prev_length-1;
+ prev_length -= 2;
+ do{
+ if(++strstart <= max_insert) {
+ ins_h=(((ins_h)<(w_size-MIN_LOOKAHEAD) ?
+ strstart-(w_size-MIN_LOOKAHEAD) : 0;
+ int nice_match=this.nice_match;
+
+ // Stop when cur_match becomes <= limit. To simplify the code,
+ // we prevent matches with the string of window index 0.
+
+ int wmask = w_mask;
+
+ int strend = strstart + MAX_MATCH;
+ byte scan_end1 = window[scan+best_len-1];
+ byte scan_end = window[scan+best_len];
+
+ // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ // It is easy to get rid of this optimization if necessary.
+
+ // Do not waste too much time if we already have a good match:
+ if (prev_length >= good_match) {
+ chain_length >>= 2;
+ }
+
+ // Do not look for matches beyond the end of the input. This is necessary
+ // to make deflate deterministic.
+ if (nice_match > lookahead) nice_match = lookahead;
+
+ do {
+ match = cur_match;
+
+ // Skip to next match if the match length cannot increase
+ // or if the match length is less than 2:
+ if (window[match+best_len] != scan_end ||
+ window[match+best_len-1] != scan_end1 ||
+ window[match] != window[scan] ||
+ window[++match] != window[scan+1]) continue;
+
+ // The check at best_len-1 can be removed because it will be made
+ // again later. (This heuristic is not always a win.)
+ // It is not necessary to compare scan[2] and match[2] since they
+ // are always equal when the other bytes match, given that
+ // the hash keys are equal and that HASH_BITS >= 8.
+ scan += 2; match++;
+
+ // We check for insufficient lookahead only every 8th comparison;
+ // the 256th check will be made at strstart+258.
+ do {
+ } while (window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ window[++scan] == window[++match] &&
+ scan < strend);
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+ if(len>best_len) {
+ match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+ scan_end1 = window[scan+best_len-1];
+ scan_end = window[scan+best_len];
+ }
+
+ } while ((cur_match = (prev[cur_match & wmask]&0xffff)) > limit
+ && --chain_length != 0);
+
+ if (best_len <= lookahead) return best_len;
+ return lookahead;
+ }
+
+ internal int deflateInit(ZStream strm, int level, int bits){
+ return deflateInit2(strm, level, Z_DEFLATED, bits, DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY);
+ }
+ internal int deflateInit(ZStream strm, int level){
+ return deflateInit(strm, level, MAX_WBITS);
+ }
+ internal int deflateInit2(ZStream strm, int level, int method, int windowBits,
+ int memLevel, int strategy){
+ int noheader = 0;
+ // byte[] my_version=ZLIB_VERSION;
+
+ //
+ // if (version == null || version[0] != my_version[0]
+ // || stream_size != sizeof(z_stream)) {
+ // return Z_VERSION_ERROR;
+ // }
+
+ strm.msg = null;
+
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+
+ if (windowBits < 0) { // undocumented feature: suppress zlib header
+ noheader = 1;
+ windowBits = -windowBits;
+ }
+
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL ||
+ method != Z_DEFLATED ||
+ windowBits < 9 || windowBits > 15 || level < 0 || level > 9 ||
+ strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+ return Z_STREAM_ERROR;
+ }
+
+ strm.dstate = (Deflate)this;
+
+ this.noheader = noheader;
+ w_bits = windowBits;
+ w_size = 1 << w_bits;
+ w_mask = w_size - 1;
+
+ hash_bits = memLevel + 7;
+ hash_size = 1 << hash_bits;
+ hash_mask = hash_size - 1;
+ hash_shift = ((hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+ window = new byte[w_size*2];
+ prev = new short[w_size];
+ head = new short[hash_size];
+
+ lit_bufsize = 1 << (memLevel + 6); // 16K elements by default
+
+ // We overlay pending_buf and d_buf+l_buf. This works since the average
+ // output size for (length,distance) codes is <= 24 bits.
+ pending_buf = new byte[lit_bufsize*4];
+ pending_buf_size = lit_bufsize*4;
+
+ d_buf = lit_bufsize/2;
+ l_buf = (1+2)*lit_bufsize;
+
+ this.level = level;
+
+ //System.out.println("level="+level);
+
+ this.strategy = strategy;
+ this.method = (byte)method;
+
+ return deflateReset(strm);
+ }
+
+ internal int deflateReset(ZStream strm){
+ strm.total_in = strm.total_out = 0;
+ strm.msg = null; //
+ strm.data_type = Z_UNKNOWN;
+
+ pending = 0;
+ pending_out = 0;
+
+ if(noheader < 0) {
+ noheader = 0; // was set to -1 by deflate(..., Z_FINISH);
+ }
+ status = (noheader!=0) ? BUSY_STATE : INIT_STATE;
+ strm.adler=strm._adler.adler32(0, null, 0, 0);
+
+ last_flush = Z_NO_FLUSH;
+
+ tr_init();
+ lm_init();
+ return Z_OK;
+ }
+
+ internal int deflateEnd(){
+ if(status!=INIT_STATE && status!=BUSY_STATE && status!=FINISH_STATE){
+ return Z_STREAM_ERROR;
+ }
+ // Deallocate in reverse order of allocations:
+ pending_buf=null;
+ head=null;
+ prev=null;
+ window=null;
+ // free
+ // dstate=null;
+ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+ }
+
+ internal int deflateParams(ZStream strm, int _level, int _strategy){
+ int err=Z_OK;
+
+ if(_level == Z_DEFAULT_COMPRESSION){
+ _level = 6;
+ }
+ if(_level < 0 || _level > 9 ||
+ _strategy < 0 || _strategy > Z_HUFFMAN_ONLY) {
+ return Z_STREAM_ERROR;
+ }
+
+ if(config_table[level].func!=config_table[_level].func &&
+ strm.total_in != 0) {
+ // Flush the last buffer:
+ err = strm.deflate(Z_PARTIAL_FLUSH);
+ }
+
+ if(level != _level) {
+ level = _level;
+ max_lazy_match = config_table[level].max_lazy;
+ good_match = config_table[level].good_length;
+ nice_match = config_table[level].nice_length;
+ max_chain_length = config_table[level].max_chain;
+ }
+ strategy = _strategy;
+ return err;
+ }
+
+ internal int deflateSetDictionary (ZStream strm, byte[] dictionary, int dictLength){
+ int length = dictLength;
+ int index=0;
+
+ if(dictionary == null || status != INIT_STATE)
+ return Z_STREAM_ERROR;
+
+ strm.adler=strm._adler.adler32(strm.adler, dictionary, 0, dictLength);
+
+ if(length < MIN_MATCH) return Z_OK;
+ if(length > w_size-MIN_LOOKAHEAD){
+ length = w_size-MIN_LOOKAHEAD;
+ index=dictLength-length; // use the tail of the dictionary
+ }
+ System.Array.Copy(dictionary, index, window, 0, length);
+ strstart = length;
+ block_start = length;
+
+ // Insert all strings in the hash table (except for the last two bytes).
+ // s->lookahead stays null, so s->ins_h will be recomputed at the next
+ // call of fill_window.
+
+ ins_h = window[0]&0xff;
+ ins_h=(((ins_h)<Z_FINISH || flush<0){
+ return Z_STREAM_ERROR;
+ }
+
+ if(strm.next_out == null ||
+ (strm.next_in == null && strm.avail_in != 0) ||
+ (status == FINISH_STATE && flush != Z_FINISH)) {
+ strm.msg=z_errmsg[Z_NEED_DICT-(Z_STREAM_ERROR)];
+ return Z_STREAM_ERROR;
+ }
+ if(strm.avail_out == 0){
+ strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)];
+ return Z_BUF_ERROR;
+ }
+
+ this.strm = strm; // just in case
+ old_flush = last_flush;
+ last_flush = flush;
+
+ // Write the zlib header
+ if(status == INIT_STATE) {
+ int header = (Z_DEFLATED+((w_bits-8)<<4))<<8;
+ int level_flags=((level-1)&0xff)>>1;
+
+ if(level_flags>3) level_flags=3;
+ header |= (level_flags<<6);
+ if(strstart!=0) header |= PRESET_DICT;
+ header+=31-(header % 31);
+
+ status=BUSY_STATE;
+ putShortMSB(header);
+
+
+ // Save the adler32 of the preset dictionary:
+ if(strstart!=0){
+ putShortMSB((int)(strm.adler>>16));
+ putShortMSB((int)(strm.adler&0xffff));
+ }
+ strm.adler=strm._adler.adler32(0, null, 0, 0);
+ }
+
+ // Flush as much pending output as possible
+ if(pending != 0) {
+ strm.flush_pending();
+ if(strm.avail_out == 0) {
+ //System.out.println(" avail_out==0");
+ // Since avail_out is 0, deflate will be called again with
+ // more output space, but possibly with both pending and
+ // avail_in equal to zero. There won't be anything to do,
+ // but this is not an error situation so make sure we
+ // return OK instead of BUF_ERROR at next call of deflate:
+ last_flush = -1;
+ return Z_OK;
+ }
+
+ // Make sure there is something to do and avoid duplicate consecutive
+ // flushes. For repeated and useless calls with Z_FINISH, we keep
+ // returning Z_STREAM_END instead of Z_BUFF_ERROR.
+ }
+ else if(strm.avail_in==0 && flush <= old_flush &&
+ flush != Z_FINISH) {
+ strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)];
+ return Z_BUF_ERROR;
+ }
+
+ // User must not provide more input after the first FINISH:
+ if(status == FINISH_STATE && strm.avail_in != 0) {
+ strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)];
+ return Z_BUF_ERROR;
+ }
+
+ // Start a new block or continue the current one.
+ if(strm.avail_in!=0 || lookahead!=0 ||
+ (flush != Z_NO_FLUSH && status != FINISH_STATE)) {
+ int bstate=-1;
+ switch(config_table[level].func){
+ case STORED:
+ bstate = deflate_stored(flush);
+ break;
+ case FAST:
+ bstate = deflate_fast(flush);
+ break;
+ case SLOW:
+ bstate = deflate_slow(flush);
+ break;
+ default:
+ break;
+ }
+
+ if (bstate==FinishStarted || bstate==FinishDone) {
+ status = FINISH_STATE;
+ }
+ if (bstate==NeedMore || bstate==FinishStarted) {
+ if(strm.avail_out == 0) {
+ last_flush = -1; // avoid BUF_ERROR next call, see above
+ }
+ return Z_OK;
+ // If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ // of deflate should use the same flush parameter to make sure
+ // that the flush is complete. So we don't have to output an
+ // empty block here, this will be done at next call. This also
+ // ensures that for a very small output buffer, we emit at most
+ // one empty block.
+ }
+
+ if (bstate==BlockDone) {
+ if(flush == Z_PARTIAL_FLUSH) {
+ _tr_align();
+ }
+ else { // FULL_FLUSH or SYNC_FLUSH
+ _tr_stored_block(0, 0, false);
+ // For a full flush, this empty block will be recognized
+ // as a special marker by inflate_sync().
+ if(flush == Z_FULL_FLUSH) {
+ //state.head[s.hash_size-1]=0;
+ for(int i=0; i>16));
+ putShortMSB((int)(strm.adler&0xffff));
+ strm.flush_pending();
+
+ // If avail_out is zero, the application will call deflate again
+ // to flush the rest.
+ noheader = -1; // write the trailer only once!
+ return pending != 0 ? Z_OK : Z_STREAM_END;
+ }
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/util/zlib/InfBlocks.cs b/bc-sharp-crypto/src/util/zlib/InfBlocks.cs
new file mode 100644
index 0000000000000000000000000000000000000000..479d9b5c91191dd173a21578fdaa9b956ec46c69
--- /dev/null
+++ b/bc-sharp-crypto/src/util/zlib/InfBlocks.cs
@@ -0,0 +1,618 @@
+using System;
+/*
+ * $Id: InfBlocks.cs,v 1.2 2008-05-10 09:35:40 bouncy Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+ internal sealed class InfBlocks{
+ private const int MANY=1440;
+
+ // And'ing with mask[n] masks the lower n bits
+ private static readonly int[] inflate_mask = {
+ 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
+ 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff,
+ 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff,
+ 0x00007fff, 0x0000ffff
+ };
+
+ // Table for deflate from PKZIP's appnote.txt.
+ static readonly int[] border = { // Order of the bit length code lengths
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
+ };
+
+ private const int Z_OK=0;
+ private const int Z_STREAM_END=1;
+ private const int Z_NEED_DICT=2;
+ private const int Z_ERRNO=-1;
+ private const int Z_STREAM_ERROR=-2;
+ private const int Z_DATA_ERROR=-3;
+ private const int Z_MEM_ERROR=-4;
+ private const int Z_BUF_ERROR=-5;
+ private const int Z_VERSION_ERROR=-6;
+
+ private const int TYPE=0; // get type bits (3, including end bit)
+ private const int LENS=1; // get lengths for stored
+ private const int STORED=2;// processing stored block
+ private const int TABLE=3; // get table lengths
+ private const int BTREE=4; // get bit lengths tree for a dynamic block
+ private const int DTREE=5; // get length, distance trees for a dynamic block
+ private const int CODES=6; // processing fixed or dynamic block
+ private const int DRY=7; // output remaining window bytes
+ private const int DONE=8; // finished last block, done
+ private const int BAD=9; // ot a data error--stuck here
+
+ internal int mode; // current inflate_block mode
+
+ internal int left; // if STORED, bytes left to copy
+
+ internal int table; // table lengths (14 bits)
+ internal int index; // index into blens (or border)
+ internal int[] blens; // bit lengths of codes
+ internal int[] bb=new int[1]; // bit length tree depth
+ internal int[] tb=new int[1]; // bit length decoding tree
+
+ internal InfCodes codes=new InfCodes(); // if CODES, current state
+
+ int last; // true if this block is the last block
+
+ // mode independent information
+ internal int bitk; // bits in bit buffer
+ internal int bitb; // bit buffer
+ internal int[] hufts; // single malloc for tree space
+ internal byte[] window; // sliding window
+ internal int end; // one byte after sliding window
+ internal int read; // window read pointer
+ internal int write; // window write pointer
+ internal Object checkfn; // check function
+ internal long check; // check on output
+
+ internal InfTree inftree=new InfTree();
+
+ internal InfBlocks(ZStream z, Object checkfn, int w){
+ hufts=new int[MANY*3];
+ window=new byte[w];
+ end=w;
+ this.checkfn = checkfn;
+ mode = TYPE;
+ reset(z, null);
+ }
+
+ internal void reset(ZStream z, long[] c){
+ if(c!=null) c[0]=check;
+ if(mode==BTREE || mode==DTREE){
+ }
+ if(mode==CODES){
+ codes.free(z);
+ }
+ mode=TYPE;
+ bitk=0;
+ bitb=0;
+ read=write=0;
+
+ if(checkfn != null)
+ z.adler=check=z._adler.adler32(0L, null, 0, 0);
+ }
+
+ internal int proc(ZStream z, int r){
+ int t; // temporary storage
+ int b; // bit buffer
+ int k; // bits in bit buffer
+ int p; // input data pointer
+ int n; // bytes available there
+ int q; // output window write pointer
+ int m; { // bytes to end of window or read pointer
+
+ // copy input/output information to locals (UPDATE macro restores)
+ p=z.next_in_index;n=z.avail_in;b=bitb;k=bitk;} {
+ q=write;m=(int)(q> 1){
+ case 0: { // stored
+ b>>=(3);k-=(3);}
+ t = k & 7; { // go to byte boundary
+
+ b>>=(t);k-=(t);}
+ mode = LENS; // get length of stored block
+ break;
+ case 1: { // fixed
+ int[] bl=new int[1];
+ int[] bd=new int[1];
+ int[][] tl=new int[1][];
+ int[][] td=new int[1][];
+
+ InfTree.inflate_trees_fixed(bl, bd, tl, td, z);
+ codes.init(bl[0], bd[0], tl[0], 0, td[0], 0, z);
+ } {
+
+ b>>=(3);k-=(3);}
+
+ mode = CODES;
+ break;
+ case 2: { // dynamic
+
+ b>>=(3);k-=(3);}
+
+ mode = TABLE;
+ break;
+ case 3: { // illegal
+
+ b>>=(3);k-=(3);}
+ mode = BAD;
+ z.msg = "invalid block type";
+ r = Z_DATA_ERROR;
+
+ bitb=b; bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ }
+ break;
+ case LENS:
+
+ while(k<(32)){
+ if(n!=0){
+ r=Z_OK;
+ }
+ else{
+ bitb=b; bitk=k;
+ z.avail_in=n;
+ z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ };
+ n--;
+ b|=(z.next_in[p++]&0xff)<> 16) & 0xffff) != (b & 0xffff)){
+ mode = BAD;
+ z.msg = "invalid stored block lengths";
+ r = Z_DATA_ERROR;
+
+ bitb=b; bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ }
+ left = (b & 0xffff);
+ b = k = 0; // dump bits
+ mode = left!=0 ? STORED : (last!=0 ? DRY : TYPE);
+ break;
+ case STORED:
+ if (n == 0){
+ bitb=b; bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ }
+
+ if(m==0){
+ if(q==end&&read!=0){
+ q=0; m=(int)(qn) t = n;
+ if(t>m) t = m;
+ System.Array.Copy(z.next_in, p, window, q, t);
+ p += t; n -= t;
+ q += t; m -= t;
+ if ((left -= t) != 0)
+ break;
+ mode = last!=0 ? DRY : TYPE;
+ break;
+ case TABLE:
+
+ while(k<(14)){
+ if(n!=0){
+ r=Z_OK;
+ }
+ else{
+ bitb=b; bitk=k;
+ z.avail_in=n;
+ z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ };
+ n--;
+ b|=(z.next_in[p++]&0xff)< 29 || ((t >> 5) & 0x1f) > 29) {
+ mode = BAD;
+ z.msg = "too many length or distance symbols";
+ r = Z_DATA_ERROR;
+
+ bitb=b; bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ }
+ t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+ if(blens==null || blens.Length>=(14);k-=(14);}
+
+ index = 0;
+ mode = BTREE;
+ goto case BTREE;
+ case BTREE:
+ while (index < 4 + (table >> 10)){
+ while(k<(3)){
+ if(n!=0){
+ r=Z_OK;
+ }
+ else{
+ bitb=b; bitk=k;
+ z.avail_in=n;
+ z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ };
+ n--;
+ b|=(z.next_in[p++]&0xff)<>=(3);k-=(3);}
+ }
+
+ while(index < 19){
+ blens[border[index++]] = 0;
+ }
+
+ bb[0] = 7;
+ t = inftree.inflate_trees_bits(blens, bb, tb, hufts, z);
+ if (t != Z_OK){
+ r = t;
+ if (r == Z_DATA_ERROR){
+ blens=null;
+ mode = BAD;
+ }
+
+ bitb=b; bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ }
+
+ index = 0;
+ mode = DTREE;
+ goto case DTREE;
+ case DTREE:
+ while (true){
+ t = table;
+ if(!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))){
+ break;
+ }
+
+ int i, j, c;
+
+ t = bb[0];
+
+ while(k<(t)){
+ if(n!=0){
+ r=Z_OK;
+ }
+ else{
+ bitb=b; bitk=k;
+ z.avail_in=n;
+ z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ };
+ n--;
+ b|=(z.next_in[p++]&0xff)<>=(t);k-=(t);
+ blens[index++] = c;
+ }
+ else { // c == 16..18
+ i = c == 18 ? 7 : c - 14;
+ j = c == 18 ? 11 : 3;
+
+ while(k<(t+i)){
+ if(n!=0){
+ r=Z_OK;
+ }
+ else{
+ bitb=b; bitk=k;
+ z.avail_in=n;
+ z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ };
+ n--;
+ b|=(z.next_in[p++]&0xff)<>=(t);k-=(t);
+
+ j += (b & inflate_mask[i]);
+
+ b>>=(i);k-=(i);
+
+ i = index;
+ t = table;
+ if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+ (c == 16 && i < 1)){
+ blens=null;
+ mode = BAD;
+ z.msg = "invalid bit length repeat";
+ r = Z_DATA_ERROR;
+
+ bitb=b; bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ }
+
+ c = c == 16 ? blens[i-1] : 0;
+ do{
+ blens[i++] = c;
+ }
+ while (--j!=0);
+ index = i;
+ }
+ }
+
+ tb[0]=-1; {
+ int[] bl=new int[1];
+ int[] bd=new int[1];
+ int[] tl=new int[1];
+ int[] td=new int[1];
+ bl[0] = 9; // must be <= 9 for lookahead assumptions
+ bd[0] = 6; // must be <= 9 for lookahead assumptions
+
+ t = table;
+ t = inftree.inflate_trees_dynamic(257 + (t & 0x1f),
+ 1 + ((t >> 5) & 0x1f),
+ blens, bl, bd, tl, td, hufts, z);
+
+ if (t != Z_OK){
+ if (t == Z_DATA_ERROR){
+ blens=null;
+ mode = BAD;
+ }
+ r = t;
+
+ bitb=b; bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+ return inflate_flush(z,r);
+ }
+ codes.init(bl[0], bd[0], hufts, tl[0], hufts, td[0], z);
+ }
+ mode = CODES;
+ goto case CODES;
+ case CODES:
+ bitb=b; bitk=k;
+ z.avail_in=n; z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ write=q;
+
+ if ((r = codes.proc(this, z, r)) != Z_STREAM_END){
+ return inflate_flush(z, r);
+ }
+ r = Z_OK;
+ codes.free(z);
+
+ p=z.next_in_index; n=z.avail_in;b=bitb;k=bitk;
+ q=write;m=(int)(q z.avail_out) n = z.avail_out;
+ if (n!=0 && r == Z_BUF_ERROR) r = Z_OK;
+
+ // update counters
+ z.avail_out -= n;
+ z.total_out += n;
+
+ // update check information
+ if(checkfn != null)
+ z.adler=check=z._adler.adler32(check, window, q, n);
+
+ // copy as far as end of window
+ System.Array.Copy(window, q, z.next_out, p, n);
+ p += n;
+ q += n;
+
+ // see if more to copy at beginning of window
+ if (q == end){
+ // wrap pointers
+ q = 0;
+ if (write == end)
+ write = 0;
+
+ // compute bytes to copy
+ n = write - q;
+ if (n > z.avail_out) n = z.avail_out;
+ if (n!=0 && r == Z_BUF_ERROR) r = Z_OK;
+
+ // update counters
+ z.avail_out -= n;
+ z.total_out += n;
+
+ // update check information
+ if(checkfn != null)
+ z.adler=check=z._adler.adler32(check, window, q, n);
+
+ // copy
+ System.Array.Copy(window, q, z.next_out, p, n);
+ p += n;
+ q += n;
+ }
+
+ // update pointers
+ z.next_out_index = p;
+ read = q;
+
+ // done
+ return r;
+ }
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/util/zlib/InfCodes.cs b/bc-sharp-crypto/src/util/zlib/InfCodes.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6fcafe4583fe2ee3e4a8ada7ca380d13468fe4f6
--- /dev/null
+++ b/bc-sharp-crypto/src/util/zlib/InfCodes.cs
@@ -0,0 +1,611 @@
+using System;
+/*
+ * $Id: InfCodes.cs,v 1.2 2008-05-10 09:35:40 bouncy Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+ internal sealed class InfCodes{
+
+ private static readonly int[] inflate_mask = {
+ 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
+ 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff,
+ 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff,
+ 0x00007fff, 0x0000ffff
+ };
+
+ private const int Z_OK=0;
+ private const int Z_STREAM_END=1;
+ private const int Z_NEED_DICT=2;
+ private const int Z_ERRNO=-1;
+ private const int Z_STREAM_ERROR=-2;
+ private const int Z_DATA_ERROR=-3;
+ private const int Z_MEM_ERROR=-4;
+ private const int Z_BUF_ERROR=-5;
+ private const int Z_VERSION_ERROR=-6;
+
+ // waiting for "i:"=input,
+ // "o:"=output,
+ // "x:"=nothing
+ private const int START=0; // x: set up for LEN
+ private const int LEN=1; // i: get length/literal/eob next
+ private const int LENEXT=2; // i: getting length extra (have base)
+ private const int DIST=3; // i: get distance next
+ private const int DISTEXT=4;// i: getting distance extra
+ private const int COPY=5; // o: copying bytes in window, waiting for space
+ private const int LIT=6; // o: got literal, waiting for output space
+ private const int WASH=7; // o: got eob, possibly still output waiting
+ private const int END=8; // x: got eob and all data flushed
+ private const int BADCODE=9;// x: got error
+
+ int mode; // current inflate_codes mode
+
+ // mode dependent information
+ int len;
+
+ int[] tree; // pointer into tree
+ int tree_index=0;
+ int need; // bits needed
+
+ int lit;
+
+ // if EXT or COPY, where and how much
+ int get; // bits to get for extra
+ int dist; // distance back to copy from
+
+ byte lbits; // ltree bits decoded per branch
+ byte dbits; // dtree bits decoder per branch
+ int[] ltree; // literal/length/eob tree
+ int ltree_index; // literal/length/eob tree
+ int[] dtree; // distance tree
+ int dtree_index; // distance tree
+
+ internal InfCodes(){
+ }
+ internal void init(int bl, int bd,
+ int[] tl, int tl_index,
+ int[] td, int td_index, ZStream z){
+ mode=START;
+ lbits=(byte)bl;
+ dbits=(byte)bd;
+ ltree=tl;
+ ltree_index=tl_index;
+ dtree = td;
+ dtree_index=td_index;
+ tree=null;
+ }
+
+ internal int proc(InfBlocks s, ZStream z, int r){
+ int j; // temporary storage
+ int tindex; // temporary pointer
+ int e; // extra bits or operation
+ int b=0; // bit buffer
+ int k=0; // bits in bit buffer
+ int p=0; // input data pointer
+ int n; // bytes available there
+ int q; // output window write pointer
+ int m; // bytes to end of window or read pointer
+ int f; // pointer to copy strings from
+
+ // copy input/output information to locals (UPDATE macro restores)
+ p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk;
+ q=s.write;m=q= 258 && n >= 10){
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+ r = inflate_fast(lbits, dbits,
+ ltree, ltree_index,
+ dtree, dtree_index,
+ s, z);
+
+ p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk;
+ q=s.write;m=q>=(tree[tindex+1]);
+ k-=(tree[tindex+1]);
+
+ e=tree[tindex];
+
+ if(e == 0){ // literal
+ lit = tree[tindex+2];
+ mode = LIT;
+ break;
+ }
+ if((e & 16)!=0 ){ // length
+ get = e & 15;
+ len = tree[tindex+2];
+ mode = LENEXT;
+ break;
+ }
+ if ((e & 64) == 0){ // next table
+ need = e;
+ tree_index = tindex/3+tree[tindex+2];
+ break;
+ }
+ if ((e & 32)!=0){ // end of block
+ mode = WASH;
+ break;
+ }
+ mode = BADCODE; // invalid code
+ z.msg = "invalid literal/length code";
+ r = Z_DATA_ERROR;
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+ return s.inflate_flush(z,r);
+
+ case LENEXT: // i: getting length extra (have base)
+ j = get;
+
+ while(k<(j)){
+ if(n!=0)r=Z_OK;
+ else{
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+ return s.inflate_flush(z,r);
+ }
+ n--; b|=(z.next_in[p++]&0xff)<>=j;
+ k-=j;
+
+ need = dbits;
+ tree = dtree;
+ tree_index=dtree_index;
+ mode = DIST;
+ goto case DIST;
+ case DIST: // i: get distance next
+ j = need;
+
+ while(k<(j)){
+ if(n!=0)r=Z_OK;
+ else{
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+ return s.inflate_flush(z,r);
+ }
+ n--; b|=(z.next_in[p++]&0xff)<>=tree[tindex+1];
+ k-=tree[tindex+1];
+
+ e = (tree[tindex]);
+ if((e & 16)!=0){ // distance
+ get = e & 15;
+ dist = tree[tindex+2];
+ mode = DISTEXT;
+ break;
+ }
+ if ((e & 64) == 0){ // next table
+ need = e;
+ tree_index = tindex/3 + tree[tindex+2];
+ break;
+ }
+ mode = BADCODE; // invalid code
+ z.msg = "invalid distance code";
+ r = Z_DATA_ERROR;
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+ return s.inflate_flush(z,r);
+
+ case DISTEXT: // i: getting distance extra
+ j = get;
+
+ while(k<(j)){
+ if(n!=0)r=Z_OK;
+ else{
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+ return s.inflate_flush(z,r);
+ }
+ n--; b|=(z.next_in[p++]&0xff)<>=j;
+ k-=j;
+
+ mode = COPY;
+ goto case COPY;
+ case COPY: // o: copying bytes in window, waiting for space
+ f = q - dist;
+ while(f < 0){ // modulo window size-"while" instead
+ f += s.end; // of "if" handles invalid distances
+ }
+ while (len!=0){
+
+ if(m==0){
+ if(q==s.end&&s.read!=0){q=0;m=q 7){ // return unused byte, if any
+ k -= 8;
+ n++;
+ p--; // can always return one
+ }
+
+ s.write=q; r=s.inflate_flush(z,r);
+ q=s.write;m=q= 258 && n >= 10
+ // get literal/length code
+ while(k<(20)){ // max bits for literal/length code
+ n--;
+ b|=(z.next_in[p++]&0xff)<>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
+
+ s.window[q++] = (byte)tp[tp_index_t_3+2];
+ m--;
+ continue;
+ }
+ do {
+
+ b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
+
+ if((e&16)!=0){
+ e &= 15;
+ c = tp[tp_index_t_3+2] + ((int)b & inflate_mask[e]);
+
+ b>>=e; k-=e;
+
+ // decode distance base of block to copy
+ while(k<(15)){ // max bits for distance code
+ n--;
+ b|=(z.next_in[p++]&0xff)<>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
+
+ if((e&16)!=0){
+ // get extra bits to add to distance base
+ e &= 15;
+ while(k<(e)){ // get extra bits (up to 13)
+ n--;
+ b|=(z.next_in[p++]&0xff)<>=(e); k-=(e);
+
+ // do the copy
+ m -= c;
+ if (q >= d){ // offset before dest
+ // just copy
+ r=q-d;
+ if(q-r>0 && 2>(q-r)){
+ s.window[q++]=s.window[r++]; // minimum count is three,
+ s.window[q++]=s.window[r++]; // so unroll loop a little
+ c-=2;
+ }
+ else{
+ System.Array.Copy(s.window, r, s.window, q, 2);
+ q+=2; r+=2; c-=2;
+ }
+ }
+ else{ // else offset after destination
+ r=q-d;
+ do{
+ r+=s.end; // force pointer in window
+ }while(r<0); // covers invalid distances
+ e=s.end-r;
+ if(c>e){ // if source crosses,
+ c-=e; // wrapped copy
+ if(q-r>0 && e>(q-r)){
+ do{s.window[q++] = s.window[r++];}
+ while(--e!=0);
+ }
+ else{
+ System.Array.Copy(s.window, r, s.window, q, e);
+ q+=e; r+=e; e=0;
+ }
+ r = 0; // copy rest from start of window
+ }
+
+ }
+
+ // copy all or what's left
+ if(q-r>0 && c>(q-r)){
+ do{s.window[q++] = s.window[r++];}
+ while(--c!=0);
+ }
+ else{
+ System.Array.Copy(s.window, r, s.window, q, c);
+ q+=c; r+=c; c=0;
+ }
+ break;
+ }
+ else if((e&64)==0){
+ t+=tp[tp_index_t_3+2];
+ t+=(b&inflate_mask[e]);
+ tp_index_t_3=(tp_index+t)*3;
+ e=tp[tp_index_t_3];
+ }
+ else{
+ z.msg = "invalid distance code";
+
+ c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+
+ return Z_DATA_ERROR;
+ }
+ }
+ while(true);
+ break;
+ }
+
+ if((e&64)==0){
+ t+=tp[tp_index_t_3+2];
+ t+=(b&inflate_mask[e]);
+ tp_index_t_3=(tp_index+t)*3;
+ if((e=tp[tp_index_t_3])==0){
+
+ b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
+
+ s.window[q++]=(byte)tp[tp_index_t_3+2];
+ m--;
+ break;
+ }
+ }
+ else if((e&32)!=0){
+
+ c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+
+ return Z_STREAM_END;
+ }
+ else{
+ z.msg="invalid literal/length code";
+
+ c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+
+ return Z_DATA_ERROR;
+ }
+ }
+ while(true);
+ }
+ while(m>=258 && n>= 10);
+
+ // not enough input or output--restore pointers and return
+ c=z.avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;
+
+ s.bitb=b;s.bitk=k;
+ z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+ s.write=q;
+
+ return Z_OK;
+ }
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/util/zlib/InfTree.cs b/bc-sharp-crypto/src/util/zlib/InfTree.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6ed7d1920bfae34c5872b959da7b76bd217454bc
--- /dev/null
+++ b/bc-sharp-crypto/src/util/zlib/InfTree.cs
@@ -0,0 +1,523 @@
+using System;
+/*
+ * $Id: InfTree.cs,v 1.2 2008-05-10 09:35:40 bouncy Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+ internal sealed class InfTree{
+
+ private const int MANY=1440;
+
+ private const int Z_OK=0;
+ private const int Z_STREAM_END=1;
+ private const int Z_NEED_DICT=2;
+ private const int Z_ERRNO=-1;
+ private const int Z_STREAM_ERROR=-2;
+ private const int Z_DATA_ERROR=-3;
+ private const int Z_MEM_ERROR=-4;
+ private const int Z_BUF_ERROR=-5;
+ private const int Z_VERSION_ERROR=-6;
+
+ private const int fixed_bl = 9;
+ private const int fixed_bd = 5;
+
+ static readonly int[] fixed_tl = {
+ 96,7,256, 0,8,80, 0,8,16, 84,8,115,
+ 82,7,31, 0,8,112, 0,8,48, 0,9,192,
+ 80,7,10, 0,8,96, 0,8,32, 0,9,160,
+ 0,8,0, 0,8,128, 0,8,64, 0,9,224,
+ 80,7,6, 0,8,88, 0,8,24, 0,9,144,
+ 83,7,59, 0,8,120, 0,8,56, 0,9,208,
+ 81,7,17, 0,8,104, 0,8,40, 0,9,176,
+ 0,8,8, 0,8,136, 0,8,72, 0,9,240,
+ 80,7,4, 0,8,84, 0,8,20, 85,8,227,
+ 83,7,43, 0,8,116, 0,8,52, 0,9,200,
+ 81,7,13, 0,8,100, 0,8,36, 0,9,168,
+ 0,8,4, 0,8,132, 0,8,68, 0,9,232,
+ 80,7,8, 0,8,92, 0,8,28, 0,9,152,
+ 84,7,83, 0,8,124, 0,8,60, 0,9,216,
+ 82,7,23, 0,8,108, 0,8,44, 0,9,184,
+ 0,8,12, 0,8,140, 0,8,76, 0,9,248,
+ 80,7,3, 0,8,82, 0,8,18, 85,8,163,
+ 83,7,35, 0,8,114, 0,8,50, 0,9,196,
+ 81,7,11, 0,8,98, 0,8,34, 0,9,164,
+ 0,8,2, 0,8,130, 0,8,66, 0,9,228,
+ 80,7,7, 0,8,90, 0,8,26, 0,9,148,
+ 84,7,67, 0,8,122, 0,8,58, 0,9,212,
+ 82,7,19, 0,8,106, 0,8,42, 0,9,180,
+ 0,8,10, 0,8,138, 0,8,74, 0,9,244,
+ 80,7,5, 0,8,86, 0,8,22, 192,8,0,
+ 83,7,51, 0,8,118, 0,8,54, 0,9,204,
+ 81,7,15, 0,8,102, 0,8,38, 0,9,172,
+ 0,8,6, 0,8,134, 0,8,70, 0,9,236,
+ 80,7,9, 0,8,94, 0,8,30, 0,9,156,
+ 84,7,99, 0,8,126, 0,8,62, 0,9,220,
+ 82,7,27, 0,8,110, 0,8,46, 0,9,188,
+ 0,8,14, 0,8,142, 0,8,78, 0,9,252,
+ 96,7,256, 0,8,81, 0,8,17, 85,8,131,
+ 82,7,31, 0,8,113, 0,8,49, 0,9,194,
+ 80,7,10, 0,8,97, 0,8,33, 0,9,162,
+ 0,8,1, 0,8,129, 0,8,65, 0,9,226,
+ 80,7,6, 0,8,89, 0,8,25, 0,9,146,
+ 83,7,59, 0,8,121, 0,8,57, 0,9,210,
+ 81,7,17, 0,8,105, 0,8,41, 0,9,178,
+ 0,8,9, 0,8,137, 0,8,73, 0,9,242,
+ 80,7,4, 0,8,85, 0,8,21, 80,8,258,
+ 83,7,43, 0,8,117, 0,8,53, 0,9,202,
+ 81,7,13, 0,8,101, 0,8,37, 0,9,170,
+ 0,8,5, 0,8,133, 0,8,69, 0,9,234,
+ 80,7,8, 0,8,93, 0,8,29, 0,9,154,
+ 84,7,83, 0,8,125, 0,8,61, 0,9,218,
+ 82,7,23, 0,8,109, 0,8,45, 0,9,186,
+ 0,8,13, 0,8,141, 0,8,77, 0,9,250,
+ 80,7,3, 0,8,83, 0,8,19, 85,8,195,
+ 83,7,35, 0,8,115, 0,8,51, 0,9,198,
+ 81,7,11, 0,8,99, 0,8,35, 0,9,166,
+ 0,8,3, 0,8,131, 0,8,67, 0,9,230,
+ 80,7,7, 0,8,91, 0,8,27, 0,9,150,
+ 84,7,67, 0,8,123, 0,8,59, 0,9,214,
+ 82,7,19, 0,8,107, 0,8,43, 0,9,182,
+ 0,8,11, 0,8,139, 0,8,75, 0,9,246,
+ 80,7,5, 0,8,87, 0,8,23, 192,8,0,
+ 83,7,51, 0,8,119, 0,8,55, 0,9,206,
+ 81,7,15, 0,8,103, 0,8,39, 0,9,174,
+ 0,8,7, 0,8,135, 0,8,71, 0,9,238,
+ 80,7,9, 0,8,95, 0,8,31, 0,9,158,
+ 84,7,99, 0,8,127, 0,8,63, 0,9,222,
+ 82,7,27, 0,8,111, 0,8,47, 0,9,190,
+ 0,8,15, 0,8,143, 0,8,79, 0,9,254,
+ 96,7,256, 0,8,80, 0,8,16, 84,8,115,
+ 82,7,31, 0,8,112, 0,8,48, 0,9,193,
+
+ 80,7,10, 0,8,96, 0,8,32, 0,9,161,
+ 0,8,0, 0,8,128, 0,8,64, 0,9,225,
+ 80,7,6, 0,8,88, 0,8,24, 0,9,145,
+ 83,7,59, 0,8,120, 0,8,56, 0,9,209,
+ 81,7,17, 0,8,104, 0,8,40, 0,9,177,
+ 0,8,8, 0,8,136, 0,8,72, 0,9,241,
+ 80,7,4, 0,8,84, 0,8,20, 85,8,227,
+ 83,7,43, 0,8,116, 0,8,52, 0,9,201,
+ 81,7,13, 0,8,100, 0,8,36, 0,9,169,
+ 0,8,4, 0,8,132, 0,8,68, 0,9,233,
+ 80,7,8, 0,8,92, 0,8,28, 0,9,153,
+ 84,7,83, 0,8,124, 0,8,60, 0,9,217,
+ 82,7,23, 0,8,108, 0,8,44, 0,9,185,
+ 0,8,12, 0,8,140, 0,8,76, 0,9,249,
+ 80,7,3, 0,8,82, 0,8,18, 85,8,163,
+ 83,7,35, 0,8,114, 0,8,50, 0,9,197,
+ 81,7,11, 0,8,98, 0,8,34, 0,9,165,
+ 0,8,2, 0,8,130, 0,8,66, 0,9,229,
+ 80,7,7, 0,8,90, 0,8,26, 0,9,149,
+ 84,7,67, 0,8,122, 0,8,58, 0,9,213,
+ 82,7,19, 0,8,106, 0,8,42, 0,9,181,
+ 0,8,10, 0,8,138, 0,8,74, 0,9,245,
+ 80,7,5, 0,8,86, 0,8,22, 192,8,0,
+ 83,7,51, 0,8,118, 0,8,54, 0,9,205,
+ 81,7,15, 0,8,102, 0,8,38, 0,9,173,
+ 0,8,6, 0,8,134, 0,8,70, 0,9,237,
+ 80,7,9, 0,8,94, 0,8,30, 0,9,157,
+ 84,7,99, 0,8,126, 0,8,62, 0,9,221,
+ 82,7,27, 0,8,110, 0,8,46, 0,9,189,
+ 0,8,14, 0,8,142, 0,8,78, 0,9,253,
+ 96,7,256, 0,8,81, 0,8,17, 85,8,131,
+ 82,7,31, 0,8,113, 0,8,49, 0,9,195,
+ 80,7,10, 0,8,97, 0,8,33, 0,9,163,
+ 0,8,1, 0,8,129, 0,8,65, 0,9,227,
+ 80,7,6, 0,8,89, 0,8,25, 0,9,147,
+ 83,7,59, 0,8,121, 0,8,57, 0,9,211,
+ 81,7,17, 0,8,105, 0,8,41, 0,9,179,
+ 0,8,9, 0,8,137, 0,8,73, 0,9,243,
+ 80,7,4, 0,8,85, 0,8,21, 80,8,258,
+ 83,7,43, 0,8,117, 0,8,53, 0,9,203,
+ 81,7,13, 0,8,101, 0,8,37, 0,9,171,
+ 0,8,5, 0,8,133, 0,8,69, 0,9,235,
+ 80,7,8, 0,8,93, 0,8,29, 0,9,155,
+ 84,7,83, 0,8,125, 0,8,61, 0,9,219,
+ 82,7,23, 0,8,109, 0,8,45, 0,9,187,
+ 0,8,13, 0,8,141, 0,8,77, 0,9,251,
+ 80,7,3, 0,8,83, 0,8,19, 85,8,195,
+ 83,7,35, 0,8,115, 0,8,51, 0,9,199,
+ 81,7,11, 0,8,99, 0,8,35, 0,9,167,
+ 0,8,3, 0,8,131, 0,8,67, 0,9,231,
+ 80,7,7, 0,8,91, 0,8,27, 0,9,151,
+ 84,7,67, 0,8,123, 0,8,59, 0,9,215,
+ 82,7,19, 0,8,107, 0,8,43, 0,9,183,
+ 0,8,11, 0,8,139, 0,8,75, 0,9,247,
+ 80,7,5, 0,8,87, 0,8,23, 192,8,0,
+ 83,7,51, 0,8,119, 0,8,55, 0,9,207,
+ 81,7,15, 0,8,103, 0,8,39, 0,9,175,
+ 0,8,7, 0,8,135, 0,8,71, 0,9,239,
+ 80,7,9, 0,8,95, 0,8,31, 0,9,159,
+ 84,7,99, 0,8,127, 0,8,63, 0,9,223,
+ 82,7,27, 0,8,111, 0,8,47, 0,9,191,
+ 0,8,15, 0,8,143, 0,8,79, 0,9,255
+ };
+ static readonly int[] fixed_td = {
+ 80,5,1, 87,5,257, 83,5,17, 91,5,4097,
+ 81,5,5, 89,5,1025, 85,5,65, 93,5,16385,
+ 80,5,3, 88,5,513, 84,5,33, 92,5,8193,
+ 82,5,9, 90,5,2049, 86,5,129, 192,5,24577,
+ 80,5,2, 87,5,385, 83,5,25, 91,5,6145,
+ 81,5,7, 89,5,1537, 85,5,97, 93,5,24577,
+ 80,5,4, 88,5,769, 84,5,49, 92,5,12289,
+ 82,5,13, 90,5,3073, 86,5,193, 192,5,24577
+ };
+
+ // Tables for deflate from PKZIP's appnote.txt.
+ static readonly int[] cplens = { // Copy lengths for literal codes 257..285
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
+ };
+
+ // see note #13 above about 258
+ static readonly int[] cplext = { // Extra bits for literal codes 257..285
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112 // 112==invalid
+ };
+
+ static readonly int[] cpdist = { // Copy offsets for distance codes 0..29
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577
+ };
+
+ static readonly int[] cpdext = { // Extra bits for distance codes
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+ // If BMAX needs to be larger than 16, then h and x[] should be uLong.
+ const int BMAX=15; // maximum bit length of any code
+
+ int[] hn = null; // hufts used in space
+ int[] v = null; // work area for huft_build
+ int[] c = null; // bit length count table
+ int[] r = null; // table entry for structure assignment
+ int[] u = null; // table stack
+ int[] x = null; // bit offsets, then code stack
+
+ private int huft_build(int[] b, // code lengths in bits (all assumed <= BMAX)
+ int bindex,
+ int n, // number of codes (assumed <= 288)
+ int s, // number of simple-valued codes (0..s-1)
+ int[] d, // list of base values for non-simple codes
+ int[] e, // list of extra bits for non-simple codes
+ int[] t, // result: starting table
+ int[] m, // maximum lookup bits, returns actual
+ int[] hp,// space for trees
+ int[] hn,// hufts used in space
+ int[] v // working area: values in order of bit length
+ ){
+ // Given a list of code lengths and a maximum table size, make a set of
+ // tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR
+ // if the given code set is incomplete (the tables are still built in this
+ // case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
+ // lengths), or Z_MEM_ERROR if not enough memory.
+
+ int a; // counter for codes of length k
+ int f; // i repeats in table every f entries
+ int g; // maximum code length
+ int h; // table level
+ int i; // counter, current code
+ int j; // counter
+ int k; // number of bits in current code
+ int l; // bits per table (returned in m)
+ int mask; // (1 << w) - 1, to avoid cc -O bug on HP
+ int p; // pointer into c[], b[], or v[]
+ int q; // points to current table
+ int w; // bits before this table == (l * h)
+ int xp; // pointer into x
+ int y; // number of dummy codes added
+ int z; // number of entries in current table
+
+ // Generate counts for each bit length
+
+ p = 0; i = n;
+ do {
+ c[b[bindex+p]]++; p++; i--; // assume all entries <= BMAX
+ }while(i!=0);
+
+ if(c[0] == n){ // null input--all zero length codes
+ t[0] = -1;
+ m[0] = 0;
+ return Z_OK;
+ }
+
+ // Find minimum and maximum length, bound *m by those
+ l = m[0];
+ for (j = 1; j <= BMAX; j++)
+ if(c[j]!=0) break;
+ k = j; // minimum code length
+ if(l < j){
+ l = j;
+ }
+ for (i = BMAX; i!=0; i--){
+ if(c[i]!=0) break;
+ }
+ g = i; // maximum code length
+ if(l > i){
+ l = i;
+ }
+ m[0] = l;
+
+ // Adjust last length count to fill out codes, if needed
+ for (y = 1 << j; j < i; j++, y <<= 1){
+ if ((y -= c[j]) < 0){
+ return Z_DATA_ERROR;
+ }
+ }
+ if ((y -= c[i]) < 0){
+ return Z_DATA_ERROR;
+ }
+ c[i] += y;
+
+ // Generate starting offsets into the value table for each length
+ x[1] = j = 0;
+ p = 1; xp = 2;
+ while (--i!=0) { // note that i == g from above
+ x[xp] = (j += c[p]);
+ xp++;
+ p++;
+ }
+
+ // Make a table of values in order of bit lengths
+ i = 0; p = 0;
+ do {
+ if ((j = b[bindex+p]) != 0){
+ v[x[j]++] = i;
+ }
+ p++;
+ }
+ while (++i < n);
+ n = x[g]; // set n to length of v
+
+ // Generate the Huffman codes and for each, make the table entries
+ x[0] = i = 0; // first Huffman code is zero
+ p = 0; // grab values in bit order
+ h = -1; // no tables yet--level -1
+ w = -l; // bits decoded == (l * h)
+ u[0] = 0; // just to keep compilers happy
+ q = 0; // ditto
+ z = 0; // ditto
+
+ // go through the bit lengths (k already is bits in shortest code)
+ for (; k <= g; k++){
+ a = c[k];
+ while (a--!=0){
+ // here i is the Huffman code of length k bits for value *p
+ // make tables up to required level
+ while (k > w + l){
+ h++;
+ w += l; // previous table always l bits
+ // compute minimum size table less than or equal to l bits
+ z = g - w;
+ z = (z > l) ? l : z; // table size upper limit
+ if((f=1<<(j=k-w))>a+1){ // try a k-w bit table
+ // too few codes for k-w bit table
+ f -= a + 1; // deduct codes from patterns left
+ xp = k;
+ if(j < z){
+ while (++j < z){ // try smaller tables up to z bits
+ if((f <<= 1) <= c[++xp])
+ break; // enough codes to use up j bits
+ f -= c[xp]; // else deduct codes from patterns
+ }
+ }
+ }
+ z = 1 << j; // table entries for j-bit table
+
+ // allocate new table
+ if (hn[0] + z > MANY){ // (note: doesn't matter for fixed)
+ return Z_DATA_ERROR; // overflow of MANY
+ }
+ u[h] = q = /*hp+*/ hn[0]; // DEBUG
+ hn[0] += z;
+
+ // connect to last table, if there is one
+ if(h!=0){
+ x[h]=i; // save pattern for backing up
+ r[0]=(byte)j; // bits in this table
+ r[1]=(byte)l; // bits to dump before this table
+ j=i>>(w - l);
+ r[2] = (int)(q - u[h-1] - j); // offset to this table
+ System.Array.Copy(r, 0, hp, (u[h-1]+j)*3, 3); // connect to last table
+ }
+ else{
+ t[0] = q; // first table is returned result
+ }
+ }
+
+ // set up table entry in r
+ r[1] = (byte)(k - w);
+ if (p >= n){
+ r[0] = 128 + 64; // out of values--invalid code
+ }
+ else if (v[p] < s){
+ r[0] = (byte)(v[p] < 256 ? 0 : 32 + 64); // 256 is end-of-block
+ r[2] = v[p++]; // simple code is just the value
+ }
+ else{
+ r[0]=(byte)(e[v[p]-s]+16+64); // non-simple--look up in lists
+ r[2]=d[v[p++] - s];
+ }
+
+ // fill code-like entries with r
+ f=1<<(k-w);
+ for (j=i>>w;j>= 1){
+ i ^= j;
+ }
+ i ^= j;
+
+ // backup over finished tables
+ mask = (1 << w) - 1; // needed on HP, cc -O bug
+ while ((i & mask) != x[h]){
+ h--; // don't need to update q
+ w -= l;
+ mask = (1 << w) - 1;
+ }
+ }
+ }
+ // Return Z_BUF_ERROR if we were given an incomplete table
+ return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+ }
+
+ internal int inflate_trees_bits(int[] c, // 19 code lengths
+ int[] bb, // bits tree desired/actual depth
+ int[] tb, // bits tree result
+ int[] hp, // space for trees
+ ZStream z // for messages
+ ){
+ int result;
+ initWorkArea(19);
+ hn[0]=0;
+ result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v);
+
+ if(result == Z_DATA_ERROR){
+ z.msg = "oversubscribed dynamic bit lengths tree";
+ }
+ else if(result == Z_BUF_ERROR || bb[0] == 0){
+ z.msg = "incomplete dynamic bit lengths tree";
+ result = Z_DATA_ERROR;
+ }
+ return result;
+ }
+
+ internal int inflate_trees_dynamic(int nl, // number of literal/length codes
+ int nd, // number of distance codes
+ int[] c, // that many (total) code lengths
+ int[] bl, // literal desired/actual bit depth
+ int[] bd, // distance desired/actual bit depth
+ int[] tl, // literal/length tree result
+ int[] td, // distance tree result
+ int[] hp, // space for trees
+ ZStream z // for messages
+ ){
+ int result;
+
+ // build literal/length tree
+ initWorkArea(288);
+ hn[0]=0;
+ result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v);
+ if (result != Z_OK || bl[0] == 0){
+ if(result == Z_DATA_ERROR){
+ z.msg = "oversubscribed literal/length tree";
+ }
+ else if (result != Z_MEM_ERROR){
+ z.msg = "incomplete literal/length tree";
+ result = Z_DATA_ERROR;
+ }
+ return result;
+ }
+
+ // build distance tree
+ initWorkArea(288);
+ result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v);
+
+ if (result != Z_OK || (bd[0] == 0 && nl > 257)){
+ if (result == Z_DATA_ERROR){
+ z.msg = "oversubscribed distance tree";
+ }
+ else if (result == Z_BUF_ERROR) {
+ z.msg = "incomplete distance tree";
+ result = Z_DATA_ERROR;
+ }
+ else if (result != Z_MEM_ERROR){
+ z.msg = "empty distance tree with lengths";
+ result = Z_DATA_ERROR;
+ }
+ return result;
+ }
+
+ return Z_OK;
+ }
+
+ internal static int inflate_trees_fixed(int[] bl, //literal desired/actual bit depth
+ int[] bd, //distance desired/actual bit depth
+ int[][] tl,//literal/length tree result
+ int[][] td,//distance tree result
+ ZStream z //for memory allocation
+ ){
+ bl[0]=fixed_bl;
+ bd[0]=fixed_bd;
+ tl[0]=fixed_tl;
+ td[0]=fixed_td;
+ return Z_OK;
+ }
+
+ private void initWorkArea(int vsize){
+ if(hn==null){
+ hn=new int[1];
+ v=new int[vsize];
+ c=new int[BMAX+1];
+ r=new int[3];
+ u=new int[BMAX];
+ x=new int[BMAX+1];
+ }
+ if(v.Lengthstate);
+ return Z_OK;
+ }
+
+ internal int inflateInit(ZStream z, int w){
+ z.msg = null;
+ blocks = null;
+
+ // handle undocumented nowrap option (no zlib header or check)
+ nowrap = 0;
+ if(w < 0){
+ w = - w;
+ nowrap = 1;
+ }
+
+ // set window size
+ if(w<8 ||w>15){
+ inflateEnd(z);
+ return Z_STREAM_ERROR;
+ }
+ wbits=w;
+
+ z.istate.blocks=new InfBlocks(z,
+ z.istate.nowrap!=0 ? null : this,
+ 1<>4)+8>z.istate.wbits){
+ z.istate.mode = BAD;
+ z.msg="invalid window size";
+ z.istate.marker = 5; // can't try inflateSync
+ break;
+ }
+ z.istate.mode=FLAG;
+ goto case FLAG;
+ case FLAG:
+
+ if(z.avail_in==0)return r;r=f;
+
+ z.avail_in--; z.total_in++;
+ b = (z.next_in[z.next_in_index++])&0xff;
+
+ if((((z.istate.method << 8)+b) % 31)!=0){
+ z.istate.mode = BAD;
+ z.msg = "incorrect header check";
+ z.istate.marker = 5; // can't try inflateSync
+ break;
+ }
+
+ if((b&PRESET_DICT)==0){
+ z.istate.mode = BLOCKS;
+ break;
+ }
+ z.istate.mode = DICT4;
+ goto case DICT4;
+ case DICT4:
+
+ if(z.avail_in==0)return r;r=f;
+
+ z.avail_in--; z.total_in++;
+ z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L;
+ z.istate.mode=DICT3;
+ goto case DICT3;
+ case DICT3:
+
+ if(z.avail_in==0)return r;r=f;
+
+ z.avail_in--; z.total_in++;
+ z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L;
+ z.istate.mode=DICT2;
+ goto case DICT2;
+ case DICT2:
+
+ if(z.avail_in==0)return r;r=f;
+
+ z.avail_in--; z.total_in++;
+ z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L;
+ z.istate.mode=DICT1;
+ goto case DICT1;
+ case DICT1:
+
+ if(z.avail_in==0)return r;r=f;
+
+ z.avail_in--; z.total_in++;
+ z.istate.need += (z.next_in[z.next_in_index++]&0xffL);
+ z.adler = z.istate.need;
+ z.istate.mode = DICT0;
+ return Z_NEED_DICT;
+ case DICT0:
+ z.istate.mode = BAD;
+ z.msg = "need dictionary";
+ z.istate.marker = 0; // can try inflateSync
+ return Z_STREAM_ERROR;
+ case BLOCKS:
+
+ r = z.istate.blocks.proc(z, r);
+ if(r == Z_DATA_ERROR){
+ z.istate.mode = BAD;
+ z.istate.marker = 0; // can try inflateSync
+ break;
+ }
+ if(r == Z_OK){
+ r = f;
+ }
+ if(r != Z_STREAM_END){
+ return r;
+ }
+ r = f;
+ z.istate.blocks.reset(z, z.istate.was);
+ if(z.istate.nowrap!=0){
+ z.istate.mode=DONE;
+ break;
+ }
+ z.istate.mode=CHECK4;
+ goto case CHECK4;
+ case CHECK4:
+
+ if(z.avail_in==0)return r;r=f;
+
+ z.avail_in--; z.total_in++;
+ z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L;
+ z.istate.mode=CHECK3;
+ goto case CHECK3;
+ case CHECK3:
+
+ if(z.avail_in==0)return r;r=f;
+
+ z.avail_in--; z.total_in++;
+ z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L;
+ z.istate.mode = CHECK2;
+ goto case CHECK2;
+ case CHECK2:
+
+ if(z.avail_in==0)return r;r=f;
+
+ z.avail_in--; z.total_in++;
+ z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L;
+ z.istate.mode = CHECK1;
+ goto case CHECK1;
+ case CHECK1:
+
+ if(z.avail_in==0)return r;r=f;
+
+ z.avail_in--; z.total_in++;
+ z.istate.need+=(z.next_in[z.next_in_index++]&0xffL);
+
+ if(((int)(z.istate.was[0])) != ((int)(z.istate.need))){
+ z.istate.mode = BAD;
+ z.msg = "incorrect data check";
+ z.istate.marker = 5; // can't try inflateSync
+ break;
+ }
+
+ z.istate.mode = DONE;
+ goto case DONE;
+ case DONE:
+ return Z_STREAM_END;
+ case BAD:
+ return Z_DATA_ERROR;
+ default:
+ return Z_STREAM_ERROR;
+ }
+ }
+ }
+
+
+ internal int inflateSetDictionary(ZStream z, byte[] dictionary, int dictLength){
+ int index=0;
+ int length = dictLength;
+ if(z==null || z.istate == null|| z.istate.mode != DICT0)
+ return Z_STREAM_ERROR;
+
+ if(z._adler.adler32(1L, dictionary, 0, dictLength)!=z.adler){
+ return Z_DATA_ERROR;
+ }
+
+ z.adler = z._adler.adler32(0, null, 0, 0);
+
+ if(length >= (1<>7)]);
+ }
+
+ internal short[] dyn_tree; // the dynamic tree
+ internal int max_code; // largest code with non zero frequency
+ internal StaticTree stat_desc; // the corresponding static tree
+
+ // Compute the optimal bit lengths for a tree and update the total bit length
+ // for the current block.
+ // IN assertion: the fields freq and dad are set, heap[heap_max] and
+ // above are the tree nodes sorted by increasing frequency.
+ // OUT assertions: the field len is set to the optimal bit length, the
+ // array bl_count contains the frequencies for each bit length.
+ // The length opt_len is updated; static_len is also updated if stree is
+ // not null.
+ internal void gen_bitlen(Deflate s){
+ short[] tree = dyn_tree;
+ short[] stree = stat_desc.static_tree;
+ int[] extra = stat_desc.extra_bits;
+ int based = stat_desc.extra_base;
+ int max_length = stat_desc.max_length;
+ int h; // heap index
+ int n, m; // iterate over the tree elements
+ int bits; // bit length
+ int xbits; // extra bits
+ short f; // frequency
+ int overflow = 0; // number of elements with bit length too large
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s.bl_count[bits] = 0;
+
+ // In a first pass, compute the optimal bit lengths (which may
+ // overflow in the case of the bit length tree).
+ tree[s.heap[s.heap_max]*2+1] = 0; // root of the heap
+
+ for(h=s.heap_max+1; h max_length){ bits = max_length; overflow++; }
+ tree[n*2+1] = (short)bits;
+ // We overwrite tree[n*2+1] which is no longer needed
+
+ if (n > max_code) continue; // not a leaf node
+
+ s.bl_count[bits]++;
+ xbits = 0;
+ if (n >= based) xbits = extra[n-based];
+ f = tree[n*2];
+ s.opt_len += f * (bits + xbits);
+ if (stree!=null) s.static_len += f * (stree[n*2+1] + xbits);
+ }
+ if (overflow == 0) return;
+
+ // This happens for example on obj2 and pic of the Calgary corpus
+ // Find the first bit length which could increase:
+ do {
+ bits = max_length-1;
+ while(s.bl_count[bits]==0) bits--;
+ s.bl_count[bits]--; // move one leaf down the tree
+ s.bl_count[bits+1]+=2; // move one overflow item as its brother
+ s.bl_count[max_length]--;
+ // The brother of the overflow item also moves one step up,
+ // but this does not affect bl_count[max_length]
+ overflow -= 2;
+ }
+ while (overflow > 0);
+
+ for (bits = max_length; bits != 0; bits--) {
+ n = s.bl_count[bits];
+ while (n != 0) {
+ m = s.heap[--h];
+ if (m > max_code) continue;
+ if (tree[m*2+1] != bits) {
+ s.opt_len += (int)(((long)bits - (long)tree[m*2+1])*(long)tree[m*2]);
+ tree[m*2+1] = (short)bits;
+ }
+ n--;
+ }
+ }
+ }
+
+ // Construct one Huffman tree and assigns the code bit strings and lengths.
+ // Update the total bit length for the current block.
+ // IN assertion: the field freq is set for all tree elements.
+ // OUT assertions: the fields len and code are set to the optimal bit length
+ // and corresponding code. The length opt_len is updated; static_len is
+ // also updated if stree is not null. The field max_code is set.
+ internal void build_tree(Deflate s){
+ short[] tree=dyn_tree;
+ short[] stree=stat_desc.static_tree;
+ int elems=stat_desc.elems;
+ int n, m; // iterate over heap elements
+ int max_code=-1; // largest code with non zero frequency
+ int node; // new node being created
+
+ // Construct the initial heap, with least frequent element in
+ // heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ // heap[0] is not used.
+ s.heap_len = 0;
+ s.heap_max = HEAP_SIZE;
+
+ for(n=0; n=1; n--)
+ s.pqdownheap(tree, n);
+
+ // Construct the Huffman tree by repeatedly combining the least two
+ // frequent nodes.
+
+ node=elems; // next internal node of the tree
+ do{
+ // n = node of least frequency
+ n=s.heap[1];
+ s.heap[1]=s.heap[s.heap_len--];
+ s.pqdownheap(tree, 1);
+ m=s.heap[1]; // m = node of next least frequency
+
+ s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency
+ s.heap[--s.heap_max] = m;
+
+ // Create a new node father of n and m
+ tree[node*2] = (short)(tree[n*2] + tree[m*2]);
+ s.depth[node] = (byte)(System.Math.Max(s.depth[n],s.depth[m])+1);
+ tree[n*2+1] = tree[m*2+1] = (short)node;
+
+ // and insert the new node in the heap
+ s.heap[1] = node++;
+ s.pqdownheap(tree, 1);
+ }
+ while(s.heap_len>=2);
+
+ s.heap[--s.heap_max] = s.heap[1];
+
+ // At this point, the fields freq and dad are set. We can now
+ // generate the bit lengths.
+
+ gen_bitlen(s);
+
+ // The field len is now set, we can generate the bit codes
+ gen_codes(tree, max_code, s.bl_count);
+ }
+
+ // Generate the codes for a given tree and bit counts (which need not be
+ // optimal).
+ // IN assertion: the array bl_count contains the bit length statistics for
+ // the given tree and the field len is set for all tree elements.
+ // OUT assertion: the field code is set for all tree elements of non
+ // zero code length.
+ internal static void gen_codes(short[] tree, // the tree to decorate
+ int max_code, // largest code with non zero frequency
+ short[] bl_count // number of codes at each bit length
+ ){
+ short[] next_code=new short[MAX_BITS+1]; // next code value for each bit length
+ short code = 0; // running code value
+ int bits; // bit index
+ int n; // code index
+
+ // The distribution counts are first used to generate the code values
+ // without bit reversal.
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (short)((code + bl_count[bits-1]) << 1);
+ }
+
+ // Check that the bit counts in bl_count are consistent. The last code
+ // must be all ones.
+ //Assert (code + bl_count[MAX_BITS]-1 == (1<>=1;
+ res<<=1;
+ }
+ while(--len>0);
+ return res>>1;
+ }
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/util/zlib/ZDeflaterOutputStream.cs b/bc-sharp-crypto/src/util/zlib/ZDeflaterOutputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d0f0bcb8dc6dfe323fe303f82e759d4c6d048723
--- /dev/null
+++ b/bc-sharp-crypto/src/util/zlib/ZDeflaterOutputStream.cs
@@ -0,0 +1,171 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+ ///
+ /// Summary description for DeflaterOutputStream.
+ ///
+ [Obsolete("Use 'ZOutputStream' instead")]
+ public class ZDeflaterOutputStream : Stream {
+ protected ZStream z=new ZStream();
+ protected int flushLevel=JZlib.Z_NO_FLUSH;
+ private const int BUFSIZE = 4192;
+ protected byte[] buf=new byte[BUFSIZE];
+ private byte[] buf1=new byte[1];
+
+ protected Stream outp;
+
+ public ZDeflaterOutputStream(Stream outp) : this(outp, 6, false) {
+ }
+
+ public ZDeflaterOutputStream(Stream outp, int level) : this(outp, level, false) {
+ }
+
+ public ZDeflaterOutputStream(Stream outp, int level, bool nowrap) {
+ this.outp=outp;
+ z.deflateInit(level, nowrap);
+ }
+
+
+ public override bool CanRead {
+ get {
+ // TODO: Add DeflaterOutputStream.CanRead getter implementation
+ return false;
+ }
+ }
+
+ public override bool CanSeek {
+ get {
+ // TODO: Add DeflaterOutputStream.CanSeek getter implementation
+ return false;
+ }
+ }
+
+ public override bool CanWrite {
+ get {
+ // TODO: Add DeflaterOutputStream.CanWrite getter implementation
+ return true;
+ }
+ }
+
+ public override long Length {
+ get {
+ // TODO: Add DeflaterOutputStream.Length getter implementation
+ return 0;
+ }
+ }
+
+ public override long Position {
+ get {
+ // TODO: Add DeflaterOutputStream.Position getter implementation
+ return 0;
+ }
+ set {
+ // TODO: Add DeflaterOutputStream.Position setter implementation
+ }
+ }
+
+ public override void Write(byte[] b, int off, int len) {
+ if(len==0)
+ return;
+ int err;
+ z.next_in=b;
+ z.next_in_index=off;
+ z.avail_in=len;
+ do{
+ z.next_out=buf;
+ z.next_out_index=0;
+ z.avail_out=BUFSIZE;
+ err=z.deflate(flushLevel);
+ if(err!=JZlib.Z_OK)
+ throw new IOException("deflating: "+z.msg);
+ if (z.avail_out < BUFSIZE)
+ {
+ outp.Write(buf, 0, BUFSIZE-z.avail_out);
+ }
+ }
+ while(z.avail_in>0 || z.avail_out==0);
+ }
+
+ public override long Seek(long offset, SeekOrigin origin) {
+ // TODO: Add DeflaterOutputStream.Seek implementation
+ return 0;
+ }
+
+ public override void SetLength(long value) {
+ // TODO: Add DeflaterOutputStream.SetLength implementation
+
+ }
+
+ public override int Read(byte[] buffer, int offset, int count) {
+ // TODO: Add DeflaterOutputStream.Read implementation
+ return 0;
+ }
+
+ public override void Flush() {
+ outp.Flush();
+ }
+
+ public override void WriteByte(byte b) {
+ buf1[0]=(byte)b;
+ Write(buf1, 0, 1);
+ }
+
+ public void Finish() {
+ int err;
+ do{
+ z.next_out=buf;
+ z.next_out_index=0;
+ z.avail_out=BUFSIZE;
+ err=z.deflate(JZlib.Z_FINISH);
+ if(err!=JZlib.Z_STREAM_END && err != JZlib.Z_OK)
+ throw new IOException("deflating: "+z.msg);
+ if(BUFSIZE-z.avail_out>0){
+ outp.Write(buf, 0, BUFSIZE-z.avail_out);
+ }
+ }
+ while(z.avail_in>0 || z.avail_out==0);
+ Flush();
+ }
+
+ public void End() {
+ if(z==null)
+ return;
+ z.deflateEnd();
+ z.free();
+ z=null;
+ }
+
+#if PORTABLE
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ try{
+ try{Finish();}
+ catch (IOException) {}
+ }
+ finally{
+ End();
+ Platform.Dispose(outp);
+ outp=null;
+ }
+ }
+ base.Dispose(disposing);
+ }
+#else
+ public override void Close() {
+ try{
+ try{Finish();}
+ catch (IOException) {}
+ }
+ finally{
+ End();
+ Platform.Dispose(outp);
+ outp=null;
+ }
+ base.Close();
+ }
+#endif
+ }
+}
diff --git a/bc-sharp-crypto/src/util/zlib/ZInflaterInputStream.cs b/bc-sharp-crypto/src/util/zlib/ZInflaterInputStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ef742bb00a02d48acc4bac068fb6d2299823fced
--- /dev/null
+++ b/bc-sharp-crypto/src/util/zlib/ZInflaterInputStream.cs
@@ -0,0 +1,140 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+ ///
+ /// Summary description for DeflaterOutputStream.
+ ///
+ [Obsolete("Use 'ZInputStream' instead")]
+ public class ZInflaterInputStream : Stream {
+ protected ZStream z=new ZStream();
+ protected int flushLevel=JZlib.Z_NO_FLUSH;
+ private const int BUFSIZE = 4192;
+ protected byte[] buf=new byte[BUFSIZE];
+ private byte[] buf1=new byte[1];
+
+ protected Stream inp=null;
+ private bool nomoreinput=false;
+
+ public ZInflaterInputStream(Stream inp) : this(inp, false) {
+ }
+
+ public ZInflaterInputStream(Stream inp, bool nowrap) {
+ this.inp=inp;
+ z.inflateInit(nowrap);
+ z.next_in=buf;
+ z.next_in_index=0;
+ z.avail_in=0;
+ }
+
+ public override bool CanRead {
+ get {
+ // TODO: Add DeflaterOutputStream.CanRead getter implementation
+ return true;
+ }
+ }
+
+ public override bool CanSeek {
+ get {
+ // TODO: Add DeflaterOutputStream.CanSeek getter implementation
+ return false;
+ }
+ }
+
+ public override bool CanWrite {
+ get {
+ // TODO: Add DeflaterOutputStream.CanWrite getter implementation
+ return false;
+ }
+ }
+
+ public override long Length {
+ get {
+ // TODO: Add DeflaterOutputStream.Length getter implementation
+ return 0;
+ }
+ }
+
+ public override long Position {
+ get {
+ // TODO: Add DeflaterOutputStream.Position getter implementation
+ return 0;
+ }
+ set {
+ // TODO: Add DeflaterOutputStream.Position setter implementation
+ }
+ }
+
+ public override void Write(byte[] b, int off, int len) {
+ }
+
+ public override long Seek(long offset, SeekOrigin origin) {
+ // TODO: Add DeflaterOutputStream.Seek implementation
+ return 0;
+ }
+
+ public override void SetLength(long value) {
+ // TODO: Add DeflaterOutputStream.SetLength implementation
+
+ }
+
+ public override int Read(byte[] b, int off, int len) {
+ if(len==0)
+ return(0);
+ int err;
+ z.next_out=b;
+ z.next_out_index=off;
+ z.avail_out=len;
+ do {
+ if((z.avail_in==0)&&(!nomoreinput)) { // if buffer is empty and more input is avaiable, refill it
+ z.next_in_index=0;
+ z.avail_in=inp.Read(buf, 0, BUFSIZE);//(BUFSIZE 0)
+ {
+ output.Write(buf, 0, count);
+ }
+ }
+ while (z.avail_in > 0 || z.avail_out == 0);
+
+ Flush();
+ }
+
+ public override void Flush()
+ {
+ output.Flush();
+ }
+
+ public virtual int FlushMode
+ {
+ get { return flushLevel; }
+ set { this.flushLevel = value; }
+ }
+
+ public sealed override long Length { get { throw new NotSupportedException(); } }
+ public sealed override long Position
+ {
+ get { throw new NotSupportedException(); }
+ set { throw new NotSupportedException(); }
+ }
+ public sealed override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
+ public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
+ public sealed override void SetLength(long value) { throw new NotSupportedException(); }
+
+ public virtual long TotalIn
+ {
+ get { return z.total_in; }
+ }
+
+ public virtual long TotalOut
+ {
+ get { return z.total_out; }
+ }
+
+ public override void Write(byte[] b, int off, int len)
+ {
+ if (len == 0)
+ return;
+
+ z.next_in = b;
+ z.next_in_index = off;
+ z.avail_in = len;
+
+ do
+ {
+ z.next_out = buf;
+ z.next_out_index = 0;
+ z.avail_out = buf.Length;
+
+ int err = compress
+ ? z.deflate(flushLevel)
+ : z.inflate(flushLevel);
+
+ if (err != JZlib.Z_OK)
+ // TODO
+// throw new ZStreamException((compress ? "de" : "in") + "flating: " + z.msg);
+ throw new IOException((compress ? "de" : "in") + "flating: " + z.msg);
+
+ output.Write(buf, 0, buf.Length - z.avail_out);
+ }
+ while (z.avail_in > 0 || z.avail_out == 0);
+ }
+
+ public override void WriteByte(byte b)
+ {
+ buf1[0] = b;
+ Write(buf1, 0, 1);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/util/zlib/ZStream.cs b/bc-sharp-crypto/src/util/zlib/ZStream.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7ff9614626d254248a89c2b17572a95649728ae1
--- /dev/null
+++ b/bc-sharp-crypto/src/util/zlib/ZStream.cs
@@ -0,0 +1,214 @@
+using System;
+/*
+ * $Id: ZStream.cs,v 1.1 2006-07-31 13:59:26 bouncy Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the distribution.
+
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+ public sealed class ZStream{
+
+ private const int MAX_WBITS=15; // 32K LZ77 window
+ private const int DEF_WBITS=MAX_WBITS;
+
+ private const int Z_NO_FLUSH=0;
+ private const int Z_PARTIAL_FLUSH=1;
+ private const int Z_SYNC_FLUSH=2;
+ private const int Z_FULL_FLUSH=3;
+ private const int Z_FINISH=4;
+
+ private const int MAX_MEM_LEVEL=9;
+
+ private const int Z_OK=0;
+ private const int Z_STREAM_END=1;
+ private const int Z_NEED_DICT=2;
+ private const int Z_ERRNO=-1;
+ private const int Z_STREAM_ERROR=-2;
+ private const int Z_DATA_ERROR=-3;
+ private const int Z_MEM_ERROR=-4;
+ private const int Z_BUF_ERROR=-5;
+ private const int Z_VERSION_ERROR=-6;
+
+ public byte[] next_in; // next input byte
+ public int next_in_index;
+ public int avail_in; // number of bytes available at next_in
+ public long total_in; // total nb of input bytes read so far
+
+ public byte[] next_out; // next output byte should be put there
+ public int next_out_index;
+ public int avail_out; // remaining free space at next_out
+ public long total_out; // total nb of bytes output so far
+
+ public String msg;
+
+ internal Deflate dstate;
+ internal Inflate istate;
+
+ internal int data_type; // best guess about the data type: ascii or binary
+
+ public long adler;
+ internal Adler32 _adler=new Adler32();
+
+ public int inflateInit(){
+ return inflateInit(DEF_WBITS);
+ }
+ public int inflateInit(bool nowrap){
+ return inflateInit(DEF_WBITS, nowrap);
+ }
+ public int inflateInit(int w){
+ return inflateInit(w, false);
+ }
+
+ public int inflateInit(int w, bool nowrap){
+ istate=new Inflate();
+ return istate.inflateInit(this, nowrap?-w:w);
+ }
+
+ public int inflate(int f){
+ if(istate==null) return Z_STREAM_ERROR;
+ return istate.inflate(this, f);
+ }
+ public int inflateEnd(){
+ if(istate==null) return Z_STREAM_ERROR;
+ int ret=istate.inflateEnd(this);
+ istate = null;
+ return ret;
+ }
+ public int inflateSync(){
+ if(istate == null)
+ return Z_STREAM_ERROR;
+ return istate.inflateSync(this);
+ }
+ public int inflateSetDictionary(byte[] dictionary, int dictLength){
+ if(istate == null)
+ return Z_STREAM_ERROR;
+ return istate.inflateSetDictionary(this, dictionary, dictLength);
+ }
+
+ public int deflateInit(int level){
+ return deflateInit(level, MAX_WBITS);
+ }
+ public int deflateInit(int level, bool nowrap){
+ return deflateInit(level, MAX_WBITS, nowrap);
+ }
+ public int deflateInit(int level, int bits){
+ return deflateInit(level, bits, false);
+ }
+ public int deflateInit(int level, int bits, bool nowrap){
+ dstate=new Deflate();
+ return dstate.deflateInit(this, level, nowrap?-bits:bits);
+ }
+ public int deflate(int flush){
+ if(dstate==null){
+ return Z_STREAM_ERROR;
+ }
+ return dstate.deflate(this, flush);
+ }
+ public int deflateEnd(){
+ if(dstate==null) return Z_STREAM_ERROR;
+ int ret=dstate.deflateEnd();
+ dstate=null;
+ return ret;
+ }
+ public int deflateParams(int level, int strategy){
+ if(dstate==null) return Z_STREAM_ERROR;
+ return dstate.deflateParams(this, level, strategy);
+ }
+ public int deflateSetDictionary (byte[] dictionary, int dictLength){
+ if(dstate == null)
+ return Z_STREAM_ERROR;
+ return dstate.deflateSetDictionary(this, dictionary, dictLength);
+ }
+
+ // Flush as much pending output as possible. All deflate() output goes
+ // through this function so some applications may wish to modify it
+ // to avoid allocating a large strm->next_out buffer and copying into it.
+ // (See also read_buf()).
+ internal void flush_pending(){
+ int len=dstate.pending;
+
+ if(len>avail_out) len=avail_out;
+ if(len==0) return;
+
+ if(dstate.pending_buf.Length<=dstate.pending_out ||
+ next_out.Length<=next_out_index ||
+ dstate.pending_buf.Length<(dstate.pending_out+len) ||
+ next_out.Length<(next_out_index+len)){
+ // System.out.println(dstate.pending_buf.length+", "+dstate.pending_out+
+ // ", "+next_out.length+", "+next_out_index+", "+len);
+ // System.out.println("avail_out="+avail_out);
+ }
+
+ System.Array.Copy(dstate.pending_buf, dstate.pending_out,
+ next_out, next_out_index, len);
+
+ next_out_index+=len;
+ dstate.pending_out+=len;
+ total_out+=len;
+ avail_out-=len;
+ dstate.pending-=len;
+ if(dstate.pending==0){
+ dstate.pending_out=0;
+ }
+ }
+
+ // Read a new buffer from the current input stream, update the adler32
+ // and total number of bytes read. All deflate() input goes through
+ // this function so some applications may wish to modify it to avoid
+ // allocating a large strm->next_in buffer and copying from it.
+ // (See also flush_pending()).
+ internal int read_buf(byte[] buf, int start, int size) {
+ int len=avail_in;
+
+ if(len>size) len=size;
+ if(len==0) return 0;
+
+ avail_in-=len;
+
+ if(dstate.noheader==0) {
+ adler=_adler.adler32(adler, next_in, next_in_index, len);
+ }
+ System.Array.Copy(next_in, next_in_index, buf, start, len);
+ next_in_index += len;
+ total_in += len;
+ return len;
+ }
+
+ public void free(){
+ next_in=null;
+ next_out=null;
+ msg=null;
+ _adler=null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/x509/AttributeCertificateHolder.cs b/bc-sharp-crypto/src/x509/AttributeCertificateHolder.cs
new file mode 100644
index 0000000000000000000000000000000000000000..04460cd59cbbfe65ce491a86631dcda6a1be4cbb
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/AttributeCertificateHolder.cs
@@ -0,0 +1,442 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// The Holder object.
+ ///
+ /// Holder ::= SEQUENCE {
+ /// baseCertificateID [0] IssuerSerial OPTIONAL,
+ /// -- the issuer and serial number of
+ /// -- the holder's Public Key Certificate
+ /// entityName [1] GeneralNames OPTIONAL,
+ /// -- the name of the claimant or role
+ /// objectDigestInfo [2] ObjectDigestInfo OPTIONAL
+ /// -- used to directly authenticate the holder,
+ /// -- for example, an executable
+ /// }
+ ///
+ ///
+ public class AttributeCertificateHolder
+ //: CertSelector, Selector
+ : IX509Selector
+ {
+ internal readonly Holder holder;
+
+ internal AttributeCertificateHolder(
+ Asn1Sequence seq)
+ {
+ holder = Holder.GetInstance(seq);
+ }
+
+ public AttributeCertificateHolder(
+ X509Name issuerName,
+ BigInteger serialNumber)
+ {
+ holder = new Holder(
+ new IssuerSerial(
+ GenerateGeneralNames(issuerName),
+ new DerInteger(serialNumber)));
+ }
+
+ public AttributeCertificateHolder(
+ X509Certificate cert)
+ {
+ X509Name name;
+ try
+ {
+ name = PrincipalUtilities.GetIssuerX509Principal(cert);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.Message);
+ }
+
+ holder = new Holder(new IssuerSerial(GenerateGeneralNames(name), new DerInteger(cert.SerialNumber)));
+ }
+
+ public AttributeCertificateHolder(
+ X509Name principal)
+ {
+ holder = new Holder(GenerateGeneralNames(principal));
+ }
+
+ /**
+ * Constructs a holder for v2 attribute certificates with a hash value for
+ * some type of object.
+ *
+ * digestedObjectType
can be one of the following:
+ *
+ * 0 - publicKey - A hash of the public key of the holder must be
+ * passed.
+ * 1 - publicKeyCert - A hash of the public key certificate of the
+ * holder must be passed.
+ * 2 - otherObjectDigest - A hash of some other object type must be
+ * passed. otherObjectTypeID
must not be empty.
+ *
+ *
+ * This cannot be used if a v1 attribute certificate is used.
+ *
+ * @param digestedObjectType The digest object type.
+ * @param digestAlgorithm The algorithm identifier for the hash.
+ * @param otherObjectTypeID The object type ID if
+ * digestedObjectType
is
+ * otherObjectDigest
.
+ * @param objectDigest The hash value.
+ */
+ public AttributeCertificateHolder(
+ int digestedObjectType,
+ string digestAlgorithm,
+ string otherObjectTypeID,
+ byte[] objectDigest)
+ {
+ // TODO Allow 'objectDigest' to be null?
+
+ holder = new Holder(new ObjectDigestInfo(digestedObjectType, otherObjectTypeID,
+ new AlgorithmIdentifier(new DerObjectIdentifier(digestAlgorithm)), Arrays.Clone(objectDigest)));
+ }
+
+ /**
+ * Returns the digest object type if an object digest info is used.
+ *
+ *
+ * 0 - publicKey - A hash of the public key of the holder must be
+ * passed.
+ * 1 - publicKeyCert - A hash of the public key certificate of the
+ * holder must be passed.
+ * 2 - otherObjectDigest - A hash of some other object type must be
+ * passed. otherObjectTypeID
must not be empty.
+ *
+ *
+ *
+ * @return The digest object type or -1 if no object digest info is set.
+ */
+ public int DigestedObjectType
+ {
+ get
+ {
+ ObjectDigestInfo odi = holder.ObjectDigestInfo;
+
+ return odi == null
+ ? -1
+ : odi.DigestedObjectType.Value.IntValue;
+ }
+ }
+
+ /**
+ * Returns the other object type ID if an object digest info is used.
+ *
+ * @return The other object type ID or null
if no object
+ * digest info is set.
+ */
+ public string DigestAlgorithm
+ {
+ get
+ {
+ ObjectDigestInfo odi = holder.ObjectDigestInfo;
+
+ return odi == null
+ ? null
+ : odi.DigestAlgorithm.Algorithm.Id;
+ }
+ }
+
+ /**
+ * Returns the hash if an object digest info is used.
+ *
+ * @return The hash or null
if no object digest info is set.
+ */
+ public byte[] GetObjectDigest()
+ {
+ ObjectDigestInfo odi = holder.ObjectDigestInfo;
+
+ return odi == null
+ ? null
+ : odi.ObjectDigest.GetBytes();
+ }
+
+ /**
+ * Returns the digest algorithm ID if an object digest info is used.
+ *
+ * @return The digest algorithm ID or null
if no object
+ * digest info is set.
+ */
+ public string OtherObjectTypeID
+ {
+ get
+ {
+ ObjectDigestInfo odi = holder.ObjectDigestInfo;
+
+ return odi == null
+ ? null
+ : odi.OtherObjectTypeID.Id;
+ }
+ }
+
+ private GeneralNames GenerateGeneralNames(
+ X509Name principal)
+ {
+// return GeneralNames.GetInstance(new DerSequence(new GeneralName(principal)));
+ return new GeneralNames(new GeneralName(principal));
+ }
+
+ private bool MatchesDN(
+ X509Name subject,
+ GeneralNames targets)
+ {
+ GeneralName[] names = targets.GetNames();
+
+ for (int i = 0; i != names.Length; i++)
+ {
+ GeneralName gn = names[i];
+
+ if (gn.TagNo == GeneralName.DirectoryName)
+ {
+ try
+ {
+ if (X509Name.GetInstance(gn.Name).Equivalent(subject))
+ {
+ return true;
+ }
+ }
+ catch (Exception)
+ {
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private object[] GetNames(
+ GeneralName[] names)
+ {
+ int count = 0;
+ for (int i = 0; i != names.Length; i++)
+ {
+ if (names[i].TagNo == GeneralName.DirectoryName)
+ {
+ ++count;
+ }
+ }
+
+ object[] result = new object[count];
+
+ int pos = 0;
+ for (int i = 0; i != names.Length; i++)
+ {
+ if (names[i].TagNo == GeneralName.DirectoryName)
+ {
+ result[pos++] = X509Name.GetInstance(names[i].Name);
+ }
+ }
+
+ return result;
+ }
+
+ private X509Name[] GetPrincipals(
+ GeneralNames names)
+ {
+ object[] p = this.GetNames(names.GetNames());
+
+ int count = 0;
+
+ for (int i = 0; i != p.Length; i++)
+ {
+ if (p[i] is X509Name)
+ {
+ ++count;
+ }
+ }
+
+ X509Name[] result = new X509Name[count];
+
+ int pos = 0;
+ for (int i = 0; i != p.Length; i++)
+ {
+ if (p[i] is X509Name)
+ {
+ result[pos++] = (X509Name)p[i];
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Return any principal objects inside the attribute certificate holder entity names field.
+ *
+ * @return an array of IPrincipal objects (usually X509Name), null if no entity names field is set.
+ */
+ public X509Name[] GetEntityNames()
+ {
+ if (holder.EntityName != null)
+ {
+ return GetPrincipals(holder.EntityName);
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the principals associated with the issuer attached to this holder
+ *
+ * @return an array of principals, null if no BaseCertificateID is set.
+ */
+ public X509Name[] GetIssuer()
+ {
+ if (holder.BaseCertificateID != null)
+ {
+ return GetPrincipals(holder.BaseCertificateID.Issuer);
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the serial number associated with the issuer attached to this holder.
+ *
+ * @return the certificate serial number, null if no BaseCertificateID is set.
+ */
+ public BigInteger SerialNumber
+ {
+ get
+ {
+ if (holder.BaseCertificateID != null)
+ {
+ return holder.BaseCertificateID.Serial.Value;
+ }
+
+ return null;
+ }
+ }
+
+ public object Clone()
+ {
+ return new AttributeCertificateHolder((Asn1Sequence)holder.ToAsn1Object());
+ }
+
+ public bool Match(
+// Certificate cert)
+ X509Certificate x509Cert)
+ {
+// if (!(cert is X509Certificate))
+// {
+// return false;
+// }
+//
+// X509Certificate x509Cert = (X509Certificate)cert;
+
+ try
+ {
+ if (holder.BaseCertificateID != null)
+ {
+ return holder.BaseCertificateID.Serial.Value.Equals(x509Cert.SerialNumber)
+ && MatchesDN(PrincipalUtilities.GetIssuerX509Principal(x509Cert), holder.BaseCertificateID.Issuer);
+ }
+
+ if (holder.EntityName != null)
+ {
+ if (MatchesDN(PrincipalUtilities.GetSubjectX509Principal(x509Cert), holder.EntityName))
+ {
+ return true;
+ }
+ }
+
+ if (holder.ObjectDigestInfo != null)
+ {
+ IDigest md = null;
+ try
+ {
+ md = DigestUtilities.GetDigest(DigestAlgorithm);
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+
+ switch (DigestedObjectType)
+ {
+ case ObjectDigestInfo.PublicKey:
+ {
+ // TODO: DSA Dss-parms
+
+ //byte[] b = x509Cert.GetPublicKey().getEncoded();
+ // TODO Is this the right way to encode?
+ byte[] b = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(
+ x509Cert.GetPublicKey()).GetEncoded();
+ md.BlockUpdate(b, 0, b.Length);
+ break;
+ }
+
+ case ObjectDigestInfo.PublicKeyCert:
+ {
+ byte[] b = x509Cert.GetEncoded();
+ md.BlockUpdate(b, 0, b.Length);
+ break;
+ }
+
+ // TODO Default handler?
+ }
+
+ // TODO Shouldn't this be the other way around?
+ if (!Arrays.AreEqual(DigestUtilities.DoFinal(md), GetObjectDigest()))
+ {
+ return false;
+ }
+ }
+ }
+ catch (CertificateEncodingException)
+ {
+ return false;
+ }
+
+ return false;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj is AttributeCertificateHolder))
+ {
+ return false;
+ }
+
+ AttributeCertificateHolder other = (AttributeCertificateHolder)obj;
+
+ return this.holder.Equals(other.holder);
+ }
+
+ public override int GetHashCode()
+ {
+ return this.holder.GetHashCode();
+ }
+
+ public bool Match(
+ object obj)
+ {
+ if (!(obj is X509Certificate))
+ {
+ return false;
+ }
+
+// return Match((Certificate)obj);
+ return Match((X509Certificate)obj);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/AttributeCertificateIssuer.cs b/bc-sharp-crypto/src/x509/AttributeCertificateIssuer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7df1416d39b0bfc2148c9acb57047cffd74b3121
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/AttributeCertificateIssuer.cs
@@ -0,0 +1,199 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * Carrying class for an attribute certificate issuer.
+ */
+ public class AttributeCertificateIssuer
+ //: CertSelector, Selector
+ : IX509Selector
+ {
+ internal readonly Asn1Encodable form;
+
+ /**
+ * Set the issuer directly with the ASN.1 structure.
+ *
+ * @param issuer The issuer
+ */
+ public AttributeCertificateIssuer(
+ AttCertIssuer issuer)
+ {
+ form = issuer.Issuer;
+ }
+
+ public AttributeCertificateIssuer(
+ X509Name principal)
+ {
+// form = new V2Form(GeneralNames.GetInstance(new DerSequence(new GeneralName(principal))));
+ form = new V2Form(new GeneralNames(new GeneralName(principal)));
+ }
+
+ private object[] GetNames()
+ {
+ GeneralNames name;
+ if (form is V2Form)
+ {
+ name = ((V2Form)form).IssuerName;
+ }
+ else
+ {
+ name = (GeneralNames)form;
+ }
+
+ GeneralName[] names = name.GetNames();
+
+ int count = 0;
+ for (int i = 0; i != names.Length; i++)
+ {
+ if (names[i].TagNo == GeneralName.DirectoryName)
+ {
+ ++count;
+ }
+ }
+
+ object[] result = new object[count];
+
+ int pos = 0;
+ for (int i = 0; i != names.Length; i++)
+ {
+ if (names[i].TagNo == GeneralName.DirectoryName)
+ {
+ result[pos++] = X509Name.GetInstance(names[i].Name);
+ }
+ }
+
+ return result;
+ }
+
+ /// Return any principal objects inside the attribute certificate issuer object.
+ /// An array of IPrincipal objects (usually X509Principal).
+ public X509Name[] GetPrincipals()
+ {
+ object[] p = this.GetNames();
+
+ int count = 0;
+ for (int i = 0; i != p.Length; i++)
+ {
+ if (p[i] is X509Name)
+ {
+ ++count;
+ }
+ }
+
+ X509Name[] result = new X509Name[count];
+
+ int pos = 0;
+ for (int i = 0; i != p.Length; i++)
+ {
+ if (p[i] is X509Name)
+ {
+ result[pos++] = (X509Name)p[i];
+ }
+ }
+
+ return result;
+ }
+
+ private bool MatchesDN(
+ X509Name subject,
+ GeneralNames targets)
+ {
+ GeneralName[] names = targets.GetNames();
+
+ for (int i = 0; i != names.Length; i++)
+ {
+ GeneralName gn = names[i];
+
+ if (gn.TagNo == GeneralName.DirectoryName)
+ {
+ try
+ {
+ if (X509Name.GetInstance(gn.Name).Equivalent(subject))
+ {
+ return true;
+ }
+ }
+ catch (Exception)
+ {
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public object Clone()
+ {
+ return new AttributeCertificateIssuer(AttCertIssuer.GetInstance(form));
+ }
+
+ public bool Match(
+// Certificate cert)
+ X509Certificate x509Cert)
+ {
+// if (!(cert is X509Certificate))
+// {
+// return false;
+// }
+//
+// X509Certificate x509Cert = (X509Certificate)cert;
+
+ if (form is V2Form)
+ {
+ V2Form issuer = (V2Form) form;
+ if (issuer.BaseCertificateID != null)
+ {
+ return issuer.BaseCertificateID.Serial.Value.Equals(x509Cert.SerialNumber)
+ && MatchesDN(x509Cert.IssuerDN, issuer.BaseCertificateID.Issuer);
+ }
+
+ return MatchesDN(x509Cert.SubjectDN, issuer.IssuerName);
+ }
+
+ return MatchesDN(x509Cert.SubjectDN, (GeneralNames) form);
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj is AttributeCertificateIssuer))
+ {
+ return false;
+ }
+
+ AttributeCertificateIssuer other = (AttributeCertificateIssuer)obj;
+
+ return this.form.Equals(other.form);
+ }
+
+ public override int GetHashCode()
+ {
+ return this.form.GetHashCode();
+ }
+
+ public bool Match(
+ object obj)
+ {
+ if (!(obj is X509Certificate))
+ {
+ return false;
+ }
+
+ //return Match((Certificate)obj);
+ return Match((X509Certificate)obj);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/IX509AttributeCertificate.cs b/bc-sharp-crypto/src/x509/IX509AttributeCertificate.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9a3004e014d5726e4e4034a52e34fa6eaa2fbff8
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/IX509AttributeCertificate.cs
@@ -0,0 +1,57 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.X509
+{
+ /// Interface for an X.509 Attribute Certificate.
+ public interface IX509AttributeCertificate
+ : IX509Extension
+ {
+ /// The version number for the certificate.
+ int Version { get; }
+
+ /// The serial number for the certificate.
+ BigInteger SerialNumber { get; }
+
+ /// The UTC DateTime before which the certificate is not valid.
+ DateTime NotBefore { get; }
+
+ /// The UTC DateTime after which the certificate is not valid.
+ DateTime NotAfter { get; }
+
+ /// The holder of the certificate.
+ AttributeCertificateHolder Holder { get; }
+
+ /// The issuer details for the certificate.
+ AttributeCertificateIssuer Issuer { get; }
+
+ /// Return the attributes contained in the attribute block in the certificate.
+ /// An array of attributes.
+ X509Attribute[] GetAttributes();
+
+ /// Return the attributes with the same type as the passed in oid.
+ /// The object identifier we wish to match.
+ /// An array of matched attributes, null if there is no match.
+ X509Attribute[] GetAttributes(string oid);
+
+ bool[] GetIssuerUniqueID();
+
+ bool IsValidNow { get; }
+ bool IsValid(DateTime date);
+
+ void CheckValidity();
+ void CheckValidity(DateTime date);
+
+ byte[] GetSignature();
+
+ void Verify(AsymmetricKeyParameter publicKey);
+
+ /// Return an ASN.1 encoded byte array representing the attribute certificate.
+ /// An ASN.1 encoded byte array.
+ /// If the certificate cannot be encoded.
+ byte[] GetEncoded();
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/IX509Extension.cs b/bc-sharp-crypto/src/x509/IX509Extension.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e861e87368ef935252377a3def2afe6109bf90f1
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/IX509Extension.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.X509
+{
+ public interface IX509Extension
+ {
+ ///
+ /// Get all critical extension values, by oid
+ ///
+ /// IDictionary with string (OID) keys and Asn1OctetString values
+ ISet GetCriticalExtensionOids();
+
+ ///
+ /// Get all non-critical extension values, by oid
+ ///
+ /// IDictionary with string (OID) keys and Asn1OctetString values
+ ISet GetNonCriticalExtensionOids();
+
+ [Obsolete("Use version taking a DerObjectIdentifier instead")]
+ Asn1OctetString GetExtensionValue(string oid);
+
+ Asn1OctetString GetExtensionValue(DerObjectIdentifier oid);
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/PEMParser.cs b/bc-sharp-crypto/src/x509/PEMParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..28f28ee0a4006e3b7b1a6016fcef92b67c20f86e
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/PEMParser.cs
@@ -0,0 +1,95 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.X509
+{
+ class PemParser
+ {
+ private readonly string _header1;
+ private readonly string _header2;
+ private readonly string _footer1;
+ private readonly string _footer2;
+
+ internal PemParser(
+ string type)
+ {
+ _header1 = "-----BEGIN " + type + "-----";
+ _header2 = "-----BEGIN X509 " + type + "-----";
+ _footer1 = "-----END " + type + "-----";
+ _footer2 = "-----END X509 " + type + "-----";
+ }
+
+ private string ReadLine(
+ Stream inStream)
+ {
+ int c;
+ StringBuilder l = new StringBuilder();
+
+ do
+ {
+ while (((c = inStream.ReadByte()) != '\r') && c != '\n' && (c >= 0))
+ {
+ if (c == '\r')
+ {
+ continue;
+ }
+
+ l.Append((char)c);
+ }
+ }
+ while (c >= 0 && l.Length == 0);
+
+ if (c < 0)
+ {
+ return null;
+ }
+
+ return l.ToString();
+ }
+
+ internal Asn1Sequence ReadPemObject(
+ Stream inStream)
+ {
+ string line;
+ StringBuilder pemBuf = new StringBuilder();
+
+ while ((line = ReadLine(inStream)) != null)
+ {
+ if (Platform.StartsWith(line, _header1) || Platform.StartsWith(line, _header2))
+ {
+ break;
+ }
+ }
+
+ while ((line = ReadLine(inStream)) != null)
+ {
+ if (Platform.StartsWith(line, _footer1) || Platform.StartsWith(line, _footer2))
+ {
+ break;
+ }
+
+ pemBuf.Append(line);
+ }
+
+ if (pemBuf.Length != 0)
+ {
+ Asn1Object o = Asn1Object.FromByteArray(Base64.Decode(pemBuf.ToString()));
+
+ if (!(o is Asn1Sequence))
+ {
+ throw new IOException("malformed PEM data encountered");
+ }
+
+ return (Asn1Sequence) o;
+ }
+
+ return null;
+ }
+ }
+}
+
diff --git a/bc-sharp-crypto/src/x509/PrincipalUtil.cs b/bc-sharp-crypto/src/x509/PrincipalUtil.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0edc4a3959a6df3416ad3ac92dcd9c3f80560498
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/PrincipalUtil.cs
@@ -0,0 +1,70 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// A utility class that will extract X509Principal objects from X.509 certificates.
+ ///
+ /// Use this in preference to trying to recreate a principal from a string, not all
+ /// DNs are what they should be, so it's best to leave them encoded where they
+ /// can be.
+ ///
+ public class PrincipalUtilities
+ {
+ /// Return the issuer of the given cert as an X509Principal.
+ public static X509Name GetIssuerX509Principal(
+ X509Certificate cert)
+ {
+ try
+ {
+ TbsCertificateStructure tbsCert = TbsCertificateStructure.GetInstance(
+ Asn1Object.FromByteArray(cert.GetTbsCertificate()));
+
+ return tbsCert.Issuer;
+ }
+ catch (Exception e)
+ {
+ throw new CertificateEncodingException("Could not extract issuer", e);
+ }
+ }
+
+ /// Return the subject of the given cert as an X509Principal.
+ public static X509Name GetSubjectX509Principal(
+ X509Certificate cert)
+ {
+ try
+ {
+ TbsCertificateStructure tbsCert = TbsCertificateStructure.GetInstance(
+ Asn1Object.FromByteArray(cert.GetTbsCertificate()));
+
+ return tbsCert.Subject;
+ }
+ catch (Exception e)
+ {
+ throw new CertificateEncodingException("Could not extract subject", e);
+ }
+ }
+
+ /// Return the issuer of the given CRL as an X509Principal.
+ public static X509Name GetIssuerX509Principal(
+ X509Crl crl)
+ {
+ try
+ {
+ TbsCertificateList tbsCertList = TbsCertificateList.GetInstance(
+ Asn1Object.FromByteArray(crl.GetTbsCertList()));
+
+ return tbsCertList.Issuer;
+ }
+ catch (Exception e)
+ {
+ throw new CrlException("Could not extract issuer", e);
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/SubjectPublicKeyInfoFactory.cs b/bc-sharp-crypto/src/x509/SubjectPublicKeyInfoFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7614321d4cccec1b09847543f79da6e4f2c03261
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/SubjectPublicKeyInfoFactory.cs
@@ -0,0 +1,184 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// A factory to produce Public Key Info Objects.
+ ///
+ public sealed class SubjectPublicKeyInfoFactory
+ {
+ private SubjectPublicKeyInfoFactory()
+ {
+ }
+
+ ///
+ /// Create a Subject Public Key Info object for a given public key.
+ ///
+ /// One of ElGammalPublicKeyParameters, DSAPublicKeyParameter, DHPublicKeyParameters, RsaKeyParameters or ECPublicKeyParameters
+ /// A subject public key info object.
+ /// Throw exception if object provided is not one of the above.
+ public static SubjectPublicKeyInfo CreateSubjectPublicKeyInfo(
+ AsymmetricKeyParameter key)
+ {
+ if (key == null)
+ throw new ArgumentNullException("key");
+ if (key.IsPrivate)
+ throw new ArgumentException("Private key passed - public key expected.", "key");
+
+ if (key is ElGamalPublicKeyParameters)
+ {
+ ElGamalPublicKeyParameters _key = (ElGamalPublicKeyParameters)key;
+ ElGamalParameters kp = _key.Parameters;
+
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier(
+ OiwObjectIdentifiers.ElGamalAlgorithm,
+ new ElGamalParameter(kp.P, kp.G).ToAsn1Object()),
+ new DerInteger(_key.Y));
+
+ return info;
+ }
+
+ if (key is DsaPublicKeyParameters)
+ {
+ DsaPublicKeyParameters _key = (DsaPublicKeyParameters) key;
+ DsaParameters kp = _key.Parameters;
+ Asn1Encodable ae = kp == null
+ ? null
+ : new DsaParameter(kp.P, kp.Q, kp.G).ToAsn1Object();
+
+ return new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier(X9ObjectIdentifiers.IdDsa, ae),
+ new DerInteger(_key.Y));
+ }
+
+ if (key is DHPublicKeyParameters)
+ {
+ DHPublicKeyParameters _key = (DHPublicKeyParameters) key;
+ DHParameters kp = _key.Parameters;
+
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier(
+ _key.AlgorithmOid,
+ new DHParameter(kp.P, kp.G, kp.L).ToAsn1Object()),
+ new DerInteger(_key.Y));
+
+ return info;
+ } // End of DH
+
+ if (key is RsaKeyParameters)
+ {
+ RsaKeyParameters _key = (RsaKeyParameters) key;
+
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier(PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance),
+ new RsaPublicKeyStructure(_key.Modulus, _key.Exponent).ToAsn1Object());
+
+ return info;
+ } // End of RSA.
+
+ if (key is ECPublicKeyParameters)
+ {
+ ECPublicKeyParameters _key = (ECPublicKeyParameters) key;
+
+ if (_key.AlgorithmName == "ECGOST3410")
+ {
+ if (_key.PublicKeyParamSet == null)
+ throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
+
+ ECPoint q = _key.Q.Normalize();
+ BigInteger bX = q.AffineXCoord.ToBigInteger();
+ BigInteger bY = q.AffineYCoord.ToBigInteger();
+
+ byte[] encKey = new byte[64];
+ ExtractBytes(encKey, 0, bX);
+ ExtractBytes(encKey, 32, bY);
+
+ Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
+ _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(
+ CryptoProObjectIdentifiers.GostR3410x2001,
+ gostParams.ToAsn1Object());
+
+ return new SubjectPublicKeyInfo(algID, new DerOctetString(encKey));
+ }
+ else
+ {
+ X962Parameters x962;
+ if (_key.PublicKeyParamSet == null)
+ {
+ ECDomainParameters kp = _key.Parameters;
+ X9ECParameters ecP = new X9ECParameters(kp.Curve, kp.G, kp.N, kp.H, kp.GetSeed());
+
+ x962 = new X962Parameters(ecP);
+ }
+ else
+ {
+ x962 = new X962Parameters(_key.PublicKeyParamSet);
+ }
+
+ Asn1OctetString p = (Asn1OctetString)(new X9ECPoint(_key.Q).ToAsn1Object());
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(
+ X9ObjectIdentifiers.IdECPublicKey, x962.ToAsn1Object());
+
+ return new SubjectPublicKeyInfo(algID, p.GetOctets());
+ }
+ } // End of EC
+
+ if (key is Gost3410PublicKeyParameters)
+ {
+ Gost3410PublicKeyParameters _key = (Gost3410PublicKeyParameters) key;
+
+ if (_key.PublicKeyParamSet == null)
+ throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
+
+ byte[] keyEnc = _key.Y.ToByteArrayUnsigned();
+ byte[] keyBytes = new byte[keyEnc.Length];
+
+ for (int i = 0; i != keyBytes.Length; i++)
+ {
+ keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // must be little endian
+ }
+
+ Gost3410PublicKeyAlgParameters algParams = new Gost3410PublicKeyAlgParameters(
+ _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
+
+ AlgorithmIdentifier algID = new AlgorithmIdentifier(
+ CryptoProObjectIdentifiers.GostR3410x94,
+ algParams.ToAsn1Object());
+
+ return new SubjectPublicKeyInfo(algID, new DerOctetString(keyBytes));
+ }
+
+ throw new ArgumentException("Class provided no convertible: " + Platform.GetTypeName(key));
+ }
+
+ private static void ExtractBytes(
+ byte[] encKey,
+ int offset,
+ BigInteger bI)
+ {
+ byte[] val = bI.ToByteArray();
+ int n = (bI.BitLength + 7) / 8;
+
+ for (int i = 0; i < n; ++i)
+ {
+ encKey[offset + i] = val[val.Length - 1 - i];
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/X509AttrCertParser.cs b/bc-sharp-crypto/src/x509/X509AttrCertParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a5c07362ee475cb0f6adc4eaf1866c505457c256
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/X509AttrCertParser.cs
@@ -0,0 +1,173 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.X509
+{
+ public class X509AttrCertParser
+ {
+ private static readonly PemParser PemAttrCertParser = new PemParser("ATTRIBUTE CERTIFICATE");
+
+ private Asn1Set sData;
+ private int sDataObjectCount;
+ private Stream currentStream;
+
+ private IX509AttributeCertificate ReadDerCertificate(
+ Asn1InputStream dIn)
+ {
+ Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject();
+
+ if (seq.Count > 1 && seq[0] is DerObjectIdentifier)
+ {
+ if (seq[0].Equals(PkcsObjectIdentifiers.SignedData))
+ {
+ sData = SignedData.GetInstance(
+ Asn1Sequence.GetInstance((Asn1TaggedObject) seq[1], true)).Certificates;
+
+ return GetCertificate();
+ }
+ }
+
+// return new X509V2AttributeCertificate(seq.getEncoded());
+ return new X509V2AttributeCertificate(AttributeCertificate.GetInstance(seq));
+ }
+
+ private IX509AttributeCertificate GetCertificate()
+ {
+ if (sData != null)
+ {
+ while (sDataObjectCount < sData.Count)
+ {
+ object obj = sData[sDataObjectCount++];
+
+ if (obj is Asn1TaggedObject && ((Asn1TaggedObject)obj).TagNo == 2)
+ {
+ //return new X509V2AttributeCertificate(
+ // Asn1Sequence.GetInstance((Asn1TaggedObject)obj, false).GetEncoded());
+ return new X509V2AttributeCertificate(
+ AttributeCertificate.GetInstance(
+ Asn1Sequence.GetInstance((Asn1TaggedObject)obj, false)));
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private IX509AttributeCertificate ReadPemCertificate(
+ Stream inStream)
+ {
+ Asn1Sequence seq = PemAttrCertParser.ReadPemObject(inStream);
+
+ return seq == null
+ ? null
+ //: new X509V2AttributeCertificate(seq.getEncoded());
+ : new X509V2AttributeCertificate(AttributeCertificate.GetInstance(seq));
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public IX509AttributeCertificate ReadAttrCert(
+ byte[] input)
+ {
+ return ReadAttrCert(new MemoryStream(input, false));
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public ICollection ReadAttrCerts(
+ byte[] input)
+ {
+ return ReadAttrCerts(new MemoryStream(input, false));
+ }
+
+ /**
+ * Generates a certificate object and initializes it with the data
+ * read from the input stream inStream.
+ */
+ public IX509AttributeCertificate ReadAttrCert(
+ Stream inStream)
+ {
+ if (inStream == null)
+ throw new ArgumentNullException("inStream");
+ if (!inStream.CanRead)
+ throw new ArgumentException("inStream must be read-able", "inStream");
+
+ if (currentStream == null)
+ {
+ currentStream = inStream;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+ else if (currentStream != inStream) // reset if input stream has changed
+ {
+ currentStream = inStream;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+
+ try
+ {
+ if (sData != null)
+ {
+ if (sDataObjectCount != sData.Count)
+ {
+ return GetCertificate();
+ }
+
+ sData = null;
+ sDataObjectCount = 0;
+ return null;
+ }
+
+ PushbackStream pis = new PushbackStream(inStream);
+ int tag = pis.ReadByte();
+
+ if (tag < 0)
+ return null;
+
+ pis.Unread(tag);
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ return ReadPemCertificate(pis);
+ }
+
+ return ReadDerCertificate(new Asn1InputStream(pis));
+ }
+ catch (Exception e)
+ {
+ throw new CertificateException(e.ToString());
+ }
+ }
+
+ /**
+ * Returns a (possibly empty) collection view of the certificates
+ * read from the given input stream inStream.
+ */
+ public ICollection ReadAttrCerts(
+ Stream inStream)
+ {
+ IX509AttributeCertificate attrCert;
+ IList attrCerts = Platform.CreateArrayList();
+
+ while ((attrCert = ReadAttrCert(inStream)) != null)
+ {
+ attrCerts.Add(attrCert);
+ }
+
+ return attrCerts;
+ }
+ }
+}
\ No newline at end of file
diff --git a/bc-sharp-crypto/src/x509/X509Attribute.cs b/bc-sharp-crypto/src/x509/X509Attribute.cs
new file mode 100644
index 0000000000000000000000000000000000000000..248d66cc4f5fbc798f93be9d59586ab1f2e3072a
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/X509Attribute.cs
@@ -0,0 +1,76 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * Class for carrying the values in an X.509 Attribute.
+ */
+ public class X509Attribute
+ : Asn1Encodable
+ {
+ private readonly AttributeX509 attr;
+
+ /**
+ * @param at an object representing an attribute.
+ */
+ internal X509Attribute(
+ Asn1Encodable at)
+ {
+ this.attr = AttributeX509.GetInstance(at);
+ }
+
+ /**
+ * Create an X.509 Attribute with the type given by the passed in oid and
+ * the value represented by an ASN.1 Set containing value.
+ *
+ * @param oid type of the attribute
+ * @param value value object to go into the atribute's value set.
+ */
+ public X509Attribute(
+ string oid,
+ Asn1Encodable value)
+ {
+ this.attr = new AttributeX509(new DerObjectIdentifier(oid), new DerSet(value));
+ }
+
+ /**
+ * Create an X.59 Attribute with the type given by the passed in oid and the
+ * value represented by an ASN.1 Set containing the objects in value.
+ *
+ * @param oid type of the attribute
+ * @param value vector of values to go in the attribute's value set.
+ */
+ public X509Attribute(
+ string oid,
+ Asn1EncodableVector value)
+ {
+ this.attr = new AttributeX509(new DerObjectIdentifier(oid), new DerSet(value));
+ }
+
+ public string Oid
+ {
+ get { return attr.AttrType.Id; }
+ }
+
+ public Asn1Encodable[] GetValues()
+ {
+ Asn1Set s = attr.AttrValues;
+ Asn1Encodable[] values = new Asn1Encodable[s.Count];
+
+ for (int i = 0; i != s.Count; i++)
+ {
+ values[i] = (Asn1Encodable)s[i];
+ }
+
+ return values;
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return attr.ToAsn1Object();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/X509CertPairParser.cs b/bc-sharp-crypto/src/x509/X509CertPairParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..82612599b7495e6581fc42b6fc4dd35e3bd1efc4
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/X509CertPairParser.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.X509
+{
+ public class X509CertPairParser
+ {
+ private Stream currentStream;
+
+ private X509CertificatePair ReadDerCrossCertificatePair(
+ Stream inStream)
+ {
+ Asn1InputStream dIn = new Asn1InputStream(inStream);//, ProviderUtil.getReadLimit(in));
+ Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject();
+ CertificatePair pair = CertificatePair.GetInstance(seq);
+ return new X509CertificatePair(pair);
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public X509CertificatePair ReadCertPair(
+ byte[] input)
+ {
+ return ReadCertPair(new MemoryStream(input, false));
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public ICollection ReadCertPairs(
+ byte[] input)
+ {
+ return ReadCertPairs(new MemoryStream(input, false));
+ }
+
+ public X509CertificatePair ReadCertPair(
+ Stream inStream)
+ {
+ if (inStream == null)
+ throw new ArgumentNullException("inStream");
+ if (!inStream.CanRead)
+ throw new ArgumentException("inStream must be read-able", "inStream");
+
+ if (currentStream == null)
+ {
+ currentStream = inStream;
+ }
+ else if (currentStream != inStream) // reset if input stream has changed
+ {
+ currentStream = inStream;
+ }
+
+ try
+ {
+ PushbackStream pis = new PushbackStream(inStream);
+ int tag = pis.ReadByte();
+
+ if (tag < 0)
+ return null;
+
+ pis.Unread(tag);
+
+ return ReadDerCrossCertificatePair(pis);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateException(e.ToString());
+ }
+ }
+
+ public ICollection ReadCertPairs(
+ Stream inStream)
+ {
+ X509CertificatePair certPair;
+ IList certPairs = Platform.CreateArrayList();
+
+ while ((certPair = ReadCertPair(inStream)) != null)
+ {
+ certPairs.Add(certPair);
+ }
+
+ return certPairs;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/X509Certificate.cs b/bc-sharp-crypto/src/x509/X509Certificate.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6d7bd7a6143823d5274eaa8404ba000b2f1e0cb1
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/X509Certificate.cs
@@ -0,0 +1,604 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Misc;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.X509.Extension;
+using Org.BouncyCastle.Crypto.Operators;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// An Object representing an X509 Certificate.
+ /// Has static methods for loading Certificates encoded in many forms that return X509Certificate Objects.
+ ///
+ public class X509Certificate
+ : X509ExtensionBase
+// , PKCS12BagAttributeCarrier
+ {
+ private readonly X509CertificateStructure c;
+// private Hashtable pkcs12Attributes = new Hashtable();
+// private ArrayList pkcs12Ordering = new ArrayList();
+ private readonly BasicConstraints basicConstraints;
+ private readonly bool[] keyUsage;
+
+ private bool hashValueSet;
+ private int hashValue;
+
+ protected X509Certificate()
+ {
+ }
+
+ public X509Certificate(
+ X509CertificateStructure c)
+ {
+ this.c = c;
+
+ try
+ {
+ Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.19"));
+
+ if (str != null)
+ {
+ basicConstraints = BasicConstraints.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(str));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct BasicConstraints: " + e);
+ }
+
+ try
+ {
+ Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.15"));
+
+ if (str != null)
+ {
+ DerBitString bits = DerBitString.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(str));
+
+ byte[] bytes = bits.GetBytes();
+ int length = (bytes.Length * 8) - bits.PadBits;
+
+ keyUsage = new bool[(length < 9) ? 9 : length];
+
+ for (int i = 0; i != length; i++)
+ {
+// keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ keyUsage[i] = (bytes[i / 8] & (0x80 >> (i % 8))) != 0;
+ }
+ }
+ else
+ {
+ keyUsage = null;
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct KeyUsage: " + e);
+ }
+ }
+
+// internal X509Certificate(
+// Asn1Sequence seq)
+// {
+// this.c = X509CertificateStructure.GetInstance(seq);
+// }
+
+// ///
+// /// Load certificate from byte array.
+// ///
+// /// Byte array containing encoded X509Certificate.
+// public X509Certificate(
+// byte[] encoded)
+// : this((Asn1Sequence) new Asn1InputStream(encoded).ReadObject())
+// {
+// }
+//
+// ///
+// /// Load certificate from Stream.
+// /// Must be positioned at start of certificate.
+// ///
+// ///
+// public X509Certificate(
+// Stream input)
+// : this((Asn1Sequence) new Asn1InputStream(input).ReadObject())
+// {
+// }
+
+ public virtual X509CertificateStructure CertificateStructure
+ {
+ get { return c; }
+ }
+
+ ///
+ /// Return true if the current time is within the start and end times nominated on the certificate.
+ ///
+ /// true id certificate is valid for the current time.
+ public virtual bool IsValidNow
+ {
+ get { return IsValid(DateTime.UtcNow); }
+ }
+
+ ///
+ /// Return true if the nominated time is within the start and end times nominated on the certificate.
+ ///
+ /// The time to test validity against.
+ /// True if certificate is valid for nominated time.
+ public virtual bool IsValid(
+ DateTime time)
+ {
+ return time.CompareTo(NotBefore) >= 0 && time.CompareTo(NotAfter) <= 0;
+ }
+
+ ///
+ /// Checks if the current date is within certificate's validity period.
+ ///
+ public virtual void CheckValidity()
+ {
+ this.CheckValidity(DateTime.UtcNow);
+ }
+
+ ///
+ /// Checks if the given date is within certificate's validity period.
+ ///
+ /// if the certificate is expired by given date
+ /// if the certificate is not yet valid on given date
+ public virtual void CheckValidity(
+ DateTime time)
+ {
+ if (time.CompareTo(NotAfter) > 0)
+ throw new CertificateExpiredException("certificate expired on " + c.EndDate.GetTime());
+ if (time.CompareTo(NotBefore) < 0)
+ throw new CertificateNotYetValidException("certificate not valid until " + c.StartDate.GetTime());
+ }
+
+ ///
+ /// Return the certificate's version.
+ ///
+ /// An integer whose value Equals the version of the cerficate.
+ public virtual int Version
+ {
+ get { return c.Version; }
+ }
+
+ ///
+ /// Return a BigInteger containing the serial number.
+ ///
+ /// The Serial number.
+ public virtual BigInteger SerialNumber
+ {
+ get { return c.SerialNumber.Value; }
+ }
+
+ ///
+ /// Get the Issuer Distinguished Name. (Who signed the certificate.)
+ ///
+ /// And X509Object containing name and value pairs.
+// public IPrincipal IssuerDN
+ public virtual X509Name IssuerDN
+ {
+ get { return c.Issuer; }
+ }
+
+ ///
+ /// Get the subject of this certificate.
+ ///
+ /// An X509Name object containing name and value pairs.
+// public IPrincipal SubjectDN
+ public virtual X509Name SubjectDN
+ {
+ get { return c.Subject; }
+ }
+
+ ///
+ /// The time that this certificate is valid from.
+ ///
+ /// A DateTime object representing that time in the local time zone.
+ public virtual DateTime NotBefore
+ {
+ get { return c.StartDate.ToDateTime(); }
+ }
+
+ ///
+ /// The time that this certificate is valid up to.
+ ///
+ /// A DateTime object representing that time in the local time zone.
+ public virtual DateTime NotAfter
+ {
+ get { return c.EndDate.ToDateTime(); }
+ }
+
+ ///
+ /// Return the Der encoded TbsCertificate data.
+ /// This is the certificate component less the signature.
+ /// To Get the whole certificate call the GetEncoded() member.
+ ///
+ /// A byte array containing the Der encoded Certificate component.
+ public virtual byte[] GetTbsCertificate()
+ {
+ return c.TbsCertificate.GetDerEncoded();
+ }
+
+ ///
+ /// The signature.
+ ///
+ /// A byte array containg the signature of the certificate.
+ public virtual byte[] GetSignature()
+ {
+ return c.GetSignatureOctets();
+ }
+
+ ///
+ /// A meaningful version of the Signature Algorithm. (EG SHA1WITHRSA)
+ ///
+ /// A sting representing the signature algorithm.
+ public virtual string SigAlgName
+ {
+ get { return SignerUtilities.GetEncodingName(c.SignatureAlgorithm.Algorithm); }
+ }
+
+ ///
+ /// Get the Signature Algorithms Object ID.
+ ///
+ /// A string containg a '.' separated object id.
+ public virtual string SigAlgOid
+ {
+ get { return c.SignatureAlgorithm.Algorithm.Id; }
+ }
+
+ ///
+ /// Get the signature algorithms parameters. (EG DSA Parameters)
+ ///
+ /// A byte array containing the Der encoded version of the parameters or null if there are none.
+ public virtual byte[] GetSigAlgParams()
+ {
+ if (c.SignatureAlgorithm.Parameters != null)
+ {
+ return c.SignatureAlgorithm.Parameters.GetDerEncoded();
+ }
+
+ return null;
+ }
+
+ ///
+ /// Get the issuers UID.
+ ///
+ /// A DerBitString.
+ public virtual DerBitString IssuerUniqueID
+ {
+ get { return c.TbsCertificate.IssuerUniqueID; }
+ }
+
+ ///
+ /// Get the subjects UID.
+ ///
+ /// A DerBitString.
+ public virtual DerBitString SubjectUniqueID
+ {
+ get { return c.TbsCertificate.SubjectUniqueID; }
+ }
+
+ ///
+ /// Get a key usage guidlines.
+ ///
+ public virtual bool[] GetKeyUsage()
+ {
+ return keyUsage == null ? null : (bool[]) keyUsage.Clone();
+ }
+
+ // TODO Replace with something that returns a list of DerObjectIdentifier
+ public virtual IList GetExtendedKeyUsage()
+ {
+ Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.37"));
+
+ if (str == null)
+ return null;
+
+ try
+ {
+ Asn1Sequence seq = Asn1Sequence.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(str));
+
+ IList list = Platform.CreateArrayList();
+
+ foreach (DerObjectIdentifier oid in seq)
+ {
+ list.Add(oid.Id);
+ }
+
+ return list;
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("error processing extended key usage extension", e);
+ }
+ }
+
+ public virtual int GetBasicConstraints()
+ {
+ if (basicConstraints != null && basicConstraints.IsCA())
+ {
+ if (basicConstraints.PathLenConstraint == null)
+ {
+ return int.MaxValue;
+ }
+
+ return basicConstraints.PathLenConstraint.IntValue;
+ }
+
+ return -1;
+ }
+
+ public virtual ICollection GetSubjectAlternativeNames()
+ {
+ return GetAlternativeNames("2.5.29.17");
+ }
+
+ public virtual ICollection GetIssuerAlternativeNames()
+ {
+ return GetAlternativeNames("2.5.29.18");
+ }
+
+ protected virtual ICollection GetAlternativeNames(
+ string oid)
+ {
+ Asn1OctetString altNames = GetExtensionValue(new DerObjectIdentifier(oid));
+
+ if (altNames == null)
+ return null;
+
+ Asn1Object asn1Object = X509ExtensionUtilities.FromExtensionValue(altNames);
+
+ GeneralNames gns = GeneralNames.GetInstance(asn1Object);
+
+ IList result = Platform.CreateArrayList();
+ foreach (GeneralName gn in gns.GetNames())
+ {
+ IList entry = Platform.CreateArrayList();
+ entry.Add(gn.TagNo);
+ entry.Add(gn.Name.ToString());
+ result.Add(entry);
+ }
+ return result;
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return c.Version >= 3
+ ? c.TbsCertificate.Extensions
+ : null;
+ }
+
+ ///
+ /// Get the public key of the subject of the certificate.
+ ///
+ /// The public key parameters.
+ public virtual AsymmetricKeyParameter GetPublicKey()
+ {
+ return PublicKeyFactory.CreateKey(c.SubjectPublicKeyInfo);
+ }
+
+ ///
+ /// Return a Der encoded version of this certificate.
+ ///
+ /// A byte array.
+ public virtual byte[] GetEncoded()
+ {
+ return c.GetDerEncoded();
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ X509Certificate other = obj as X509Certificate;
+
+ if (other == null)
+ return false;
+
+ return c.Equals(other.c);
+
+ // NB: May prefer this implementation of Equals if more than one certificate implementation in play
+// return Arrays.AreEqual(this.GetEncoded(), other.GetEncoded());
+ }
+
+ public override int GetHashCode()
+ {
+ lock (this)
+ {
+ if (!hashValueSet)
+ {
+ hashValue = c.GetHashCode();
+ hashValueSet = true;
+ }
+ }
+
+ return hashValue;
+ }
+
+// public void setBagAttribute(
+// DERObjectIdentifier oid,
+// DEREncodable attribute)
+// {
+// pkcs12Attributes.put(oid, attribute);
+// pkcs12Ordering.addElement(oid);
+// }
+//
+// public DEREncodable getBagAttribute(
+// DERObjectIdentifier oid)
+// {
+// return (DEREncodable)pkcs12Attributes.get(oid);
+// }
+//
+// public Enumeration getBagAttributeKeys()
+// {
+// return pkcs12Ordering.elements();
+// }
+
+ public override string ToString()
+ {
+ StringBuilder buf = new StringBuilder();
+ string nl = Platform.NewLine;
+
+ buf.Append(" [0] Version: ").Append(this.Version).Append(nl);
+ buf.Append(" SerialNumber: ").Append(this.SerialNumber).Append(nl);
+ buf.Append(" IssuerDN: ").Append(this.IssuerDN).Append(nl);
+ buf.Append(" Start Date: ").Append(this.NotBefore).Append(nl);
+ buf.Append(" Final Date: ").Append(this.NotAfter).Append(nl);
+ buf.Append(" SubjectDN: ").Append(this.SubjectDN).Append(nl);
+ buf.Append(" Public Key: ").Append(this.GetPublicKey()).Append(nl);
+ buf.Append(" Signature Algorithm: ").Append(this.SigAlgName).Append(nl);
+
+ byte[] sig = this.GetSignature();
+ buf.Append(" Signature: ").Append(Hex.ToHexString(sig, 0, 20)).Append(nl);
+
+ for (int i = 20; i < sig.Length; i += 20)
+ {
+ int len = System.Math.Min(20, sig.Length - i);
+ buf.Append(" ").Append(Hex.ToHexString(sig, i, len)).Append(nl);
+ }
+
+ X509Extensions extensions = c.TbsCertificate.Extensions;
+
+ if (extensions != null)
+ {
+ IEnumerator e = extensions.ExtensionOids.GetEnumerator();
+
+ if (e.MoveNext())
+ {
+ buf.Append(" Extensions: \n");
+ }
+
+ do
+ {
+ DerObjectIdentifier oid = (DerObjectIdentifier)e.Current;
+ X509Extension ext = extensions.GetExtension(oid);
+
+ if (ext.Value != null)
+ {
+ byte[] octs = ext.Value.GetOctets();
+ Asn1Object obj = Asn1Object.FromByteArray(octs);
+ buf.Append(" critical(").Append(ext.IsCritical).Append(") ");
+ try
+ {
+ if (oid.Equals(X509Extensions.BasicConstraints))
+ {
+ buf.Append(BasicConstraints.GetInstance(obj));
+ }
+ else if (oid.Equals(X509Extensions.KeyUsage))
+ {
+ buf.Append(KeyUsage.GetInstance(obj));
+ }
+ else if (oid.Equals(MiscObjectIdentifiers.NetscapeCertType))
+ {
+ buf.Append(new NetscapeCertType((DerBitString) obj));
+ }
+ else if (oid.Equals(MiscObjectIdentifiers.NetscapeRevocationUrl))
+ {
+ buf.Append(new NetscapeRevocationUrl((DerIA5String) obj));
+ }
+ else if (oid.Equals(MiscObjectIdentifiers.VerisignCzagExtension))
+ {
+ buf.Append(new VerisignCzagExtension((DerIA5String) obj));
+ }
+ else
+ {
+ buf.Append(oid.Id);
+ buf.Append(" value = ").Append(Asn1Dump.DumpAsString(obj));
+ //buf.Append(" value = ").Append("*****").Append(nl);
+ }
+ }
+ catch (Exception)
+ {
+ buf.Append(oid.Id);
+ //buf.Append(" value = ").Append(new string(Hex.encode(ext.getValue().getOctets()))).Append(nl);
+ buf.Append(" value = ").Append("*****");
+ }
+ }
+
+ buf.Append(nl);
+ }
+ while (e.MoveNext());
+ }
+
+ return buf.ToString();
+ }
+
+ ///
+ /// Verify the certificate's signature using the nominated public key.
+ ///
+ /// An appropriate public key parameter object, RsaPublicKeyParameters, DsaPublicKeyParameters or ECDsaPublicKeyParameters
+ /// True if the signature is valid.
+ /// If key submitted is not of the above nominated types.
+ public virtual void Verify(
+ AsymmetricKeyParameter key)
+ {
+ CheckSignature(new Asn1VerifierFactory(c.SignatureAlgorithm, key));
+ }
+
+ ///
+ /// Verify the certificate's signature using a verifier created using the passed in verifier provider.
+ ///
+ /// An appropriate provider for verifying the certificate's signature.
+ /// True if the signature is valid.
+ /// If verifier provider is not appropriate or the certificate algorithm is invalid.
+ public virtual void Verify(
+ IVerifierFactoryProvider verifierProvider)
+ {
+ CheckSignature(verifierProvider.CreateVerifierFactory (c.SignatureAlgorithm));
+ }
+
+ protected virtual void CheckSignature(
+ IVerifierFactory verifier)
+ {
+ if (!IsAlgIDEqual(c.SignatureAlgorithm, c.TbsCertificate.Signature))
+ throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
+
+ Asn1Encodable parameters = c.SignatureAlgorithm.Parameters;
+
+ IStreamCalculator streamCalculator = verifier.CreateCalculator();
+
+ byte[] b = this.GetTbsCertificate();
+
+ streamCalculator.Stream.Write(b, 0, b.Length);
+
+ Platform.Dispose(streamCalculator.Stream);
+
+ if (!((IVerifier)streamCalculator.GetResult()).IsVerified(this.GetSignature()))
+ {
+ throw new InvalidKeyException("Public key presented not for certificate signature");
+ }
+ }
+
+ private static bool IsAlgIDEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2)
+ {
+ if (!id1.Algorithm.Equals(id2.Algorithm))
+ return false;
+
+ Asn1Encodable p1 = id1.Parameters;
+ Asn1Encodable p2 = id2.Parameters;
+
+ if ((p1 == null) == (p2 == null))
+ return Platform.Equals(p1, p2);
+
+ // Exactly one of p1, p2 is null at this point
+ return p1 == null
+ ? p2.ToAsn1Object() is Asn1Null
+ : p1.ToAsn1Object() is Asn1Null;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/X509CertificatePair.cs b/bc-sharp-crypto/src/x509/X509CertificatePair.cs
new file mode 100644
index 0000000000000000000000000000000000000000..fbeba4dc619b3547accde346697d2493b03459bb
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/X509CertificatePair.cs
@@ -0,0 +1,123 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// This class contains a cross certificate pair. Cross certificates pairs may
+ /// contain two cross signed certificates from two CAs. A certificate from the
+ /// other CA to this CA is contained in the forward certificate, the certificate
+ /// from this CA to the other CA is contained in the reverse certificate.
+ ///
+ public class X509CertificatePair
+ {
+ private readonly X509Certificate forward;
+ private readonly X509Certificate reverse;
+
+ /// Constructor
+ /// Certificate from the other CA to this CA.
+ /// Certificate from this CA to the other CA.
+ public X509CertificatePair(
+ X509Certificate forward,
+ X509Certificate reverse)
+ {
+ this.forward = forward;
+ this.reverse = reverse;
+ }
+
+ /// Constructor from a ASN.1 CertificatePair structure.
+ /// The CertificatePair ASN.1 object.
+ public X509CertificatePair(
+ CertificatePair pair)
+ {
+ if (pair.Forward != null)
+ {
+ this.forward = new X509Certificate(pair.Forward);
+ }
+ if (pair.Reverse != null)
+ {
+ this.reverse = new X509Certificate(pair.Reverse);
+ }
+ }
+
+ public byte[] GetEncoded()
+ {
+ try
+ {
+ X509CertificateStructure f = null, r = null;
+
+ if (forward != null)
+ {
+ f = X509CertificateStructure.GetInstance(
+ Asn1Object.FromByteArray(forward.GetEncoded()));
+
+ if (f == null)
+ throw new CertificateEncodingException("unable to get encoding for forward");
+ }
+
+ if (reverse != null)
+ {
+ r = X509CertificateStructure.GetInstance(
+ Asn1Object.FromByteArray(reverse.GetEncoded()));
+
+ if (r == null)
+ throw new CertificateEncodingException("unable to get encoding for reverse");
+ }
+
+ return new CertificatePair(f, r).GetDerEncoded();
+ }
+ catch (Exception e)
+ {
+ // TODO
+// throw new ExtCertificateEncodingException(e.toString(), e);
+ throw new CertificateEncodingException(e.Message, e);
+ }
+ }
+
+ /// Returns the certificate from the other CA to this CA.
+ public X509Certificate Forward
+ {
+ get { return forward; }
+ }
+
+ /// Returns the certificate from this CA to the other CA.
+ public X509Certificate Reverse
+ {
+ get { return reverse; }
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ X509CertificatePair other = obj as X509CertificatePair;
+
+ if (other == null)
+ return false;
+
+ return Platform.Equals(this.forward, other.forward)
+ && Platform.Equals(this.reverse, other.reverse);
+ }
+
+ public override int GetHashCode()
+ {
+ int hash = -1;
+ if (forward != null)
+ {
+ hash ^= forward.GetHashCode();
+ }
+ if (reverse != null)
+ {
+ hash *= 17;
+ hash ^= reverse.GetHashCode();
+ }
+ return hash;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/X509CertificateParser.cs b/bc-sharp-crypto/src/x509/X509CertificateParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8f0e7406c9b1b6cd3ba6de529e1e7edab8f790c3
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/X509CertificateParser.cs
@@ -0,0 +1,183 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * class for dealing with X509 certificates.
+ *
+ * At the moment this will deal with "-----BEGIN CERTIFICATE-----" to "-----END CERTIFICATE-----"
+ * base 64 encoded certs, as well as the BER binaries of certificates and some classes of PKCS#7
+ * objects.
+ */
+ public class X509CertificateParser
+ {
+ private static readonly PemParser PemCertParser = new PemParser("CERTIFICATE");
+
+ private Asn1Set sData;
+ private int sDataObjectCount;
+ private Stream currentStream;
+
+ private X509Certificate ReadDerCertificate(
+ Asn1InputStream dIn)
+ {
+ Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject();
+
+ if (seq.Count > 1 && seq[0] is DerObjectIdentifier)
+ {
+ if (seq[0].Equals(PkcsObjectIdentifiers.SignedData))
+ {
+ sData = SignedData.GetInstance(
+ Asn1Sequence.GetInstance((Asn1TaggedObject) seq[1], true)).Certificates;
+
+ return GetCertificate();
+ }
+ }
+
+ return CreateX509Certificate(X509CertificateStructure.GetInstance(seq));
+ }
+
+ private X509Certificate GetCertificate()
+ {
+ if (sData != null)
+ {
+ while (sDataObjectCount < sData.Count)
+ {
+ object obj = sData[sDataObjectCount++];
+
+ if (obj is Asn1Sequence)
+ {
+ return CreateX509Certificate(
+ X509CertificateStructure.GetInstance(obj));
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private X509Certificate ReadPemCertificate(
+ Stream inStream)
+ {
+ Asn1Sequence seq = PemCertParser.ReadPemObject(inStream);
+
+ return seq == null
+ ? null
+ : CreateX509Certificate(X509CertificateStructure.GetInstance(seq));
+ }
+
+ protected virtual X509Certificate CreateX509Certificate(
+ X509CertificateStructure c)
+ {
+ return new X509Certificate(c);
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public X509Certificate ReadCertificate(
+ byte[] input)
+ {
+ return ReadCertificate(new MemoryStream(input, false));
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public ICollection ReadCertificates(
+ byte[] input)
+ {
+ return ReadCertificates(new MemoryStream(input, false));
+ }
+
+ /**
+ * Generates a certificate object and initializes it with the data
+ * read from the input stream inStream.
+ */
+ public X509Certificate ReadCertificate(
+ Stream inStream)
+ {
+ if (inStream == null)
+ throw new ArgumentNullException("inStream");
+ if (!inStream.CanRead)
+ throw new ArgumentException("inStream must be read-able", "inStream");
+
+ if (currentStream == null)
+ {
+ currentStream = inStream;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+ else if (currentStream != inStream) // reset if input stream has changed
+ {
+ currentStream = inStream;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+
+ try
+ {
+ if (sData != null)
+ {
+ if (sDataObjectCount != sData.Count)
+ {
+ return GetCertificate();
+ }
+
+ sData = null;
+ sDataObjectCount = 0;
+ return null;
+ }
+
+ PushbackStream pis = new PushbackStream(inStream);
+ int tag = pis.ReadByte();
+
+ if (tag < 0)
+ return null;
+
+ pis.Unread(tag);
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ return ReadPemCertificate(pis);
+ }
+
+ return ReadDerCertificate(new Asn1InputStream(pis));
+ }
+ catch (Exception e)
+ {
+ throw new CertificateException("Failed to read certificate", e);
+ }
+ }
+
+ /**
+ * Returns a (possibly empty) collection view of the certificates
+ * read from the given input stream inStream.
+ */
+ public ICollection ReadCertificates(
+ Stream inStream)
+ {
+ X509Certificate cert;
+ IList certs = Platform.CreateArrayList();
+
+ while ((cert = ReadCertificate(inStream)) != null)
+ {
+ certs.Add(cert);
+ }
+
+ return certs;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/X509Crl.cs b/bc-sharp-crypto/src/x509/X509Crl.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ecfb14132ca277654c55a62ee0208181d02c1634
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/X509Crl.cs
@@ -0,0 +1,426 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.X509.Extension;
+using Org.BouncyCastle.Crypto.Operators;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * The following extensions are listed in RFC 2459 as relevant to CRLs
+ *
+ * Authority Key Identifier
+ * Issuer Alternative Name
+ * CRL Number
+ * Delta CRL Indicator (critical)
+ * Issuing Distribution Point (critical)
+ */
+ public class X509Crl
+ : X509ExtensionBase
+ // TODO Add interface Crl?
+ {
+ private readonly CertificateList c;
+ private readonly string sigAlgName;
+ private readonly byte[] sigAlgParams;
+ private readonly bool isIndirect;
+
+ public X509Crl(
+ CertificateList c)
+ {
+ this.c = c;
+
+ try
+ {
+ this.sigAlgName = X509SignatureUtilities.GetSignatureName(c.SignatureAlgorithm);
+
+ if (c.SignatureAlgorithm.Parameters != null)
+ {
+ this.sigAlgParams = ((Asn1Encodable)c.SignatureAlgorithm.Parameters).GetDerEncoded();
+ }
+ else
+ {
+ this.sigAlgParams = null;
+ }
+
+ this.isIndirect = IsIndirectCrl;
+ }
+ catch (Exception e)
+ {
+ throw new CrlException("CRL contents invalid: " + e);
+ }
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return c.Version >= 2
+ ? c.TbsCertList.Extensions
+ : null;
+ }
+
+ public virtual byte[] GetEncoded()
+ {
+ try
+ {
+ return c.GetDerEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new CrlException(e.ToString());
+ }
+ }
+
+ public virtual void Verify(
+ AsymmetricKeyParameter publicKey)
+ {
+ Verify(new Asn1VerifierFactoryProvider(publicKey));
+ }
+
+ ///
+ /// Verify the CRL's signature using a verifier created using the passed in verifier provider.
+ ///
+ /// An appropriate provider for verifying the CRL's signature.
+ /// True if the signature is valid.
+ /// If verifier provider is not appropriate or the CRL algorithm is invalid.
+ public virtual void Verify(
+ IVerifierFactoryProvider verifierProvider)
+ {
+ CheckSignature(verifierProvider.CreateVerifierFactory(c.SignatureAlgorithm));
+ }
+
+ protected virtual void CheckSignature(
+ IVerifierFactory verifier)
+ {
+ if (!c.SignatureAlgorithm.Equals(c.TbsCertList.Signature))
+ {
+ throw new CrlException("Signature algorithm on CertificateList does not match TbsCertList.");
+ }
+
+ Asn1Encodable parameters = c.SignatureAlgorithm.Parameters;
+
+ IStreamCalculator streamCalculator = verifier.CreateCalculator();
+
+ byte[] b = this.GetTbsCertList();
+
+ streamCalculator.Stream.Write(b, 0, b.Length);
+
+ Platform.Dispose(streamCalculator.Stream);
+
+ if (!((IVerifier)streamCalculator.GetResult()).IsVerified(this.GetSignature()))
+ {
+ throw new InvalidKeyException("CRL does not verify with supplied public key.");
+ }
+ }
+
+ public virtual int Version
+ {
+ get { return c.Version; }
+ }
+
+ public virtual X509Name IssuerDN
+ {
+ get { return c.Issuer; }
+ }
+
+ public virtual DateTime ThisUpdate
+ {
+ get { return c.ThisUpdate.ToDateTime(); }
+ }
+
+ public virtual DateTimeObject NextUpdate
+ {
+ get
+ {
+ return c.NextUpdate == null
+ ? null
+ : new DateTimeObject(c.NextUpdate.ToDateTime());
+ }
+ }
+
+ private ISet LoadCrlEntries()
+ {
+ ISet entrySet = new HashSet();
+ IEnumerable certs = c.GetRevokedCertificateEnumeration();
+
+ X509Name previousCertificateIssuer = IssuerDN;
+ foreach (CrlEntry entry in certs)
+ {
+ X509CrlEntry crlEntry = new X509CrlEntry(entry, isIndirect, previousCertificateIssuer);
+ entrySet.Add(crlEntry);
+ previousCertificateIssuer = crlEntry.GetCertificateIssuer();
+ }
+
+ return entrySet;
+ }
+
+ public virtual X509CrlEntry GetRevokedCertificate(
+ BigInteger serialNumber)
+ {
+ IEnumerable certs = c.GetRevokedCertificateEnumeration();
+
+ X509Name previousCertificateIssuer = IssuerDN;
+ foreach (CrlEntry entry in certs)
+ {
+ X509CrlEntry crlEntry = new X509CrlEntry(entry, isIndirect, previousCertificateIssuer);
+
+ if (serialNumber.Equals(entry.UserCertificate.Value))
+ {
+ return crlEntry;
+ }
+
+ previousCertificateIssuer = crlEntry.GetCertificateIssuer();
+ }
+
+ return null;
+ }
+
+ public virtual ISet GetRevokedCertificates()
+ {
+ ISet entrySet = LoadCrlEntries();
+
+ if (entrySet.Count > 0)
+ {
+ return entrySet; // TODO? Collections.unmodifiableSet(entrySet);
+ }
+
+ return null;
+ }
+
+ public virtual byte[] GetTbsCertList()
+ {
+ try
+ {
+ return c.TbsCertList.GetDerEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new CrlException(e.ToString());
+ }
+ }
+
+ public virtual byte[] GetSignature()
+ {
+ return c.GetSignatureOctets();
+ }
+
+ public virtual string SigAlgName
+ {
+ get { return sigAlgName; }
+ }
+
+ public virtual string SigAlgOid
+ {
+ get { return c.SignatureAlgorithm.Algorithm.Id; }
+ }
+
+ public virtual byte[] GetSigAlgParams()
+ {
+ return Arrays.Clone(sigAlgParams);
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ X509Crl other = obj as X509Crl;
+
+ if (other == null)
+ return false;
+
+ return c.Equals(other.c);
+
+ // NB: May prefer this implementation of Equals if more than one certificate implementation in play
+ //return Arrays.AreEqual(this.GetEncoded(), other.GetEncoded());
+ }
+
+ public override int GetHashCode()
+ {
+ return c.GetHashCode();
+ }
+
+ /**
+ * Returns a string representation of this CRL.
+ *
+ * @return a string representation of this CRL.
+ */
+ public override string ToString()
+ {
+ StringBuilder buf = new StringBuilder();
+ string nl = Platform.NewLine;
+
+ buf.Append(" Version: ").Append(this.Version).Append(nl);
+ buf.Append(" IssuerDN: ").Append(this.IssuerDN).Append(nl);
+ buf.Append(" This update: ").Append(this.ThisUpdate).Append(nl);
+ buf.Append(" Next update: ").Append(this.NextUpdate).Append(nl);
+ buf.Append(" Signature Algorithm: ").Append(this.SigAlgName).Append(nl);
+
+ byte[] sig = this.GetSignature();
+
+ buf.Append(" Signature: ");
+ buf.Append(Hex.ToHexString(sig, 0, 20)).Append(nl);
+
+ for (int i = 20; i < sig.Length; i += 20)
+ {
+ int count = System.Math.Min(20, sig.Length - i);
+ buf.Append(" ");
+ buf.Append(Hex.ToHexString(sig, i, count)).Append(nl);
+ }
+
+ X509Extensions extensions = c.TbsCertList.Extensions;
+
+ if (extensions != null)
+ {
+ IEnumerator e = extensions.ExtensionOids.GetEnumerator();
+
+ if (e.MoveNext())
+ {
+ buf.Append(" Extensions: ").Append(nl);
+ }
+
+ do
+ {
+ DerObjectIdentifier oid = (DerObjectIdentifier) e.Current;
+ X509Extension ext = extensions.GetExtension(oid);
+
+ if (ext.Value != null)
+ {
+ Asn1Object asn1Value = X509ExtensionUtilities.FromExtensionValue(ext.Value);
+
+ buf.Append(" critical(").Append(ext.IsCritical).Append(") ");
+ try
+ {
+ if (oid.Equals(X509Extensions.CrlNumber))
+ {
+ buf.Append(new CrlNumber(DerInteger.GetInstance(asn1Value).PositiveValue)).Append(nl);
+ }
+ else if (oid.Equals(X509Extensions.DeltaCrlIndicator))
+ {
+ buf.Append(
+ "Base CRL: "
+ + new CrlNumber(DerInteger.GetInstance(
+ asn1Value).PositiveValue))
+ .Append(nl);
+ }
+ else if (oid.Equals(X509Extensions.IssuingDistributionPoint))
+ {
+ buf.Append(IssuingDistributionPoint.GetInstance((Asn1Sequence) asn1Value)).Append(nl);
+ }
+ else if (oid.Equals(X509Extensions.CrlDistributionPoints))
+ {
+ buf.Append(CrlDistPoint.GetInstance((Asn1Sequence) asn1Value)).Append(nl);
+ }
+ else if (oid.Equals(X509Extensions.FreshestCrl))
+ {
+ buf.Append(CrlDistPoint.GetInstance((Asn1Sequence) asn1Value)).Append(nl);
+ }
+ else
+ {
+ buf.Append(oid.Id);
+ buf.Append(" value = ").Append(
+ Asn1Dump.DumpAsString(asn1Value))
+ .Append(nl);
+ }
+ }
+ catch (Exception)
+ {
+ buf.Append(oid.Id);
+ buf.Append(" value = ").Append("*****").Append(nl);
+ }
+ }
+ else
+ {
+ buf.Append(nl);
+ }
+ }
+ while (e.MoveNext());
+ }
+
+ ISet certSet = GetRevokedCertificates();
+ if (certSet != null)
+ {
+ foreach (X509CrlEntry entry in certSet)
+ {
+ buf.Append(entry);
+ buf.Append(nl);
+ }
+ }
+
+ return buf.ToString();
+ }
+
+ /**
+ * Checks whether the given certificate is on this CRL.
+ *
+ * @param cert the certificate to check for.
+ * @return true if the given certificate is on this CRL,
+ * false otherwise.
+ */
+// public bool IsRevoked(
+// Certificate cert)
+// {
+// if (!cert.getType().Equals("X.509"))
+// {
+// throw new RuntimeException("X.509 CRL used with non X.509 Cert");
+// }
+ public virtual bool IsRevoked(
+ X509Certificate cert)
+ {
+ CrlEntry[] certs = c.GetRevokedCertificates();
+
+ if (certs != null)
+ {
+// BigInteger serial = ((X509Certificate)cert).SerialNumber;
+ BigInteger serial = cert.SerialNumber;
+
+ for (int i = 0; i < certs.Length; i++)
+ {
+ if (certs[i].UserCertificate.Value.Equals(serial))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ protected virtual bool IsIndirectCrl
+ {
+ get
+ {
+ Asn1OctetString idp = GetExtensionValue(X509Extensions.IssuingDistributionPoint);
+ bool isIndirect = false;
+
+ try
+ {
+ if (idp != null)
+ {
+ isIndirect = IssuingDistributionPoint.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(idp)).IsIndirectCrl;
+ }
+ }
+ catch (Exception e)
+ {
+ // TODO
+// throw new ExtCrlException("Exception reading IssuingDistributionPoint", e);
+ throw new CrlException("Exception reading IssuingDistributionPoint" + e);
+ }
+
+ return isIndirect;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/X509CrlEntry.cs b/bc-sharp-crypto/src/x509/X509CrlEntry.cs
new file mode 100644
index 0000000000000000000000000000000000000000..caca29470ac09879cd4804796ed3e11124c64e90
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/X509CrlEntry.cs
@@ -0,0 +1,201 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * The following extensions are listed in RFC 2459 as relevant to CRL Entries
+ *
+ * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer
+ * (critical)
+ */
+ public class X509CrlEntry
+ : X509ExtensionBase
+ {
+ private CrlEntry c;
+ private bool isIndirect;
+ private X509Name previousCertificateIssuer;
+ private X509Name certificateIssuer;
+
+ public X509CrlEntry(
+ CrlEntry c)
+ {
+ this.c = c;
+ this.certificateIssuer = loadCertificateIssuer();
+ }
+
+ /**
+ * Constructor for CRLEntries of indirect CRLs. If isIndirect
+ * is false
{@link #getCertificateIssuer()} will always
+ * return null
, previousCertificateIssuer
is
+ * ignored. If this isIndirect
is specified and this CrlEntry
+ * has no certificate issuer CRL entry extension
+ * previousCertificateIssuer
is returned by
+ * {@link #getCertificateIssuer()}.
+ *
+ * @param c
+ * TbsCertificateList.CrlEntry object.
+ * @param isIndirect
+ * true
if the corresponding CRL is a indirect
+ * CRL.
+ * @param previousCertificateIssuer
+ * Certificate issuer of the previous CrlEntry.
+ */
+ public X509CrlEntry(
+ CrlEntry c,
+ bool isIndirect,
+ X509Name previousCertificateIssuer)
+ {
+ this.c = c;
+ this.isIndirect = isIndirect;
+ this.previousCertificateIssuer = previousCertificateIssuer;
+ this.certificateIssuer = loadCertificateIssuer();
+ }
+
+ private X509Name loadCertificateIssuer()
+ {
+ if (!isIndirect)
+ {
+ return null;
+ }
+
+ Asn1OctetString ext = GetExtensionValue(X509Extensions.CertificateIssuer);
+ if (ext == null)
+ {
+ return previousCertificateIssuer;
+ }
+
+ try
+ {
+ GeneralName[] names = GeneralNames.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(ext)).GetNames();
+
+ for (int i = 0; i < names.Length; i++)
+ {
+ if (names[i].TagNo == GeneralName.DirectoryName)
+ {
+ return X509Name.GetInstance(names[i].Name);
+ }
+ }
+ }
+ catch (Exception)
+ {
+ }
+
+ return null;
+ }
+
+ public X509Name GetCertificateIssuer()
+ {
+ return certificateIssuer;
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return c.Extensions;
+ }
+
+ public byte[] GetEncoded()
+ {
+ try
+ {
+ return c.GetDerEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new CrlException(e.ToString());
+ }
+ }
+
+ public BigInteger SerialNumber
+ {
+ get { return c.UserCertificate.Value; }
+ }
+
+ public DateTime RevocationDate
+ {
+ get { return c.RevocationDate.ToDateTime(); }
+ }
+
+ public bool HasExtensions
+ {
+ get { return c.Extensions != null; }
+ }
+
+ public override string ToString()
+ {
+ StringBuilder buf = new StringBuilder();
+ string nl = Platform.NewLine;
+
+ buf.Append(" userCertificate: ").Append(this.SerialNumber).Append(nl);
+ buf.Append(" revocationDate: ").Append(this.RevocationDate).Append(nl);
+ buf.Append(" certificateIssuer: ").Append(this.GetCertificateIssuer()).Append(nl);
+
+ X509Extensions extensions = c.Extensions;
+
+ if (extensions != null)
+ {
+ IEnumerator e = extensions.ExtensionOids.GetEnumerator();
+ if (e.MoveNext())
+ {
+ buf.Append(" crlEntryExtensions:").Append(nl);
+
+ do
+ {
+ DerObjectIdentifier oid = (DerObjectIdentifier)e.Current;
+ X509Extension ext = extensions.GetExtension(oid);
+
+ if (ext.Value != null)
+ {
+ Asn1Object obj = Asn1Object.FromByteArray(ext.Value.GetOctets());
+
+ buf.Append(" critical(")
+ .Append(ext.IsCritical)
+ .Append(") ");
+ try
+ {
+ if (oid.Equals(X509Extensions.ReasonCode))
+ {
+ buf.Append(new CrlReason(DerEnumerated.GetInstance(obj)));
+ }
+ else if (oid.Equals(X509Extensions.CertificateIssuer))
+ {
+ buf.Append("Certificate issuer: ").Append(
+ GeneralNames.GetInstance((Asn1Sequence)obj));
+ }
+ else
+ {
+ buf.Append(oid.Id);
+ buf.Append(" value = ").Append(Asn1Dump.DumpAsString(obj));
+ }
+ buf.Append(nl);
+ }
+ catch (Exception)
+ {
+ buf.Append(oid.Id);
+ buf.Append(" value = ").Append("*****").Append(nl);
+ }
+ }
+ else
+ {
+ buf.Append(nl);
+ }
+ }
+ while (e.MoveNext());
+ }
+ }
+
+ return buf.ToString();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/X509CrlParser.cs b/bc-sharp-crypto/src/x509/X509CrlParser.cs
new file mode 100644
index 0000000000000000000000000000000000000000..d830bb9a669032bfa3ce6b6d014401f1db48c82c
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/X509CrlParser.cs
@@ -0,0 +1,195 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.X509
+{
+ public class X509CrlParser
+ {
+ private static readonly PemParser PemCrlParser = new PemParser("CRL");
+
+ private readonly bool lazyAsn1;
+
+ private Asn1Set sCrlData;
+ private int sCrlDataObjectCount;
+ private Stream currentCrlStream;
+
+ public X509CrlParser()
+ : this(false)
+ {
+ }
+
+ public X509CrlParser(
+ bool lazyAsn1)
+ {
+ this.lazyAsn1 = lazyAsn1;
+ }
+
+ private X509Crl ReadPemCrl(
+ Stream inStream)
+ {
+ Asn1Sequence seq = PemCrlParser.ReadPemObject(inStream);
+
+ return seq == null
+ ? null
+ : CreateX509Crl(CertificateList.GetInstance(seq));
+ }
+
+ private X509Crl ReadDerCrl(
+ Asn1InputStream dIn)
+ {
+ Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject();
+
+ if (seq.Count > 1 && seq[0] is DerObjectIdentifier)
+ {
+ if (seq[0].Equals(PkcsObjectIdentifiers.SignedData))
+ {
+ sCrlData = SignedData.GetInstance(
+ Asn1Sequence.GetInstance((Asn1TaggedObject) seq[1], true)).Crls;
+
+ return GetCrl();
+ }
+ }
+
+ return CreateX509Crl(CertificateList.GetInstance(seq));
+ }
+
+ private X509Crl GetCrl()
+ {
+ if (sCrlData == null || sCrlDataObjectCount >= sCrlData.Count)
+ {
+ return null;
+ }
+
+ return CreateX509Crl(
+ CertificateList.GetInstance(
+ sCrlData[sCrlDataObjectCount++]));
+ }
+
+ protected virtual X509Crl CreateX509Crl(
+ CertificateList c)
+ {
+ return new X509Crl(c);
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public X509Crl ReadCrl(
+ byte[] input)
+ {
+ return ReadCrl(new MemoryStream(input, false));
+ }
+
+ ///
+ /// Create loading data from byte array.
+ ///
+ ///
+ public ICollection ReadCrls(
+ byte[] input)
+ {
+ return ReadCrls(new MemoryStream(input, false));
+ }
+
+ /**
+ * Generates a certificate revocation list (CRL) object and initializes
+ * it with the data read from the input stream inStream.
+ */
+ public X509Crl ReadCrl(
+ Stream inStream)
+ {
+ if (inStream == null)
+ throw new ArgumentNullException("inStream");
+ if (!inStream.CanRead)
+ throw new ArgumentException("inStream must be read-able", "inStream");
+
+ if (currentCrlStream == null)
+ {
+ currentCrlStream = inStream;
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ }
+ else if (currentCrlStream != inStream) // reset if input stream has changed
+ {
+ currentCrlStream = inStream;
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ }
+
+ try
+ {
+ if (sCrlData != null)
+ {
+ if (sCrlDataObjectCount != sCrlData.Count)
+ {
+ return GetCrl();
+ }
+
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ return null;
+ }
+
+ PushbackStream pis = new PushbackStream(inStream);
+ int tag = pis.ReadByte();
+
+ if (tag < 0)
+ return null;
+
+ pis.Unread(tag);
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ return ReadPemCrl(pis);
+ }
+
+ Asn1InputStream asn1 = lazyAsn1
+ ? new LazyAsn1InputStream(pis)
+ : new Asn1InputStream(pis);
+
+ return ReadDerCrl(asn1);
+ }
+ catch (CrlException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new CrlException(e.ToString());
+ }
+ }
+
+ /**
+ * Returns a (possibly empty) collection view of the CRLs read from
+ * the given input stream inStream.
+ *
+ * The inStream may contain a sequence of DER-encoded CRLs, or
+ * a PKCS#7 CRL set. This is a PKCS#7 SignedData object, with the
+ * only significant field being crls. In particular the signature
+ * and the contents are ignored.
+ */
+ public ICollection ReadCrls(
+ Stream inStream)
+ {
+ X509Crl crl;
+ IList crls = Platform.CreateArrayList();
+
+ while ((crl = ReadCrl(inStream)) != null)
+ {
+ crls.Add(crl);
+ }
+
+ return crls;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/X509ExtensionBase.cs b/bc-sharp-crypto/src/x509/X509ExtensionBase.cs
new file mode 100644
index 0000000000000000000000000000000000000000..aaf6695c0098276517260bbc4f7afb5069387f92
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/X509ExtensionBase.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.X509
+{
+ public abstract class X509ExtensionBase
+ : IX509Extension
+ {
+ protected abstract X509Extensions GetX509Extensions();
+
+ protected virtual ISet GetExtensionOids(
+ bool critical)
+ {
+ X509Extensions extensions = GetX509Extensions();
+ if (extensions != null)
+ {
+ HashSet set = new HashSet();
+ foreach (DerObjectIdentifier oid in extensions.ExtensionOids)
+ {
+ X509Extension ext = extensions.GetExtension(oid);
+ if (ext.IsCritical == critical)
+ {
+ set.Add(oid.Id);
+ }
+ }
+
+ return set;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Get non critical extensions.
+ ///
+ /// A set of non critical extension oids.
+ public virtual ISet GetNonCriticalExtensionOids()
+ {
+ return GetExtensionOids(false);
+ }
+
+ ///
+ /// Get any critical extensions.
+ ///
+ /// A sorted list of critical entension.
+ public virtual ISet GetCriticalExtensionOids()
+ {
+ return GetExtensionOids(true);
+ }
+
+ ///
+ /// Get the value of a given extension.
+ ///
+ /// The object ID of the extension.
+ /// An Asn1OctetString object if that extension is found or null if not.
+ [Obsolete("Use version taking a DerObjectIdentifier instead")]
+ public Asn1OctetString GetExtensionValue(
+ string oid)
+ {
+ return GetExtensionValue(new DerObjectIdentifier(oid));
+ }
+
+ public virtual Asn1OctetString GetExtensionValue(
+ DerObjectIdentifier oid)
+ {
+ X509Extensions exts = GetX509Extensions();
+ if (exts != null)
+ {
+ X509Extension ext = exts.GetExtension(oid);
+ if (ext != null)
+ {
+ return ext.Value;
+ }
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/X509KeyUsage.cs b/bc-sharp-crypto/src/x509/X509KeyUsage.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e0a7b49392899e3b33043d5e7b55725bd5a56239
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/X509KeyUsage.cs
@@ -0,0 +1,59 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * A holding class for constructing an X509 Key Usage extension.
+ *
+ *
+ * id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 }
+ *
+ * KeyUsage ::= BIT STRING {
+ * digitalSignature (0),
+ * nonRepudiation (1),
+ * keyEncipherment (2),
+ * dataEncipherment (3),
+ * keyAgreement (4),
+ * keyCertSign (5),
+ * cRLSign (6),
+ * encipherOnly (7),
+ * decipherOnly (8) }
+ *
+ */
+ public class X509KeyUsage
+ : Asn1Encodable
+ {
+ public const int DigitalSignature = 1 << 7;
+ public const int NonRepudiation = 1 << 6;
+ public const int KeyEncipherment = 1 << 5;
+ public const int DataEncipherment = 1 << 4;
+ public const int KeyAgreement = 1 << 3;
+ public const int KeyCertSign = 1 << 2;
+ public const int CrlSign = 1 << 1;
+ public const int EncipherOnly = 1 << 0;
+ public const int DecipherOnly = 1 << 15;
+
+ private readonly int usage;
+
+ /**
+ * Basic constructor.
+ *
+ * @param usage - the bitwise OR of the Key Usage flags giving the
+ * allowed uses for the key.
+ * e.g. (X509KeyUsage.keyEncipherment | X509KeyUsage.dataEncipherment)
+ */
+ public X509KeyUsage(
+ int usage)
+ {
+ this.usage = usage;
+ }
+
+ public override Asn1Object ToAsn1Object()
+ {
+ return new KeyUsage(usage);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/X509SignatureUtil.cs b/bc-sharp-crypto/src/x509/X509SignatureUtil.cs
new file mode 100644
index 0000000000000000000000000000000000000000..83863aee16f43f5ffa6ff5251ff74deb1a156be7
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/X509SignatureUtil.cs
@@ -0,0 +1,128 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.X509
+{
+ internal class X509SignatureUtilities
+ {
+ private static readonly Asn1Null derNull = DerNull.Instance;
+
+ internal static void SetSignatureParameters(
+ ISigner signature,
+ Asn1Encodable parameters)
+ {
+ if (parameters != null && !derNull.Equals(parameters))
+ {
+ // TODO Put back in
+// AlgorithmParameters sigParams = AlgorithmParameters.GetInstance(signature.getAlgorithm());
+//
+// try
+// {
+// sigParams.Init(parameters.ToAsn1Object().GetDerEncoded());
+// }
+// catch (IOException e)
+// {
+// throw new SignatureException("IOException decoding parameters: " + e.Message);
+// }
+//
+// if (Platform.EndsWith(signature.getAlgorithm(), "MGF1"))
+// {
+// try
+// {
+// signature.setParameter(sigParams.getParameterSpec(PSSParameterSpec.class));
+// }
+// catch (GeneralSecurityException e)
+// {
+// throw new SignatureException("Exception extracting parameters: " + e.Message);
+// }
+// }
+ }
+ }
+
+ internal static string GetSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ Asn1Encodable parameters = sigAlgId.Parameters;
+
+ if (parameters != null && !derNull.Equals(parameters))
+ {
+ if (sigAlgId.Algorithm.Equals(PkcsObjectIdentifiers.IdRsassaPss))
+ {
+ RsassaPssParameters rsaParams = RsassaPssParameters.GetInstance(parameters);
+
+ return GetDigestAlgName(rsaParams.HashAlgorithm.Algorithm) + "withRSAandMGF1";
+ }
+ if (sigAlgId.Algorithm.Equals(X9ObjectIdentifiers.ECDsaWithSha2))
+ {
+ Asn1Sequence ecDsaParams = Asn1Sequence.GetInstance(parameters);
+
+ return GetDigestAlgName((DerObjectIdentifier)ecDsaParams[0]) + "withECDSA";
+ }
+ }
+
+ return sigAlgId.Algorithm.Id;
+ }
+
+ /**
+ * Return the digest algorithm using one of the standard JCA string
+ * representations rather than the algorithm identifier (if possible).
+ */
+ private static string GetDigestAlgName(
+ DerObjectIdentifier digestAlgOID)
+ {
+ if (PkcsObjectIdentifiers.MD5.Equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OiwObjectIdentifiers.IdSha1.Equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ else if (NistObjectIdentifiers.IdSha224.Equals(digestAlgOID))
+ {
+ return "SHA224";
+ }
+ else if (NistObjectIdentifiers.IdSha256.Equals(digestAlgOID))
+ {
+ return "SHA256";
+ }
+ else if (NistObjectIdentifiers.IdSha384.Equals(digestAlgOID))
+ {
+ return "SHA384";
+ }
+ else if (NistObjectIdentifiers.IdSha512.Equals(digestAlgOID))
+ {
+ return "SHA512";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD128.Equals(digestAlgOID))
+ {
+ return "RIPEMD128";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD160.Equals(digestAlgOID))
+ {
+ return "RIPEMD160";
+ }
+ else if (TeleTrusTObjectIdentifiers.RipeMD256.Equals(digestAlgOID))
+ {
+ return "RIPEMD256";
+ }
+ else if (CryptoProObjectIdentifiers.GostR3411.Equals(digestAlgOID))
+ {
+ return "GOST3411";
+ }
+ else
+ {
+ return digestAlgOID.Id;
+ }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/X509Utilities.cs b/bc-sharp-crypto/src/x509/X509Utilities.cs
new file mode 100644
index 0000000000000000000000000000000000000000..52a122c213fb468d35331a33728dfd98e93693d9
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/X509Utilities.cs
@@ -0,0 +1,187 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.X509
+{
+ internal class X509Utilities
+ {
+ private static readonly IDictionary algorithms = Platform.CreateHashtable();
+ private static readonly IDictionary exParams = Platform.CreateHashtable();
+ private static readonly ISet noParams = new HashSet();
+
+ static X509Utilities()
+ {
+ algorithms.Add("MD2WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+ algorithms.Add("MD2WITHRSA", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+ algorithms.Add("MD5WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+ algorithms.Add("MD5WITHRSA", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSA", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+ algorithms.Add("SHA224WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+ algorithms.Add("SHA224WITHRSA", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+ algorithms.Add("SHA256WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+ algorithms.Add("SHA256WITHRSA", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+ algorithms.Add("SHA384WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+ algorithms.Add("SHA384WITHRSA", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+ algorithms.Add("SHA512WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+ algorithms.Add("SHA512WITHRSA", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+ algorithms.Add("SHA1WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA224WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA256WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA384WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("SHA512WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+ algorithms.Add("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+ algorithms.Add("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+ algorithms.Add("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+ algorithms.Add("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+ algorithms.Add("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+ algorithms.Add("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+ algorithms.Add("SHA1WITHDSA", X9ObjectIdentifiers.IdDsaWithSha1);
+ algorithms.Add("DSAWITHSHA1", X9ObjectIdentifiers.IdDsaWithSha1);
+ algorithms.Add("SHA224WITHDSA", NistObjectIdentifiers.DsaWithSha224);
+ algorithms.Add("SHA256WITHDSA", NistObjectIdentifiers.DsaWithSha256);
+ algorithms.Add("SHA384WITHDSA", NistObjectIdentifiers.DsaWithSha384);
+ algorithms.Add("SHA512WITHDSA", NistObjectIdentifiers.DsaWithSha512);
+ algorithms.Add("SHA1WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha1);
+ algorithms.Add("ECDSAWITHSHA1", X9ObjectIdentifiers.ECDsaWithSha1);
+ algorithms.Add("SHA224WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha224);
+ algorithms.Add("SHA256WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha256);
+ algorithms.Add("SHA384WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha384);
+ algorithms.Add("SHA512WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha512);
+ algorithms.Add("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ algorithms.Add("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ algorithms.Add("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+ algorithms.Add("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+ algorithms.Add("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha1);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha224);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha256);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha384);
+ noParams.Add(X9ObjectIdentifiers.ECDsaWithSha512);
+ noParams.Add(X9ObjectIdentifiers.IdDsaWithSha1);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha224);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha256);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha384);
+ noParams.Add(NistObjectIdentifiers.DsaWithSha512);
+
+ //
+ // RFC 4491
+ //
+ noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+ noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+ //
+ // explicit params
+ //
+ AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+ exParams.Add("SHA1WITHRSAANDMGF1", CreatePssParams(sha1AlgId, 20));
+
+ AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha224, DerNull.Instance);
+ exParams.Add("SHA224WITHRSAANDMGF1", CreatePssParams(sha224AlgId, 28));
+
+ AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha256, DerNull.Instance);
+ exParams.Add("SHA256WITHRSAANDMGF1", CreatePssParams(sha256AlgId, 32));
+
+ AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha384, DerNull.Instance);
+ exParams.Add("SHA384WITHRSAANDMGF1", CreatePssParams(sha384AlgId, 48));
+
+ AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha512, DerNull.Instance);
+ exParams.Add("SHA512WITHRSAANDMGF1", CreatePssParams(sha512AlgId, 64));
+ }
+
+ private static RsassaPssParameters CreatePssParams(
+ AlgorithmIdentifier hashAlgId,
+ int saltSize)
+ {
+ return new RsassaPssParameters(
+ hashAlgId,
+ new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, hashAlgId),
+ new DerInteger(saltSize),
+ new DerInteger(1));
+ }
+
+ internal static DerObjectIdentifier GetAlgorithmOid(
+ string algorithmName)
+ {
+ algorithmName = Platform.ToUpperInvariant(algorithmName);
+
+ if (algorithms.Contains(algorithmName))
+ {
+ return (DerObjectIdentifier) algorithms[algorithmName];
+ }
+
+ return new DerObjectIdentifier(algorithmName);
+ }
+
+ internal static AlgorithmIdentifier GetSigAlgID(
+ DerObjectIdentifier sigOid,
+ string algorithmName)
+ {
+ if (noParams.Contains(sigOid))
+ {
+ return new AlgorithmIdentifier(sigOid);
+ }
+
+ algorithmName = Platform.ToUpperInvariant(algorithmName);
+
+ if (exParams.Contains(algorithmName))
+ {
+ return new AlgorithmIdentifier(sigOid, (Asn1Encodable) exParams[algorithmName]);
+ }
+
+ return new AlgorithmIdentifier(sigOid, DerNull.Instance);
+ }
+
+ internal static IEnumerable GetAlgNames()
+ {
+ return new EnumerableProxy(algorithms.Keys);
+ }
+
+ internal static byte[] GetSignatureForObject(
+ DerObjectIdentifier sigOid, // TODO Redundant now?
+ string sigName,
+ AsymmetricKeyParameter privateKey,
+ SecureRandom random,
+ Asn1Encodable ae)
+ {
+ if (sigOid == null)
+ throw new ArgumentNullException("sigOid");
+
+ ISigner sig = SignerUtilities.GetSigner(sigName);
+
+ if (random != null)
+ {
+ sig.Init(true, new ParametersWithRandom(privateKey, random));
+ }
+ else
+ {
+ sig.Init(true, privateKey);
+ }
+
+ byte[] encoded = ae.GetDerEncoded();
+ sig.BlockUpdate(encoded, 0, encoded.Length);
+
+ return sig.GenerateSignature();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/X509V1CertificateGenerator.cs b/bc-sharp-crypto/src/x509/X509V1CertificateGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9adebcb169e59632b8a6ce77f8c2560782564d97
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/X509V1CertificateGenerator.cs
@@ -0,0 +1,210 @@
+using System;
+using System.IO;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Operators;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// Class to Generate X509V1 Certificates.
+ ///
+ public class X509V1CertificateGenerator
+ {
+ private V1TbsCertificateGenerator tbsGen;
+ private DerObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private string signatureAlgorithm;
+
+ ///
+ /// Default Constructor.
+ ///
+ public X509V1CertificateGenerator()
+ {
+ tbsGen = new V1TbsCertificateGenerator();
+ }
+
+ ///
+ /// Reset the generator.
+ ///
+ public void Reset()
+ {
+ tbsGen = new V1TbsCertificateGenerator();
+ }
+
+ ///
+ /// Set the certificate's serial number.
+ ///
+ /// Make serial numbers long, if you have no serial number policy make sure the number is at least 16 bytes of secure random data.
+ /// You will be surprised how ugly a serial number collision can get.
+ /// The serial number.
+ public void SetSerialNumber(
+ BigInteger serialNumber)
+ {
+ if (serialNumber.SignValue <= 0)
+ {
+ throw new ArgumentException("serial number must be a positive integer", "serialNumber");
+ }
+
+ tbsGen.SetSerialNumber(new DerInteger(serialNumber));
+ }
+
+ ///
+ /// Set the issuer distinguished name.
+ /// The issuer is the entity whose private key is used to sign the certificate.
+ ///
+ /// The issuers DN.
+ public void SetIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.SetIssuer(issuer);
+ }
+
+ ///
+ /// Set the date that this certificate is to be valid from.
+ ///
+ ///
+ public void SetNotBefore(
+ DateTime date)
+ {
+ tbsGen.SetStartDate(new Time(date));
+ }
+
+ ///
+ /// Set the date after which this certificate will no longer be valid.
+ ///
+ ///
+ public void SetNotAfter(
+ DateTime date)
+ {
+ tbsGen.SetEndDate(new Time(date));
+ }
+
+ ///
+ /// Set the subject distinguished name.
+ /// The subject describes the entity associated with the public key.
+ ///
+ ///
+ public void SetSubjectDN(
+ X509Name subject)
+ {
+ tbsGen.SetSubject(subject);
+ }
+
+ ///
+ /// Set the public key that this certificate identifies.
+ ///
+ ///
+ public void SetPublicKey(
+ AsymmetricKeyParameter publicKey)
+ {
+ try
+ {
+ tbsGen.SetSubjectPublicKeyInfo(
+ SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey));
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("unable to process key - " + e.ToString());
+ }
+ }
+
+ ///
+ /// Set the signature algorithm that will be used to sign this certificate.
+ /// This can be either a name or an OID, names are treated as case insensitive.
+ ///
+ /// string representation of the algorithm name
+ [Obsolete("Not needed if Generate used with an ISignatureFactory")]
+ public void SetSignatureAlgorithm(
+ string signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Utilities.GetAlgorithmOid(signatureAlgorithm);
+ }
+ catch (Exception)
+ {
+ throw new ArgumentException("Unknown signature type requested", "signatureAlgorithm");
+ }
+
+ sigAlgId = X509Utilities.GetSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.SetSignature(sigAlgId);
+ }
+
+ ///
+ /// Generate a new X509Certificate.
+ ///
+ /// The private key of the issuer used to sign this certificate.
+ /// An X509Certificate.
+ [Obsolete("Use Generate with an ISignatureFactory")]
+ public X509Certificate Generate(
+ AsymmetricKeyParameter privateKey)
+ {
+ return Generate(privateKey, null);
+ }
+
+ ///
+ /// Generate a new X509Certificate specifying a SecureRandom instance that you would like to use.
+ ///
+ /// The private key of the issuer used to sign this certificate.
+ /// The Secure Random you want to use.
+ /// An X509Certificate.
+ [Obsolete("Use Generate with an ISignatureFactory")]
+ public X509Certificate Generate(
+ AsymmetricKeyParameter privateKey,
+ SecureRandom random)
+ {
+ return Generate(new Asn1SignatureFactory(signatureAlgorithm, privateKey, random));
+ }
+
+ ///
+ /// Generate a new X509Certificate using the passed in SignatureCalculator.
+ ///
+ /// A signature calculator factory with the necessary algorithm details.
+ /// An X509Certificate.
+ public X509Certificate Generate(ISignatureFactory signatureCalculatorFactory)
+ {
+ tbsGen.SetSignature ((AlgorithmIdentifier)signatureCalculatorFactory.AlgorithmDetails);
+
+ TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate();
+
+ IStreamCalculator streamCalculator = signatureCalculatorFactory.CreateCalculator();
+
+ byte[] encoded = tbsCert.GetDerEncoded();
+
+ streamCalculator.Stream.Write(encoded, 0, encoded.Length);
+
+ Platform.Dispose(streamCalculator.Stream);
+
+ return GenerateJcaObject(tbsCert, (AlgorithmIdentifier)signatureCalculatorFactory.AlgorithmDetails, ((IBlockResult)streamCalculator.GetResult()).Collect());
+ }
+
+ private X509Certificate GenerateJcaObject(
+ TbsCertificateStructure tbsCert,
+ AlgorithmIdentifier sigAlg,
+ byte[] signature)
+ {
+ return new X509Certificate(
+ new X509CertificateStructure(tbsCert, sigAlg, new DerBitString(signature)));
+ }
+
+ ///
+ /// Allows enumeration of the signature names supported by the generator.
+ ///
+ public IEnumerable SignatureAlgNames
+ {
+ get { return X509Utilities.GetAlgNames(); }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/X509V2AttributeCertificate.cs b/bc-sharp-crypto/src/x509/X509V2AttributeCertificate.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c41b31239dddfb86ab4e34de381f6f0abc1d1604
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/X509V2AttributeCertificate.cs
@@ -0,0 +1,280 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Operators;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509
+{
+ /// An implementation of a version 2 X.509 Attribute Certificate.
+ public class X509V2AttributeCertificate
+ : X509ExtensionBase, IX509AttributeCertificate
+ {
+ private readonly AttributeCertificate cert;
+ private readonly DateTime notBefore;
+ private readonly DateTime notAfter;
+
+ private static AttributeCertificate GetObject(Stream input)
+ {
+ try
+ {
+ return AttributeCertificate.GetInstance(Asn1Object.FromStream(input));
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception decoding certificate structure", e);
+ }
+ }
+
+ public X509V2AttributeCertificate(
+ Stream encIn)
+ : this(GetObject(encIn))
+ {
+ }
+
+ public X509V2AttributeCertificate(
+ byte[] encoded)
+ : this(new MemoryStream(encoded, false))
+ {
+ }
+
+ internal X509V2AttributeCertificate(
+ AttributeCertificate cert)
+ {
+ this.cert = cert;
+
+ try
+ {
+ this.notAfter = cert.ACInfo.AttrCertValidityPeriod.NotAfterTime.ToDateTime();
+ this.notBefore = cert.ACInfo.AttrCertValidityPeriod.NotBeforeTime.ToDateTime();
+ }
+ catch (Exception e)
+ {
+ throw new IOException("invalid data structure in certificate!", e);
+ }
+ }
+
+ public virtual int Version
+ {
+ get { return cert.ACInfo.Version.Value.IntValue + 1; }
+ }
+
+ public virtual BigInteger SerialNumber
+ {
+ get { return cert.ACInfo.SerialNumber.Value; }
+ }
+
+ public virtual AttributeCertificateHolder Holder
+ {
+ get
+ {
+ return new AttributeCertificateHolder((Asn1Sequence)cert.ACInfo.Holder.ToAsn1Object());
+ }
+ }
+
+ public virtual AttributeCertificateIssuer Issuer
+ {
+ get
+ {
+ return new AttributeCertificateIssuer(cert.ACInfo.Issuer);
+ }
+ }
+
+ public virtual DateTime NotBefore
+ {
+ get { return notBefore; }
+ }
+
+ public virtual DateTime NotAfter
+ {
+ get { return notAfter; }
+ }
+
+ public virtual bool[] GetIssuerUniqueID()
+ {
+ DerBitString id = cert.ACInfo.IssuerUniqueID;
+
+ if (id != null)
+ {
+ byte[] bytes = id.GetBytes();
+ bool[] boolId = new bool[bytes.Length * 8 - id.PadBits];
+
+ for (int i = 0; i != boolId.Length; i++)
+ {
+ //boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ boolId[i] = (bytes[i / 8] & (0x80 >> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public virtual bool IsValidNow
+ {
+ get { return IsValid(DateTime.UtcNow); }
+ }
+
+ public virtual bool IsValid(
+ DateTime date)
+ {
+ return date.CompareTo(NotBefore) >= 0 && date.CompareTo(NotAfter) <= 0;
+ }
+
+ public virtual void CheckValidity()
+ {
+ this.CheckValidity(DateTime.UtcNow);
+ }
+
+ public virtual void CheckValidity(
+ DateTime date)
+ {
+ if (date.CompareTo(NotAfter) > 0)
+ throw new CertificateExpiredException("certificate expired on " + NotAfter);
+ if (date.CompareTo(NotBefore) < 0)
+ throw new CertificateNotYetValidException("certificate not valid until " + NotBefore);
+ }
+
+ public virtual AlgorithmIdentifier SignatureAlgorithm
+ {
+ get { return cert.SignatureAlgorithm; }
+ }
+
+ public virtual byte[] GetSignature()
+ {
+ return cert.GetSignatureOctets();
+ }
+
+ public virtual void Verify(
+ AsymmetricKeyParameter key)
+ {
+ CheckSignature(new Asn1VerifierFactory(cert.SignatureAlgorithm, key));
+ }
+
+ ///
+ /// Verify the certificate's signature using a verifier created using the passed in verifier provider.
+ ///
+ /// An appropriate provider for verifying the certificate's signature.
+ /// True if the signature is valid.
+ /// If verifier provider is not appropriate or the certificate algorithm is invalid.
+ public virtual void Verify(
+ IVerifierFactoryProvider verifierProvider)
+ {
+ CheckSignature(verifierProvider.CreateVerifierFactory(cert.SignatureAlgorithm));
+ }
+
+ protected virtual void CheckSignature(
+ IVerifierFactory verifier)
+ {
+ if (!cert.SignatureAlgorithm.Equals(cert.ACInfo.Signature))
+ {
+ throw new CertificateException("Signature algorithm in certificate info not same as outer certificate");
+ }
+
+ IStreamCalculator streamCalculator = verifier.CreateCalculator();
+
+ try
+ {
+ byte[] b = this.cert.ACInfo.GetEncoded();
+
+ streamCalculator.Stream.Write(b, 0, b.Length);
+
+ Platform.Dispose(streamCalculator.Stream);
+ }
+ catch (IOException e)
+ {
+ throw new SignatureException("Exception encoding certificate info object", e);
+ }
+
+ if (!((IVerifier)streamCalculator.GetResult()).IsVerified(this.GetSignature()))
+ {
+ throw new InvalidKeyException("Public key presented not for certificate signature");
+ }
+ }
+
+ public virtual byte[] GetEncoded()
+ {
+ return cert.GetEncoded();
+ }
+
+ protected override X509Extensions GetX509Extensions()
+ {
+ return cert.ACInfo.Extensions;
+ }
+
+ public virtual X509Attribute[] GetAttributes()
+ {
+ Asn1Sequence seq = cert.ACInfo.Attributes;
+ X509Attribute[] attrs = new X509Attribute[seq.Count];
+
+ for (int i = 0; i != seq.Count; i++)
+ {
+ attrs[i] = new X509Attribute((Asn1Encodable)seq[i]);
+ }
+
+ return attrs;
+ }
+
+ public virtual X509Attribute[] GetAttributes(
+ string oid)
+ {
+ Asn1Sequence seq = cert.ACInfo.Attributes;
+ IList list = Platform.CreateArrayList();
+
+ for (int i = 0; i != seq.Count; i++)
+ {
+ X509Attribute attr = new X509Attribute((Asn1Encodable)seq[i]);
+ if (attr.Oid.Equals(oid))
+ {
+ list.Add(attr);
+ }
+ }
+
+ if (list.Count < 1)
+ {
+ return null;
+ }
+
+ X509Attribute[] result = new X509Attribute[list.Count];
+ for (int i = 0; i < list.Count; ++i)
+ {
+ result[i] = (X509Attribute)list[i];
+ }
+ return result;
+ }
+
+ public override bool Equals(
+ object obj)
+ {
+ if (obj == this)
+ return true;
+
+ X509V2AttributeCertificate other = obj as X509V2AttributeCertificate;
+
+ if (other == null)
+ return false;
+
+ return cert.Equals(other.cert);
+
+ // NB: May prefer this implementation of Equals if more than one certificate implementation in play
+ //return Arrays.AreEqual(this.GetEncoded(), other.GetEncoded());
+ }
+
+ public override int GetHashCode()
+ {
+ return cert.GetHashCode();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/X509V2AttributeCertificateGenerator.cs b/bc-sharp-crypto/src/x509/X509V2AttributeCertificateGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bf046cd1effb44ae3b04aab45eb527c1920e278c
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/X509V2AttributeCertificateGenerator.cs
@@ -0,0 +1,203 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Operators;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509
+{
+ /// Class to produce an X.509 Version 2 AttributeCertificate.
+ public class X509V2AttributeCertificateGenerator
+ {
+ private readonly X509ExtensionsGenerator extGenerator = new X509ExtensionsGenerator();
+
+ private V2AttributeCertificateInfoGenerator acInfoGen;
+ private DerObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private string signatureAlgorithm;
+
+ public X509V2AttributeCertificateGenerator()
+ {
+ acInfoGen = new V2AttributeCertificateInfoGenerator();
+ }
+
+ /// Reset the generator
+ public void Reset()
+ {
+ acInfoGen = new V2AttributeCertificateInfoGenerator();
+ extGenerator.Reset();
+ }
+
+ /// Set the Holder of this Attribute Certificate.
+ public void SetHolder(
+ AttributeCertificateHolder holder)
+ {
+ acInfoGen.SetHolder(holder.holder);
+ }
+
+ /// Set the issuer.
+ public void SetIssuer(
+ AttributeCertificateIssuer issuer)
+ {
+ acInfoGen.SetIssuer(AttCertIssuer.GetInstance(issuer.form));
+ }
+
+ /// Set the serial number for the certificate.
+ public void SetSerialNumber(
+ BigInteger serialNumber)
+ {
+ acInfoGen.SetSerialNumber(new DerInteger(serialNumber));
+ }
+
+ public void SetNotBefore(
+ DateTime date)
+ {
+ acInfoGen.SetStartDate(new DerGeneralizedTime(date));
+ }
+
+ public void SetNotAfter(
+ DateTime date)
+ {
+ acInfoGen.SetEndDate(new DerGeneralizedTime(date));
+ }
+
+ ///
+ /// Set the signature algorithm. This can be either a name or an OID, names
+ /// are treated as case insensitive.
+ ///
+ /// The algorithm name.
+ [Obsolete("Not needed if Generate used with an ISignatureFactory")]
+ public void SetSignatureAlgorithm(
+ string signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Utilities.GetAlgorithmOid(signatureAlgorithm);
+ }
+ catch (Exception)
+ {
+ throw new ArgumentException("Unknown signature type requested");
+ }
+
+ sigAlgId = X509Utilities.GetSigAlgID(sigOID, signatureAlgorithm);
+
+ acInfoGen.SetSignature(sigAlgId);
+ }
+
+ /// Add an attribute.
+ public void AddAttribute(
+ X509Attribute attribute)
+ {
+ acInfoGen.AddAttribute(AttributeX509.GetInstance(attribute.ToAsn1Object()));
+ }
+
+ public void SetIssuerUniqueId(
+ bool[] iui)
+ {
+ // TODO convert bool array to bit string
+ //acInfoGen.SetIssuerUniqueID(iui);
+ throw Platform.CreateNotImplementedException("SetIssuerUniqueId()");
+ }
+
+ /// Add a given extension field for the standard extensions tag.
+ public void AddExtension(
+ string oid,
+ bool critical,
+ Asn1Encodable extensionValue)
+ {
+ extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
+ }
+
+ ///
+ /// Add a given extension field for the standard extensions tag.
+ /// The value parameter becomes the contents of the octet string associated
+ /// with the extension.
+ ///
+ public void AddExtension(
+ string oid,
+ bool critical,
+ byte[] extensionValue)
+ {
+ extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
+ }
+
+ ///
+ /// Generate an X509 certificate, based on the current issuer and subject.
+ ///
+ [Obsolete("Use Generate with an ISignatureFactory")]
+ public IX509AttributeCertificate Generate(
+ AsymmetricKeyParameter privateKey)
+ {
+ return Generate(privateKey, null);
+ }
+
+ ///
+ /// Generate an X509 certificate, based on the current issuer and subject,
+ /// using the supplied source of randomness, if required.
+ ///
+ [Obsolete("Use Generate with an ISignatureFactory")]
+ public IX509AttributeCertificate Generate(
+ AsymmetricKeyParameter privateKey,
+ SecureRandom random)
+ {
+ return Generate(new Asn1SignatureFactory(signatureAlgorithm, privateKey, random));
+ }
+
+ ///
+ /// Generate a new X.509 Attribute Certificate using the passed in SignatureCalculator.
+ ///
+ /// A signature calculator factory with the necessary algorithm details.
+ /// An IX509AttributeCertificate.
+ public IX509AttributeCertificate Generate(ISignatureFactory signatureCalculatorFactory)
+ {
+ if (!extGenerator.IsEmpty)
+ {
+ acInfoGen.SetExtensions(extGenerator.Generate());
+ }
+
+ AttributeCertificateInfo acInfo = acInfoGen.GenerateAttributeCertificateInfo();
+
+ byte[] encoded = acInfo.GetDerEncoded();
+
+ IStreamCalculator streamCalculator = signatureCalculatorFactory.CreateCalculator();
+
+ streamCalculator.Stream.Write(encoded, 0, encoded.Length);
+
+ Platform.Dispose(streamCalculator.Stream);
+
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ v.Add(acInfo, (AlgorithmIdentifier)signatureCalculatorFactory.AlgorithmDetails);
+
+ try
+ {
+ v.Add(new DerBitString(((IBlockResult)streamCalculator.GetResult()).Collect()));
+
+ return new X509V2AttributeCertificate(AttributeCertificate.GetInstance(new DerSequence(v)));
+ }
+ catch (Exception e)
+ {
+ // TODO
+// throw new ExtCertificateEncodingException("constructed invalid certificate", e);
+ throw new CertificateEncodingException("constructed invalid certificate", e);
+ }
+ }
+
+ ///
+ /// Allows enumeration of the signature names supported by the generator.
+ ///
+ public IEnumerable SignatureAlgNames
+ {
+ get { return X509Utilities.GetAlgNames(); }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/X509V2CRLGenerator.cs b/bc-sharp-crypto/src/x509/X509V2CRLGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..566d502344d54fa15462fea179d27dcf49ec5a8a
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/X509V2CRLGenerator.cs
@@ -0,0 +1,278 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Operators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.X509
+{
+ /**
+ * class to produce an X.509 Version 2 CRL.
+ */
+ public class X509V2CrlGenerator
+ {
+ private readonly X509ExtensionsGenerator extGenerator = new X509ExtensionsGenerator();
+
+ private V2TbsCertListGenerator tbsGen;
+ private DerObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private string signatureAlgorithm;
+
+ public X509V2CrlGenerator()
+ {
+ tbsGen = new V2TbsCertListGenerator();
+ }
+
+ /**
+ * reset the generator
+ */
+ public void Reset()
+ {
+ tbsGen = new V2TbsCertListGenerator();
+ extGenerator.Reset();
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void SetIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.SetIssuer(issuer);
+ }
+
+ public void SetThisUpdate(
+ DateTime date)
+ {
+ tbsGen.SetThisUpdate(new Time(date));
+ }
+
+ public void SetNextUpdate(
+ DateTime date)
+ {
+ tbsGen.SetNextUpdate(new Time(date));
+ }
+
+ /**
+ * Reason being as indicated by CrlReason, i.e. CrlReason.KeyCompromise
+ * or 0 if CrlReason is not to be used
+ **/
+ public void AddCrlEntry(
+ BigInteger userCertificate,
+ DateTime revocationDate,
+ int reason)
+ {
+ tbsGen.AddCrlEntry(new DerInteger(userCertificate), new Time(revocationDate), reason);
+ }
+
+ /**
+ * Add a CRL entry with an Invalidity Date extension as well as a CrlReason extension.
+ * Reason being as indicated by CrlReason, i.e. CrlReason.KeyCompromise
+ * or 0 if CrlReason is not to be used
+ **/
+ public void AddCrlEntry(
+ BigInteger userCertificate,
+ DateTime revocationDate,
+ int reason,
+ DateTime invalidityDate)
+ {
+ tbsGen.AddCrlEntry(new DerInteger(userCertificate), new Time(revocationDate), reason, new DerGeneralizedTime(invalidityDate));
+ }
+
+ /**
+ * Add a CRL entry with extensions.
+ **/
+ public void AddCrlEntry(
+ BigInteger userCertificate,
+ DateTime revocationDate,
+ X509Extensions extensions)
+ {
+ tbsGen.AddCrlEntry(new DerInteger(userCertificate), new Time(revocationDate), extensions);
+ }
+
+ /**
+ * Add the CRLEntry objects contained in a previous CRL.
+ *
+ * @param other the X509Crl to source the other entries from.
+ */
+ public void AddCrl(
+ X509Crl other)
+ {
+ if (other == null)
+ throw new ArgumentNullException("other");
+
+ ISet revocations = other.GetRevokedCertificates();
+
+ if (revocations != null)
+ {
+ foreach (X509CrlEntry entry in revocations)
+ {
+ try
+ {
+ tbsGen.AddCrlEntry(
+ Asn1Sequence.GetInstance(
+ Asn1Object.FromByteArray(entry.GetEncoded())));
+ }
+ catch (IOException e)
+ {
+ throw new CrlException("exception processing encoding of CRL", e);
+ }
+ }
+ }
+ }
+
+ ///
+ /// Set the signature algorithm that will be used to sign this CRL.
+ ///
+ ///
+ [Obsolete("Not needed if Generate used with an ISignatureFactory")]
+ public void SetSignatureAlgorithm(
+ string signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Utilities.GetAlgorithmOid(signatureAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new ArgumentException("Unknown signature type requested", e);
+ }
+
+ sigAlgId = X509Utilities.GetSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.SetSignature(sigAlgId);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void AddExtension(
+ string oid,
+ bool critical,
+ Asn1Encodable extensionValue)
+ {
+ extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void AddExtension(
+ DerObjectIdentifier oid,
+ bool critical,
+ Asn1Encodable extensionValue)
+ {
+ extGenerator.AddExtension(oid, critical, extensionValue);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void AddExtension(
+ string oid,
+ bool critical,
+ byte[] extensionValue)
+ {
+ extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, new DerOctetString(extensionValue));
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void AddExtension(
+ DerObjectIdentifier oid,
+ bool critical,
+ byte[] extensionValue)
+ {
+ extGenerator.AddExtension(oid, critical, new DerOctetString(extensionValue));
+ }
+
+ ///
+ /// Generate an X.509 CRL, based on the current issuer and subject.
+ ///
+ /// The private key of the issuer that is signing this certificate.
+ /// An X509Crl.
+ [Obsolete("Use Generate with an ISignatureFactory")]
+ public X509Crl Generate(
+ AsymmetricKeyParameter privateKey)
+ {
+ return Generate(privateKey, null);
+ }
+
+ ///
+ /// Generate an X.509 CRL, based on the current issuer and subject using the specified secure random.
+ ///
+ /// The private key of the issuer that is signing this certificate.
+ /// Your Secure Random instance.
+ /// An X509Crl.
+ [Obsolete("Use Generate with an ISignatureFactory")]
+ public X509Crl Generate(
+ AsymmetricKeyParameter privateKey,
+ SecureRandom random)
+ {
+ return Generate(new Asn1SignatureFactory(signatureAlgorithm, privateKey, random));
+ }
+
+ ///
+ /// Generate a new X509Crl using the passed in SignatureCalculator.
+ ///
+ /// A signature calculator factory with the necessary algorithm details.
+ /// An X509Crl.
+ public X509Crl Generate(ISignatureFactory signatureCalculatorFactory)
+ {
+ tbsGen.SetSignature((AlgorithmIdentifier)signatureCalculatorFactory.AlgorithmDetails);
+
+ TbsCertificateList tbsCertList = GenerateCertList();
+
+ IStreamCalculator streamCalculator = signatureCalculatorFactory.CreateCalculator();
+
+ byte[] encoded = tbsCertList.GetDerEncoded();
+
+ streamCalculator.Stream.Write(encoded, 0, encoded.Length);
+
+ Platform.Dispose(streamCalculator.Stream);
+
+ return GenerateJcaObject(tbsCertList, (AlgorithmIdentifier)signatureCalculatorFactory.AlgorithmDetails, ((IBlockResult)streamCalculator.GetResult()).Collect());
+ }
+
+ private TbsCertificateList GenerateCertList()
+ {
+ if (!extGenerator.IsEmpty)
+ {
+ tbsGen.SetExtensions(extGenerator.Generate());
+ }
+
+ return tbsGen.GenerateTbsCertList();
+ }
+
+ private X509Crl GenerateJcaObject(
+ TbsCertificateList tbsCrl,
+ AlgorithmIdentifier algId,
+ byte[] signature)
+ {
+ return new X509Crl(
+ CertificateList.GetInstance(
+ new DerSequence(tbsCrl, algId, new DerBitString(signature))));
+ }
+
+ ///
+ /// Allows enumeration of the signature names supported by the generator.
+ ///
+ public IEnumerable SignatureAlgNames
+ {
+ get { return X509Utilities.GetAlgNames(); }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/X509V3CertificateGenerator.cs b/bc-sharp-crypto/src/x509/X509V3CertificateGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bc619c37b625fff5728e7d34580497c4b1821714
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/X509V3CertificateGenerator.cs
@@ -0,0 +1,344 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Operators;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509
+{
+ ///
+ /// A class to Generate Version 3 X509Certificates.
+ ///
+ public class X509V3CertificateGenerator
+ {
+ private readonly X509ExtensionsGenerator extGenerator = new X509ExtensionsGenerator();
+
+ private V3TbsCertificateGenerator tbsGen;
+ private DerObjectIdentifier sigOid;
+ private AlgorithmIdentifier sigAlgId;
+ private string signatureAlgorithm;
+
+ public X509V3CertificateGenerator()
+ {
+ tbsGen = new V3TbsCertificateGenerator();
+ }
+
+ ///
+ /// Reset the Generator.
+ ///
+ public void Reset()
+ {
+ tbsGen = new V3TbsCertificateGenerator();
+ extGenerator.Reset();
+ }
+
+ ///
+ /// Set the certificate's serial number.
+ ///
+ /// Make serial numbers long, if you have no serial number policy make sure the number is at least 16 bytes of secure random data.
+ /// You will be surprised how ugly a serial number collision can Get.
+ /// The serial number.
+ public void SetSerialNumber(
+ BigInteger serialNumber)
+ {
+ if (serialNumber.SignValue <= 0)
+ {
+ throw new ArgumentException("serial number must be a positive integer", "serialNumber");
+ }
+
+ tbsGen.SetSerialNumber(new DerInteger(serialNumber));
+ }
+
+ ///
+ /// Set the distinguished name of the issuer.
+ /// The issuer is the entity which is signing the certificate.
+ ///
+ /// The issuer's DN.
+ public void SetIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.SetIssuer(issuer);
+ }
+
+ ///
+ /// Set the date that this certificate is to be valid from.
+ ///
+ ///
+ public void SetNotBefore(
+ DateTime date)
+ {
+ tbsGen.SetStartDate(new Time(date));
+ }
+
+ ///
+ /// Set the date after which this certificate will no longer be valid.
+ ///
+ ///
+ public void SetNotAfter(
+ DateTime date)
+ {
+ tbsGen.SetEndDate(new Time(date));
+ }
+
+ ///
+ /// Set the DN of the entity that this certificate is about.
+ ///
+ ///
+ public void SetSubjectDN(
+ X509Name subject)
+ {
+ tbsGen.SetSubject(subject);
+ }
+
+ ///
+ /// Set the public key that this certificate identifies.
+ ///
+ ///
+ public void SetPublicKey(
+ AsymmetricKeyParameter publicKey)
+ {
+ tbsGen.SetSubjectPublicKeyInfo(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey));
+ }
+
+ ///
+ /// Set the signature algorithm that will be used to sign this certificate.
+ ///
+ ///
+ [Obsolete("Not needed if Generate used with an ISignatureFactory")]
+ public void SetSignatureAlgorithm(
+ string signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOid = X509Utilities.GetAlgorithmOid(signatureAlgorithm);
+ }
+ catch (Exception)
+ {
+ throw new ArgumentException("Unknown signature type requested: " + signatureAlgorithm);
+ }
+
+ sigAlgId = X509Utilities.GetSigAlgID(sigOid, signatureAlgorithm);
+
+ tbsGen.SetSignature(sigAlgId);
+ }
+
+ ///
+ /// Set the subject unique ID - note: it is very rare that it is correct to do this.
+ ///
+ ///
+ public void SetSubjectUniqueID(
+ bool[] uniqueID)
+ {
+ tbsGen.SetSubjectUniqueID(booleanToBitString(uniqueID));
+ }
+
+ ///
+ /// Set the issuer unique ID - note: it is very rare that it is correct to do this.
+ ///
+ ///
+ public void SetIssuerUniqueID(
+ bool[] uniqueID)
+ {
+ tbsGen.SetIssuerUniqueID(booleanToBitString(uniqueID));
+ }
+
+ private DerBitString booleanToBitString(
+ bool[] id)
+ {
+ byte[] bytes = new byte[(id.Length + 7) / 8];
+
+ for (int i = 0; i != id.Length; i++)
+ {
+ if (id[i])
+ {
+ bytes[i / 8] |= (byte)(1 << ((7 - (i % 8))));
+ }
+ }
+
+ int pad = id.Length % 8;
+
+ if (pad == 0)
+ {
+ return new DerBitString(bytes);
+ }
+
+ return new DerBitString(bytes, 8 - pad);
+ }
+
+ ///
+ /// Add a given extension field for the standard extensions tag (tag 3).
+ ///
+ /// string containing a dotted decimal Object Identifier.
+ /// Is it critical.
+ /// The value.
+ public void AddExtension(
+ string oid,
+ bool critical,
+ Asn1Encodable extensionValue)
+ {
+ extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
+ }
+
+ ///
+ /// Add an extension to this certificate.
+ ///
+ /// Its Object Identifier.
+ /// Is it critical.
+ /// The value.
+ public void AddExtension(
+ DerObjectIdentifier oid,
+ bool critical,
+ Asn1Encodable extensionValue)
+ {
+ extGenerator.AddExtension(oid, critical, extensionValue);
+ }
+
+ ///
+ /// Add an extension using a string with a dotted decimal OID.
+ ///
+ /// string containing a dotted decimal Object Identifier.
+ /// Is it critical.
+ /// byte[] containing the value of this extension.
+ public void AddExtension(
+ string oid,
+ bool critical,
+ byte[] extensionValue)
+ {
+ extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, new DerOctetString(extensionValue));
+ }
+
+ ///
+ /// Add an extension to this certificate.
+ ///
+ /// Its Object Identifier.
+ /// Is it critical.
+ /// byte[] containing the value of this extension.
+ public void AddExtension(
+ DerObjectIdentifier oid,
+ bool critical,
+ byte[] extensionValue)
+ {
+ extGenerator.AddExtension(oid, critical, new DerOctetString(extensionValue));
+ }
+
+ ///
+ /// Add a given extension field for the standard extensions tag (tag 3),
+ /// copying the extension value from another certificate.
+ ///
+ public void CopyAndAddExtension(
+ string oid,
+ bool critical,
+ X509Certificate cert)
+ {
+ CopyAndAddExtension(new DerObjectIdentifier(oid), critical, cert);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * copying the extension value from another certificate.
+ * @throws CertificateParsingException if the extension cannot be extracted.
+ */
+ public void CopyAndAddExtension(
+ DerObjectIdentifier oid,
+ bool critical,
+ X509Certificate cert)
+ {
+ Asn1OctetString extValue = cert.GetExtensionValue(oid);
+
+ if (extValue == null)
+ {
+ throw new CertificateParsingException("extension " + oid + " not present");
+ }
+
+ try
+ {
+ Asn1Encodable value = X509ExtensionUtilities.FromExtensionValue(extValue);
+
+ this.AddExtension(oid, critical, value);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.Message, e);
+ }
+ }
+
+ ///
+ /// Generate an X509Certificate.
+ ///
+ /// The private key of the issuer that is signing this certificate.
+ /// An X509Certificate.
+ [Obsolete("Use Generate with an ISignatureFactory")]
+ public X509Certificate Generate(
+ AsymmetricKeyParameter privateKey)
+ {
+ return Generate(privateKey, null);
+ }
+
+ ///
+ /// Generate an X509Certificate using your own SecureRandom.
+ ///
+ /// The private key of the issuer that is signing this certificate.
+ /// You Secure Random instance.
+ /// An X509Certificate.
+ [Obsolete("Use Generate with an ISignatureFactory")]
+ public X509Certificate Generate(
+ AsymmetricKeyParameter privateKey,
+ SecureRandom random)
+ {
+ return Generate(new Asn1SignatureFactory(signatureAlgorithm, privateKey, random));
+ }
+
+ ///
+ /// Generate a new X509Certificate using the passed in SignatureCalculator.
+ ///
+ /// A signature calculator factory with the necessary algorithm details.
+ /// An X509Certificate.
+ public X509Certificate Generate(ISignatureFactory signatureCalculatorFactory)
+ {
+ tbsGen.SetSignature ((AlgorithmIdentifier)signatureCalculatorFactory.AlgorithmDetails);
+
+ if (!extGenerator.IsEmpty)
+ {
+ tbsGen.SetExtensions(extGenerator.Generate());
+ }
+
+ TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate();
+
+ IStreamCalculator streamCalculator = signatureCalculatorFactory.CreateCalculator();
+
+ byte[] encoded = tbsCert.GetDerEncoded();
+
+ streamCalculator.Stream.Write(encoded, 0, encoded.Length);
+
+ Platform.Dispose(streamCalculator.Stream);
+
+ return GenerateJcaObject(tbsCert, (AlgorithmIdentifier)signatureCalculatorFactory.AlgorithmDetails, ((IBlockResult)streamCalculator.GetResult()).Collect());
+ }
+
+ private X509Certificate GenerateJcaObject(
+ TbsCertificateStructure tbsCert,
+ AlgorithmIdentifier sigAlg,
+ byte[] signature)
+ {
+ return new X509Certificate(
+ new X509CertificateStructure(tbsCert, sigAlg, new DerBitString(signature)));
+ }
+
+ ///
+ /// Allows enumeration of the signature names supported by the generator.
+ ///
+ public IEnumerable SignatureAlgNames
+ {
+ get { return X509Utilities.GetAlgNames(); }
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/extension/AuthorityKeyIdentifierStructure.cs b/bc-sharp-crypto/src/x509/extension/AuthorityKeyIdentifierStructure.cs
new file mode 100644
index 0000000000000000000000000000000000000000..006dc009b022f80ad44ed42a2ad1918d174f705c
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/extension/AuthorityKeyIdentifierStructure.cs
@@ -0,0 +1,102 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+
+namespace Org.BouncyCastle.X509.Extension
+{
+ /// A high level authority key identifier.
+ public class AuthorityKeyIdentifierStructure
+ : AuthorityKeyIdentifier
+ {
+ /**
+ * Constructor which will take the byte[] returned from getExtensionValue()
+ *
+ * @param encodedValue a DER octet encoded string with the extension structure in it.
+ * @throws IOException on parsing errors.
+ */
+ // TODO Add a functional constructor from byte[]?
+ public AuthorityKeyIdentifierStructure(
+ Asn1OctetString encodedValue)
+ : base((Asn1Sequence) X509ExtensionUtilities.FromExtensionValue(encodedValue))
+ {
+ }
+
+ private static Asn1Sequence FromCertificate(
+ X509Certificate certificate)
+ {
+ try
+ {
+ GeneralName genName = new GeneralName(
+ PrincipalUtilities.GetIssuerX509Principal(certificate));
+
+ if (certificate.Version == 3)
+ {
+ Asn1OctetString ext = certificate.GetExtensionValue(X509Extensions.SubjectKeyIdentifier);
+
+ if (ext != null)
+ {
+ Asn1OctetString str = (Asn1OctetString) X509ExtensionUtilities.FromExtensionValue(ext);
+
+ return (Asn1Sequence) new AuthorityKeyIdentifier(
+ str.GetOctets(), new GeneralNames(genName), certificate.SerialNumber).ToAsn1Object();
+ }
+ }
+
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(
+ certificate.GetPublicKey());
+
+ return (Asn1Sequence) new AuthorityKeyIdentifier(
+ info, new GeneralNames(genName), certificate.SerialNumber).ToAsn1Object();
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("Exception extracting certificate details", e);
+ }
+ }
+
+ private static Asn1Sequence FromKey(
+ AsymmetricKeyParameter pubKey)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey);
+
+ return (Asn1Sequence) new AuthorityKeyIdentifier(info).ToAsn1Object();
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("can't process key: " + e);
+ }
+ }
+
+ /**
+ * Create an AuthorityKeyIdentifier using the passed in certificate's public
+ * key, issuer and serial number.
+ *
+ * @param certificate the certificate providing the information.
+ * @throws CertificateParsingException if there is a problem processing the certificate
+ */
+ public AuthorityKeyIdentifierStructure(
+ X509Certificate certificate)
+ : base(FromCertificate(certificate))
+ {
+ }
+
+ /**
+ * Create an AuthorityKeyIdentifier using just the hash of the
+ * public key.
+ *
+ * @param pubKey the key to generate the hash from.
+ * @throws InvalidKeyException if there is a problem using the key.
+ */
+ public AuthorityKeyIdentifierStructure(
+ AsymmetricKeyParameter pubKey)
+ : base(FromKey(pubKey))
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/extension/SubjectKeyIdentifierStructure.cs b/bc-sharp-crypto/src/x509/extension/SubjectKeyIdentifierStructure.cs
new file mode 100644
index 0000000000000000000000000000000000000000..4c7b79ab83a639d54f3f08413c479dfb2d0a3786
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/extension/SubjectKeyIdentifierStructure.cs
@@ -0,0 +1,49 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security.Certificates;
+
+namespace Org.BouncyCastle.X509.Extension
+{
+ /**
+ * A high level subject key identifier.
+ */
+ public class SubjectKeyIdentifierStructure
+ : SubjectKeyIdentifier
+ {
+ /**
+ * Constructor which will take the byte[] returned from getExtensionValue()
+ *
+ * @param encodedValue a DER octet encoded string with the extension structure in it.
+ * @throws IOException on parsing errors.
+ */
+ public SubjectKeyIdentifierStructure(
+ Asn1OctetString encodedValue)
+ : base((Asn1OctetString) X509ExtensionUtilities.FromExtensionValue(encodedValue))
+ {
+ }
+
+ private static Asn1OctetString FromPublicKey(
+ AsymmetricKeyParameter pubKey)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey);
+
+ return (Asn1OctetString) new SubjectKeyIdentifier(info).ToAsn1Object();
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("Exception extracting certificate details: " + e.ToString());
+ }
+ }
+
+ public SubjectKeyIdentifierStructure(
+ AsymmetricKeyParameter pubKey)
+ : base(FromPublicKey(pubKey))
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/extension/X509ExtensionUtil.cs b/bc-sharp-crypto/src/x509/extension/X509ExtensionUtil.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5f65ebfdad694f90d47f68c92db19b905379a4f0
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/extension/X509ExtensionUtil.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509.Extension
+{
+ public class X509ExtensionUtilities
+ {
+ public static Asn1Object FromExtensionValue(
+ Asn1OctetString extensionValue)
+ {
+ return Asn1Object.FromByteArray(extensionValue.GetOctets());
+ }
+
+ public static ICollection GetIssuerAlternativeNames(
+ X509Certificate cert)
+ {
+ Asn1OctetString extVal = cert.GetExtensionValue(X509Extensions.IssuerAlternativeName);
+
+ return GetAlternativeName(extVal);
+ }
+
+ public static ICollection GetSubjectAlternativeNames(
+ X509Certificate cert)
+ {
+ Asn1OctetString extVal = cert.GetExtensionValue(X509Extensions.SubjectAlternativeName);
+
+ return GetAlternativeName(extVal);
+ }
+
+ private static ICollection GetAlternativeName(
+ Asn1OctetString extVal)
+ {
+ IList temp = Platform.CreateArrayList();
+
+ if (extVal != null)
+ {
+ try
+ {
+ Asn1Sequence seq = DerSequence.GetInstance(FromExtensionValue(extVal));
+
+ foreach (Asn1Encodable primName in seq)
+ {
+ IList list = Platform.CreateArrayList();
+ GeneralName genName = GeneralName.GetInstance(primName);
+
+ list.Add(genName.TagNo);
+
+ switch (genName.TagNo)
+ {
+ case GeneralName.EdiPartyName:
+ case GeneralName.X400Address:
+ case GeneralName.OtherName:
+ list.Add(genName.Name.ToAsn1Object());
+ break;
+ case GeneralName.DirectoryName:
+ list.Add(X509Name.GetInstance(genName.Name).ToString());
+ break;
+ case GeneralName.DnsName:
+ case GeneralName.Rfc822Name:
+ case GeneralName.UniformResourceIdentifier:
+ list.Add(((IAsn1String)genName.Name).GetString());
+ break;
+ case GeneralName.RegisteredID:
+ list.Add(DerObjectIdentifier.GetInstance(genName.Name).Id);
+ break;
+ case GeneralName.IPAddress:
+ list.Add(DerOctetString.GetInstance(genName.Name).GetOctets());
+ break;
+ default:
+ throw new IOException("Bad tag number: " + genName.TagNo);
+ }
+
+ temp.Add(list);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.Message);
+ }
+ }
+
+ return temp;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/store/IX509Selector.cs b/bc-sharp-crypto/src/x509/store/IX509Selector.cs
new file mode 100644
index 0000000000000000000000000000000000000000..75358cbbf6375224bda0b06ddf827a67a14f44e9
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/store/IX509Selector.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public interface IX509Selector
+#if !(SILVERLIGHT || PORTABLE)
+ : ICloneable
+#endif
+ {
+#if SILVERLIGHT || PORTABLE
+ object Clone();
+#endif
+ bool Match(object obj);
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/store/IX509Store.cs b/bc-sharp-crypto/src/x509/store/IX509Store.cs
new file mode 100644
index 0000000000000000000000000000000000000000..e5c3a462a4b49db3eefefdd95b0b7859991e491c
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/store/IX509Store.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public interface IX509Store
+ {
+// void Init(IX509StoreParameters parameters);
+ ICollection GetMatches(IX509Selector selector);
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/store/IX509StoreParameters.cs b/bc-sharp-crypto/src/x509/store/IX509StoreParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..aee3036c2db5a9e9d2fbc7fac504a7a808f4653e
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/store/IX509StoreParameters.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public interface IX509StoreParameters
+ {
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/store/NoSuchStoreException.cs b/bc-sharp-crypto/src/x509/store/NoSuchStoreException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..28b18892aaae1dea000b29e2bcd27ffc8e96cde7
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/store/NoSuchStoreException.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class NoSuchStoreException
+ : X509StoreException
+ {
+ public NoSuchStoreException()
+ {
+ }
+
+ public NoSuchStoreException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public NoSuchStoreException(
+ string message,
+ Exception e)
+ : base(message, e)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/store/X509AttrCertStoreSelector.cs b/bc-sharp-crypto/src/x509/store/X509AttrCertStoreSelector.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9f1dc20d1d78981a0849f235316c72009631b965
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/store/X509AttrCertStoreSelector.cs
@@ -0,0 +1,376 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ /**
+ * This class is an Selector
like implementation to select
+ * attribute certificates from a given set of criteria.
+ *
+ * @see org.bouncycastle.x509.X509AttributeCertificate
+ * @see org.bouncycastle.x509.X509Store
+ */
+ public class X509AttrCertStoreSelector
+ : IX509Selector
+ {
+ // TODO: name constraints???
+
+ private IX509AttributeCertificate attributeCert;
+ private DateTimeObject attributeCertificateValid;
+ private AttributeCertificateHolder holder;
+ private AttributeCertificateIssuer issuer;
+ private BigInteger serialNumber;
+ private ISet targetNames = new HashSet();
+ private ISet targetGroups = new HashSet();
+
+ public X509AttrCertStoreSelector()
+ {
+ }
+
+ private X509AttrCertStoreSelector(
+ X509AttrCertStoreSelector o)
+ {
+ this.attributeCert = o.attributeCert;
+ this.attributeCertificateValid = o.attributeCertificateValid;
+ this.holder = o.holder;
+ this.issuer = o.issuer;
+ this.serialNumber = o.serialNumber;
+ this.targetGroups = new HashSet(o.targetGroups);
+ this.targetNames = new HashSet(o.targetNames);
+ }
+
+ ///
+ /// Decides if the given attribute certificate should be selected.
+ ///
+ /// The attribute certificate to be checked.
+ /// true
if the object matches this selector.
+ public bool Match(
+ object obj)
+ {
+ if (obj == null)
+ throw new ArgumentNullException("obj");
+
+ IX509AttributeCertificate attrCert = obj as IX509AttributeCertificate;
+
+ if (attrCert == null)
+ return false;
+
+ if (this.attributeCert != null && !this.attributeCert.Equals(attrCert))
+ return false;
+
+ if (serialNumber != null && !attrCert.SerialNumber.Equals(serialNumber))
+ return false;
+
+ if (holder != null && !attrCert.Holder.Equals(holder))
+ return false;
+
+ if (issuer != null && !attrCert.Issuer.Equals(issuer))
+ return false;
+
+ if (attributeCertificateValid != null && !attrCert.IsValid(attributeCertificateValid.Value))
+ return false;
+
+ if (targetNames.Count > 0 || targetGroups.Count > 0)
+ {
+ Asn1OctetString targetInfoExt = attrCert.GetExtensionValue(
+ X509Extensions.TargetInformation);
+
+ if (targetInfoExt != null)
+ {
+ TargetInformation targetinfo;
+ try
+ {
+ targetinfo = TargetInformation.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(targetInfoExt));
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+
+ Targets[] targetss = targetinfo.GetTargetsObjects();
+
+ if (targetNames.Count > 0)
+ {
+ bool found = false;
+
+ for (int i = 0; i < targetss.Length && !found; i++)
+ {
+ Target[] targets = targetss[i].GetTargets();
+
+ for (int j = 0; j < targets.Length; j++)
+ {
+ GeneralName targetName = targets[j].TargetName;
+
+ if (targetName != null && targetNames.Contains(targetName))
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ return false;
+ }
+ }
+
+ if (targetGroups.Count > 0)
+ {
+ bool found = false;
+
+ for (int i = 0; i < targetss.Length && !found; i++)
+ {
+ Target[] targets = targetss[i].GetTargets();
+
+ for (int j = 0; j < targets.Length; j++)
+ {
+ GeneralName targetGroup = targets[j].TargetGroup;
+
+ if (targetGroup != null && targetGroups.Contains(targetGroup))
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public object Clone()
+ {
+ return new X509AttrCertStoreSelector(this);
+ }
+
+ /// The attribute certificate which must be matched.
+ /// If null is given, any will do.
+ public IX509AttributeCertificate AttributeCert
+ {
+ get { return attributeCert; }
+ set { this.attributeCert = value; }
+ }
+
+ [Obsolete("Use AttributeCertificateValid instead")]
+ public DateTimeObject AttribueCertificateValid
+ {
+ get { return attributeCertificateValid; }
+ set { this.attributeCertificateValid = value; }
+ }
+
+ /// The criteria for validity
+ /// If null is given any will do.
+ public DateTimeObject AttributeCertificateValid
+ {
+ get { return attributeCertificateValid; }
+ set { this.attributeCertificateValid = value; }
+ }
+
+ /// The holder.
+ /// If null is given any will do.
+ public AttributeCertificateHolder Holder
+ {
+ get { return holder; }
+ set { this.holder = value; }
+ }
+
+ /// The issuer.
+ /// If null is given any will do.
+ public AttributeCertificateIssuer Issuer
+ {
+ get { return issuer; }
+ set { this.issuer = value; }
+ }
+
+ /// The serial number.
+ /// If null is given any will do.
+ public BigInteger SerialNumber
+ {
+ get { return serialNumber; }
+ set { this.serialNumber = value; }
+ }
+
+ /**
+ * Adds a target name criterion for the attribute certificate to the target
+ * information extension criteria. The X509AttributeCertificate
+ * must contain at least one of the specified target names.
+ *
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ *
+ * @param name The name as a GeneralName (not null
)
+ */
+ public void AddTargetName(
+ GeneralName name)
+ {
+ targetNames.Add(name);
+ }
+
+ /**
+ * Adds a target name criterion for the attribute certificate to the target
+ * information extension criteria. The X509AttributeCertificate
+ * must contain at least one of the specified target names.
+ *
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ *
+ * @param name a byte array containing the name in ASN.1 DER encoded form of a GeneralName
+ * @throws IOException if a parsing error occurs.
+ */
+ public void AddTargetName(
+ byte[] name)
+ {
+ AddTargetName(GeneralName.GetInstance(Asn1Object.FromByteArray(name)));
+ }
+
+ /**
+ * Adds a collection with target names criteria. If null
is
+ * given any will do.
+ *
+ * The collection consists of either GeneralName objects or byte[] arrays representing
+ * DER encoded GeneralName structures.
+ *
+ *
+ * @param names A collection of target names.
+ * @throws IOException if a parsing error occurs.
+ * @see #AddTargetName(byte[])
+ * @see #AddTargetName(GeneralName)
+ */
+ public void SetTargetNames(
+ IEnumerable names)
+ {
+ targetNames = ExtractGeneralNames(names);
+ }
+
+ /**
+ * Gets the target names. The collection consists of List
s
+ * made up of an Integer
in the first entry and a DER encoded
+ * byte array or a String
in the second entry.
+ * The returned collection is immutable.
+ *
+ * @return The collection of target names
+ * @see #setTargetNames(Collection)
+ */
+ public IEnumerable GetTargetNames()
+ {
+ return new EnumerableProxy(targetNames);
+ }
+
+ /**
+ * Adds a target group criterion for the attribute certificate to the target
+ * information extension criteria. The X509AttributeCertificate
+ * must contain at least one of the specified target groups.
+ *
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ *
+ * @param group The group as GeneralName form (not null
)
+ */
+ public void AddTargetGroup(
+ GeneralName group)
+ {
+ targetGroups.Add(group);
+ }
+
+ /**
+ * Adds a target group criterion for the attribute certificate to the target
+ * information extension criteria. The X509AttributeCertificate
+ * must contain at least one of the specified target groups.
+ *
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ *
+ * @param name a byte array containing the group in ASN.1 DER encoded form of a GeneralName
+ * @throws IOException if a parsing error occurs.
+ */
+ public void AddTargetGroup(
+ byte[] name)
+ {
+ AddTargetGroup(GeneralName.GetInstance(Asn1Object.FromByteArray(name)));
+ }
+
+ /**
+ * Adds a collection with target groups criteria. If null
is
+ * given any will do.
+ *
+ * The collection consists of GeneralName
objects or byte[]
+ * representing DER encoded GeneralNames.
+ *
+ *
+ * @param names A collection of target groups.
+ * @throws IOException if a parsing error occurs.
+ * @see #AddTargetGroup(byte[])
+ * @see #AddTargetGroup(GeneralName)
+ */
+ public void SetTargetGroups(
+ IEnumerable names)
+ {
+ targetGroups = ExtractGeneralNames(names);
+ }
+
+ /**
+ * Gets the target groups. The collection consists of List
s
+ * made up of an Integer
in the first entry and a DER encoded
+ * byte array or a String
in the second entry.
+ * The returned collection is immutable.
+ *
+ * @return The collection of target groups.
+ * @see #setTargetGroups(Collection)
+ */
+ public IEnumerable GetTargetGroups()
+ {
+ return new EnumerableProxy(targetGroups);
+ }
+
+ private ISet ExtractGeneralNames(
+ IEnumerable names)
+ {
+ ISet result = new HashSet();
+
+ if (names != null)
+ {
+ foreach (object o in names)
+ {
+ if (o is GeneralName)
+ {
+ result.Add(o);
+ }
+ else
+ {
+ result.Add(GeneralName.GetInstance(Asn1Object.FromByteArray((byte[]) o)));
+ }
+ }
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/store/X509CertPairStoreSelector.cs b/bc-sharp-crypto/src/x509/store/X509CertPairStoreSelector.cs
new file mode 100644
index 0000000000000000000000000000000000000000..2796971c78c365a6f0cbf6fb44f5286df2ff6f05
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/store/X509CertPairStoreSelector.cs
@@ -0,0 +1,92 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ ///
+ /// This class is an IX509Selector
implementation to select
+ /// certificate pairs, which are e.g. used for cross certificates. The set of
+ /// criteria is given from two X509CertStoreSelector
objects,
+ /// each of which, if present, must match the respective component of a pair.
+ ///
+ public class X509CertPairStoreSelector
+ : IX509Selector
+ {
+ private static X509CertStoreSelector CloneSelector(
+ X509CertStoreSelector s)
+ {
+ return s == null ? null : (X509CertStoreSelector) s.Clone();
+ }
+
+ private X509CertificatePair certPair;
+ private X509CertStoreSelector forwardSelector;
+ private X509CertStoreSelector reverseSelector;
+
+ public X509CertPairStoreSelector()
+ {
+ }
+
+ private X509CertPairStoreSelector(
+ X509CertPairStoreSelector o)
+ {
+ this.certPair = o.CertPair;
+ this.forwardSelector = o.ForwardSelector;
+ this.reverseSelector = o.ReverseSelector;
+ }
+
+ /// The certificate pair which is used for testing on equality.
+ public X509CertificatePair CertPair
+ {
+ get { return certPair; }
+ set { this.certPair = value; }
+ }
+
+ /// The certificate selector for the forward part.
+ public X509CertStoreSelector ForwardSelector
+ {
+ get { return CloneSelector(forwardSelector); }
+ set { this.forwardSelector = CloneSelector(value); }
+ }
+
+ /// The certificate selector for the reverse part.
+ public X509CertStoreSelector ReverseSelector
+ {
+ get { return CloneSelector(reverseSelector); }
+ set { this.reverseSelector = CloneSelector(value); }
+ }
+
+ ///
+ /// Decides if the given certificate pair should be selected. If
+ /// obj is not a X509CertificatePair
, this method
+ /// returns false
.
+ ///
+ /// The X509CertificatePair
to be tested.
+ /// true
if the object matches this selector.
+ public bool Match(
+ object obj)
+ {
+ if (obj == null)
+ throw new ArgumentNullException("obj");
+
+ X509CertificatePair pair = obj as X509CertificatePair;
+
+ if (pair == null)
+ return false;
+
+ if (certPair != null && !certPair.Equals(pair))
+ return false;
+
+ if (forwardSelector != null && !forwardSelector.Match(pair.Forward))
+ return false;
+
+ if (reverseSelector != null && !reverseSelector.Match(pair.Reverse))
+ return false;
+
+ return true;
+ }
+
+ public object Clone()
+ {
+ return new X509CertPairStoreSelector(this);
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/store/X509CertStoreSelector.cs b/bc-sharp-crypto/src/x509/store/X509CertStoreSelector.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3874edf1d174d9954caa60a921069cb0eaffad5d
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/store/X509CertStoreSelector.cs
@@ -0,0 +1,337 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public class X509CertStoreSelector
+ : IX509Selector
+ {
+ // TODO Missing criteria?
+
+ private byte[] authorityKeyIdentifier;
+ private int basicConstraints = -1;
+ private X509Certificate certificate;
+ private DateTimeObject certificateValid;
+ private ISet extendedKeyUsage;
+ private X509Name issuer;
+ private bool[] keyUsage;
+ private ISet policy;
+ private DateTimeObject privateKeyValid;
+ private BigInteger serialNumber;
+ private X509Name subject;
+ private byte[] subjectKeyIdentifier;
+ private SubjectPublicKeyInfo subjectPublicKey;
+ private DerObjectIdentifier subjectPublicKeyAlgID;
+
+ public X509CertStoreSelector()
+ {
+ }
+
+ public X509CertStoreSelector(
+ X509CertStoreSelector o)
+ {
+ this.authorityKeyIdentifier = o.AuthorityKeyIdentifier;
+ this.basicConstraints = o.BasicConstraints;
+ this.certificate = o.Certificate;
+ this.certificateValid = o.CertificateValid;
+ this.extendedKeyUsage = o.ExtendedKeyUsage;
+ this.issuer = o.Issuer;
+ this.keyUsage = o.KeyUsage;
+ this.policy = o.Policy;
+ this.privateKeyValid = o.PrivateKeyValid;
+ this.serialNumber = o.SerialNumber;
+ this.subject = o.Subject;
+ this.subjectKeyIdentifier = o.SubjectKeyIdentifier;
+ this.subjectPublicKey = o.SubjectPublicKey;
+ this.subjectPublicKeyAlgID = o.SubjectPublicKeyAlgID;
+ }
+
+ public virtual object Clone()
+ {
+ return new X509CertStoreSelector(this);
+ }
+
+ public byte[] AuthorityKeyIdentifier
+ {
+ get { return Arrays.Clone(authorityKeyIdentifier); }
+ set { authorityKeyIdentifier = Arrays.Clone(value); }
+ }
+
+ public int BasicConstraints
+ {
+ get { return basicConstraints; }
+ set
+ {
+ if (value < -2)
+ throw new ArgumentException("value can't be less than -2", "value");
+
+ basicConstraints = value;
+ }
+ }
+
+ public X509Certificate Certificate
+ {
+ get { return certificate; }
+ set { this.certificate = value; }
+ }
+
+ public DateTimeObject CertificateValid
+ {
+ get { return certificateValid; }
+ set { certificateValid = value; }
+ }
+
+ public ISet ExtendedKeyUsage
+ {
+ get { return CopySet(extendedKeyUsage); }
+ set { extendedKeyUsage = CopySet(value); }
+ }
+
+ public X509Name Issuer
+ {
+ get { return issuer; }
+ set { issuer = value; }
+ }
+
+ [Obsolete("Avoid working with X509Name objects in string form")]
+ public string IssuerAsString
+ {
+ get { return issuer != null ? issuer.ToString() : null; }
+ }
+
+ public bool[] KeyUsage
+ {
+ get { return CopyBoolArray(keyUsage); }
+ set { keyUsage = CopyBoolArray(value); }
+ }
+
+ ///
+ /// An ISet
of DerObjectIdentifier
objects.
+ ///
+ public ISet Policy
+ {
+ get { return CopySet(policy); }
+ set { policy = CopySet(value); }
+ }
+
+ public DateTimeObject PrivateKeyValid
+ {
+ get { return privateKeyValid; }
+ set { privateKeyValid = value; }
+ }
+
+ public BigInteger SerialNumber
+ {
+ get { return serialNumber; }
+ set { serialNumber = value; }
+ }
+
+ public X509Name Subject
+ {
+ get { return subject; }
+ set { subject = value; }
+ }
+
+ public string SubjectAsString
+ {
+ get { return subject != null ? subject.ToString() : null; }
+ }
+
+ public byte[] SubjectKeyIdentifier
+ {
+ get { return Arrays.Clone(subjectKeyIdentifier); }
+ set { subjectKeyIdentifier = Arrays.Clone(value); }
+ }
+
+ public SubjectPublicKeyInfo SubjectPublicKey
+ {
+ get { return subjectPublicKey; }
+ set { subjectPublicKey = value; }
+ }
+
+ public DerObjectIdentifier SubjectPublicKeyAlgID
+ {
+ get { return subjectPublicKeyAlgID; }
+ set { subjectPublicKeyAlgID = value; }
+ }
+
+ public virtual bool Match(
+ object obj)
+ {
+ X509Certificate c = obj as X509Certificate;
+
+ if (c == null)
+ return false;
+
+ if (!MatchExtension(authorityKeyIdentifier, c, X509Extensions.AuthorityKeyIdentifier))
+ return false;
+
+ if (basicConstraints != -1)
+ {
+ int bc = c.GetBasicConstraints();
+
+ if (basicConstraints == -2)
+ {
+ if (bc != -1)
+ return false;
+ }
+ else
+ {
+ if (bc < basicConstraints)
+ return false;
+ }
+ }
+
+ if (certificate != null && !certificate.Equals(c))
+ return false;
+
+ if (certificateValid != null && !c.IsValid(certificateValid.Value))
+ return false;
+
+ if (extendedKeyUsage != null)
+ {
+ IList eku = c.GetExtendedKeyUsage();
+
+ // Note: if no extended key usage set, all key purposes are implicitly allowed
+
+ if (eku != null)
+ {
+ foreach (DerObjectIdentifier oid in extendedKeyUsage)
+ {
+ if (!eku.Contains(oid.Id))
+ return false;
+ }
+ }
+ }
+
+ if (issuer != null && !issuer.Equivalent(c.IssuerDN, true))
+ return false;
+
+ if (keyUsage != null)
+ {
+ bool[] ku = c.GetKeyUsage();
+
+ // Note: if no key usage set, all key purposes are implicitly allowed
+
+ if (ku != null)
+ {
+ for (int i = 0; i < 9; ++i)
+ {
+ if (keyUsage[i] && !ku[i])
+ return false;
+ }
+ }
+ }
+
+ if (policy != null)
+ {
+ Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.CertificatePolicies);
+ if (extVal == null)
+ return false;
+
+ Asn1Sequence certPolicies = Asn1Sequence.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(extVal));
+
+ if (policy.Count < 1 && certPolicies.Count < 1)
+ return false;
+
+ bool found = false;
+ foreach (PolicyInformation pi in certPolicies)
+ {
+ if (policy.Contains(pi.PolicyIdentifier))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return false;
+ }
+
+ if (privateKeyValid != null)
+ {
+ Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.PrivateKeyUsagePeriod);
+ if (extVal == null)
+ return false;
+
+ PrivateKeyUsagePeriod pkup = PrivateKeyUsagePeriod.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(extVal));
+
+ DateTime dt = privateKeyValid.Value;
+ DateTime notAfter = pkup.NotAfter.ToDateTime();
+ DateTime notBefore = pkup.NotBefore.ToDateTime();
+
+ if (dt.CompareTo(notAfter) > 0 || dt.CompareTo(notBefore) < 0)
+ return false;
+ }
+
+ if (serialNumber != null && !serialNumber.Equals(c.SerialNumber))
+ return false;
+
+ if (subject != null && !subject.Equivalent(c.SubjectDN, true))
+ return false;
+
+ if (!MatchExtension(subjectKeyIdentifier, c, X509Extensions.SubjectKeyIdentifier))
+ return false;
+
+ if (subjectPublicKey != null && !subjectPublicKey.Equals(GetSubjectPublicKey(c)))
+ return false;
+
+ if (subjectPublicKeyAlgID != null
+ && !subjectPublicKeyAlgID.Equals(GetSubjectPublicKey(c).AlgorithmID))
+ return false;
+
+ return true;
+ }
+
+ internal static bool IssuersMatch(
+ X509Name a,
+ X509Name b)
+ {
+ return a == null ? b == null : a.Equivalent(b, true);
+ }
+
+ private static bool[] CopyBoolArray(
+ bool[] b)
+ {
+ return b == null ? null : (bool[]) b.Clone();
+ }
+
+ private static ISet CopySet(
+ ISet s)
+ {
+ return s == null ? null : new HashSet(s);
+ }
+
+ private static SubjectPublicKeyInfo GetSubjectPublicKey(
+ X509Certificate c)
+ {
+ return SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(c.GetPublicKey());
+ }
+
+ private static bool MatchExtension(
+ byte[] b,
+ X509Certificate c,
+ DerObjectIdentifier oid)
+ {
+ if (b == null)
+ return true;
+
+ Asn1OctetString extVal = c.GetExtensionValue(oid);
+
+ if (extVal == null)
+ return false;
+
+ return Arrays.AreEqual(b, extVal.GetOctets());
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/store/X509CollectionStore.cs b/bc-sharp-crypto/src/x509/store/X509CollectionStore.cs
new file mode 100644
index 0000000000000000000000000000000000000000..92173140be051fe6007edd1fd4a1703db2e0dc0c
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/store/X509CollectionStore.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ /**
+ * A simple collection backed store.
+ */
+ internal class X509CollectionStore
+ : IX509Store
+ {
+ private ICollection _local;
+
+ /**
+ * Basic constructor.
+ *
+ * @param collection - initial contents for the store, this is copied.
+ */
+ internal X509CollectionStore(
+ ICollection collection)
+ {
+ _local = Platform.CreateArrayList(collection);
+ }
+
+ /**
+ * Return the matches in the collection for the passed in selector.
+ *
+ * @param selector the selector to match against.
+ * @return a possibly empty collection of matching objects.
+ */
+ public ICollection GetMatches(
+ IX509Selector selector)
+ {
+ if (selector == null)
+ {
+ return Platform.CreateArrayList(_local);
+ }
+
+ IList result = Platform.CreateArrayList();
+ foreach (object obj in _local)
+ {
+ if (selector.Match(obj))
+ result.Add(obj);
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/store/X509CollectionStoreParameters.cs b/bc-sharp-crypto/src/x509/store/X509CollectionStoreParameters.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7fd047a470c0ee88124b95933dd7a95394d4bc99
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/store/X509CollectionStoreParameters.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ /// This class contains a collection for collection based X509Store
s.
+ public class X509CollectionStoreParameters
+ : IX509StoreParameters
+ {
+ private readonly IList collection;
+
+ ///
+ /// Constructor.
+ ///
+ /// The collection is copied.
+ ///
+ ///
+ /// The collection containing X.509 object types.
+ /// If collection is null.
+ public X509CollectionStoreParameters(
+ ICollection collection)
+ {
+ if (collection == null)
+ throw new ArgumentNullException("collection");
+
+ this.collection = Platform.CreateArrayList(collection);
+ }
+
+ // TODO Do we need to be able to Clone() these, and should it really be shallow?
+// /**
+// * Returns a shallow clone. The returned contents are not copied, so adding
+// * or removing objects will effect this.
+// *
+// * @return a shallow clone.
+// */
+// public object Clone()
+// {
+// return new X509CollectionStoreParameters(collection);
+// }
+
+ /// Returns a copy of the ICollection
.
+ public ICollection GetCollection()
+ {
+ return Platform.CreateArrayList(collection);
+ }
+
+ /// Returns a formatted string describing the parameters.
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("X509CollectionStoreParameters: [\n");
+ sb.Append(" collection: " + collection + "\n");
+ sb.Append("]");
+ return sb.ToString();
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/store/X509CrlStoreSelector.cs b/bc-sharp-crypto/src/x509/store/X509CrlStoreSelector.cs
new file mode 100644
index 0000000000000000000000000000000000000000..c4b0062c1d0142369b284ad89a6844d1f0bb8f37
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/store/X509CrlStoreSelector.cs
@@ -0,0 +1,283 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public class X509CrlStoreSelector
+ : IX509Selector
+ {
+ // TODO Missing criteria?
+
+ private X509Certificate certificateChecking;
+ private DateTimeObject dateAndTime;
+ private ICollection issuers;
+ private BigInteger maxCrlNumber;
+ private BigInteger minCrlNumber;
+
+ private IX509AttributeCertificate attrCertChecking;
+ private bool completeCrlEnabled;
+ private bool deltaCrlIndicatorEnabled;
+ private byte[] issuingDistributionPoint;
+ private bool issuingDistributionPointEnabled;
+ private BigInteger maxBaseCrlNumber;
+
+ public X509CrlStoreSelector()
+ {
+ }
+
+ public X509CrlStoreSelector(
+ X509CrlStoreSelector o)
+ {
+ this.certificateChecking = o.CertificateChecking;
+ this.dateAndTime = o.DateAndTime;
+ this.issuers = o.Issuers;
+ this.maxCrlNumber = o.MaxCrlNumber;
+ this.minCrlNumber = o.MinCrlNumber;
+
+ this.deltaCrlIndicatorEnabled = o.DeltaCrlIndicatorEnabled;
+ this.completeCrlEnabled = o.CompleteCrlEnabled;
+ this.maxBaseCrlNumber = o.MaxBaseCrlNumber;
+ this.attrCertChecking = o.AttrCertChecking;
+ this.issuingDistributionPointEnabled = o.IssuingDistributionPointEnabled;
+ this.issuingDistributionPoint = o.IssuingDistributionPoint;
+ }
+
+ public virtual object Clone()
+ {
+ return new X509CrlStoreSelector(this);
+ }
+
+ public X509Certificate CertificateChecking
+ {
+ get { return certificateChecking; }
+ set { certificateChecking = value; }
+ }
+
+ public DateTimeObject DateAndTime
+ {
+ get { return dateAndTime; }
+ set { dateAndTime = value; }
+ }
+
+ ///
+ /// An ICollection
of X509Name
objects
+ ///
+ public ICollection Issuers
+ {
+ get { return Platform.CreateArrayList(issuers); }
+ set { issuers = Platform.CreateArrayList(value); }
+ }
+
+ public BigInteger MaxCrlNumber
+ {
+ get { return maxCrlNumber; }
+ set { maxCrlNumber = value; }
+ }
+
+ public BigInteger MinCrlNumber
+ {
+ get { return minCrlNumber; }
+ set { minCrlNumber = value; }
+ }
+
+ /**
+ * The attribute certificate being checked. This is not a criterion.
+ * Rather, it is optional information that may help a {@link X509Store} find
+ * CRLs that would be relevant when checking revocation for the specified
+ * attribute certificate. If null
is specified, then no such
+ * optional information is provided.
+ *
+ * @param attrCert the IX509AttributeCertificate
being checked (or
+ * null
)
+ * @see #getAttrCertificateChecking()
+ */
+ public IX509AttributeCertificate AttrCertChecking
+ {
+ get { return attrCertChecking; }
+ set { this.attrCertChecking = value; }
+ }
+
+ /**
+ * If true
only complete CRLs are returned. Defaults to
+ * false
.
+ *
+ * @return true
if only complete CRLs are returned.
+ */
+ public bool CompleteCrlEnabled
+ {
+ get { return completeCrlEnabled; }
+ set { this.completeCrlEnabled = value; }
+ }
+
+ /**
+ * Returns if this selector must match CRLs with the delta CRL indicator
+ * extension set. Defaults to false
.
+ *
+ * @return Returns true
if only CRLs with the delta CRL
+ * indicator extension are selected.
+ */
+ public bool DeltaCrlIndicatorEnabled
+ {
+ get { return deltaCrlIndicatorEnabled; }
+ set { this.deltaCrlIndicatorEnabled = value; }
+ }
+
+ /**
+ * The issuing distribution point.
+ *
+ * The issuing distribution point extension is a CRL extension which
+ * identifies the scope and the distribution point of a CRL. The scope
+ * contains among others information about revocation reasons contained in
+ * the CRL. Delta CRLs and complete CRLs must have matching issuing
+ * distribution points.
+ *
+ * The byte array is cloned to protect against subsequent modifications.
+ *
+ * You must also enable or disable this criteria with
+ * {@link #setIssuingDistributionPointEnabled(bool)}.
+ *
+ * @param issuingDistributionPoint The issuing distribution point to set.
+ * This is the DER encoded OCTET STRING extension value.
+ * @see #getIssuingDistributionPoint()
+ */
+ public byte[] IssuingDistributionPoint
+ {
+ get { return Arrays.Clone(issuingDistributionPoint); }
+ set { this.issuingDistributionPoint = Arrays.Clone(value); }
+ }
+
+ /**
+ * Whether the issuing distribution point criteria should be applied.
+ * Defaults to false
.
+ *
+ * You may also set the issuing distribution point criteria if not a missing
+ * issuing distribution point should be assumed.
+ *
+ * @return Returns if the issuing distribution point check is enabled.
+ */
+ public bool IssuingDistributionPointEnabled
+ {
+ get { return issuingDistributionPointEnabled; }
+ set { this.issuingDistributionPointEnabled = value; }
+ }
+
+ /**
+ * The maximum base CRL number. Defaults to null
.
+ *
+ * @return Returns the maximum base CRL number.
+ * @see #setMaxBaseCRLNumber(BigInteger)
+ */
+ public BigInteger MaxBaseCrlNumber
+ {
+ get { return maxBaseCrlNumber; }
+ set { this.maxBaseCrlNumber = value; }
+ }
+
+ public virtual bool Match(
+ object obj)
+ {
+ X509Crl c = obj as X509Crl;
+
+ if (c == null)
+ return false;
+
+ if (dateAndTime != null)
+ {
+ DateTime dt = dateAndTime.Value;
+ DateTime tu = c.ThisUpdate;
+ DateTimeObject nu = c.NextUpdate;
+
+ if (dt.CompareTo(tu) < 0 || nu == null || dt.CompareTo(nu.Value) >= 0)
+ return false;
+ }
+
+ if (issuers != null)
+ {
+ X509Name i = c.IssuerDN;
+
+ bool found = false;
+
+ foreach (X509Name issuer in issuers)
+ {
+ if (issuer.Equivalent(i, true))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ return false;
+ }
+
+ if (maxCrlNumber != null || minCrlNumber != null)
+ {
+ Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.CrlNumber);
+ if (extVal == null)
+ return false;
+
+ BigInteger cn = CrlNumber.GetInstance(
+ X509ExtensionUtilities.FromExtensionValue(extVal)).PositiveValue;
+
+ if (maxCrlNumber != null && cn.CompareTo(maxCrlNumber) > 0)
+ return false;
+
+ if (minCrlNumber != null && cn.CompareTo(minCrlNumber) < 0)
+ return false;
+ }
+
+ DerInteger dci = null;
+ try
+ {
+ Asn1OctetString bytes = c.GetExtensionValue(X509Extensions.DeltaCrlIndicator);
+ if (bytes != null)
+ {
+ dci = DerInteger.GetInstance(X509ExtensionUtilities.FromExtensionValue(bytes));
+ }
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+
+ if (dci == null)
+ {
+ if (DeltaCrlIndicatorEnabled)
+ return false;
+ }
+ else
+ {
+ if (CompleteCrlEnabled)
+ return false;
+
+ if (maxBaseCrlNumber != null && dci.PositiveValue.CompareTo(maxBaseCrlNumber) > 0)
+ return false;
+ }
+
+ if (issuingDistributionPointEnabled)
+ {
+ Asn1OctetString idp = c.GetExtensionValue(X509Extensions.IssuingDistributionPoint);
+ if (issuingDistributionPoint == null)
+ {
+ if (idp != null)
+ return false;
+ }
+ else
+ {
+ if (!Arrays.AreEqual(idp.GetOctets(), issuingDistributionPoint))
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/store/X509StoreException.cs b/bc-sharp-crypto/src/x509/store/X509StoreException.cs
new file mode 100644
index 0000000000000000000000000000000000000000..ea7e51e79a0077986494940364598aa00007f09f
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/store/X509StoreException.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+ [Serializable]
+#endif
+ public class X509StoreException
+ : Exception
+ {
+ public X509StoreException()
+ {
+ }
+
+ public X509StoreException(
+ string message)
+ : base(message)
+ {
+ }
+
+ public X509StoreException(
+ string message,
+ Exception e)
+ : base(message, e)
+ {
+ }
+ }
+}
diff --git a/bc-sharp-crypto/src/x509/store/X509StoreFactory.cs b/bc-sharp-crypto/src/x509/store/X509StoreFactory.cs
new file mode 100644
index 0000000000000000000000000000000000000000..96f22be3fb94e78ab376800a7ec9c19ea49ac8d3
--- /dev/null
+++ b/bc-sharp-crypto/src/x509/store/X509StoreFactory.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509.Store
+{
+ public sealed class X509StoreFactory
+ {
+ private X509StoreFactory()
+ {
+ }
+
+ public static IX509Store Create(
+ string type,
+ IX509StoreParameters parameters)
+ {
+ if (type == null)
+ throw new ArgumentNullException("type");
+
+ string[] parts = Platform.ToUpperInvariant(type).Split('/');
+
+ if (parts.Length < 2)
+ throw new ArgumentException("type");
+
+ if (parts[1] != "COLLECTION")
+ throw new NoSuchStoreException("X.509 store type '" + type + "' not available.");
+
+ X509CollectionStoreParameters p = (X509CollectionStoreParameters) parameters;
+ ICollection coll = p.GetCollection();
+
+ switch (parts[0])
+ {
+ case "ATTRIBUTECERTIFICATE":
+ checkCorrectType(coll, typeof(IX509AttributeCertificate));
+ break;
+ case "CERTIFICATE":
+ checkCorrectType(coll, typeof(X509Certificate));
+ break;
+ case "CERTIFICATEPAIR":
+ checkCorrectType(coll, typeof(X509CertificatePair));
+ break;
+ case "CRL":
+ checkCorrectType(coll, typeof(X509Crl));
+ break;
+ default:
+ throw new NoSuchStoreException("X.509 store type '" + type + "' not available.");
+ }
+
+ return new X509CollectionStore(coll);
+ }
+
+ private static void checkCorrectType(ICollection coll, Type t)
+ {
+ foreach (object o in coll)
+ {
+ if (!t.IsInstanceOfType(o))
+ throw new InvalidCastException("Can't cast object to type: " + t.FullName);
+ }
+ }
+ }
+}
diff --git a/bin/x64/Debug/ufr-signer.exe b/bin/x64/Debug/ufr-signer.exe
new file mode 100644
index 0000000000000000000000000000000000000000..a60e67897b6a08ea1acbe84bfd395d6cd714e3db
Binary files /dev/null and b/bin/x64/Debug/ufr-signer.exe differ
diff --git a/bin/x64/Debug/ufr-signer.exe.config b/bin/x64/Debug/ufr-signer.exe.config
new file mode 100644
index 0000000000000000000000000000000000000000..8324aa6ff159e0630b9811cf7d53f09b4b8adf91
--- /dev/null
+++ b/bin/x64/Debug/ufr-signer.exe.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/bin/x64/Release/ufr-signer.exe b/bin/x64/Release/ufr-signer.exe
new file mode 100644
index 0000000000000000000000000000000000000000..cfe5318ccf5eba1f12fc9eafe1eb0c40c9a08f98
Binary files /dev/null and b/bin/x64/Release/ufr-signer.exe differ
diff --git a/bin/x64/Release/ufr-signer.exe.config b/bin/x64/Release/ufr-signer.exe.config
new file mode 100644
index 0000000000000000000000000000000000000000..8324aa6ff159e0630b9811cf7d53f09b4b8adf91
--- /dev/null
+++ b/bin/x64/Release/ufr-signer.exe.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/bin/x86/Release/ufr-signer.exe b/bin/x86/Release/ufr-signer.exe
new file mode 100644
index 0000000000000000000000000000000000000000..6b33bfebfa6abd0aa27df5b6f1b94bdbae2874e4
Binary files /dev/null and b/bin/x86/Release/ufr-signer.exe differ
diff --git a/bin/x86/Release/ufr-signer.exe.config b/bin/x86/Release/ufr-signer.exe.config
new file mode 100644
index 0000000000000000000000000000000000000000..8324aa6ff159e0630b9811cf7d53f09b4b8adf91
--- /dev/null
+++ b/bin/x86/Release/ufr-signer.exe.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/digital-signature-verifier.csproj b/digital-signature-verifier.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..316840d2d02e49d7b5053ea420f69d75aa0b8898
--- /dev/null
+++ b/digital-signature-verifier.csproj
@@ -0,0 +1,1625 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {0D346CC0-83C5-4117-B2E6-2A33686B3FC0}
+ WinExe
+ Properties
+ EcdsaTest
+ ufr-signer
+ v4.6
+ 512
+ true
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 1
+ 0.0.0.1
+ false
+ false
+ true
+
+
+ true
+ bin\x64\Debug\
+ TRACE;DEBUG;WIN64
+ full
+ x64
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+
+
+ bin\x64\Release\
+ TRACE;WIN64
+ true
+ pdbonly
+ x64
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Form
+
+
+ frmMain.cs
+
+
+ Form
+
+
+ frmPassword.cs
+
+
+
+
+ frmMain.cs
+
+
+ frmPassword.cs
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+ Designer
+
+
+ True
+ Resources.resx
+ True
+
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+ True
+ Settings.settings
+ True
+
+
+
+
+
+
+
+ False
+ Microsoft .NET Framework 4.6 %28x86 and x64%29
+ true
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+
+
+
\ No newline at end of file
diff --git a/digital-signature-verifier.sln b/digital-signature-verifier.sln
new file mode 100644
index 0000000000000000000000000000000000000000..b1266c49129ad48cbe32b4fb799d6093aa52e538
--- /dev/null
+++ b/digital-signature-verifier.sln
@@ -0,0 +1,32 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.23107.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "digital-signature-verifier", "digital-signature-verifier.csproj", "{0D346CC0-83C5-4117-B2E6-2A33686B3FC0}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0D346CC0-83C5-4117-B2E6-2A33686B3FC0}.Debug|Any CPU.ActiveCfg = Debug|x86
+ {0D346CC0-83C5-4117-B2E6-2A33686B3FC0}.Debug|x64.ActiveCfg = Debug|x64
+ {0D346CC0-83C5-4117-B2E6-2A33686B3FC0}.Debug|x64.Build.0 = Debug|x64
+ {0D346CC0-83C5-4117-B2E6-2A33686B3FC0}.Debug|x86.ActiveCfg = Debug|x64
+ {0D346CC0-83C5-4117-B2E6-2A33686B3FC0}.Debug|x86.Build.0 = Debug|x64
+ {0D346CC0-83C5-4117-B2E6-2A33686B3FC0}.Release|Any CPU.ActiveCfg = Release|x86
+ {0D346CC0-83C5-4117-B2E6-2A33686B3FC0}.Release|x64.ActiveCfg = Release|x64
+ {0D346CC0-83C5-4117-B2E6-2A33686B3FC0}.Release|x64.Build.0 = Release|x64
+ {0D346CC0-83C5-4117-B2E6-2A33686B3FC0}.Release|x86.ActiveCfg = Release|x86
+ {0D346CC0-83C5-4117-B2E6-2A33686B3FC0}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/frmMain.cs b/frmMain.cs
new file mode 100644
index 0000000000000000000000000000000000000000..b7973eff6f6560108e44a1bec818322525b327a6
--- /dev/null
+++ b/frmMain.cs
@@ -0,0 +1,1304 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Xml;
+using System.Linq;
+using System.Drawing;
+using System.Windows.Forms;
+using System.ComponentModel;
+using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
+using System.Security.Cryptography.Xml;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.OpenSsl;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace SignatureVerifier
+{
+ public partial class frmMain : Form
+ {
+ ECPrivateKeyParameters mPrivateKey;
+ X9ECParameters mECCurve;
+
+ public frmMain()
+ {
+ InitializeComponent();
+ }
+
+ private void frmMain_Load(object sender, EventArgs e)
+ {
+ Text = this.Text + " v" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
+
+ cbRSAKeyLength.SelectedIndex = 8;
+
+ cbECName.SelectedIndex = 0;
+ cbECKeyLength.SelectedIndex = 0;
+
+ cbDigest.SelectedIndex = 0;
+ cbCipher.SelectedIndex = 0;
+
+ //Oid o = new Oid("1.2.840.10045.2.1");
+ //MessageBox.Show(o.FriendlyName);
+ }
+
+ private void llbDLogicURL_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+ {
+ System.Diagnostics.Process.Start("http://www.d-logic.net/nfc-rfid-reader-sdk/");
+ }
+
+ private byte[] zeroPadArray(byte[] theArray, byte paddingVal, Int32 paddingSize)
+ {
+ byte[] newArray = new byte[theArray.Length + paddingSize];
+ for (UInt32 i = 0; i < paddingSize; i++)
+ {
+ newArray[i] = paddingVal;
+ }
+ theArray.CopyTo(newArray, paddingSize);
+ return newArray;
+ }
+
+ //======================================================================================================================
+ // RSA Keys page:
+ //======================================================================================================================
+ private void btnRSAImportP12_Click(object sender, EventArgs e)
+ {
+ OpenFileDialog dialog = new OpenFileDialog();
+ dialog.Filter = "PKCS#12 files (*.p12;*.pfx)|*.p12;*.pfx|All files (*.*)|*.*";
+ //dialog.InitialDirectory = @"C:\";
+ dialog.Title = "Please select the cert file";
+
+ Asn1InputStream decoder = null;
+
+ if (dialog.ShowDialog() == DialogResult.OK)
+ {
+ frmPassword dlgPasswd = new frmPassword();
+ if (dlgPasswd.ShowDialog() == DialogResult.OK)
+ {
+ try
+ {
+ // Load your certificate from p12 file
+ X509Certificate2 certificate = new X509Certificate2(dialog.FileName, dlgPasswd.password, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
+ //RSACryptoServiceProvider pub_key = (RSACryptoServiceProvider)certificate.PublicKey.Key;
+ PublicKey pub_key = certificate.PublicKey;
+ //certificate.Dispose(); ToDo: See if needed
+
+ if (!pub_key.EncodedKeyValue.Oid.FriendlyName.Equals("RSA"))
+ {
+ MessageBox.Show("Selected cert. file doesn't contain RSA public key.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ return;
+ }
+
+ Int32 key_len = cbRSAKeyLength.FindStringExact(pub_key.Key.KeySize.ToString());
+ if (key_len < 0)
+ {
+ MessageBox.Show("Unsupported key length of " + pub_key.Key.KeySize + "bytes.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ cbRSAKeyLength.SelectedIndex = key_len;
+ key_len = pub_key.Key.KeySize;
+
+ decoder = new Asn1InputStream(new MemoryStream(pub_key.EncodedKeyValue.RawData));
+ DerSequence seq = (DerSequence)decoder.ReadObject();
+ DerInteger rr = (DerInteger)seq[0];
+ DerInteger ss = (DerInteger)seq[1];
+ byte[] br = rr.PositiveValue.ToByteArray();
+ byte[] bs = ss.PositiveValue.ToByteArray();
+
+ // Remove leading zeros:
+ while (br[0] == 0 && br.Length > key_len / 8)
+ {
+ br = br.Skip(1).ToArray();
+ }
+ while (bs[0] == 0 && br.Length > 0)
+ {
+ bs = br.Skip(1).ToArray();
+ }
+ tbRSAModulus.Text = BitConverter.ToString(br).Replace("-", "");
+ tbRSAPubExp.Text = BitConverter.ToString(bs).Replace("-", "");
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ finally
+ {
+ if (decoder != null)
+ decoder.Close();
+ }
+ }
+ }
+ }
+
+ private void btnRSAImportPem_Click(object sender, EventArgs e)
+ {
+ Int32 key_len, key_idx;
+ byte[] modulus;
+ byte[] exponent;
+ OpenFileDialog dialog = new OpenFileDialog();
+ dialog.Filter = "PEM files (*.pem;*.crt;*.cer)|*.pem;*.crt;*.cer|All files (*.*)|*.*";
+ //dialog.InitialDirectory = @"C:\";
+ dialog.Title = "Please select the PEM file";
+
+ if (dialog.ShowDialog() == DialogResult.OK)
+ {
+ try
+ {
+ // Load your certificate from PEM file
+ TextReader fileStream = System.IO.File.OpenText(dialog.FileName);
+ PemReader pemReader = new Org.BouncyCastle.OpenSsl.PemReader(fileStream);
+ object KeyParameter = pemReader.ReadObject();
+
+ if (KeyParameter.GetType() == typeof(Org.BouncyCastle.X509.X509Certificate))
+ {
+ // Load your certificate:
+ X509Certificate2 certificate = new X509Certificate2(dialog.FileName);
+ KeyParameter = Org.BouncyCastle.Security.DotNetUtilities.GetRsaPublicKey(certificate.GetRSAPublicKey());
+ //certificate.Dispose(); ToDo: See if needed
+ }
+
+ if (KeyParameter.GetType() == typeof(Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters))
+ {
+ key_len = ((RsaPrivateCrtKeyParameters)KeyParameter).Modulus.BitLength;
+ modulus = ((RsaPrivateCrtKeyParameters)KeyParameter).Modulus.ToByteArray();
+ exponent = ((RsaPrivateCrtKeyParameters)KeyParameter).PublicExponent.ToByteArray();
+ }
+ else if (KeyParameter.GetType() == typeof(Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair))
+ {
+ key_len = ((RsaKeyParameters)((AsymmetricCipherKeyPair)KeyParameter).Public).Modulus.BitLength;
+ modulus = ((RsaKeyParameters)((AsymmetricCipherKeyPair)KeyParameter).Public).Modulus.ToByteArray();
+ exponent = ((RsaKeyParameters)((AsymmetricCipherKeyPair)KeyParameter).Public).Exponent.ToByteArray();
+ }
+ else if (KeyParameter.GetType() == typeof(Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters))
+ {
+ key_len = ((RsaKeyParameters)KeyParameter).Modulus.BitLength;
+ modulus = ((RsaKeyParameters)KeyParameter).Modulus.ToByteArray();
+ exponent = ((RsaKeyParameters)KeyParameter).Exponent.ToByteArray();
+ }
+ else
+ {
+ MessageBox.Show("File doesn't contain RSA public key.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ return;
+ }
+ //? Org.BouncyCastle.Crypto.AsymmetricKeyParameter
+ //? Org.BouncyCastle.Crypto.Parameters.RsaBlindingParameters
+ //? Org.BouncyCastle.Crypto.Parameters.RsaKeyGenerationParameters
+ //MessageBox.Show(KeyParameter.GetType().ToString());
+
+ key_idx = cbRSAKeyLength.FindStringExact(key_len.ToString());
+ if (key_idx < 0)
+ {
+ MessageBox.Show("Unsupported key length of " + key_len + "bytes.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ cbRSAKeyLength.SelectedIndex = key_idx;
+
+ // Remove leading zeros:
+ while (modulus[0] == 0 && modulus.Length > key_len / 8)
+ {
+ modulus = modulus.Skip(1).ToArray();
+ }
+ while (exponent[0] == 0 && exponent.Length > 0)
+ {
+ exponent = exponent.Skip(1).ToArray();
+ }
+ tbRSAModulus.Text = BitConverter.ToString(modulus).Replace("-", "");
+ tbRSAPubExp.Text = BitConverter.ToString(exponent).Replace("-", "");
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ }
+ }
+
+ //======================================================================================================================
+ // EC Keys page:
+ //======================================================================================================================
+ void populateECDomainParameters(string curve_name)
+ {
+ byte[] barr1;
+ Int32 key_bytes_len;
+ mECCurve = SecNamedCurves.GetByName(curve_name);
+
+ try
+ {
+ key_bytes_len = (mECCurve.Curve.FieldSize + 7) / 8;
+
+ if (mECCurve.Curve.GetType() == typeof(FpCurve))
+ {
+ rbECFieldPrime.Checked = true;
+ barr1 = mECCurve.Curve.Field.Characteristic.ToByteArray();
+ if (key_bytes_len > barr1.Length)
+ barr1 = zeroPadArray(barr1, 0, key_bytes_len - barr1.Length);
+ while (barr1[0] == 0 && barr1.Length > key_bytes_len)
+ {
+ barr1 = barr1.Skip(1).ToArray();
+ }
+ tbECParamPrime.Text = BitConverter.ToString(barr1).Replace("-", "");
+ }
+ else if (mECCurve.Curve.GetType() == typeof(F2mCurve))
+ {
+ rbECFieldBinary.Checked = true;
+ populateECReductionPolynomial(!((F2mCurve)mECCurve.Curve).IsTrinomial(),
+ (ushort)mECCurve.Curve.FieldSize,
+ (ushort)((F2mCurve)mECCurve.Curve).K3,
+ (ushort)((F2mCurve)mECCurve.Curve).K2,
+ (ushort)((F2mCurve)mECCurve.Curve).K1);
+ }
+
+ barr1 = mECCurve.Curve.A.ToBigInteger().ToByteArray();
+ if (key_bytes_len > barr1.Length)
+ barr1 = zeroPadArray(barr1, 0, key_bytes_len - barr1.Length);
+ while (barr1[0] == 0 && barr1.Length > key_bytes_len)
+ {
+ barr1 = barr1.Skip(1).ToArray();
+ }
+ tbECParamA.Text = BitConverter.ToString(barr1).Replace("-", "");
+
+ barr1 = mECCurve.Curve.B.ToBigInteger().ToByteArray();
+ if (key_bytes_len > barr1.Length)
+ barr1 = zeroPadArray(barr1, 0, key_bytes_len - barr1.Length);
+ while (barr1[0] == 0 && barr1.Length > key_bytes_len)
+ {
+ barr1 = barr1.Skip(1).ToArray();
+ }
+ tbECParamB.Text = BitConverter.ToString(barr1).Replace("-", "");
+
+ barr1 = mECCurve.G.XCoord.ToBigInteger().ToByteArray();
+ if (key_bytes_len > barr1.Length)
+ barr1 = zeroPadArray(barr1, 0, key_bytes_len - barr1.Length);
+ while (barr1[0] == 0 && barr1.Length > key_bytes_len)
+ {
+ barr1 = barr1.Skip(1).ToArray();
+ }
+ tbECParamG.Text = "04" + BitConverter.ToString(barr1).Replace("-", "");
+
+ barr1 = mECCurve.G.YCoord.ToBigInteger().ToByteArray();
+ if (key_bytes_len > barr1.Length)
+ barr1 = zeroPadArray(barr1, 0, key_bytes_len - barr1.Length);
+ while (barr1[0] == 0 && barr1.Length > key_bytes_len)
+ {
+ barr1 = barr1.Skip(1).ToArray();
+ }
+ tbECParamG.Text += BitConverter.ToString(barr1).Replace("-", "");
+
+ barr1 = mECCurve.N.ToByteArray();
+ if (key_bytes_len > barr1.Length)
+ barr1 = zeroPadArray(barr1, 0, key_bytes_len - barr1.Length);
+ while (barr1[0] == 0 && barr1.Length > key_bytes_len)
+ {
+ barr1 = barr1.Skip(1).ToArray();
+ }
+ tbECParamR.Text = BitConverter.ToString(barr1).Replace("-", "");
+
+ tbECParamK.Text = mECCurve.H.ToString(); // mECCurve.Curve.Cofactor.ToString();
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ }
+
+ private void clearECReductionPolynomial()
+ {
+ rtbECReductionPolynomial.Clear();
+ //richTextBox1.SelectionColor = Color.Black;
+ rtbECReductionPolynomial.SelectionFont = new Font("Times New Roman", 10, FontStyle.Italic);
+ rtbECReductionPolynomial.SelectedText = " f(x) = ";
+ }
+
+ private void populateECReductionPolynomial(Boolean isPentanomial, UInt16 m, UInt16 e1, UInt16 e2, UInt16 e3)
+ {
+ tbECParamE1.Enabled = true;
+
+ rtbECReductionPolynomial.Clear();
+ //richTextBox1.SelectionColor = Color.Black;
+ rtbECReductionPolynomial.SelectionFont = new Font("Times New Roman", 10, FontStyle.Italic);
+ rtbECReductionPolynomial.SelectedText = " f(x) = x";
+ // superscripted text...
+ rtbECReductionPolynomial.SelectionFont = new Font("Times New Roman", 7, FontStyle.Italic);
+ rtbECReductionPolynomial.SelectionCharOffset = 8;
+ rtbECReductionPolynomial.SelectedText = m.ToString();
+ // normal text...
+ rtbECReductionPolynomial.SelectionFont = new Font("Times New Roman", 10, FontStyle.Italic);
+ rtbECReductionPolynomial.SelectionCharOffset = 0;
+ rtbECReductionPolynomial.SelectedText = " + x";
+
+ if (isPentanomial)
+ {
+ lbECParamE1.Text = "e1:";
+ tbECParamE1.Text = e1.ToString();
+ lbECParamE2.Enabled = true;
+ lbECParamE3.Enabled = true;
+ tbECParamE2.Enabled = true;
+ tbECParamE3.Enabled = true;
+ tbECParamE2.Text = e2.ToString();
+ tbECParamE3.Text = e3.ToString();
+
+ // superscripted text...
+ rtbECReductionPolynomial.SelectionFont = new Font("Times New Roman", 7, FontStyle.Italic);
+ rtbECReductionPolynomial.SelectionCharOffset = 8;
+ rtbECReductionPolynomial.SelectedText = e1.ToString();
+ // normal text...
+ rtbECReductionPolynomial.SelectionFont = new Font("Times New Roman", 10, FontStyle.Italic);
+ rtbECReductionPolynomial.SelectionCharOffset = 0;
+ rtbECReductionPolynomial.SelectedText = " + x";
+ // superscripted text...
+ rtbECReductionPolynomial.SelectionFont = new Font("Times New Roman", 7, FontStyle.Italic);
+ rtbECReductionPolynomial.SelectionCharOffset = 8;
+ rtbECReductionPolynomial.SelectedText = e2.ToString();
+ // normal text...
+ rtbECReductionPolynomial.SelectionFont = new Font("Times New Roman", 10, FontStyle.Italic);
+ rtbECReductionPolynomial.SelectionCharOffset = 0;
+ rtbECReductionPolynomial.SelectedText = " + x";
+ // superscripted text...
+ rtbECReductionPolynomial.SelectionFont = new Font("Times New Roman", 7, FontStyle.Italic);
+ rtbECReductionPolynomial.SelectionCharOffset = 8;
+ rtbECReductionPolynomial.SelectedText = e3.ToString();
+ }
+ else
+ {
+ lbECParamE1.Text = "e:";
+ tbECParamE1.Text = e3.ToString();
+ tbECParamE2.Clear();
+ tbECParamE3.Clear();
+ tbECParamE2.Enabled = false;
+ tbECParamE3.Enabled = false;
+ lbECParamE2.Enabled = false;
+ lbECParamE3.Enabled = false;
+
+ // superscripted text...
+ rtbECReductionPolynomial.SelectionFont = new Font("Times New Roman", 7, FontStyle.Italic);
+ rtbECReductionPolynomial.SelectionCharOffset = 8;
+ rtbECReductionPolynomial.SelectedText = e3.ToString();
+ }
+ // normal text...
+ rtbECReductionPolynomial.SelectionFont = new Font("Times New Roman", 10, FontStyle.Italic);
+ rtbECReductionPolynomial.SelectionCharOffset = 0;
+ rtbECReductionPolynomial.SelectedText = " + 1";
+ }
+
+ private void rbECFieldPrime_CheckedChanged(object sender, EventArgs e)
+ {
+ if (rbECFieldPrime.Checked)
+ {
+ tbECParamPrime.Enabled = true;
+ clearECReductionPolynomial();
+ tbECParamE1.Clear();
+ tbECParamE2.Clear();
+ tbECParamE3.Clear();
+ gbECReductionPolynomial.Enabled = false;
+ }
+ }
+
+ private void rbECFieldBinary_CheckedChanged(object sender, EventArgs e)
+ {
+ if (rbECFieldBinary.Checked)
+ {
+ tbECParamPrime.Enabled = false;
+ tbECParamPrime.Clear();
+ gbECReductionPolynomial.Enabled = true;
+ }
+ }
+
+ private bool m_gate_cbECKeyLength = false;
+ private int mECNameCurrComboIndex = 0;
+ private void cbECName_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ m_gate_cbECKeyLength = true;
+
+ if (mECNameCurrComboIndex != cbECName.SelectedIndex)
+ {
+ mECNameCurrComboIndex = cbECName.SelectedIndex;
+ tbECPubKey.Text = "";
+ }
+
+ if (cbECName.SelectedIndex < 15)
+ {
+ rbECFieldPrime.Checked = true;
+ }
+ else
+ {
+ rbECFieldBinary.Checked = true;
+ }
+ switch (cbECName.SelectedIndex)
+ {
+ case 0:
+ case 1:
+
+ cbECKeyLength.SelectedIndex = 0;
+ break;
+ case 2:
+ case 3:
+ cbECKeyLength.SelectedIndex = 2;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ cbECKeyLength.SelectedIndex = 4;
+ break;
+ case 7:
+ case 8:
+ cbECKeyLength.SelectedIndex = 6;
+ break;
+ case 9:
+ case 10:
+ cbECKeyLength.SelectedIndex = 8;
+ break;
+ case 11:
+ case 12:
+ cbECKeyLength.SelectedIndex = 11;
+ break;
+ case 13:
+ cbECKeyLength.SelectedIndex = 13;
+ break;
+ case 14:
+ cbECKeyLength.SelectedIndex = 15;
+ break;
+ case 15:
+ case 16:
+ cbECKeyLength.SelectedIndex = 1;
+ break;
+ case 17:
+ case 18:
+ cbECKeyLength.SelectedIndex = 3;
+ break;
+ case 19:
+ case 20:
+ case 21:
+ cbECKeyLength.SelectedIndex = 5;
+ break;
+ case 22:
+ case 23:
+ cbECKeyLength.SelectedIndex = 7;
+ break;
+ case 24:
+ case 25:
+ cbECKeyLength.SelectedIndex = 9;
+ break;
+
+ case 26:
+ cbECKeyLength.SelectedIndex = 10;
+ break;
+ case 27:
+ case 28:
+ cbECKeyLength.SelectedIndex = 12;
+ break;
+ case 29:
+ case 30:
+ cbECKeyLength.SelectedIndex = 14;
+ break;
+ case 31:
+ case 32:
+ cbECKeyLength.SelectedIndex = 16;
+ break;
+ }
+ populateECDomainParameters(cbECName.Text);
+ m_gate_cbECKeyLength = false;
+ }
+
+ private void cbECKeyLength_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ if (m_gate_cbECKeyLength)
+ return;
+
+ switch (cbECKeyLength.SelectedIndex)
+ {
+ case 0:
+ if (cbECName.SelectedIndex != 1)
+ cbECName.SelectedIndex = 0;
+ break;
+ case 1:
+ if (cbECName.SelectedIndex != 16)
+ cbECName.SelectedIndex = 15;
+ break;
+ case 2:
+ if (cbECName.SelectedIndex != 3)
+ cbECName.SelectedIndex = 2;
+ break;
+ case 3:
+ if (cbECName.SelectedIndex != 18)
+ cbECName.SelectedIndex = 17;
+ break;
+ case 4:
+ if (cbECName.SelectedIndex != 5 && cbECName.SelectedIndex != 6)
+ cbECName.SelectedIndex = 4;
+ break;
+ case 5:
+ if (cbECName.SelectedIndex != 20 && cbECName.SelectedIndex != 21)
+ cbECName.SelectedIndex = 19;
+ break;
+ case 6:
+ if (cbECName.SelectedIndex != 8)
+ cbECName.SelectedIndex = 7;
+ break;
+ case 7:
+ if (cbECName.SelectedIndex != 23)
+ cbECName.SelectedIndex = 22;
+ break;
+ case 8:
+ if (cbECName.SelectedIndex != 10)
+ cbECName.SelectedIndex = 9;
+ break;
+ case 9:
+ if (cbECName.SelectedIndex != 25)
+ cbECName.SelectedIndex = 24;
+ break;
+ case 10:
+ cbECName.SelectedIndex = 26;
+ break;
+ case 11:
+ if (cbECName.SelectedIndex != 12)
+ cbECName.SelectedIndex = 11;
+ break;
+ case 12:
+ if (cbECName.SelectedIndex != 28)
+ cbECName.SelectedIndex = 27;
+ break;
+ case 13:
+ cbECName.SelectedIndex = 13;
+ break;
+ case 14:
+ if (cbECName.SelectedIndex != 30)
+ cbECName.SelectedIndex = 29;
+ break;
+ case 15:
+ cbECName.SelectedIndex = 14;
+ break;
+ case 16:
+ if (cbECName.SelectedIndex != 32)
+ cbECName.SelectedIndex = 31;
+ break;
+ }
+ }
+
+ private void btnECImportP12_Click(object sender, EventArgs e)
+ {
+ OpenFileDialog dialog = new OpenFileDialog();
+ dialog.Filter = "PKCS#12 files (*.p12;*.pfx)|*.p12;*.pfx|All files (*.*)|*.*";
+ //dialog.InitialDirectory = @"C:\";
+ dialog.Title = "Please select the cert file";
+
+ if (dialog.ShowDialog() == DialogResult.OK)
+ {
+ frmPassword dlgPasswd = new frmPassword();
+ if (dlgPasswd.ShowDialog() == DialogResult.OK)
+ {
+ try
+ {
+ // Load your certificate from p12 file
+ X509Certificate2 certificate = new X509Certificate2(dialog.FileName, dlgPasswd.password, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
+ //RSACryptoServiceProvider pub_key = (RSACryptoServiceProvider)certificate.PublicKey.Key;
+ PublicKey pub_key = certificate.PublicKey;
+
+ if (pub_key.EncodedKeyValue.Oid.FriendlyName.Equals("ECC"))
+ {
+ var parser = new X509CertificateParser();
+ // Load your certificate
+ var bouncyCertificate = parser.ReadCertificate(certificate.RawData);
+ //certificate.Dispose(); ToDo: See if needed
+
+ string curve_name = SecNamedCurves.GetName(
+ (DerObjectIdentifier)DerObjectIdentifier.FromByteArray(
+ bouncyCertificate.CertificateStructure.SubjectPublicKeyInfo.AlgorithmID.Parameters.GetDerEncoded()
+ )
+ );
+
+ if (cbECName.Items.Contains(curve_name))
+ {
+ int index = cbECName.FindString(curve_name);
+ cbECName.SelectedIndex = index;
+ }
+ else
+ throw new Exception("Unknown ECC Parameters in certificate.");
+
+ tbECPubKey.Text = BitConverter.ToString(
+ bouncyCertificate.CertificateStructure.SubjectPublicKeyInfo.PublicKeyData.GetBytes()
+ ).Replace("-", "");
+ }
+ else
+ {
+ MessageBox.Show("File doesn't contain EC public key.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ return;
+ }
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ }
+ }
+ }
+
+ private void btnECImportFromPem_Click(object sender, EventArgs e)
+ {
+ byte[] barr1, barr2;
+
+ OpenFileDialog dialog = new OpenFileDialog();
+ dialog.Filter = "PEM files (*.pem;*.crt;*.cer)|*.pem;*.crt;*.cer|All files (*.*)|*.*";
+ dialog.InitialDirectory = @"C:\";
+ dialog.Title = "Please select the PEM file";
+
+ if (dialog.ShowDialog() == DialogResult.OK)
+ {
+ try
+ {
+ // ToDo: Find beter strategy to open Org.BouncyCastle.X509.X509Certificate
+
+ // Load your certificate from PEM file
+ TextReader fileStream = System.IO.File.OpenText(dialog.FileName);
+ PemReader pemReader = new Org.BouncyCastle.OpenSsl.PemReader(fileStream);
+ object KeyParameter = pemReader.ReadObject();
+
+ if (KeyParameter.GetType() == typeof(Org.BouncyCastle.Crypto.Parameters.ECPublicKeyParameters))
+ {
+ int idx = 0;
+ foreach (string s in cbECName.Items)
+ {
+ var EC = SecNamedCurves.GetByName(s);
+ if (EC.Curve.Equals(((ECPublicKeyParameters)KeyParameter).Parameters.Curve))
+ break;
+ idx++;
+ }
+ if ((idx + 1) >= cbECName.Items.Count)
+ throw new Exception("Unknown ECC Parameters in pem file.");
+
+ cbECName.SelectedIndex = idx;
+
+ var publicKeyParam = ((ECPublicKeyParameters)KeyParameter);
+ int key_bytes_len = (publicKeyParam.Parameters.Curve.FieldSize + 7) / 8;
+ barr1 = publicKeyParam.Q.XCoord.ToBigInteger().ToByteArray();
+ if (key_bytes_len > barr1.Length)
+ barr1 = zeroPadArray(barr1, 0, key_bytes_len - barr1.Length);
+ while (barr1[0] == 0 && barr1.Length > key_bytes_len)
+ {
+ barr1 = barr1.Skip(1).ToArray();
+ }
+ barr2 = publicKeyParam.Q.YCoord.ToBigInteger().ToByteArray();
+ if (key_bytes_len > barr2.Length)
+ barr2 = zeroPadArray(barr2, 0, key_bytes_len - barr2.Length);
+ while (barr2[0] == 0 && barr2.Length > key_bytes_len)
+ {
+ barr2 = barr2.Skip(1).ToArray();
+ }
+ tbECPubKey.Text = "04" + BitConverter.ToString(barr1).Replace("-", "") + BitConverter.ToString(barr2).Replace("-", "");
+ }
+ else if (KeyParameter.GetType() == typeof(Org.BouncyCastle.X509.X509Certificate))
+ {
+ var parser = new X509CertificateParser();
+ // Load your certificate
+ X509Certificate2 certificate = new X509Certificate2(dialog.FileName);
+ var bouncyCertificate = parser.ReadCertificate(certificate.RawData);
+ //certificate.Dispose(); ToDo: See if needed
+
+ string curve_name = SecNamedCurves.GetName(
+ (DerObjectIdentifier)DerObjectIdentifier.FromByteArray(
+ bouncyCertificate.CertificateStructure.SubjectPublicKeyInfo.AlgorithmID.Parameters.GetDerEncoded()
+ )
+ );
+
+ if (cbECName.Items.Contains(curve_name))
+ {
+ int index = cbECName.FindString(curve_name);
+ cbECName.SelectedIndex = index;
+ }
+ else
+ throw new Exception("Unknown ECC Parameters in certificate.");
+
+ tbECPubKey.Text = BitConverter.ToString(
+ bouncyCertificate.CertificateStructure.SubjectPublicKeyInfo.PublicKeyData.GetBytes()
+ ).Replace("-", "");
+ }
+ else
+ {
+ MessageBox.Show("File doesn't contain EC public key.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ return;
+ }
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ }
+ }
+
+ //======================================================================================================================
+ // Signature page:
+ //======================================================================================================================
+ private void button3_Click(object sender, EventArgs e)
+ {
+ try
+ {
+ // The URI to sign.
+ string resourceToSign = "file:///test.txt";
+
+ // The name of the file to which to save the XML signature.
+ string XmlFileName = "signature.xml";
+
+ // Generate a signing key.
+ RSACryptoServiceProvider Key = new RSACryptoServiceProvider();
+
+ //Console.WriteLine("Signing: {0}", resourceToSign);
+
+ // Sign the detached resourceand save the signature in an XML file.
+ SignDetachedResource(resourceToSign, XmlFileName, Key);
+
+ //Console.WriteLine("XML Signature was succesfully computed and saved to {0}.", XmlFileName);
+
+ /*
+ // Verify the signature of the signed XML.
+ Console.WriteLine("Verifying signature...");
+
+ //Verify the XML signature in the XML file against the key.
+ //bool result = VerifyDetachedSignatureWithRSAPublicKey(XmlFileName, Key);
+ bool result = VerifyDetachedSignature(XmlFileName);
+
+ // Display the results of the signature verification to
+ // the console.
+ if (result)
+ {
+ Console.WriteLine("The XML signature is valid.");
+ }
+ else
+ {
+ Console.WriteLine("The XML signature is not valid.");
+ }
+ */
+ }
+ catch (CryptographicException ex)
+ {
+ Console.WriteLine(ex.Message);
+ }
+ }
+ // Sign an XML file and save the signature in a new file. This method does not
+ // save the public key within the XML file. This file cannot be verified unless
+ // the verifying code has the key with which it was signed.
+ public static void SignDetachedResource(string URIString, string XmlSigFileName, RSA RSAKey)
+ {
+ // Create a SignedXml object.
+ SignedXml signedXml = new SignedXml();
+
+ // Assign the DSA key to the SignedXml object.
+ signedXml.SigningKey = RSAKey;
+
+ // Create a reference to be signed.
+ Reference reference = new Reference();
+
+ // Add the passed URI to the reference object.
+ reference.Uri = URIString;
+
+ // Add the reference to the SignedXml object.
+ signedXml.AddReference(reference);
+
+ // Add a DSAKeyValue to the KeyInfo (optional; helps recipient find key to validate).
+ KeyInfo keyInfo = new KeyInfo();
+ keyInfo.AddClause(new RSAKeyValue((RSA)RSAKey));
+ signedXml.KeyInfo = keyInfo;
+
+ // Compute the signature.
+ signedXml.ComputeSignature();
+
+ // Get the XML representation of the signature and save
+ // it to an XmlElement object.
+ XmlElement xmlDigitalSignature = signedXml.GetXml();
+
+ // Save the signed XML document to a file specified
+ // using the passed string.
+ XmlTextWriter xmltw = new XmlTextWriter(XmlSigFileName, new UTF8Encoding(false));
+ xmlDigitalSignature.WriteTo(xmltw);
+ xmltw.Close();
+ }
+
+ // Verify the signature of an XML file against an asymetric
+ // algorithm and return the result.
+ public static Boolean VerifyDetachedSignatureWithRSAPublicKey(string XmlSigFileName, RSA Key)
+ {
+ // Create a new XML document.
+ XmlDocument xmlDocument = new XmlDocument();
+
+ // Load the passedXML file into the document.
+ xmlDocument.Load(XmlSigFileName);
+
+ // Create a new SignedXml object.
+ SignedXml signedXml = new SignedXml();
+
+ // Find the "Signature" node and create a new XmlNodeList object.
+ XmlNodeList nodeList = xmlDocument.GetElementsByTagName("Signature");
+
+ // Load the signature node.
+ signedXml.LoadXml((XmlElement)nodeList[0]);
+
+ // Check the signature against the passed asymetric key
+ // and return the result.
+ return signedXml.CheckSignature(Key);
+ }
+
+ //Verify the siganature of an XML file
+ public static Boolean VerifyDetachedSignature(String XmlSigFileName)
+ {
+ // Create a new XML document.
+ XmlDocument xmlDocument = new XmlDocument();
+
+ // Load the passedXML file into the document.
+ xmlDocument.Load(XmlSigFileName);
+
+ // Find the "KeyValue" node,
+ // get the public key and use the key to initialize
+ // a RSACryptoServiceProvider object.
+ XmlNodeList nodeList = xmlDocument.GetElementsByTagName("KeyValue");
+ RSACryptoServiceProvider Key = new RSACryptoServiceProvider();
+ Key.FromXmlString(nodeList[0].InnerXml);
+
+ // Check the signature against the RSACryptoServiceProvider object
+ // and return the result.
+ return VerifyDetachedSignatureWithRSAPublicKey(XmlSigFileName, Key);
+ }
+
+ //======================================================================================================================
+ // Verify Signature page:
+ //======================================================================================================================
+ enum RADIX
+ {
+ Hex,
+ Base64,
+ ASCII,
+ Exception_FromFile
+ };
+ RADIX mMessageRadix = RADIX.Hex;
+ RADIX mSignatureRadix = RADIX.Hex;
+
+ private void tbMessageRadixChanged(object sender, EventArgs e)
+ {
+ bool showExceptionMessage = true;
+ try
+ {
+ if (sender == rbMessageFromFile)
+ {
+ OpenFileDialog dialog = new OpenFileDialog();
+ dialog.Filter = "All files (*.*)|*.*";
+ //dialog.InitialDirectory = @"C:\";
+ dialog.Title = "Please select file for signing";
+ if (dialog.ShowDialog() == DialogResult.OK)
+ {
+ tbMessage.ReadOnly = true;
+ tbMessage.BackColor = SystemColors.Info;
+ tbMessage.Text = dialog.FileName;
+ mMessageRadix = RADIX.Exception_FromFile;
+ }
+ else
+ {
+ showExceptionMessage = false;
+ throw new Exception("File selection canceled");
+ }
+ }
+ else
+ {
+ switch (mMessageRadix) // from radix
+ {
+ case RADIX.Hex:
+ if (sender == rbMessageBase64)
+ {
+ tbMessage.Text = Convert.ToBase64String(Hex.Decode(tbMessage.Text));
+ mMessageRadix = RADIX.Base64;
+ }
+ else if (sender == rbMessageAscii)
+ {
+ tbMessage.Text = Encoding.ASCII.GetString(Hex.Decode(tbMessage.Text));
+ mMessageRadix = RADIX.ASCII;
+ }
+ break;
+ case RADIX.Base64:
+ if (sender == rbMessageHex)
+ {
+ tbMessage.Text = BitConverter.ToString(Convert.FromBase64String(tbMessage.Text)).Replace("-", "");
+ mMessageRadix = RADIX.Hex;
+ }
+ else if (sender == rbMessageAscii)
+ {
+ tbMessage.Text = Encoding.ASCII.GetString(Convert.FromBase64String(tbMessage.Text));
+ mMessageRadix = RADIX.ASCII;
+ }
+ break;
+ case RADIX.ASCII:
+ if (sender == rbMessageHex)
+ {
+ tbMessage.Text = BitConverter.ToString(Encoding.ASCII.GetBytes(tbMessage.Text)).Replace("-", "");
+ mMessageRadix = RADIX.Hex;
+ }
+ else if (sender == rbMessageBase64)
+ {
+ tbMessage.Text = Convert.ToBase64String(Encoding.ASCII.GetBytes(tbMessage.Text));
+ mMessageRadix = RADIX.Base64;
+ }
+ break;
+ case RADIX.Exception_FromFile:
+ tbMessage.BackColor = SystemColors.Window;
+ tbMessage.Text = "";
+ tbMessage.ReadOnly = false;
+ if (sender == rbMessageHex)
+ mMessageRadix = RADIX.Hex;
+ else if (sender == rbMessageBase64)
+ mMessageRadix = RADIX.Base64;
+ else if (sender == rbMessageAscii)
+ mMessageRadix = RADIX.ASCII;
+
+ break;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ switch (mMessageRadix)
+ {
+ case RADIX.Hex:
+ rbMessageHex.Checked = true;
+ break;
+ case RADIX.Base64:
+ rbMessageBase64.Checked = true;
+ break;
+ case RADIX.ASCII:
+ rbMessageAscii.Checked = true;
+ break;
+ case RADIX.Exception_FromFile:
+ rbMessageFromFile.Checked = true;
+ break;
+ }
+ if (showExceptionMessage)
+ MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ }
+
+ private void tbSignatureRadixChanged(object sender, EventArgs e)
+ {
+ try
+ {
+ if (mSignatureRadix == RADIX.Hex && sender == rbSignatureBase64)
+ {
+ tbSignature.Text = Convert.ToBase64String(Hex.Decode(tbSignature.Text));
+ mSignatureRadix = RADIX.Base64;
+ }
+ else if (mSignatureRadix == RADIX.Base64 && sender == rbSignatureHex)
+ {
+ tbSignature.Text = BitConverter.ToString(Convert.FromBase64String(tbSignature.Text)).Replace("-", "");
+ mSignatureRadix = RADIX.Hex;
+ }
+ }
+ catch (Exception ex)
+ {
+ if (mSignatureRadix == RADIX.Hex)
+ rbSignatureHex.Checked = true;
+ else // case RADIX.Base64:
+ rbSignatureBase64.Checked = true;
+
+ MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ }
+
+ public static T[] RangeSubset(T[] array, int startIndex, int length)
+ {
+ T[] subset = new T[length];
+ Array.Copy(array, startIndex, subset, 0, length);
+ return subset;
+ }
+
+ private static byte[] derEncodeSignature(byte[] signature)
+ {
+ byte[] r = RangeSubset(signature, 0, (signature.Length / 2));
+ byte[] s = RangeSubset(signature, (signature.Length / 2), (signature.Length / 2));
+
+ MemoryStream stream = new MemoryStream();
+ DerOutputStream der = new DerOutputStream(stream);
+
+ Asn1EncodableVector v = new Asn1EncodableVector();
+ v.Add(new DerInteger(new BigInteger(1, r)));
+ v.Add(new DerInteger(new BigInteger(1, s)));
+ der.WriteObject(new DerSequence(v));
+
+ return stream.ToArray();
+ }
+
+ const int INPUT_FILE_BUFFER_LEN = 8192;
+ ISigner mSigner;
+ byte[] mSignature;
+ byte[] mMessage;
+
+ void bgw_DoWork(object sender, DoWorkEventArgs e)
+ {
+ Int64 temp = 0, percentSize;
+
+ try
+ {
+ ((BackgroundWorker)sender).ReportProgress(0);
+
+ using (Stream source = File.OpenRead(tbMessage.Text))
+ {
+ percentSize = source.Length / 1000;
+ int bytesRead;
+ while ((bytesRead = source.Read(mMessage, 0, mMessage.Length)) > 0)
+ {
+ mSigner.BlockUpdate(mMessage, 0, bytesRead);
+ temp += bytesRead;
+ if (temp >= percentSize)
+ {
+ temp = 0;
+ // when using PerformStep() the percentProgress arg is redundant
+ ((BackgroundWorker)sender).ReportProgress(0);
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ }
+
+ void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
+ {
+ pbVerification.PerformStep();
+ }
+
+ void bgw_WorkCompleted(object sender, RunWorkerCompletedEventArgs e)
+ {
+ try
+ {
+ pbVerification.Value = pbVerification.Maximum;
+ pbVerification.Value = pbVerification.Maximum - 1; // workaround for animation feature (aero theme)
+ pbVerification.Value = pbVerification.Maximum;
+
+ if (mSigner.VerifySignature(mSignature))
+ MessageBox.Show("Signature successfully verified", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ else
+ MessageBox.Show("Bad signature", "Fail", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ }
+ finally
+ {
+ // Enable controls critical for execution:
+ tabControl.Enabled = true;
+ }
+ }
+
+ private void btnVerifySignature_Click(object sender, EventArgs e)
+ {
+ string signatureMechanism;
+ AsymmetricKeyParameter key;
+
+ try
+ {
+ if (tbMessage.Text.Trim().Equals(""))
+ throw new Exception("Signed message can't have a zero length.");
+ if (tbSignature.Text.Trim().Equals(""))
+ throw new Exception("Signature can't have a zero length.");
+
+ if (cbCipher.Text.Equals("RSA"))
+ {
+ switch (cbDigest.Text)
+ {
+ case "SHA-1":
+ signatureMechanism = "SHA-1withRSA";
+ break;
+ case "SHA-224":
+ signatureMechanism = "SHA-224withRSA";
+ break;
+ case "SHA-256":
+ signatureMechanism = "SHA-256withRSA";
+ break;
+ case "SHA-384":
+ signatureMechanism = "SHA-384withRSA";
+ break;
+ case "SHA-512":
+ signatureMechanism = "SHA-512withRSA";
+ break;
+ default:
+ throw new Exception("Unknown hash algorithm");
+ }
+
+ key = new RsaKeyParameters(false, new BigInteger(1, Hex.Decode(tbRSAModulus.Text)),
+ new BigInteger(1, Hex.Decode(tbRSAPubExp.Text)));
+ }
+ else if (cbCipher.Text.Equals("ECDSA"))
+ {
+ switch (cbDigest.Text)
+ {
+ case "SHA-1":
+ signatureMechanism = "SHA-1withECDSA";
+ break;
+ case "SHA-224":
+ signatureMechanism = "SHA-224withECDSA";
+ break;
+ case "SHA-256":
+ signatureMechanism = "SHA-256withECDSA";
+ break;
+ case "SHA-384":
+ signatureMechanism = "SHA-384withECDSA";
+ break;
+ case "SHA-512":
+ signatureMechanism = "SHA-512withECDSA";
+ break;
+ default:
+ throw new Exception("Unknown digest algorithm");
+ }
+
+ X9ECParameters curve = SecNamedCurves.GetByName(cbECName.Text);
+ ECDomainParameters curveSpec = new ECDomainParameters(curve.Curve, curve.G, curve.N, curve.H, curve.GetSeed());
+ key = new ECPublicKeyParameters("ECDSA", curve.Curve.DecodePoint(Hex.Decode(tbECPubKey.Text)), curveSpec);
+ }
+ else
+ throw new Exception("Unknown cipher algorithm");
+
+ mSigner = SignerUtilities.GetSigner(signatureMechanism);
+ mSigner.Init(false, key);
+
+ switch (mMessageRadix) // from radix
+ {
+ case RADIX.Hex:
+ mMessage = Hex.Decode(tbMessage.Text);
+ break;
+ case RADIX.Base64:
+ mMessage = Convert.FromBase64String(tbMessage.Text);
+ break;
+ case RADIX.ASCII:
+ mMessage = Encoding.ASCII.GetBytes(tbMessage.Text);
+ break;
+ case RADIX.Exception_FromFile:
+ mMessage = new byte[INPUT_FILE_BUFFER_LEN];
+ break;
+ default:
+ throw new Exception("Unknown input data radix");
+ }
+
+ if (cbCipher.Text.Equals("ECDSA"))
+ {
+ // Have to be DER encoded before verification:
+ if (mSignatureRadix == RADIX.Hex)
+ {
+ mSignature = derEncodeSignature(Hex.Decode(tbSignature.Text));
+ }
+ else // mSignatureRadix == RADIX.Base64
+ {
+ mSignature = derEncodeSignature(Convert.FromBase64String(tbSignature.Text));
+ }
+ }
+ else
+ {
+ if (mSignatureRadix == RADIX.Hex)
+ {
+ mSignature = Hex.Decode(tbSignature.Text);
+ }
+ else // mSignatureRadix == RADIX.Base64
+ {
+ mSignature = Convert.FromBase64String(tbSignature.Text);
+ }
+ }
+
+ pbVerification.Value = 0;
+ Refresh();
+
+ if (mMessageRadix == RADIX.Exception_FromFile)
+ {
+ var bgw = new BackgroundWorker();
+ bgw.ProgressChanged += bgw_ProgressChanged;
+ bgw.DoWork += bgw_DoWork;
+ bgw.WorkerReportsProgress = true;
+ bgw.RunWorkerCompleted += bgw_WorkCompleted;
+ bgw.RunWorkerAsync();
+
+ // Disable controls critical for execution:
+ tabControl.Enabled = false;
+ return;
+ }
+ else
+ mSigner.BlockUpdate(mMessage, 0, mMessage.Length);
+
+ bool result = mSigner.VerifySignature(mSignature);
+ pbVerification.Value = pbVerification.Maximum;
+ pbVerification.Value = pbVerification.Maximum - 1; // workaround for animation feature (aero theme)
+ pbVerification.Value = pbVerification.Maximum;
+ if (result)
+ MessageBox.Show("Signature successfully verified", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ else
+ MessageBox.Show("Bad signature", "Fail", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ }
+
+ const long MAX_INPUT_BIN_FILE = 65536;
+
+ private void btnPlainLoadFromBin_Click(object sender, EventArgs e)
+ {
+ long file_len;
+
+ try
+ {
+ OpenFileDialog dialog = new OpenFileDialog();
+ dialog.Filter = "Binary files (*.bin)|*.bin|All files (*.*)|*.*";
+ //dialog.InitialDirectory = @"C:\";
+ dialog.Title = "Please select binary file";
+
+ if (dialog.ShowDialog() == DialogResult.OK)
+ {
+ file_len = new FileInfo(dialog.FileName).Length;
+
+ if (file_len > MAX_INPUT_BIN_FILE)
+ {
+ MessageBox.Show("Binary file is to large for this purpose.\r\nMaximum file size accepted here is 64 kB.",
+ "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ return;
+ }
+ tbMessage.Text = "";
+ tbMessageRadixChanged(rbMessageHex, new EventArgs());
+ rbMessageHex.Checked = true;
+
+ tbMessage.Text = BitConverter.ToString(File.ReadAllBytes(dialog.FileName)).Replace("-", "");
+ }
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ }
+
+ private void btnSignatureLoadFromBin_Click(object sender, EventArgs e)
+ {
+ long file_len;
+
+ try
+ {
+ OpenFileDialog dialog = new OpenFileDialog();
+ dialog.Filter = "Signature binary files (*.sig)|*.sig|Binary files (*.bin)|*.bin|All files (*.*)|*.*";
+ //dialog.InitialDirectory = @"C:\";
+ dialog.Title = "Please select binary file";
+
+ if (dialog.ShowDialog() == DialogResult.OK)
+ {
+ file_len = new FileInfo(dialog.FileName).Length;
+
+ if (file_len > MAX_INPUT_BIN_FILE)
+ {
+ MessageBox.Show("Binary file is to large for this purpose.\r\nMaximum file size accepted here is 64 kB.",
+ "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+
+ }
+ tbSignature.Text = "";
+ tbSignatureRadixChanged(rbSignatureHex, new EventArgs());
+ rbSignatureHex.Checked = true;
+
+ tbSignature.Text = BitConverter.ToString(File.ReadAllBytes(dialog.FileName)).Replace("-", "");
+ }
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ }
+ }
+}
diff --git a/frmMain.designer.cs b/frmMain.designer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..42f73533d32ae42d24a3a5b64c935439940b88ab
--- /dev/null
+++ b/frmMain.designer.cs
@@ -0,0 +1,1155 @@
+namespace SignatureVerifier
+{
+ partial class frmMain
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.tabControl = new System.Windows.Forms.TabControl();
+ this.tabRSAPubKey = new System.Windows.Forms.TabPage();
+ this.gbRSAModulus = new System.Windows.Forms.GroupBox();
+ this.lbRSAPubExp = new System.Windows.Forms.Label();
+ this.tbRSAPubExp = new System.Windows.Forms.TextBox();
+ this.lbRSAModulus = new System.Windows.Forms.Label();
+ this.tbRSAModulus = new System.Windows.Forms.TextBox();
+ this.gbRSACommands = new System.Windows.Forms.GroupBox();
+ this.btnRSAImportPem = new System.Windows.Forms.Button();
+ this.cbRSAKeyLength = new System.Windows.Forms.ComboBox();
+ this.lbRSAKeyLength = new System.Windows.Forms.Label();
+ this.btnRSAImportP12 = new System.Windows.Forms.Button();
+ this.tabECPubKey = new System.Windows.Forms.TabPage();
+ this.gbECPubKey = new System.Windows.Forms.GroupBox();
+ this.lbECPubKey = new System.Windows.Forms.Label();
+ this.tbECPubKey = new System.Windows.Forms.TextBox();
+ this.gbECDomainParameters = new System.Windows.Forms.GroupBox();
+ this.lbECParamK = new System.Windows.Forms.Label();
+ this.tbECParamK = new System.Windows.Forms.TextBox();
+ this.lbECParamR = new System.Windows.Forms.Label();
+ this.tbECParamR = new System.Windows.Forms.TextBox();
+ this.lbECParamG = new System.Windows.Forms.Label();
+ this.tbECParamG = new System.Windows.Forms.TextBox();
+ this.lbECParamB = new System.Windows.Forms.Label();
+ this.tbECParamB = new System.Windows.Forms.TextBox();
+ this.ltbECParamA = new System.Windows.Forms.Label();
+ this.tbECParamA = new System.Windows.Forms.TextBox();
+ this.gbECReductionPolynomial = new System.Windows.Forms.GroupBox();
+ this.rtbECReductionPolynomial = new System.Windows.Forms.RichTextBox();
+ this.lbECParamE3 = new System.Windows.Forms.Label();
+ this.tbECParamE3 = new System.Windows.Forms.TextBox();
+ this.lbECParamE2 = new System.Windows.Forms.Label();
+ this.tbECParamE2 = new System.Windows.Forms.TextBox();
+ this.lbECParamE1 = new System.Windows.Forms.Label();
+ this.tbECParamE1 = new System.Windows.Forms.TextBox();
+ this.groupBox1 = new System.Windows.Forms.GroupBox();
+ this.rbECFieldPrime = new System.Windows.Forms.RadioButton();
+ this.rbECFieldBinary = new System.Windows.Forms.RadioButton();
+ this.lbECParamPrime = new System.Windows.Forms.Label();
+ this.tbECParamPrime = new System.Windows.Forms.TextBox();
+ this.gbECCommands = new System.Windows.Forms.GroupBox();
+ this.btnECImportFromPem = new System.Windows.Forms.Button();
+ this.cbECName = new System.Windows.Forms.ComboBox();
+ this.lbECName = new System.Windows.Forms.Label();
+ this.cbECKeyLength = new System.Windows.Forms.ComboBox();
+ this.lbECKeyLength = new System.Windows.Forms.Label();
+ this.btnECImportP12 = new System.Windows.Forms.Button();
+ this.tabVerify = new System.Windows.Forms.TabPage();
+ this.gbSignature = new System.Windows.Forms.GroupBox();
+ this.pbVerification = new System.Windows.Forms.ProgressBar();
+ this.btnVerifySignature = new System.Windows.Forms.Button();
+ this.btnSignatureLoadFromBin = new System.Windows.Forms.Button();
+ this.rbSignatureBase64 = new System.Windows.Forms.RadioButton();
+ this.rbSignatureHex = new System.Windows.Forms.RadioButton();
+ this.lbSignature = new System.Windows.Forms.Label();
+ this.tbSignature = new System.Windows.Forms.TextBox();
+ this.gbMessage = new System.Windows.Forms.GroupBox();
+ this.btnPlainLoadFromBin = new System.Windows.Forms.Button();
+ this.rbMessageFromFile = new System.Windows.Forms.RadioButton();
+ this.rbMessageBase64 = new System.Windows.Forms.RadioButton();
+ this.rbMessageHex = new System.Windows.Forms.RadioButton();
+ this.rbMessageAscii = new System.Windows.Forms.RadioButton();
+ this.lbMessage = new System.Windows.Forms.Label();
+ this.tbMessage = new System.Windows.Forms.TextBox();
+ this.gbSignatureParameters = new System.Windows.Forms.GroupBox();
+ this.cbCipher = new System.Windows.Forms.ComboBox();
+ this.lbCipher = new System.Windows.Forms.Label();
+ this.cbDigest = new System.Windows.Forms.ComboBox();
+ this.lbDigest = new System.Windows.Forms.Label();
+ this.llbDLogicURL = new System.Windows.Forms.LinkLabel();
+ this.tabControl.SuspendLayout();
+ this.tabRSAPubKey.SuspendLayout();
+ this.gbRSAModulus.SuspendLayout();
+ this.gbRSACommands.SuspendLayout();
+ this.tabECPubKey.SuspendLayout();
+ this.gbECPubKey.SuspendLayout();
+ this.gbECDomainParameters.SuspendLayout();
+ this.gbECReductionPolynomial.SuspendLayout();
+ this.groupBox1.SuspendLayout();
+ this.gbECCommands.SuspendLayout();
+ this.tabVerify.SuspendLayout();
+ this.gbSignature.SuspendLayout();
+ this.gbMessage.SuspendLayout();
+ this.gbSignatureParameters.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // tabControl
+ //
+ this.tabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.tabControl.Controls.Add(this.tabRSAPubKey);
+ this.tabControl.Controls.Add(this.tabECPubKey);
+ this.tabControl.Controls.Add(this.tabVerify);
+ this.tabControl.Location = new System.Drawing.Point(12, 12);
+ this.tabControl.Name = "tabControl";
+ this.tabControl.SelectedIndex = 0;
+ this.tabControl.Size = new System.Drawing.Size(1142, 514);
+ this.tabControl.TabIndex = 0;
+ //
+ // tabRSAPubKey
+ //
+ this.tabRSAPubKey.BackColor = System.Drawing.SystemColors.Control;
+ this.tabRSAPubKey.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
+ this.tabRSAPubKey.Controls.Add(this.gbRSAModulus);
+ this.tabRSAPubKey.Controls.Add(this.gbRSACommands);
+ this.tabRSAPubKey.Location = new System.Drawing.Point(4, 22);
+ this.tabRSAPubKey.Margin = new System.Windows.Forms.Padding(0);
+ this.tabRSAPubKey.Name = "tabRSAPubKey";
+ this.tabRSAPubKey.Padding = new System.Windows.Forms.Padding(3);
+ this.tabRSAPubKey.Size = new System.Drawing.Size(1134, 488);
+ this.tabRSAPubKey.TabIndex = 0;
+ this.tabRSAPubKey.Text = "RSA public key";
+ //
+ // gbRSAModulus
+ //
+ this.gbRSAModulus.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.gbRSAModulus.Controls.Add(this.lbRSAPubExp);
+ this.gbRSAModulus.Controls.Add(this.tbRSAPubExp);
+ this.gbRSAModulus.Controls.Add(this.lbRSAModulus);
+ this.gbRSAModulus.Controls.Add(this.tbRSAModulus);
+ this.gbRSAModulus.Location = new System.Drawing.Point(8, 82);
+ this.gbRSAModulus.Margin = new System.Windows.Forms.Padding(8);
+ this.gbRSAModulus.Name = "gbRSAModulus";
+ this.gbRSAModulus.Size = new System.Drawing.Size(1116, 96);
+ this.gbRSAModulus.TabIndex = 1;
+ this.gbRSAModulus.TabStop = false;
+ this.gbRSAModulus.Text = "Public key:";
+ //
+ // lbRSAPubExp
+ //
+ this.lbRSAPubExp.AutoSize = true;
+ this.lbRSAPubExp.Location = new System.Drawing.Point(6, 62);
+ this.lbRSAPubExp.Margin = new System.Windows.Forms.Padding(3);
+ this.lbRSAPubExp.Name = "lbRSAPubExp";
+ this.lbRSAPubExp.Size = new System.Drawing.Size(55, 13);
+ this.lbRSAPubExp.TabIndex = 2;
+ this.lbRSAPubExp.Text = "Exponent:";
+ //
+ // tbRSAPubExp
+ //
+ this.tbRSAPubExp.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.tbRSAPubExp.BackColor = System.Drawing.SystemColors.Window;
+ this.tbRSAPubExp.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
+ this.tbRSAPubExp.Location = new System.Drawing.Point(64, 58);
+ this.tbRSAPubExp.Margin = new System.Windows.Forms.Padding(0);
+ this.tbRSAPubExp.Name = "tbRSAPubExp";
+ this.tbRSAPubExp.Size = new System.Drawing.Size(1039, 22);
+ this.tbRSAPubExp.TabIndex = 3;
+ //
+ // lbRSAModulus
+ //
+ this.lbRSAModulus.AutoSize = true;
+ this.lbRSAModulus.Location = new System.Drawing.Point(6, 30);
+ this.lbRSAModulus.Margin = new System.Windows.Forms.Padding(3);
+ this.lbRSAModulus.Name = "lbRSAModulus";
+ this.lbRSAModulus.Size = new System.Drawing.Size(50, 13);
+ this.lbRSAModulus.TabIndex = 0;
+ this.lbRSAModulus.Text = "Modulus:";
+ //
+ // tbRSAModulus
+ //
+ this.tbRSAModulus.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.tbRSAModulus.BackColor = System.Drawing.SystemColors.Window;
+ this.tbRSAModulus.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
+ this.tbRSAModulus.Location = new System.Drawing.Point(64, 26);
+ this.tbRSAModulus.Margin = new System.Windows.Forms.Padding(10);
+ this.tbRSAModulus.Name = "tbRSAModulus";
+ this.tbRSAModulus.Size = new System.Drawing.Size(1039, 22);
+ this.tbRSAModulus.TabIndex = 1;
+ //
+ // gbRSACommands
+ //
+ this.gbRSACommands.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.gbRSACommands.Controls.Add(this.btnRSAImportPem);
+ this.gbRSACommands.Controls.Add(this.cbRSAKeyLength);
+ this.gbRSACommands.Controls.Add(this.lbRSAKeyLength);
+ this.gbRSACommands.Controls.Add(this.btnRSAImportP12);
+ this.gbRSACommands.Location = new System.Drawing.Point(8, 0);
+ this.gbRSACommands.Margin = new System.Windows.Forms.Padding(8);
+ this.gbRSACommands.Name = "gbRSACommands";
+ this.gbRSACommands.Size = new System.Drawing.Size(1116, 74);
+ this.gbRSACommands.TabIndex = 0;
+ this.gbRSACommands.TabStop = false;
+ //
+ // btnRSAImportPem
+ //
+ this.btnRSAImportPem.Location = new System.Drawing.Point(406, 15);
+ this.btnRSAImportPem.Margin = new System.Windows.Forms.Padding(0);
+ this.btnRSAImportPem.Name = "btnRSAImportPem";
+ this.btnRSAImportPem.Size = new System.Drawing.Size(160, 48);
+ this.btnRSAImportPem.TabIndex = 4;
+ this.btnRSAImportPem.Text = "Import from PEM file";
+ this.btnRSAImportPem.UseVisualStyleBackColor = true;
+ this.btnRSAImportPem.Click += new System.EventHandler(this.btnRSAImportPem_Click);
+ //
+ // cbRSAKeyLength
+ //
+ this.cbRSAKeyLength.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.cbRSAKeyLength.FormattingEnabled = true;
+ this.cbRSAKeyLength.Items.AddRange(new object[] {
+ "512",
+ "736",
+ "768",
+ "896",
+ "1024",
+ "1280",
+ "1536",
+ "1984",
+ "2048",
+ "4096"});
+ this.cbRSAKeyLength.Location = new System.Drawing.Point(99, 16);
+ this.cbRSAKeyLength.Name = "cbRSAKeyLength";
+ this.cbRSAKeyLength.Size = new System.Drawing.Size(124, 21);
+ this.cbRSAKeyLength.TabIndex = 3;
+ //
+ // lbRSAKeyLength
+ //
+ this.lbRSAKeyLength.AutoSize = true;
+ this.lbRSAKeyLength.Location = new System.Drawing.Point(8, 19);
+ this.lbRSAKeyLength.Name = "lbRSAKeyLength";
+ this.lbRSAKeyLength.Size = new System.Drawing.Size(85, 13);
+ this.lbRSAKeyLength.TabIndex = 2;
+ this.lbRSAKeyLength.Text = "Key length [bits]:";
+ //
+ // btnRSAImportP12
+ //
+ this.btnRSAImportP12.Location = new System.Drawing.Point(236, 15);
+ this.btnRSAImportP12.Margin = new System.Windows.Forms.Padding(10);
+ this.btnRSAImportP12.Name = "btnRSAImportP12";
+ this.btnRSAImportP12.Size = new System.Drawing.Size(160, 48);
+ this.btnRSAImportP12.TabIndex = 0;
+ this.btnRSAImportP12.Text = "Import from PKCS#12 file (.p12 ; .pfx)";
+ this.btnRSAImportP12.UseVisualStyleBackColor = true;
+ this.btnRSAImportP12.Click += new System.EventHandler(this.btnRSAImportP12_Click);
+ //
+ // tabECPubKey
+ //
+ this.tabECPubKey.BackColor = System.Drawing.SystemColors.Control;
+ this.tabECPubKey.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
+ this.tabECPubKey.Controls.Add(this.gbECPubKey);
+ this.tabECPubKey.Controls.Add(this.gbECDomainParameters);
+ this.tabECPubKey.Controls.Add(this.gbECCommands);
+ this.tabECPubKey.Location = new System.Drawing.Point(4, 22);
+ this.tabECPubKey.Name = "tabECPubKey";
+ this.tabECPubKey.Padding = new System.Windows.Forms.Padding(3);
+ this.tabECPubKey.Size = new System.Drawing.Size(1134, 488);
+ this.tabECPubKey.TabIndex = 1;
+ this.tabECPubKey.Text = "EC public key";
+ //
+ // gbECPubKey
+ //
+ this.gbECPubKey.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.gbECPubKey.Controls.Add(this.lbECPubKey);
+ this.gbECPubKey.Controls.Add(this.tbECPubKey);
+ this.gbECPubKey.Location = new System.Drawing.Point(8, 373);
+ this.gbECPubKey.Margin = new System.Windows.Forms.Padding(8);
+ this.gbECPubKey.Name = "gbECPubKey";
+ this.gbECPubKey.Size = new System.Drawing.Size(1116, 104);
+ this.gbECPubKey.TabIndex = 6;
+ this.gbECPubKey.TabStop = false;
+ this.gbECPubKey.Text = "EC public key:";
+ //
+ // lbECPubKey
+ //
+ this.lbECPubKey.AutoSize = true;
+ this.lbECPubKey.Location = new System.Drawing.Point(8, 48);
+ this.lbECPubKey.Margin = new System.Windows.Forms.Padding(3);
+ this.lbECPubKey.Name = "lbECPubKey";
+ this.lbECPubKey.Size = new System.Drawing.Size(39, 13);
+ this.lbECPubKey.TabIndex = 17;
+ this.lbECPubKey.Text = "W(uc):";
+ //
+ // tbECPubKey
+ //
+ this.tbECPubKey.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.tbECPubKey.BackColor = System.Drawing.SystemColors.Window;
+ this.tbECPubKey.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
+ this.tbECPubKey.Location = new System.Drawing.Point(53, 22);
+ this.tbECPubKey.Multiline = true;
+ this.tbECPubKey.Name = "tbECPubKey";
+ this.tbECPubKey.ScrollBars = System.Windows.Forms.ScrollBars.Horizontal;
+ this.tbECPubKey.Size = new System.Drawing.Size(1049, 65);
+ this.tbECPubKey.TabIndex = 18;
+ //
+ // gbECDomainParameters
+ //
+ this.gbECDomainParameters.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.gbECDomainParameters.Controls.Add(this.lbECParamK);
+ this.gbECDomainParameters.Controls.Add(this.tbECParamK);
+ this.gbECDomainParameters.Controls.Add(this.lbECParamR);
+ this.gbECDomainParameters.Controls.Add(this.tbECParamR);
+ this.gbECDomainParameters.Controls.Add(this.lbECParamG);
+ this.gbECDomainParameters.Controls.Add(this.tbECParamG);
+ this.gbECDomainParameters.Controls.Add(this.lbECParamB);
+ this.gbECDomainParameters.Controls.Add(this.tbECParamB);
+ this.gbECDomainParameters.Controls.Add(this.ltbECParamA);
+ this.gbECDomainParameters.Controls.Add(this.tbECParamA);
+ this.gbECDomainParameters.Controls.Add(this.gbECReductionPolynomial);
+ this.gbECDomainParameters.Controls.Add(this.groupBox1);
+ this.gbECDomainParameters.Controls.Add(this.lbECParamPrime);
+ this.gbECDomainParameters.Controls.Add(this.tbECParamPrime);
+ this.gbECDomainParameters.Location = new System.Drawing.Point(7, 82);
+ this.gbECDomainParameters.Margin = new System.Windows.Forms.Padding(0);
+ this.gbECDomainParameters.Name = "gbECDomainParameters";
+ this.gbECDomainParameters.Size = new System.Drawing.Size(1116, 283);
+ this.gbECDomainParameters.TabIndex = 4;
+ this.gbECDomainParameters.TabStop = false;
+ this.gbECDomainParameters.Text = "EC domain parameters:";
+ //
+ // lbECParamK
+ //
+ this.lbECParamK.AutoSize = true;
+ this.lbECParamK.Location = new System.Drawing.Point(260, 239);
+ this.lbECParamK.Margin = new System.Windows.Forms.Padding(3);
+ this.lbECParamK.Name = "lbECParamK";
+ this.lbECParamK.Size = new System.Drawing.Size(17, 13);
+ this.lbECParamK.TabIndex = 19;
+ this.lbECParamK.Text = "K:";
+ //
+ // tbECParamK
+ //
+ this.tbECParamK.BackColor = System.Drawing.SystemColors.Window;
+ this.tbECParamK.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
+ this.tbECParamK.Location = new System.Drawing.Point(284, 235);
+ this.tbECParamK.Margin = new System.Windows.Forms.Padding(0);
+ this.tbECParamK.Name = "tbECParamK";
+ this.tbECParamK.ReadOnly = true;
+ this.tbECParamK.Size = new System.Drawing.Size(139, 22);
+ this.tbECParamK.TabIndex = 20;
+ //
+ // lbECParamR
+ //
+ this.lbECParamR.AutoSize = true;
+ this.lbECParamR.Location = new System.Drawing.Point(260, 207);
+ this.lbECParamR.Margin = new System.Windows.Forms.Padding(3);
+ this.lbECParamR.Name = "lbECParamR";
+ this.lbECParamR.Size = new System.Drawing.Size(18, 13);
+ this.lbECParamR.TabIndex = 17;
+ this.lbECParamR.Text = "R:";
+ //
+ // tbECParamR
+ //
+ this.tbECParamR.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.tbECParamR.BackColor = System.Drawing.SystemColors.Window;
+ this.tbECParamR.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
+ this.tbECParamR.Location = new System.Drawing.Point(284, 203);
+ this.tbECParamR.Margin = new System.Windows.Forms.Padding(10);
+ this.tbECParamR.Name = "tbECParamR";
+ this.tbECParamR.ReadOnly = true;
+ this.tbECParamR.Size = new System.Drawing.Size(819, 22);
+ this.tbECParamR.TabIndex = 18;
+ //
+ // lbECParamG
+ //
+ this.lbECParamG.AutoSize = true;
+ this.lbECParamG.Location = new System.Drawing.Point(242, 152);
+ this.lbECParamG.Margin = new System.Windows.Forms.Padding(3);
+ this.lbECParamG.Name = "lbECParamG";
+ this.lbECParamG.Size = new System.Drawing.Size(36, 13);
+ this.lbECParamG.TabIndex = 15;
+ this.lbECParamG.Text = "G(uc):";
+ //
+ // tbECParamG
+ //
+ this.tbECParamG.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.tbECParamG.BackColor = System.Drawing.SystemColors.Window;
+ this.tbECParamG.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
+ this.tbECParamG.Location = new System.Drawing.Point(284, 126);
+ this.tbECParamG.Margin = new System.Windows.Forms.Padding(0);
+ this.tbECParamG.Multiline = true;
+ this.tbECParamG.Name = "tbECParamG";
+ this.tbECParamG.ReadOnly = true;
+ this.tbECParamG.ScrollBars = System.Windows.Forms.ScrollBars.Horizontal;
+ this.tbECParamG.Size = new System.Drawing.Size(819, 65);
+ this.tbECParamG.TabIndex = 16;
+ //
+ // lbECParamB
+ //
+ this.lbECParamB.AutoSize = true;
+ this.lbECParamB.Location = new System.Drawing.Point(212, 94);
+ this.lbECParamB.Margin = new System.Windows.Forms.Padding(3);
+ this.lbECParamB.Name = "lbECParamB";
+ this.lbECParamB.Size = new System.Drawing.Size(16, 13);
+ this.lbECParamB.TabIndex = 13;
+ this.lbECParamB.Text = "b:";
+ //
+ // tbECParamB
+ //
+ this.tbECParamB.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.tbECParamB.BackColor = System.Drawing.SystemColors.Window;
+ this.tbECParamB.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
+ this.tbECParamB.Location = new System.Drawing.Point(233, 90);
+ this.tbECParamB.Margin = new System.Windows.Forms.Padding(14);
+ this.tbECParamB.Name = "tbECParamB";
+ this.tbECParamB.ReadOnly = true;
+ this.tbECParamB.Size = new System.Drawing.Size(870, 22);
+ this.tbECParamB.TabIndex = 14;
+ //
+ // ltbECParamA
+ //
+ this.ltbECParamA.AutoSize = true;
+ this.ltbECParamA.Location = new System.Drawing.Point(212, 64);
+ this.ltbECParamA.Margin = new System.Windows.Forms.Padding(3);
+ this.ltbECParamA.Name = "ltbECParamA";
+ this.ltbECParamA.Size = new System.Drawing.Size(16, 13);
+ this.ltbECParamA.TabIndex = 11;
+ this.ltbECParamA.Text = "a:";
+ //
+ // tbECParamA
+ //
+ this.tbECParamA.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.tbECParamA.BackColor = System.Drawing.SystemColors.Window;
+ this.tbECParamA.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
+ this.tbECParamA.Location = new System.Drawing.Point(233, 60);
+ this.tbECParamA.Margin = new System.Windows.Forms.Padding(10);
+ this.tbECParamA.Name = "tbECParamA";
+ this.tbECParamA.ReadOnly = true;
+ this.tbECParamA.Size = new System.Drawing.Size(870, 22);
+ this.tbECParamA.TabIndex = 12;
+ //
+ // gbECReductionPolynomial
+ //
+ this.gbECReductionPolynomial.Controls.Add(this.rtbECReductionPolynomial);
+ this.gbECReductionPolynomial.Controls.Add(this.lbECParamE3);
+ this.gbECReductionPolynomial.Controls.Add(this.tbECParamE3);
+ this.gbECReductionPolynomial.Controls.Add(this.lbECParamE2);
+ this.gbECReductionPolynomial.Controls.Add(this.tbECParamE2);
+ this.gbECReductionPolynomial.Controls.Add(this.lbECParamE1);
+ this.gbECReductionPolynomial.Controls.Add(this.tbECParamE1);
+ this.gbECReductionPolynomial.Enabled = false;
+ this.gbECReductionPolynomial.Location = new System.Drawing.Point(11, 120);
+ this.gbECReductionPolynomial.Margin = new System.Windows.Forms.Padding(8);
+ this.gbECReductionPolynomial.Name = "gbECReductionPolynomial";
+ this.gbECReductionPolynomial.Size = new System.Drawing.Size(220, 151);
+ this.gbECReductionPolynomial.TabIndex = 10;
+ this.gbECReductionPolynomial.TabStop = false;
+ this.gbECReductionPolynomial.Text = "Reduction polynomial:";
+ //
+ // rtbECReductionPolynomial
+ //
+ this.rtbECReductionPolynomial.BorderStyle = System.Windows.Forms.BorderStyle.None;
+ this.rtbECReductionPolynomial.Font = new System.Drawing.Font("Times New Roman", 9.75F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
+ this.rtbECReductionPolynomial.Location = new System.Drawing.Point(12, 22);
+ this.rtbECReductionPolynomial.Multiline = false;
+ this.rtbECReductionPolynomial.Name = "rtbECReductionPolynomial";
+ this.rtbECReductionPolynomial.ReadOnly = true;
+ this.rtbECReductionPolynomial.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.None;
+ this.rtbECReductionPolynomial.Size = new System.Drawing.Size(202, 29);
+ this.rtbECReductionPolynomial.TabIndex = 17;
+ this.rtbECReductionPolynomial.Text = " f(x) = ";
+ //
+ // lbECParamE3
+ //
+ this.lbECParamE3.AutoSize = true;
+ this.lbECParamE3.Location = new System.Drawing.Point(12, 119);
+ this.lbECParamE3.Margin = new System.Windows.Forms.Padding(3);
+ this.lbECParamE3.Name = "lbECParamE3";
+ this.lbECParamE3.Size = new System.Drawing.Size(22, 13);
+ this.lbECParamE3.TabIndex = 15;
+ this.lbECParamE3.Text = "e3:";
+ //
+ // tbECParamE3
+ //
+ this.tbECParamE3.BackColor = System.Drawing.SystemColors.Window;
+ this.tbECParamE3.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
+ this.tbECParamE3.Location = new System.Drawing.Point(41, 115);
+ this.tbECParamE3.Margin = new System.Windows.Forms.Padding(0);
+ this.tbECParamE3.Name = "tbECParamE3";
+ this.tbECParamE3.ReadOnly = true;
+ this.tbECParamE3.Size = new System.Drawing.Size(139, 22);
+ this.tbECParamE3.TabIndex = 16;
+ //
+ // lbECParamE2
+ //
+ this.lbECParamE2.AutoSize = true;
+ this.lbECParamE2.Location = new System.Drawing.Point(12, 87);
+ this.lbECParamE2.Margin = new System.Windows.Forms.Padding(3);
+ this.lbECParamE2.Name = "lbECParamE2";
+ this.lbECParamE2.Size = new System.Drawing.Size(22, 13);
+ this.lbECParamE2.TabIndex = 13;
+ this.lbECParamE2.Text = "e2:";
+ //
+ // tbECParamE2
+ //
+ this.tbECParamE2.BackColor = System.Drawing.SystemColors.Window;
+ this.tbECParamE2.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
+ this.tbECParamE2.Location = new System.Drawing.Point(41, 83);
+ this.tbECParamE2.Margin = new System.Windows.Forms.Padding(10);
+ this.tbECParamE2.Name = "tbECParamE2";
+ this.tbECParamE2.ReadOnly = true;
+ this.tbECParamE2.Size = new System.Drawing.Size(139, 22);
+ this.tbECParamE2.TabIndex = 14;
+ //
+ // lbECParamE1
+ //
+ this.lbECParamE1.AutoSize = true;
+ this.lbECParamE1.Location = new System.Drawing.Point(12, 55);
+ this.lbECParamE1.Margin = new System.Windows.Forms.Padding(3);
+ this.lbECParamE1.Name = "lbECParamE1";
+ this.lbECParamE1.Size = new System.Drawing.Size(22, 13);
+ this.lbECParamE1.TabIndex = 11;
+ this.lbECParamE1.Text = "e1:";
+ //
+ // tbECParamE1
+ //
+ this.tbECParamE1.BackColor = System.Drawing.SystemColors.Window;
+ this.tbECParamE1.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
+ this.tbECParamE1.Location = new System.Drawing.Point(41, 51);
+ this.tbECParamE1.Margin = new System.Windows.Forms.Padding(10);
+ this.tbECParamE1.Name = "tbECParamE1";
+ this.tbECParamE1.ReadOnly = true;
+ this.tbECParamE1.Size = new System.Drawing.Size(139, 22);
+ this.tbECParamE1.TabIndex = 12;
+ //
+ // groupBox1
+ //
+ this.groupBox1.Controls.Add(this.rbECFieldPrime);
+ this.groupBox1.Controls.Add(this.rbECFieldBinary);
+ this.groupBox1.Enabled = false;
+ this.groupBox1.Location = new System.Drawing.Point(11, 24);
+ this.groupBox1.Margin = new System.Windows.Forms.Padding(0);
+ this.groupBox1.Name = "groupBox1";
+ this.groupBox1.Size = new System.Drawing.Size(180, 88);
+ this.groupBox1.TabIndex = 2;
+ this.groupBox1.TabStop = false;
+ this.groupBox1.Text = "EC over field:";
+ //
+ // rbECFieldPrime
+ //
+ this.rbECFieldPrime.AutoSize = true;
+ this.rbECFieldPrime.Checked = true;
+ this.rbECFieldPrime.Location = new System.Drawing.Point(12, 26);
+ this.rbECFieldPrime.Margin = new System.Windows.Forms.Padding(10);
+ this.rbECFieldPrime.Name = "rbECFieldPrime";
+ this.rbECFieldPrime.Size = new System.Drawing.Size(102, 17);
+ this.rbECFieldPrime.TabIndex = 0;
+ this.rbECFieldPrime.TabStop = true;
+ this.rbECFieldPrime.Text = "Prime field { Fp }";
+ this.rbECFieldPrime.UseVisualStyleBackColor = true;
+ this.rbECFieldPrime.CheckedChanged += new System.EventHandler(this.rbECFieldPrime_CheckedChanged);
+ //
+ // rbECFieldBinary
+ //
+ this.rbECFieldBinary.AutoSize = true;
+ this.rbECFieldBinary.Location = new System.Drawing.Point(12, 53);
+ this.rbECFieldBinary.Margin = new System.Windows.Forms.Padding(0);
+ this.rbECFieldBinary.Name = "rbECFieldBinary";
+ this.rbECFieldBinary.Size = new System.Drawing.Size(113, 17);
+ this.rbECFieldBinary.TabIndex = 1;
+ this.rbECFieldBinary.Text = "Binary field { F2m }";
+ this.rbECFieldBinary.UseVisualStyleBackColor = true;
+ this.rbECFieldBinary.CheckedChanged += new System.EventHandler(this.rbECFieldBinary_CheckedChanged);
+ //
+ // lbECParamPrime
+ //
+ this.lbECParamPrime.AutoSize = true;
+ this.lbECParamPrime.Location = new System.Drawing.Point(212, 34);
+ this.lbECParamPrime.Margin = new System.Windows.Forms.Padding(3);
+ this.lbECParamPrime.Name = "lbECParamPrime";
+ this.lbECParamPrime.Size = new System.Drawing.Size(16, 13);
+ this.lbECParamPrime.TabIndex = 0;
+ this.lbECParamPrime.Text = "p:";
+ //
+ // tbECParamPrime
+ //
+ this.tbECParamPrime.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.tbECParamPrime.BackColor = System.Drawing.SystemColors.Window;
+ this.tbECParamPrime.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
+ this.tbECParamPrime.Location = new System.Drawing.Point(233, 30);
+ this.tbECParamPrime.Margin = new System.Windows.Forms.Padding(10);
+ this.tbECParamPrime.Name = "tbECParamPrime";
+ this.tbECParamPrime.ReadOnly = true;
+ this.tbECParamPrime.Size = new System.Drawing.Size(870, 22);
+ this.tbECParamPrime.TabIndex = 1;
+ //
+ // gbECCommands
+ //
+ this.gbECCommands.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.gbECCommands.Controls.Add(this.btnECImportFromPem);
+ this.gbECCommands.Controls.Add(this.cbECName);
+ this.gbECCommands.Controls.Add(this.lbECName);
+ this.gbECCommands.Controls.Add(this.cbECKeyLength);
+ this.gbECCommands.Controls.Add(this.lbECKeyLength);
+ this.gbECCommands.Controls.Add(this.btnECImportP12);
+ this.gbECCommands.Location = new System.Drawing.Point(8, 0);
+ this.gbECCommands.Margin = new System.Windows.Forms.Padding(8);
+ this.gbECCommands.Name = "gbECCommands";
+ this.gbECCommands.Size = new System.Drawing.Size(1116, 74);
+ this.gbECCommands.TabIndex = 1;
+ this.gbECCommands.TabStop = false;
+ //
+ // btnECImportFromPem
+ //
+ this.btnECImportFromPem.Location = new System.Drawing.Point(406, 15);
+ this.btnECImportFromPem.Margin = new System.Windows.Forms.Padding(0);
+ this.btnECImportFromPem.Name = "btnECImportFromPem";
+ this.btnECImportFromPem.Size = new System.Drawing.Size(160, 48);
+ this.btnECImportFromPem.TabIndex = 10;
+ this.btnECImportFromPem.Text = "Import from PEM file";
+ this.btnECImportFromPem.UseVisualStyleBackColor = true;
+ this.btnECImportFromPem.Click += new System.EventHandler(this.btnECImportFromPem_Click);
+ //
+ // cbECName
+ //
+ this.cbECName.DropDownHeight = 432;
+ this.cbECName.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.cbECName.FormattingEnabled = true;
+ this.cbECName.IntegralHeight = false;
+ this.cbECName.Items.AddRange(new object[] {
+ "secp112r1",
+ "secp112r2",
+ "secp128r1",
+ "secp128r2",
+ "secp160k1",
+ "secp160r1",
+ "secp160r2",
+ "secp192k1",
+ "secp192r1",
+ "secp224k1",
+ "secp224r1",
+ "secp256k1",
+ "secp256r1",
+ "secp384r1",
+ "secp521r1",
+ "sect113r1",
+ "sect113r2",
+ "sect131r1",
+ "sect131r2",
+ "sect163k1",
+ "sect163r1",
+ "sect163r2",
+ "sect193r1",
+ "sect193r2",
+ "sect233k1",
+ "sect233r1",
+ "sect239k1",
+ "sect283k1",
+ "sect283r1",
+ "sect409k1",
+ "sect409r1",
+ "sect571k1",
+ "sect571r1"});
+ this.cbECName.Location = new System.Drawing.Point(99, 16);
+ this.cbECName.Margin = new System.Windows.Forms.Padding(2);
+ this.cbECName.Name = "cbECName";
+ this.cbECName.Size = new System.Drawing.Size(124, 21);
+ this.cbECName.TabIndex = 9;
+ this.cbECName.SelectedIndexChanged += new System.EventHandler(this.cbECName_SelectedIndexChanged);
+ //
+ // lbECName
+ //
+ this.lbECName.AutoSize = true;
+ this.lbECName.Location = new System.Drawing.Point(8, 19);
+ this.lbECName.Name = "lbECName";
+ this.lbECName.Size = new System.Drawing.Size(67, 13);
+ this.lbECName.TabIndex = 8;
+ this.lbECName.Text = "Curve name:";
+ //
+ // cbECKeyLength
+ //
+ this.cbECKeyLength.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.cbECKeyLength.FormattingEnabled = true;
+ this.cbECKeyLength.Items.AddRange(new object[] {
+ "112",
+ "113",
+ "128",
+ "131",
+ "160",
+ "163",
+ "192",
+ "193",
+ "224",
+ "233",
+ "239",
+ "256",
+ "283",
+ "384",
+ "409",
+ "521",
+ "571"});
+ this.cbECKeyLength.Location = new System.Drawing.Point(99, 42);
+ this.cbECKeyLength.Name = "cbECKeyLength";
+ this.cbECKeyLength.Size = new System.Drawing.Size(124, 21);
+ this.cbECKeyLength.TabIndex = 3;
+ this.cbECKeyLength.SelectedIndexChanged += new System.EventHandler(this.cbECKeyLength_SelectedIndexChanged);
+ //
+ // lbECKeyLength
+ //
+ this.lbECKeyLength.AutoSize = true;
+ this.lbECKeyLength.Location = new System.Drawing.Point(8, 45);
+ this.lbECKeyLength.Name = "lbECKeyLength";
+ this.lbECKeyLength.Size = new System.Drawing.Size(85, 13);
+ this.lbECKeyLength.TabIndex = 2;
+ this.lbECKeyLength.Text = "Key length [bits]:";
+ //
+ // btnECImportP12
+ //
+ this.btnECImportP12.Location = new System.Drawing.Point(236, 15);
+ this.btnECImportP12.Margin = new System.Windows.Forms.Padding(10);
+ this.btnECImportP12.Name = "btnECImportP12";
+ this.btnECImportP12.Size = new System.Drawing.Size(160, 48);
+ this.btnECImportP12.TabIndex = 0;
+ this.btnECImportP12.Text = "Import from PKCS#12 file (.p12 ; .pfx)";
+ this.btnECImportP12.UseVisualStyleBackColor = true;
+ this.btnECImportP12.Click += new System.EventHandler(this.btnECImportP12_Click);
+ //
+ // tabVerify
+ //
+ this.tabVerify.BackColor = System.Drawing.SystemColors.Control;
+ this.tabVerify.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
+ this.tabVerify.Controls.Add(this.gbSignature);
+ this.tabVerify.Controls.Add(this.gbMessage);
+ this.tabVerify.Controls.Add(this.gbSignatureParameters);
+ this.tabVerify.Location = new System.Drawing.Point(4, 22);
+ this.tabVerify.Name = "tabVerify";
+ this.tabVerify.Size = new System.Drawing.Size(1134, 488);
+ this.tabVerify.TabIndex = 3;
+ this.tabVerify.Text = "Verify signature";
+ //
+ // gbSignature
+ //
+ this.gbSignature.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.gbSignature.Controls.Add(this.pbVerification);
+ this.gbSignature.Controls.Add(this.btnVerifySignature);
+ this.gbSignature.Controls.Add(this.btnSignatureLoadFromBin);
+ this.gbSignature.Controls.Add(this.rbSignatureBase64);
+ this.gbSignature.Controls.Add(this.rbSignatureHex);
+ this.gbSignature.Controls.Add(this.lbSignature);
+ this.gbSignature.Controls.Add(this.tbSignature);
+ this.gbSignature.Location = new System.Drawing.Point(8, 219);
+ this.gbSignature.Margin = new System.Windows.Forms.Padding(8);
+ this.gbSignature.Name = "gbSignature";
+ this.gbSignature.Size = new System.Drawing.Size(1116, 137);
+ this.gbSignature.TabIndex = 24;
+ this.gbSignature.TabStop = false;
+ this.gbSignature.Text = "Signature:";
+ //
+ // pbVerification
+ //
+ this.pbVerification.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.pbVerification.Location = new System.Drawing.Point(69, 118);
+ this.pbVerification.Maximum = 1000;
+ this.pbVerification.Name = "pbVerification";
+ this.pbVerification.Size = new System.Drawing.Size(1033, 10);
+ this.pbVerification.Step = 1;
+ this.pbVerification.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
+ this.pbVerification.TabIndex = 31;
+ //
+ // btnVerifySignature
+ //
+ this.btnVerifySignature.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btnVerifySignature.BackColor = System.Drawing.Color.LightBlue;
+ this.btnVerifySignature.Location = new System.Drawing.Point(942, 19);
+ this.btnVerifySignature.Margin = new System.Windows.Forms.Padding(0);
+ this.btnVerifySignature.Name = "btnVerifySignature";
+ this.btnVerifySignature.Size = new System.Drawing.Size(160, 21);
+ this.btnVerifySignature.TabIndex = 30;
+ this.btnVerifySignature.Text = "Verify signature";
+ this.btnVerifySignature.UseVisualStyleBackColor = false;
+ this.btnVerifySignature.Click += new System.EventHandler(this.btnVerifySignature_Click);
+ //
+ // btnSignatureLoadFromBin
+ //
+ this.btnSignatureLoadFromBin.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btnSignatureLoadFromBin.Location = new System.Drawing.Point(772, 19);
+ this.btnSignatureLoadFromBin.Margin = new System.Windows.Forms.Padding(0);
+ this.btnSignatureLoadFromBin.Name = "btnSignatureLoadFromBin";
+ this.btnSignatureLoadFromBin.Size = new System.Drawing.Size(160, 21);
+ this.btnSignatureLoadFromBin.TabIndex = 29;
+ this.btnSignatureLoadFromBin.Text = "Load signature from binary file";
+ this.btnSignatureLoadFromBin.UseVisualStyleBackColor = true;
+ this.btnSignatureLoadFromBin.Click += new System.EventHandler(this.btnSignatureLoadFromBin_Click);
+ //
+ // rbSignatureBase64
+ //
+ this.rbSignatureBase64.AutoSize = true;
+ this.rbSignatureBase64.Location = new System.Drawing.Point(122, 24);
+ this.rbSignatureBase64.Name = "rbSignatureBase64";
+ this.rbSignatureBase64.Size = new System.Drawing.Size(61, 17);
+ this.rbSignatureBase64.TabIndex = 22;
+ this.rbSignatureBase64.TabStop = true;
+ this.rbSignatureBase64.Text = "Base64";
+ this.rbSignatureBase64.UseVisualStyleBackColor = true;
+ this.rbSignatureBase64.Click += new System.EventHandler(this.tbSignatureRadixChanged);
+ //
+ // rbSignatureHex
+ //
+ this.rbSignatureHex.AutoSize = true;
+ this.rbSignatureHex.Checked = true;
+ this.rbSignatureHex.Location = new System.Drawing.Point(69, 24);
+ this.rbSignatureHex.Name = "rbSignatureHex";
+ this.rbSignatureHex.Size = new System.Drawing.Size(47, 17);
+ this.rbSignatureHex.TabIndex = 21;
+ this.rbSignatureHex.TabStop = true;
+ this.rbSignatureHex.Text = "HEX";
+ this.rbSignatureHex.UseVisualStyleBackColor = true;
+ this.rbSignatureHex.Click += new System.EventHandler(this.tbSignatureRadixChanged);
+ //
+ // lbSignature
+ //
+ this.lbSignature.AutoSize = true;
+ this.lbSignature.Location = new System.Drawing.Point(8, 73);
+ this.lbSignature.Margin = new System.Windows.Forms.Padding(3);
+ this.lbSignature.Name = "lbSignature";
+ this.lbSignature.Size = new System.Drawing.Size(55, 13);
+ this.lbSignature.TabIndex = 17;
+ this.lbSignature.Text = "Signature:";
+ //
+ // tbSignature
+ //
+ this.tbSignature.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.tbSignature.BackColor = System.Drawing.SystemColors.Window;
+ this.tbSignature.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
+ this.tbSignature.Location = new System.Drawing.Point(69, 47);
+ this.tbSignature.Multiline = true;
+ this.tbSignature.Name = "tbSignature";
+ this.tbSignature.ScrollBars = System.Windows.Forms.ScrollBars.Horizontal;
+ this.tbSignature.Size = new System.Drawing.Size(1033, 65);
+ this.tbSignature.TabIndex = 18;
+ //
+ // gbMessage
+ //
+ this.gbMessage.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.gbMessage.Controls.Add(this.btnPlainLoadFromBin);
+ this.gbMessage.Controls.Add(this.rbMessageFromFile);
+ this.gbMessage.Controls.Add(this.rbMessageBase64);
+ this.gbMessage.Controls.Add(this.rbMessageHex);
+ this.gbMessage.Controls.Add(this.rbMessageAscii);
+ this.gbMessage.Controls.Add(this.lbMessage);
+ this.gbMessage.Controls.Add(this.tbMessage);
+ this.gbMessage.Location = new System.Drawing.Point(8, 84);
+ this.gbMessage.Margin = new System.Windows.Forms.Padding(0);
+ this.gbMessage.Name = "gbMessage";
+ this.gbMessage.Size = new System.Drawing.Size(1116, 127);
+ this.gbMessage.TabIndex = 7;
+ this.gbMessage.TabStop = false;
+ this.gbMessage.Text = "Plain text (message for verification):";
+ //
+ // btnPlainLoadFromBin
+ //
+ this.btnPlainLoadFromBin.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btnPlainLoadFromBin.Location = new System.Drawing.Point(942, 20);
+ this.btnPlainLoadFromBin.Margin = new System.Windows.Forms.Padding(0);
+ this.btnPlainLoadFromBin.Name = "btnPlainLoadFromBin";
+ this.btnPlainLoadFromBin.Size = new System.Drawing.Size(160, 21);
+ this.btnPlainLoadFromBin.TabIndex = 30;
+ this.btnPlainLoadFromBin.Text = "Load message from binary file";
+ this.btnPlainLoadFromBin.UseVisualStyleBackColor = true;
+ this.btnPlainLoadFromBin.Click += new System.EventHandler(this.btnPlainLoadFromBin_Click);
+ //
+ // rbMessageFromFile
+ //
+ this.rbMessageFromFile.AutoSize = true;
+ this.rbMessageFromFile.Location = new System.Drawing.Point(211, 24);
+ this.rbMessageFromFile.Name = "rbMessageFromFile";
+ this.rbMessageFromFile.Size = new System.Drawing.Size(379, 17);
+ this.rbMessageFromFile.TabIndex = 23;
+ this.rbMessageFromFile.TabStop = true;
+ this.rbMessageFromFile.Text = "Set file for verification (ATTENTION: it will remove any message text below)";
+ this.rbMessageFromFile.UseVisualStyleBackColor = true;
+ this.rbMessageFromFile.Click += new System.EventHandler(this.tbMessageRadixChanged);
+ //
+ // rbMessageBase64
+ //
+ this.rbMessageBase64.AutoSize = true;
+ this.rbMessageBase64.Location = new System.Drawing.Point(86, 24);
+ this.rbMessageBase64.Name = "rbMessageBase64";
+ this.rbMessageBase64.Size = new System.Drawing.Size(61, 17);
+ this.rbMessageBase64.TabIndex = 22;
+ this.rbMessageBase64.TabStop = true;
+ this.rbMessageBase64.Text = "Base64";
+ this.rbMessageBase64.UseVisualStyleBackColor = true;
+ this.rbMessageBase64.Click += new System.EventHandler(this.tbMessageRadixChanged);
+ //
+ // rbMessageHex
+ //
+ this.rbMessageHex.AutoSize = true;
+ this.rbMessageHex.Checked = true;
+ this.rbMessageHex.Location = new System.Drawing.Point(33, 24);
+ this.rbMessageHex.Name = "rbMessageHex";
+ this.rbMessageHex.Size = new System.Drawing.Size(47, 17);
+ this.rbMessageHex.TabIndex = 21;
+ this.rbMessageHex.TabStop = true;
+ this.rbMessageHex.Text = "HEX";
+ this.rbMessageHex.UseVisualStyleBackColor = true;
+ this.rbMessageHex.Click += new System.EventHandler(this.tbMessageRadixChanged);
+ //
+ // rbMessageAscii
+ //
+ this.rbMessageAscii.AutoSize = true;
+ this.rbMessageAscii.Location = new System.Drawing.Point(153, 24);
+ this.rbMessageAscii.Name = "rbMessageAscii";
+ this.rbMessageAscii.Size = new System.Drawing.Size(52, 17);
+ this.rbMessageAscii.TabIndex = 20;
+ this.rbMessageAscii.Text = "ASCII";
+ this.rbMessageAscii.UseVisualStyleBackColor = true;
+ this.rbMessageAscii.Click += new System.EventHandler(this.tbMessageRadixChanged);
+ //
+ // lbMessage
+ //
+ this.lbMessage.AutoSize = true;
+ this.lbMessage.Location = new System.Drawing.Point(8, 73);
+ this.lbMessage.Margin = new System.Windows.Forms.Padding(3);
+ this.lbMessage.Name = "lbMessage";
+ this.lbMessage.Size = new System.Drawing.Size(19, 13);
+ this.lbMessage.TabIndex = 17;
+ this.lbMessage.Text = "M:";
+ //
+ // tbMessage
+ //
+ this.tbMessage.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.tbMessage.BackColor = System.Drawing.SystemColors.Window;
+ this.tbMessage.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
+ this.tbMessage.Location = new System.Drawing.Point(33, 47);
+ this.tbMessage.Multiline = true;
+ this.tbMessage.Name = "tbMessage";
+ this.tbMessage.ScrollBars = System.Windows.Forms.ScrollBars.Horizontal;
+ this.tbMessage.Size = new System.Drawing.Size(1069, 65);
+ this.tbMessage.TabIndex = 18;
+ //
+ // gbSignatureParameters
+ //
+ this.gbSignatureParameters.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.gbSignatureParameters.Controls.Add(this.cbCipher);
+ this.gbSignatureParameters.Controls.Add(this.lbCipher);
+ this.gbSignatureParameters.Controls.Add(this.cbDigest);
+ this.gbSignatureParameters.Controls.Add(this.lbDigest);
+ this.gbSignatureParameters.Location = new System.Drawing.Point(8, 0);
+ this.gbSignatureParameters.Margin = new System.Windows.Forms.Padding(8);
+ this.gbSignatureParameters.Name = "gbSignatureParameters";
+ this.gbSignatureParameters.Size = new System.Drawing.Size(1116, 76);
+ this.gbSignatureParameters.TabIndex = 2;
+ this.gbSignatureParameters.TabStop = false;
+ //
+ // cbCipher
+ //
+ this.cbCipher.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.cbCipher.FormattingEnabled = true;
+ this.cbCipher.Items.AddRange(new object[] {
+ "RSA",
+ "ECDSA"});
+ this.cbCipher.Location = new System.Drawing.Point(99, 42);
+ this.cbCipher.Name = "cbCipher";
+ this.cbCipher.Size = new System.Drawing.Size(124, 21);
+ this.cbCipher.TabIndex = 9;
+ //
+ // lbCipher
+ //
+ this.lbCipher.AutoSize = true;
+ this.lbCipher.Location = new System.Drawing.Point(8, 45);
+ this.lbCipher.Name = "lbCipher";
+ this.lbCipher.Size = new System.Drawing.Size(85, 13);
+ this.lbCipher.TabIndex = 8;
+ this.lbCipher.Text = "Cipher algorithm:";
+ //
+ // cbDigest
+ //
+ this.cbDigest.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.cbDigest.FormattingEnabled = true;
+ this.cbDigest.Items.AddRange(new object[] {
+ "SHA-1",
+ "SHA-224",
+ "SHA-256",
+ "SHA-384",
+ "SHA-512"});
+ this.cbDigest.Location = new System.Drawing.Point(143, 16);
+ this.cbDigest.Name = "cbDigest";
+ this.cbDigest.Size = new System.Drawing.Size(80, 21);
+ this.cbDigest.TabIndex = 9;
+ //
+ // lbDigest
+ //
+ this.lbDigest.AutoSize = true;
+ this.lbDigest.Location = new System.Drawing.Point(8, 19);
+ this.lbDigest.Name = "lbDigest";
+ this.lbDigest.Size = new System.Drawing.Size(129, 13);
+ this.lbDigest.TabIndex = 8;
+ this.lbDigest.Text = "Message digest algorithm:";
+ //
+ // llbDLogicURL
+ //
+ this.llbDLogicURL.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.llbDLogicURL.Location = new System.Drawing.Point(690, 7);
+ this.llbDLogicURL.Name = "llbDLogicURL";
+ this.llbDLogicURL.Size = new System.Drawing.Size(460, 24);
+ this.llbDLogicURL.TabIndex = 1;
+ this.llbDLogicURL.TabStop = true;
+ this.llbDLogicURL.Text = "http://www.d-logic.net/nfc-rfid-reader-sdk/";
+ this.llbDLogicURL.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ this.llbDLogicURL.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.llbDLogicURL_LinkClicked);
+ //
+ // frmMain
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(1164, 537);
+ this.Controls.Add(this.llbDLogicURL);
+ this.Controls.Add(this.tabControl);
+ this.MinimumSize = new System.Drawing.Size(1040, 576);
+ this.Name = "frmMain";
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+ this.Text = "Digital Signature Verifier";
+ this.Load += new System.EventHandler(this.frmMain_Load);
+ this.tabControl.ResumeLayout(false);
+ this.tabRSAPubKey.ResumeLayout(false);
+ this.gbRSAModulus.ResumeLayout(false);
+ this.gbRSAModulus.PerformLayout();
+ this.gbRSACommands.ResumeLayout(false);
+ this.gbRSACommands.PerformLayout();
+ this.tabECPubKey.ResumeLayout(false);
+ this.gbECPubKey.ResumeLayout(false);
+ this.gbECPubKey.PerformLayout();
+ this.gbECDomainParameters.ResumeLayout(false);
+ this.gbECDomainParameters.PerformLayout();
+ this.gbECReductionPolynomial.ResumeLayout(false);
+ this.gbECReductionPolynomial.PerformLayout();
+ this.groupBox1.ResumeLayout(false);
+ this.groupBox1.PerformLayout();
+ this.gbECCommands.ResumeLayout(false);
+ this.gbECCommands.PerformLayout();
+ this.tabVerify.ResumeLayout(false);
+ this.gbSignature.ResumeLayout(false);
+ this.gbSignature.PerformLayout();
+ this.gbMessage.ResumeLayout(false);
+ this.gbMessage.PerformLayout();
+ this.gbSignatureParameters.ResumeLayout(false);
+ this.gbSignatureParameters.PerformLayout();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+ private System.Windows.Forms.TabControl tabControl;
+ private System.Windows.Forms.TabPage tabRSAPubKey;
+ private System.Windows.Forms.TabPage tabECPubKey;
+ private System.Windows.Forms.TabPage tabVerify;
+ private System.Windows.Forms.Label lbRSAKeyLength;
+ private System.Windows.Forms.LinkLabel llbDLogicURL;
+ private System.Windows.Forms.ComboBox cbRSAKeyLength;
+ private System.Windows.Forms.GroupBox gbRSACommands;
+ private System.Windows.Forms.Button btnRSAImportP12;
+ private System.Windows.Forms.GroupBox gbRSAModulus;
+ private System.Windows.Forms.Label lbRSAModulus;
+ private System.Windows.Forms.TextBox tbRSAModulus;
+ private System.Windows.Forms.GroupBox gbECCommands;
+ private System.Windows.Forms.ComboBox cbECKeyLength;
+ private System.Windows.Forms.Label lbECKeyLength;
+ private System.Windows.Forms.Button btnECImportP12;
+ private System.Windows.Forms.ComboBox cbECName;
+ private System.Windows.Forms.Label lbECName;
+ private System.Windows.Forms.GroupBox gbECDomainParameters;
+ private System.Windows.Forms.GroupBox groupBox1;
+ private System.Windows.Forms.RadioButton rbECFieldPrime;
+ private System.Windows.Forms.RadioButton rbECFieldBinary;
+ private System.Windows.Forms.Label lbECParamPrime;
+ private System.Windows.Forms.TextBox tbECParamPrime;
+ private System.Windows.Forms.GroupBox gbECReductionPolynomial;
+ private System.Windows.Forms.RichTextBox rtbECReductionPolynomial;
+ private System.Windows.Forms.Label lbECParamE3;
+ private System.Windows.Forms.TextBox tbECParamE3;
+ private System.Windows.Forms.Label lbECParamE2;
+ private System.Windows.Forms.TextBox tbECParamE2;
+ private System.Windows.Forms.Label lbECParamE1;
+ private System.Windows.Forms.TextBox tbECParamE1;
+ private System.Windows.Forms.Label lbECParamK;
+ private System.Windows.Forms.TextBox tbECParamK;
+ private System.Windows.Forms.Label lbECParamR;
+ private System.Windows.Forms.TextBox tbECParamR;
+ private System.Windows.Forms.Label lbECParamG;
+ private System.Windows.Forms.TextBox tbECParamG;
+ private System.Windows.Forms.Label lbECParamB;
+ private System.Windows.Forms.TextBox tbECParamB;
+ private System.Windows.Forms.Label ltbECParamA;
+ private System.Windows.Forms.TextBox tbECParamA;
+ private System.Windows.Forms.GroupBox gbECPubKey;
+ private System.Windows.Forms.Label lbECPubKey;
+ private System.Windows.Forms.TextBox tbECPubKey;
+ private System.Windows.Forms.GroupBox gbSignatureParameters;
+ private System.Windows.Forms.ComboBox cbDigest;
+ private System.Windows.Forms.Label lbDigest;
+ private System.Windows.Forms.ComboBox cbCipher;
+ private System.Windows.Forms.Label lbCipher;
+ private System.Windows.Forms.GroupBox gbMessage;
+ private System.Windows.Forms.RadioButton rbMessageFromFile;
+ private System.Windows.Forms.RadioButton rbMessageBase64;
+ private System.Windows.Forms.RadioButton rbMessageHex;
+ private System.Windows.Forms.RadioButton rbMessageAscii;
+ private System.Windows.Forms.Label lbMessage;
+ private System.Windows.Forms.TextBox tbMessage;
+ private System.Windows.Forms.GroupBox gbSignature;
+ private System.Windows.Forms.RadioButton rbSignatureBase64;
+ private System.Windows.Forms.RadioButton rbSignatureHex;
+ private System.Windows.Forms.Label lbSignature;
+ private System.Windows.Forms.TextBox tbSignature;
+ private System.Windows.Forms.Label lbRSAPubExp;
+ private System.Windows.Forms.TextBox tbRSAPubExp;
+ private System.Windows.Forms.Button btnSignatureLoadFromBin;
+ private System.Windows.Forms.Button btnVerifySignature;
+ private System.Windows.Forms.Button btnPlainLoadFromBin;
+ private System.Windows.Forms.Button btnRSAImportPem;
+ private System.Windows.Forms.Button btnECImportFromPem;
+ private System.Windows.Forms.ProgressBar pbVerification;
+ }
+}
+
diff --git a/frmMain.resx b/frmMain.resx
new file mode 100644
index 0000000000000000000000000000000000000000..1af7de150c99c12dd67a509fe57c10d63e4eeb04
--- /dev/null
+++ b/frmMain.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/frmPassword.cs b/frmPassword.cs
new file mode 100644
index 0000000000000000000000000000000000000000..27b5641792adcfa1ae533fd4a27a7db545816e79
--- /dev/null
+++ b/frmPassword.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace SignatureVerifier
+{
+ public partial class frmPassword : Form
+ {
+ public string password
+ {
+ get { return tbPassword.Text; }
+ }
+
+ public frmPassword()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/frmPassword.designer.cs b/frmPassword.designer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..950520b4eb0fed396de5122ab79707a4fd1c44f4
--- /dev/null
+++ b/frmPassword.designer.cs
@@ -0,0 +1,102 @@
+namespace SignatureVerifier
+{
+ partial class frmPassword
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.lbPassword = new System.Windows.Forms.Label();
+ this.tbPassword = new System.Windows.Forms.TextBox();
+ this.btnOk = new System.Windows.Forms.Button();
+ this.btnCancel = new System.Windows.Forms.Button();
+ this.SuspendLayout();
+ //
+ // lbPassword
+ //
+ this.lbPassword.AutoSize = true;
+ this.lbPassword.Location = new System.Drawing.Point(102, 24);
+ this.lbPassword.Name = "lbPassword";
+ this.lbPassword.Size = new System.Drawing.Size(80, 13);
+ this.lbPassword.TabIndex = 0;
+ this.lbPassword.Text = "Enter password";
+ //
+ // tbPassword
+ //
+ this.tbPassword.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
+ this.tbPassword.Location = new System.Drawing.Point(12, 49);
+ this.tbPassword.Name = "tbPassword";
+ this.tbPassword.PasswordChar = '*';
+ this.tbPassword.Size = new System.Drawing.Size(260, 22);
+ this.tbPassword.TabIndex = 1;
+ //
+ // btnOk
+ //
+ this.btnOk.DialogResult = System.Windows.Forms.DialogResult.OK;
+ this.btnOk.Location = new System.Drawing.Point(12, 89);
+ this.btnOk.Name = "btnOk";
+ this.btnOk.Size = new System.Drawing.Size(122, 23);
+ this.btnOk.TabIndex = 2;
+ this.btnOk.Text = "&OK";
+ this.btnOk.UseVisualStyleBackColor = true;
+ //
+ // btnCancel
+ //
+ this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+ this.btnCancel.Location = new System.Drawing.Point(140, 89);
+ this.btnCancel.Name = "btnCancel";
+ this.btnCancel.Size = new System.Drawing.Size(132, 23);
+ this.btnCancel.TabIndex = 3;
+ this.btnCancel.Text = "&Cancel";
+ this.btnCancel.UseVisualStyleBackColor = true;
+ //
+ // frmPassword
+ //
+ this.AcceptButton = this.btnOk;
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.CancelButton = this.btnCancel;
+ this.ClientSize = new System.Drawing.Size(284, 141);
+ this.Controls.Add(this.btnCancel);
+ this.Controls.Add(this.btnOk);
+ this.Controls.Add(this.tbPassword);
+ this.Controls.Add(this.lbPassword);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.Name = "frmPassword";
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+ this.Text = "Password";
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label lbPassword;
+ private System.Windows.Forms.TextBox tbPassword;
+ private System.Windows.Forms.Button btnOk;
+ private System.Windows.Forms.Button btnCancel;
+ }
+}
\ No newline at end of file
diff --git a/frmPassword.resx b/frmPassword.resx
new file mode 100644
index 0000000000000000000000000000000000000000..1af7de150c99c12dd67a509fe57c10d63e4eeb04
--- /dev/null
+++ b/frmPassword.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file