Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@@ -0,0 +1,201 @@
//
// ARC4Managed.cs: Alleged RC4(tm) compatible symmetric stream cipher
// RC4 is a trademark of RSA Security
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Globalization;
using System.Security.Cryptography;
namespace Mono.Security.Cryptography {
// References:
// a. Usenet 1994 - RC4 Algorithm revealed
// http://www.qrst.de/html/dsds/rc4.htm
#if !INSIDE_CORLIB
public
#endif
class ARC4Managed : RC4, ICryptoTransform {
private byte[] key;
private byte[] state;
private byte x;
private byte y;
private bool m_disposed;
public ARC4Managed () : base ()
{
state = new byte [256];
m_disposed = false;
}
~ARC4Managed ()
{
Dispose (true);
}
protected override void Dispose (bool disposing)
{
if (!m_disposed) {
x = 0;
y = 0;
if (key != null) {
Array.Clear (key, 0, key.Length);
key = null;
}
Array.Clear (state, 0, state.Length);
state = null;
GC.SuppressFinalize (this);
m_disposed = true;
}
}
public override byte[] Key {
get {
if (KeyValue == null)
GenerateKey ();
return (byte[]) KeyValue.Clone ();
}
set {
if (value == null)
throw new ArgumentNullException ("Key");
KeyValue = key = (byte[]) value.Clone ();
KeySetup (key);
}
}
public bool CanReuseTransform {
get { return false; }
}
public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgvIV)
{
Key = rgbKey;
return (ICryptoTransform) this;
}
public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgvIV)
{
Key = rgbKey;
return CreateEncryptor ();
}
public override void GenerateIV ()
{
// not used for a stream cipher
IV = new byte [0];
}
public override void GenerateKey ()
{
KeyValue = KeyBuilder.Key (KeySizeValue >> 3);
}
public bool CanTransformMultipleBlocks {
get { return true; }
}
public int InputBlockSize {
get { return 1; }
}
public int OutputBlockSize {
get { return 1; }
}
private void KeySetup (byte[] key)
{
byte index1 = 0;
byte index2 = 0;
for (int counter = 0; counter < 256; counter++)
state [counter] = (byte) counter;
x = 0;
y = 0;
for (int counter = 0; counter < 256; counter++) {
index2 = (byte) (key [index1] + state [counter] + index2);
// swap byte
byte tmp = state [counter];
state [counter] = state [index2];
state [index2] = tmp;
index1 = (byte) ((index1 + 1) % key.Length);
}
}
private void CheckInput (byte[] inputBuffer, int inputOffset, int inputCount)
{
if (inputBuffer == null)
throw new ArgumentNullException ("inputBuffer");
if (inputOffset < 0)
throw new ArgumentOutOfRangeException ("inputOffset", "< 0");
if (inputCount < 0)
throw new ArgumentOutOfRangeException ("inputCount", "< 0");
// ordered to avoid possible integer overflow
if (inputOffset > inputBuffer.Length - inputCount)
throw new ArgumentException ("inputBuffer", Locale.GetText ("Overflow"));
}
public int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
CheckInput (inputBuffer, inputOffset, inputCount);
// check output parameters
if (outputBuffer == null)
throw new ArgumentNullException ("outputBuffer");
if (outputOffset < 0)
throw new ArgumentOutOfRangeException ("outputOffset", "< 0");
// ordered to avoid possible integer overflow
if (outputOffset > outputBuffer.Length - inputCount)
throw new ArgumentException ("outputBuffer", Locale.GetText ("Overflow"));
return InternalTransformBlock (inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
}
private int InternalTransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
byte xorIndex;
for (int counter = 0; counter < inputCount; counter ++) {
x = (byte) (x + 1);
y = (byte) (state [x] + y);
// swap byte
byte tmp = state [x];
state [x] = state [y];
state [y] = tmp;
xorIndex = (byte) (state [x] + state [y]);
outputBuffer [outputOffset + counter] = (byte) (inputBuffer [inputOffset + counter] ^ state [xorIndex]);
}
return inputCount;
}
public byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
{
CheckInput (inputBuffer, inputOffset, inputCount);
byte[] output = new byte [inputCount];
InternalTransformBlock (inputBuffer, inputOffset, inputCount, output, 0);
return output;
}
}
}

View File

@@ -0,0 +1,328 @@
2010-07-16 Sebastien Pouliot <sebastien@ximian.com>
* MD2Managed.cs:
* MD4Managed.cs:
Increment ibStart in HashCore
2008-08-07 Sebastien Pouliot <sebastien@ximian.com>
* CryptoTools.cs: Make this usable with Silverlight 2.0 (NET_2_1)
* SymmetricTransform.cs: Make this (more) usable with SL2 limited
crypto support.
2008-04-21 Sebastien Pouliot <sebastien@ximian.com>
* CryptoConvert.cs: Fix HMAC to respect start index inside an array.
Patch by Kazuki Oikawa.
2008-03-13 Sebastien Pouliot <sebastien@ximian.com>
* CryptoConvert.cs: Re-order exception handling to report the most
precise error to caller. Apply RSA extra check to DSA.
* RSAManaged.cs: Test imported parameters to ensure the public and
private parts of the keypair match together.
2008-03-04 Sebastien Pouliot <sebastien@ximian.com>
* SymmetricTransform.cs: Sync with corlib. Fix ANSIX923 padding check
(#366623)
2008-02-03 Sebastien Pouliot <sebastien@ximian.com>
* RSAManaged.cs: Replace "" (found by Gendarme) with more useful text.
2008-01-10 Sebastien Pouliot <sebastien@ximian.com>
* PKCS1.cs: Add a new method that optionally checks for badly
padding, technically invalid, PKCS#1 block. This is required to
support timestamping verification for Authenticode (since the
main timestamping service does this). Fix for #350958
2007-11-18 Sebastien Pouliot <sebastien@ximian.com>
* RSAManaged.cs: Fix the rare case where the inverse of q modulo p
can result in bigint one byte shorter than expected, which could
mess up the export/import of the key.
2007-05-08 Randolph Chung <tausq@debian.org>
* CryptoConvert.cs: Add DSA blob conversion functions.
2007-03-05 Sebastien Pouliot <sebastien@ximian.com>
* SymmetricTransform.cs: Fix KeepLastBlock to be true for decryption
with no padding or zero padding. Part of the fix for #81008.
2007-01-08 Sebastien Pouliot <sebastien@ximian.com>
* SymmetricTransform.cs: Fix #80439 again. This time we have tests for
all ciphers, modes and padding.
2007-01-04 Sebastien Pouliot <sebastien@ximian.com>
* SymmetricTransform.cs: Fix previous fix (for #80439) as we were now
too permissive.
2007-01-03 Sebastien Pouliot <sebastien@ximian.com>
* SymmetricTransform.cs: Reduce inputCount if larger than the output
data can hold. Fix bug #80439.
2006-12-11 Sebastien Pouliot <sebastien@ximian.com>
* PKCS8.cs: Normalize the private key X integer, not it's ASN.1
container, to 20 bytes.
2006-10-04 Sebastien Pouliot <sebastien@ximian.com>
* PKCS1.cs: Remove compatibility block where all padding wasn't
verified (can't find the original test case for it). Note: the
existing implementation wasn't affected by CVE-2006-4339, aka RSA
PKCS#1 1.5 signature forgery (but we're stronger without it).
2006-09-27 Sebastien Pouliot <sebastien@ximian.com>
* RSAManaged.cs: Ensure that the results of Encrypt and Decrypt will
always be the same length as the key. If smaller then we left pad the
result with 0x00 (same integer, correct length for everyone). Fix bug
#79502 where an LDAP/SSL server didn't like the missing byte.
2006-09-05 Sebastien Pouliot <sebastien@ximian.com>
* RSAManaged.cs: Backport NRE fix from mscorlib.dll.
2006-06-15 Sebastien Pouliot <sebastien@ximian.com>
* CryptoTools.cs: Fix offset in block processor. This fix the HMAC
algorithms when large buffer where used (with multiple calls to
TransformBlock).
2006-02-28 Sebastien Pouliot <sebastien@ximian.com>
* CryptoConvert.cs: Make sure we can import a keypair into our RSA
instance (even if the key store isn't available). See bug #77559.
* PKCS8.cs: Make sure we can import a keypair into our RSA instance
(even if the key store isn't available). See bug #77559.
2005-11-23 Sebastien Pouliot <sebastien@ximian.com>
* SymmetricTransform.cs: Synched with corlib version (IV behaviour for
NET_2_0). Virtualized some methods (like Dispose). Fix bug #76801.
2005-05-09 Sebastien Pouliot <sebastien@ximian.com>
* KeyPairPersistence.cs: Use PlatformID.Unix under NET_2_0.
* PKCS8.cs: In sync with corlib;
2005-04-18 Sebastien Pouliot <sebastien@ximian.com>
* Null.cs: New "null" symmetric encryption for debugging. This class
isn't (and shouldn't be) built by default.
* SymmetricTransform.cs: Fixed a division by zero if someone changes
the feedback value to 0.
* SHA224Managed.cs: Fixed warning about unused private constant.
2005-03-30 Sebastien Pouliot <sebastien@ximian.com>
* SymmetricTransform.cs: Fixed a padding bug affecting that can occurs
when no padding is used.
2005-03-07 Sebastien Pouliot <sebastien@ximian.com>
* MD2Managed.cs: Removed memory allocation from the transform method.
* MD4Managed.cs: Moved memoty allocation to constructor (from init).
* SHA224Managed.cs: Fixed bug #73404 which gaves bad results when the
digested data is longer than 2^32 bits.
2005-01-11 Sebastien Pouliot <sebastien@ximian.com>
* SymmetricTransform.cs: Added support for ANSI X9.23 padding and
ISO 10126 padding modes (applies to all symmetric block ciphers).
2004-12-22 Sebastien Pouliot <sebastien@ximian.com>
* KeyPairPersistence.cs: Commented imperative asserts until it is
supported by the runtime.
2004-12-06 Sebastien Pouliot <sebastien@ximian.com>
* RSAManaged.cs: Implement key blinding for RSA decryption with, or
without, using CRT.
2004-11-23 Sebastien Pouliot <sebastien@ximian.com>
* PKCS1.cs: Fix PKCS#1 v1.5 decryption when the ciphertext isn't
exactly the same of the public key (which happens sometimes on Fx 1.1
probably because it doesn't do the last I2OSP operation to left pad
the resulting big integer with zeros).
2004-11-10 Sebastien Pouliot <sebastien@ximian.com>
* RC4.cs: Fixed RC4 for compatibility with .NET 2.0. The algorithm is
OK but the check for IV, unused for stream ciphers, has changed.
2004-10-28 Sebastien Pouliot <sebastien@ximian.com>
* KeyPairPersistence.cs: Added localization for exceptions messages.
Also added more details (type and path) when an exception is thrown.
2004-09-29 Sebastien Pouliot <sebastien@ximian.com>
* RSAManaged.cs: In synch with corlib. KeySize is now always a
multiple of 8 bits. Fix #66929.
2004-09-17 Sebastien Pouliot <sebastien@ximian.com>
* CryptoConvert.cs: In synch with corlib version. Fixed all level 4
compilation warnings.
* KeyPairPersistence.cs: In synch with corlib version. Fixed all level
4 compilation warnings.
* PKCS1.cs: In synch with corlib version. Fixed all level 4
compilation warnings.
* SHA224Managed.cs: Fixed all level 4 compilation warnings.
2004-09-17 Sebastien Pouliot <sebastien@ximian.com>
* SHA224.cs: New. Abstract class for all SHA224 implementations.
* SHA224Managed.cs: New. Managed implementation of SHA224 (a SHA256
derivate) as specified in RFC3874 and FIPS 180-2 Change Notice.
2004-06-23 Sebastien Pouliot <sebastien@ximian.com>
* SymmetricTransform.cs: Reduce by one the number of block when
decrypting. This operation was in CryptoStream before but is only
required for decryption (which CryptoStream can't know).
Fix bug #60573.
2004-05-27 Sebastien Pouliot <sebastien@ximian.com>
* ARC4Managed.cs: Added missing exception handling in TransformBlock
and TransformFinalBlock.
* SymmetricTransform.cs: Fixed possible integer overflow. Added
missing exception handling in TransformBlock and TransformFinalBlock.
2004-05-10 Sebastien Pouliot <sebastien@ximian.com>
* PKCS8.cs: Fixed negative Version check.
* MD2Managed.cs: Added readonly to static array constants.
* MD4Managed.cs: Removed unrequired memory allocation in MD4Transform.
2004-05-01 Sebastien Pouliot <sebastien@ximian.com>
* CryptoConvert.cs: Added support for truncated, but still valid, RSA
private key blob. Fix #57941 (couldn't sign with nunit key).
* RSAManaged.cs: Normalized the size of D when not present. This
allows us to output a compatible base64 representation of 1024bits 0.
2004-04-28 Sebastien Pouliot <sebastien@ximian.com>
* SymmetricTransform.cs: Fixed bug when offset > 0 in destination
buffer.
2004-04-22 Sebastien Pouliot <sebastien@ximian.com>
* CryptoConvert.cs: FxCop-ized. Sealed class. Use Buffer.BlockCopy.
* CryptoTools.cs: FxCop-ized. Sealed KeyBuilder class. Delay creation
of RNG object. Use Buffer.BlockCopy.
* DiffieHellman.cs: FxCop-ized. Removed public constructor.
* DiffieHellmanManaged.cs: FxCop-ized. Actualized with changes from
BigInteger.
* KeyPairPersistance.cs: FxCop-ized. Updated version for management
of keypairs.
* MD2Managed.cs: Use Buffer.BlockCopy instead of Array.Copy.
* PKCS1.cs: FxCop-ized. Sealed class. Use Buffer.BlockCopy instead of
Array.Copy. Also includes endian patches from Bernie Solomon.
* PKCS8.cs: FxCop-ized. Sealed class.
* RSAManaged.cs: FxCop-ized. Actualized with changes from BigInteger.
* SymmetricTransform.cs: Use Buffer.BlockCopy instead of Array.Copy.
2004-04-20 Sebastien Pouliot <sebastien@ximian.com>
* CryptoConvert.cs: Synched with corlib version to get endian fixes
from Bernie Solomon.
2004-03-23 Sebastien Pouliot <sebastien@ximian.com>
* CryptoConvert.cs: Added exception for null and bad parameters.
* RSAManaged.cs: CryptographicException thrown when trying to export
the private key when only the public key is present (CRT aware).
2004-03-22 Sebastien Pouliot <sebastien@ximian.com>
* CryptoConvert.cs: Added new methods to convert [From|To]Hex. Added
new version of FromCapiPublicKeyBlob with an integer offset.
2004-03-10 Sebastien Pouliot <sebastien@ximian.com>
* PKCS8.cs: Added EncodeRSA, EncodeDSA and completed GetBytes() so it
is now possible to encode PKCS8 files (this is required to encode
PKCS12 files).
2004-02-15 Sebastien Pouliot <sebastien@ximian.com>
* ARC4Managed.cs: Removed all % 256 (modulo) because typecasting to
byte already ensure the result would be correct (as suggested by
Technoboy). Now use KeyBuilder to create new keys.
2004-02-13 Sebastien Pouliot <sebastien@ximian.com>
* DHKeyGeneration.cs: New. Enumuration of possible key generation for
Diffie-Hellman. Contributed by Pieter Philippaerts (mentalis.org).
* DHParameters.cs: New. Structure to hold the different elements of a
Diffie-Hellman key. Contributed by Pieter Philippaerts (mentalis.org).
* DiffieHellman.cs: New. Astract class as base for all Diffie-Hellman
implementations. Contributed by Pieter Philippaerts (mentalis.org).
* DiffieHellmanManaged.cs: New. Managed implementation of the Diffie-
Hellman key agreement algorithm. Contributed by Pieter Philippaerts.
2004-02-09 Sebastien Pouliot <sebastien@ximian.com>
* PKCS1.cs: New. Copied from corlib. Required for RSAManaged.
* RSAManaged.cs: New. Copied from corlib. Required for TLS - some
parts (MD5SHA1) cannot work with the default RSACryptoServiceProvider.
2004-02-06 Sebastien Pouliot <sebastien@ximian.com>
* CryptoTools.cs: New. Copied from corlib to offer the sames services
to symmetric algorithms in Mono.Security assembly.
* KeyPairPersistance.cs: Provides a similar to CryptoAPI persistence
mechanism for keypairs (based on CspParameters).
* SymmetricTransform.cs: New. Copied from corlib to offer the sames
services to symmetric algorithms in Mono.Security assembly.
2004-01-12 Sebastien Pouliot <spouliot@videotron.ca>
* CryptoConvert.cs: RSA doesn't start with a Q - at least that what
a strongname told me. Sorry Ron :(
2003-11-27 Sebastien Pouliot <spouliot@videotron.ca>
* MD4.cs: New. Asbtract class for all MD4 implementations. WARNING:
The MD4 algorithm is BROKEN (collisions) and SHOULDN'T be used in
NEW designs. However some higher level algorithms (like NTLM) requires
MD4 (and may even be secure using it). YOU'RE WARNED!
* MD4Managed.cs: New. Managed implementation of MD4 (RFC1320).
* PKCS8.cs: New. Added Private-Key Information Syntax Standard as a
building block for PKCS12.
2003-10-30 Sebastien Pouliot <spouliot@videotron.ca>
* CryptoConvert.cs: Fixed strongname generation for small exponents
(like 17). Part of the fixed for bug #50341.
2003-06-19 Nick Drochak <ndrochak@gol.com>
* CryptoConvert.cs: Work around for mcs? bug 45127.
2003-03-07 Sebastien Pouliot <spouliot@videotron.ca>
* ARC4Managed.cs: New. Implementation of the Alleged RC4(tm)
stream cipher in managed code (required for SSL/TLS).
* CryptoConvert.cs: New. Helper class to help convert between
Windows crypto structures and .NET crypto classes (required
for security tools).
* MD2.cs: New. Abstract class for all MD2 hash implementations.
* MD2Managed.cs: New. Managed implementation of the MD2 hash
algorithm (required for old, but still valid, X.509 certificates).
* RC4.cs: New. Abstract class for all RC4 stream cipher
implementations.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,143 @@
//
// Mono.Security.Cryptography.CryptoTools
// Shared class for common cryptographic functionalities
//
// Authors:
// Sebastien Pouliot <sebastien@ximian.com>
//
// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
// Copyright (C) 2004, 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Security.Cryptography;
namespace Mono.Security.Cryptography {
#if INSIDE_CORLIB
internal
#else
public
#endif
sealed class KeyBuilder {
static private RandomNumberGenerator rng;
private KeyBuilder ()
{
}
static RandomNumberGenerator Rng {
get {
if (rng == null)
rng = RandomNumberGenerator.Create ();
return rng;
}
}
static public byte[] Key (int size)
{
byte[] key = new byte [size];
Rng.GetBytes (key);
return key;
}
static public byte[] IV (int size)
{
byte[] iv = new byte [size];
Rng.GetBytes (iv);
return iv;
}
}
// Process an array as a sequence of blocks
#if INSIDE_CORLIB
internal
#else
public
#endif
class BlockProcessor {
private ICryptoTransform transform;
private byte[] block;
private int blockSize; // in bytes (not in bits)
private int blockCount;
public BlockProcessor (ICryptoTransform transform)
: this (transform, transform.InputBlockSize) {}
// some Transforms (like HashAlgorithm descendant) return 1 for
// block size (which isn't their real internal block size)
public BlockProcessor (ICryptoTransform transform, int blockSize)
{
this.transform = transform;
this.blockSize = blockSize;
block = new byte [blockSize];
}
~BlockProcessor ()
{
// zeroize our block (so we don't retain any information)
Array.Clear (block, 0, blockSize);
}
public void Initialize ()
{
Array.Clear (block, 0, blockSize);
blockCount = 0;
}
public void Core (byte[] rgb)
{
Core (rgb, 0, rgb.Length);
}
public void Core (byte[] rgb, int ib, int cb)
{
// 1. fill the rest of the "block"
int n = System.Math.Min (blockSize - blockCount, cb);
Buffer.BlockCopy (rgb, ib, block, blockCount, n);
blockCount += n;
// 2. if block is full then transform it
if (blockCount == blockSize) {
transform.TransformBlock (block, 0, blockSize, block, 0);
// 3. transform any other full block in specified buffer
int b = (int) ((cb - n) / blockSize);
for (int i=0; i < b; i++) {
transform.TransformBlock (rgb, n + ib, blockSize, block, 0);
n += blockSize;
}
// 4. if data is still present fill the "block" with the remainder
blockCount = cb - n;
if (blockCount > 0)
Buffer.BlockCopy (rgb, n + ib, block, 0, blockCount);
}
}
public byte[] Final ()
{
return transform.TransformFinalBlock (block, 0, blockCount);
}
}
}

View File

@@ -0,0 +1,66 @@
//
// DHKeyGeneration.cs: Defines the different key generation methods.
//
// Author:
// Pieter Philippaerts (Pieter@mentalis.org)
//
// (C) 2003 The Mentalis.org Team (http://www.mentalis.org/)
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
namespace Mono.Security.Cryptography {
/// <summary>
/// Defines the different Diffie-Hellman key generation methods.
/// </summary>
public enum DHKeyGeneration {
/// <summary>
/// [TODO] you first randomly select a prime Q of size 160 bits, then choose P randomly among numbers like
/// Q*R+1 with R random. Then you go along with finding a generator G which has order exactly Q. The private
/// key X is then a number modulo Q.
/// [FIPS 186-2-Change1 -- http://csrc.nist.gov/publications/fips/]
/// </summary>
// see RFC2631 [http://www.faqs.org/rfcs/rfc2631.html]
//DSA,
/// <summary>
/// Returns dynamically generated values for P and G. Unlike the Sophie Germain or DSA key generation methods,
/// this method does not ensure that the selected prime offers an adequate security level.
/// </summary>
Random,
/// <summary>
/// Returns dynamically generated values for P and G. P is a Sophie Germain prime, which has some interesting
/// security features when used with Diffie Hellman.
/// </summary>
//SophieGermain,
/// <summary>
/// Returns values for P and G that are hard coded in this library. Contrary to what your intuition may tell you,
/// using these hard coded values is perfectly safe.
/// The values of the P and G parameters are taken from 'The OAKLEY Key Determination Protocol' [RFC2412].
/// This is the prefered key generation method, because it is very fast and very safe.
/// Because this method uses fixed values for the P and G parameters, not all bit sizes are supported.
/// The current implementation supports bit sizes of 768, 1024 and 1536.
/// </summary>
Static
}
}

View File

@@ -0,0 +1,53 @@
//
// DHParameters.cs: Defines a structure that holds the parameters of the Diffie-Hellman algorithm
//
// Author:
// Pieter Philippaerts (Pieter@mentalis.org)
//
// (C) 2003 The Mentalis.org Team (http://www.mentalis.org/)
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
namespace Mono.Security.Cryptography {
/// <summary>
/// Represents the parameters of the Diffie-Hellman algorithm.
/// </summary>
[Serializable]
public struct DHParameters {
/// <summary>
/// Represents the public <b>P</b> parameter of the Diffie-Hellman algorithm.
/// </summary>
public byte[] P;
/// <summary>
/// Represents the public <b>G</b> parameter of the Diffie-Hellman algorithm.
/// </summary>
public byte[] G;
/// <summary>
/// Represents the private <b>X</b> parameter of the Diffie-Hellman algorithm.
/// </summary>
[NonSerialized]
public byte[] X;
}
}

View File

@@ -0,0 +1,153 @@
//
// DiffieHellman.cs: Defines a base class from which all Diffie-Hellman implementations inherit
//
// Author:
// Pieter Philippaerts (Pieter@mentalis.org)
//
// (C) 2003 The Mentalis.org Team (http://www.mentalis.org/)
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Text;
using System.Security;
using System.Security.Cryptography;
using Mono.Xml;
using Mono.Math;
namespace Mono.Security.Cryptography {
/// <summary>
/// Defines a base class from which all Diffie-Hellman implementations inherit.
/// </summary>
public abstract class DiffieHellman : AsymmetricAlgorithm {
/// <summary>
/// Creates an instance of the default implementation of the <see cref="DiffieHellman"/> algorithm.
/// </summary>
/// <returns>A new instance of the default implementation of DiffieHellman.</returns>
public static new DiffieHellman Create () {
return Create ("Mono.Security.Cryptography.DiffieHellman");
}
/// <summary>
/// Creates an instance of the specified implementation of <see cref="DiffieHellman"/>.
/// </summary>
/// <param name="algName">The name of the implementation of DiffieHellman to use.</param>
/// <returns>A new instance of the specified implementation of DiffieHellman.</returns>
public static new DiffieHellman Create (string algName) {
return (DiffieHellman) CryptoConfig.CreateFromName (algName);
}
/// <summary>
/// When overridden in a derived class, creates the key exchange data.
/// </summary>
/// <returns>The key exchange data to be sent to the intended recipient.</returns>
public abstract byte[] CreateKeyExchange();
/// <summary>
/// When overridden in a derived class, extracts secret information from the key exchange data.
/// </summary>
/// <param name="keyex">The key exchange data within which the secret information is hidden.</param>
/// <returns>The secret information derived from the key exchange data.</returns>
public abstract byte[] DecryptKeyExchange (byte[] keyex);
/// <summary>
/// When overridden in a derived class, exports the <see cref="DHParameters"/>.
/// </summary>
/// <param name="includePrivate"><b>true</b> to include private parameters; otherwise, <b>false</b>.</param>
/// <returns>The parameters for Diffie-Hellman.</returns>
public abstract DHParameters ExportParameters (bool includePrivate);
/// <summary>
/// When overridden in a derived class, imports the specified <see cref="DHParameters"/>.
/// </summary>
/// <param name="parameters">The parameters for Diffie-Hellman.</param>
public abstract void ImportParameters (DHParameters parameters);
private byte[] GetNamedParam(SecurityElement se, string param) {
SecurityElement sep = se.SearchForChildByTag(param);
if (sep == null)
return null;
return Convert.FromBase64String(sep.Text);
}
/// <summary>
/// Reconstructs a <see cref="DiffieHellman"/> object from an XML string.
/// </summary>
/// <param name="xmlString">The XML string to use to reconstruct the DiffieHellman object.</param>
/// <exception cref="CryptographicException">One of the values in the XML string is invalid.</exception>
public override void FromXmlString (string xmlString) {
if (xmlString == null)
throw new ArgumentNullException ("xmlString");
DHParameters dhParams = new DHParameters();
try {
SecurityParser sp = new SecurityParser();
sp.LoadXml(xmlString);
SecurityElement se = sp.ToXml();
if (se.Tag != "DHKeyValue")
throw new CryptographicException();
dhParams.P = GetNamedParam(se, "P");
dhParams.G = GetNamedParam(se, "G");
dhParams.X = GetNamedParam(se, "X");
ImportParameters(dhParams);
} finally {
if (dhParams.P != null)
Array.Clear(dhParams.P, 0, dhParams.P.Length);
if (dhParams.G != null)
Array.Clear(dhParams.G, 0, dhParams.G.Length);
if (dhParams.X != null)
Array.Clear(dhParams.X, 0, dhParams.X.Length);
}
}
/// <summary>
/// Creates and returns an XML string representation of the current <see cref="DiffieHellman"/> object.
/// </summary>
/// <param name="includePrivateParameters"><b>true</b> to include private parameters; otherwise, <b>false</b>.</param>
/// <returns>An XML string encoding of the current DiffieHellman object.</returns>
public override string ToXmlString (bool includePrivateParameters) {
StringBuilder sb = new StringBuilder ();
DHParameters dhParams = ExportParameters(includePrivateParameters);
try {
sb.Append ("<DHKeyValue>");
sb.Append ("<P>");
sb.Append (Convert.ToBase64String (dhParams.P));
sb.Append ("</P>");
sb.Append ("<G>");
sb.Append (Convert.ToBase64String (dhParams.G));
sb.Append ("</G>");
if (includePrivateParameters) {
sb.Append ("<X>");
sb.Append (Convert.ToBase64String (dhParams.X));
sb.Append ("</X>");
}
sb.Append ("</DHKeyValue>");
} finally {
Array.Clear(dhParams.P, 0, dhParams.P.Length);
Array.Clear(dhParams.G, 0, dhParams.G.Length);
if (dhParams.X != null)
Array.Clear(dhParams.X, 0, dhParams.X.Length);
}
return sb.ToString ();
}
}
}

View File

@@ -0,0 +1,273 @@
//
// DiffieHellmanManaged.cs: Implements the Diffie-Hellman key agreement algorithm
//
// Author:
// Pieter Philippaerts (Pieter@mentalis.org)
//
// (C) 2003 The Mentalis.org Team (http://www.mentalis.org/)
//
// References:
// - PKCS#3 [http://www.rsasecurity.com/rsalabs/pkcs/pkcs-3/]
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Security.Cryptography;
using Mono.Math;
namespace Mono.Security.Cryptography {
/// <summary>
/// Implements the Diffie-Hellman algorithm.
/// </summary>
public sealed class DiffieHellmanManaged : DiffieHellman {
/// <summary>
/// Initializes a new <see cref="DiffieHellmanManaged"/> instance.
/// </summary>
/// <remarks>The default length of the shared secret is 1024 bits.</remarks>
public DiffieHellmanManaged() : this(1024, 160, DHKeyGeneration.Static) {}
/// <summary>
/// Initializes a new <see cref="DiffieHellmanManaged"/> instance.
/// </summary>
/// <param name="bitLength">The length, in bits, of the public P parameter.</param>
/// <param name="l">The length, in bits, of the secret value X. This parameter can be set to 0 to use the default size.</param>
/// <param name="method">One of the <see cref="DHKeyGeneration"/> values.</param>
/// <remarks>The larger the bit length, the more secure the algorithm is. The default is 1024 bits. The minimum bit length is 128 bits.<br/>The size of the private value will be one fourth of the bit length specified.</remarks>
/// <exception cref="ArgumentException">The specified bit length is invalid.</exception>
public DiffieHellmanManaged(int bitLength, int l, DHKeyGeneration method) {
if (bitLength < 256 || l < 0)
throw new ArgumentException();
BigInteger p, g;
GenerateKey (bitLength, method, out p, out g);
Initialize(p, g, null, l, false);
}
/// <summary>
/// Initializes a new <see cref="DiffieHellmanManaged"/> instance.
/// </summary>
/// <param name="p">The P parameter of the Diffie-Hellman algorithm. This is a public parameter.</param>
/// <param name="g">The G parameter of the Diffie-Hellman algorithm. This is a public parameter.</param>
/// <param name="x">The X parameter of the Diffie-Hellman algorithm. This is a private parameter. If this parameters is a null reference (<b>Nothing</b> in Visual Basic), a secret value of the default size will be generated.</param>
/// <exception cref="ArgumentNullException"><paramref name="p"/> or <paramref name="g"/> is a null reference (<b>Nothing</b> in Visual Basic).</exception>
/// <exception cref="CryptographicException"><paramref name="p"/> or <paramref name="g"/> is invalid.</exception>
public DiffieHellmanManaged(byte[] p, byte[] g, byte[] x) {
if (p == null || g == null)
throw new ArgumentNullException();
if (x == null)
Initialize(new BigInteger(p), new BigInteger(g), null, 0, true);
else
Initialize(new BigInteger(p), new BigInteger(g), new BigInteger(x), 0, true);
}
/// <summary>
/// Initializes a new <see cref="DiffieHellmanManaged"/> instance.
/// </summary>
/// <param name="p">The P parameter of the Diffie-Hellman algorithm.</param>
/// <param name="g">The G parameter of the Diffie-Hellman algorithm.</param>
/// <param name="l">The length, in bits, of the private value. If 0 is specified, the default value will be used.</param>
/// <exception cref="ArgumentNullException"><paramref name="p"/> or <paramref name="g"/> is a null reference (<b>Nothing</b> in Visual Basic).</exception>
/// <exception cref="ArgumentException"><paramref name="l"/> is invalid.</exception>
/// <exception cref="CryptographicException"><paramref name="p"/> or <paramref name="g"/> is invalid.</exception>
public DiffieHellmanManaged(byte[] p, byte[] g, int l) {
if (p == null || g == null)
throw new ArgumentNullException();
if (l < 0)
throw new ArgumentException();
Initialize(new BigInteger(p), new BigInteger(g), null, l, true);
}
// initializes the private variables (throws CryptographicException)
private void Initialize(BigInteger p, BigInteger g, BigInteger x, int secretLen, bool checkInput) {
if (checkInput) {
if (!p.IsProbablePrime() || g <= 0 || g >= p || (x != null && (x <= 0 || x > p - 2)))
throw new CryptographicException();
}
// default is to generate a number as large as the prime this
// is usually overkill, but it's the most secure thing we can
// do if the user doesn't specify a desired secret length ...
if (secretLen == 0)
secretLen = p.BitCount();
m_P = p;
m_G = g;
if (x == null) {
BigInteger pm1 = m_P - 1;
for(m_X = BigInteger.GenerateRandom(secretLen); m_X >= pm1 || m_X == 0; m_X = BigInteger.GenerateRandom(secretLen)) {}
} else {
m_X = x;
}
}
/// <summary>
/// Creates the key exchange data.
/// </summary>
/// <returns>The key exchange data to be sent to the intended recipient.</returns>
public override byte[] CreateKeyExchange() {
BigInteger y = m_G.ModPow(m_X, m_P);
byte[] ret = y.GetBytes();
y.Clear();
return ret;
}
/// <summary>
/// Extracts secret information from the key exchange data.
/// </summary>
/// <param name="keyEx">The key exchange data within which the shared key is hidden.</param>
/// <returns>The shared key derived from the key exchange data.</returns>
public override byte[] DecryptKeyExchange(byte[] keyEx) {
BigInteger pvr = new BigInteger(keyEx);
BigInteger z = pvr.ModPow(m_X, m_P);
byte[] ret = z.GetBytes();
z.Clear();
return ret;
}
/// <summary>
/// Gets the name of the key exchange algorithm.
/// </summary>
/// <value>The name of the key exchange algorithm.</value>
public override string KeyExchangeAlgorithm {
get {
return "1.2.840.113549.1.3"; // PKCS#3 OID
}
}
/// <summary>
/// Gets the name of the signature algorithm.
/// </summary>
/// <value>The name of the signature algorithm.</value>
public override string SignatureAlgorithm {
get {
return null;
}
}
// clear keys
protected override void Dispose(bool disposing) {
if (!m_Disposed) {
m_P.Clear();
m_G.Clear();
m_X.Clear();
}
m_Disposed = true;
}
/// <summary>
/// Exports the <see cref="DHParameters"/>.
/// </summary>
/// <param name="includePrivateParameters"><b>true</b> to include private parameters; otherwise, <b>false</b>.</param>
/// <returns>The parameters for <see cref="DiffieHellman"/>.</returns>
public override DHParameters ExportParameters(bool includePrivateParameters) {
DHParameters ret = new DHParameters();
ret.P = m_P.GetBytes();
ret.G = m_G.GetBytes();
if (includePrivateParameters) {
ret.X = m_X.GetBytes();
}
return ret;
}
/// <summary>
/// Imports the specified <see cref="DHParameters"/>.
/// </summary>
/// <param name="parameters">The parameters for <see cref="DiffieHellman"/>.</param>
/// <exception cref="CryptographicException"><paramref name="P"/> or <paramref name="G"/> is a null reference (<b>Nothing</b> in Visual Basic) -or- <paramref name="P"/> is not a prime number.</exception>
public override void ImportParameters(DHParameters parameters) {
if (parameters.P == null)
throw new CryptographicException("Missing P value.");
if (parameters.G == null)
throw new CryptographicException("Missing G value.");
BigInteger p = new BigInteger(parameters.P), g = new BigInteger(parameters.G), x = null;
if (parameters.X != null) {
x = new BigInteger(parameters.X);
}
Initialize(p, g, x, 0, true);
}
~DiffieHellmanManaged() {
Dispose(false);
}
//TODO: implement DH key generation methods
private void GenerateKey(int bitlen, DHKeyGeneration keygen, out BigInteger p, out BigInteger g) {
if (keygen == DHKeyGeneration.Static) {
if (bitlen == 768)
p = new BigInteger(m_OAKLEY768);
else if (bitlen == 1024)
p = new BigInteger(m_OAKLEY1024);
else if (bitlen == 1536)
p = new BigInteger(m_OAKLEY1536);
else
throw new ArgumentException("Invalid bit size.");
g = new BigInteger(22); // all OAKLEY keys use 22 as generator
//} else if (keygen == DHKeyGeneration.SophieGermain) {
// throw new NotSupportedException(); //TODO
//} else if (keygen == DHKeyGeneration.DSA) {
// 1. Let j = (p - 1)/q.
// 2. Set h = any integer, where 1 < h < p - 1
// 3. Set g = h^j mod p
// 4. If g = 1 go to step 2
// BigInteger j = (p - 1) / q;
} else { // random
p = BigInteger.GeneratePseudoPrime(bitlen);
g = new BigInteger(3); // always use 3 as a generator
}
}
private BigInteger m_P;
private BigInteger m_G;
private BigInteger m_X;
private bool m_Disposed;
private static byte[] m_OAKLEY768 = new byte[] {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
0xA6, 0x3A, 0x36, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
private static byte[] m_OAKLEY1024 = new byte[] {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
private static byte[] m_OAKLEY1536 = new byte[] {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36,
0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
0xCA, 0x23, 0x73, 0x27, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
}
}

View File

@@ -0,0 +1,464 @@
//
// KeyPairPersistence.cs: Keypair persistence
//
// Author:
// Sebastien Pouliot <sebastien@ximian.com>
//
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Globalization;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using Mono.Xml;
namespace Mono.Security.Cryptography {
/* File name
* [type][unique name][key number].xml
*
* where
* type CspParameters.ProviderType
* unique name A unique name for the keypair, which is
* a. default (for a provider default keypair)
* b. a GUID derived from
* i. random if no container name was
* specified at generation time
* ii. the MD5 hash of the container
* name (CspParameters.KeyContainerName)
* key number CspParameters.KeyNumber
*
* File format
* <KeyPair>
* <Properties>
* <Provider Name="" Type=""/>
* <Container Name=""/>
* </Properties>
* <KeyValue Id="">
* RSAKeyValue, DSAKeyValue ...
* </KeyValue>
* </KeyPair>
*/
/* NOTES
*
* - There's NO confidentiality / integrity built in this
* persistance mechanism. The container directories (both user and
* machine) are created with restrited ACL. The ACL is also checked
* when a key is accessed (so totally public keys won't be used).
* see /mono/mono/metadata/security.c for implementation
*
* - As we do not use CSP we limit ourselves to provider types (not
* names). This means that for a same type and container type, but
* two different provider names) will return the same keypair. This
* should work as CspParameters always requires a csp type in its
* constructors.
*
* - Assert (CAS) are used so only the OS permission will limit access
* to the keypair files. I.e. this will work even in high-security
* scenarios where users do not have access to file system (e.g. web
* application). We can allow this because the filename used is
* TOTALLY under our control (no direct user input is used).
*
* - You CAN'T changes properties of the keypair once it's been
* created (saved). You must remove the container than save it
* back. This is the same behaviour as CSP under Windows.
*/
#if INSIDE_CORLIB
internal
#else
public
#endif
class KeyPairPersistence {
private static bool _userPathExists; // check at 1st use
private static string _userPath;
private static bool _machinePathExists; // check at 1st use
private static string _machinePath;
private CspParameters _params;
private string _keyvalue;
private string _filename;
private string _container;
// constructors
public KeyPairPersistence (CspParameters parameters)
: this (parameters, null)
{
}
public KeyPairPersistence (CspParameters parameters, string keyPair)
{
if (parameters == null)
throw new ArgumentNullException ("parameters");
_params = Copy (parameters);
_keyvalue = keyPair;
}
// properties
public string Filename {
get {
if (_filename == null) {
_filename = String.Format (CultureInfo.InvariantCulture,
"[{0}][{1}][{2}].xml",
_params.ProviderType,
this.ContainerName,
_params.KeyNumber);
if (UseMachineKeyStore)
_filename = Path.Combine (MachinePath, _filename);
else
_filename = Path.Combine (UserPath, _filename);
}
return _filename;
}
}
public string KeyValue {
get { return _keyvalue; }
set {
if (this.CanChange)
_keyvalue = value;
}
}
// return a (read-only) copy
public CspParameters Parameters {
get { return Copy (_params); }
}
// methods
public bool Load ()
{
// see NOTES
// FIXME new FileIOPermission (FileIOPermissionAccess.Read, this.Filename).Assert ();
bool result = File.Exists (this.Filename);
if (result) {
using (StreamReader sr = File.OpenText (this.Filename)) {
FromXml (sr.ReadToEnd ());
}
}
return result;
}
public void Save ()
{
// see NOTES
// FIXME new FileIOPermission (FileIOPermissionAccess.Write, this.Filename).Assert ();
using (FileStream fs = File.Open (this.Filename, FileMode.Create)) {
StreamWriter sw = new StreamWriter (fs, Encoding.UTF8);
sw.Write (this.ToXml ());
sw.Close ();
}
// apply protection to newly created files
if (UseMachineKeyStore)
ProtectMachine (Filename);
else
ProtectUser (Filename);
}
public void Remove ()
{
// see NOTES
// FIXME new FileIOPermission (FileIOPermissionAccess.Write, this.Filename).Assert ();
File.Delete (this.Filename);
// it's now possible to change the keypair un the container
}
// private static stuff
static object lockobj = new object ();
private static string UserPath {
get {
lock (lockobj) {
if ((_userPath == null) || (!_userPathExists)) {
_userPath = Path.Combine (
Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData),
".mono");
_userPath = Path.Combine (_userPath, "keypairs");
_userPathExists = Directory.Exists (_userPath);
if (!_userPathExists) {
try {
Directory.CreateDirectory (_userPath);
}
catch (Exception e) {
string msg = Locale.GetText ("Could not create user key store '{0}'.");
throw new CryptographicException (String.Format (msg, _userPath), e);
}
if (!ProtectUser (_userPath)) {
string msg = Locale.GetText ("Could not secure user key store '{0}'.");
throw new IOException (String.Format (msg, _userPath));
}
_userPathExists = true;
}
}
}
// is it properly protected ?
if (!IsUserProtected (_userPath)) {
string msg = Locale.GetText ("Improperly protected user's key pairs in '{0}'.");
throw new CryptographicException (String.Format (msg, _userPath));
}
return _userPath;
}
}
private static string MachinePath {
get {
lock (lockobj) {
if ((_machinePath == null) || (!_machinePathExists)) {
_machinePath = Path.Combine (
Environment.GetFolderPath (Environment.SpecialFolder.CommonApplicationData),
".mono");
_machinePath = Path.Combine (_machinePath, "keypairs");
_machinePathExists = Directory.Exists (_machinePath);
if (!_machinePathExists) {
try {
Directory.CreateDirectory (_machinePath);
}
catch (Exception e) {
string msg = Locale.GetText ("Could not create machine key store '{0}'.");
throw new CryptographicException (String.Format (msg, _machinePath), e);
}
if (!ProtectMachine (_machinePath)) {
string msg = Locale.GetText ("Could not secure machine key store '{0}'.");
throw new IOException (String.Format (msg, _machinePath));
}
_machinePathExists = true;
}
}
}
// is it properly protected ?
if (!IsMachineProtected (_machinePath)) {
string msg = Locale.GetText ("Improperly protected machine's key pairs in '{0}'.");
throw new CryptographicException (String.Format (msg, _machinePath));
}
return _machinePath;
}
}
#if INSIDE_CORLIB
[MethodImplAttribute (MethodImplOptions.InternalCall)]
internal static extern bool _CanSecure (string root);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
internal static extern bool _ProtectUser (string path);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
internal static extern bool _ProtectMachine (string path);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
internal static extern bool _IsUserProtected (string path);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
internal static extern bool _IsMachineProtected (string path);
#else
// Mono.Security.dll assembly can't use the internal
// call (and still run with other runtimes)
// Note: Class is only available in Mono.Security.dll as
// a management helper (e.g. build a GUI app)
internal static bool _CanSecure (string root)
{
return true;
}
internal static bool _ProtectUser (string path)
{
return true;
}
internal static bool _ProtectMachine (string path)
{
return true;
}
internal static bool _IsUserProtected (string path)
{
return true;
}
internal static bool _IsMachineProtected (string path)
{
return true;
}
#endif
// private stuff
private static bool CanSecure (string path)
{
// we assume POSIX filesystems can always be secured
// check for Unix platforms - see FAQ for more details
// http://www.mono-project.com/FAQ:_Technical#How_to_detect_the_execution_platform_.3F
int platform = (int) Environment.OSVersion.Platform;
if ((platform == 4) || (platform == 128) || (platform == 6))
return true;
// while we ask the runtime for Windows OS
return _CanSecure (Path.GetPathRoot (path));
}
private static bool ProtectUser (string path)
{
// we cannot protect on some filsystem (like FAT)
if (CanSecure (path)) {
return _ProtectUser (path);
}
// but Mono still needs to run on them :(
return true;
}
private static bool ProtectMachine (string path)
{
// we cannot protect on some filsystem (like FAT)
if (CanSecure (path)) {
return _ProtectMachine (path);
}
// but Mono still needs to run on them :(
return true;
}
private static bool IsUserProtected (string path)
{
// we cannot protect on some filsystem (like FAT)
if (CanSecure (path)) {
return _IsUserProtected (path);
}
// but Mono still needs to run on them :(
return true;
}
private static bool IsMachineProtected (string path)
{
// we cannot protect on some filsystem (like FAT)
if (CanSecure (path)) {
return _IsMachineProtected (path);
}
// but Mono still needs to run on them :(
return true;
}
private bool CanChange {
get { return (_keyvalue == null); }
}
private bool UseDefaultKeyContainer {
get { return ((_params.Flags & CspProviderFlags.UseDefaultKeyContainer) == CspProviderFlags.UseDefaultKeyContainer); }
}
private bool UseMachineKeyStore {
get { return ((_params.Flags & CspProviderFlags.UseMachineKeyStore) == CspProviderFlags.UseMachineKeyStore); }
}
private string ContainerName {
get {
if (_container == null) {
if (UseDefaultKeyContainer) {
// easy to spot
_container = "default";
}
else if ((_params.KeyContainerName == null) || (_params.KeyContainerName.Length == 0)) {
_container = Guid.NewGuid ().ToString ();
}
else {
// we don't want to trust the key container name as we don't control it
// anyway some characters may not be compatible with the file system
byte[] data = Encoding.UTF8.GetBytes (_params.KeyContainerName);
// Note: We use MD5 as it is faster than SHA1 and has the same length
// as a GUID. Recent problems found in MD5 (like collisions) aren't a
// problem in this case.
MD5 hash = MD5.Create ();
byte[] result = hash.ComputeHash (data);
_container = new Guid (result).ToString ();
}
}
return _container;
}
}
// we do not want any changes after receiving the csp informations
private CspParameters Copy (CspParameters p)
{
CspParameters copy = new CspParameters (p.ProviderType, p.ProviderName, p.KeyContainerName);
copy.KeyNumber = p.KeyNumber;
copy.Flags = p.Flags;
return copy;
}
private void FromXml (string xml)
{
SecurityParser sp = new SecurityParser ();
sp.LoadXml (xml);
SecurityElement root = sp.ToXml ();
if (root.Tag == "KeyPair") {
//SecurityElement prop = root.SearchForChildByTag ("Properties");
SecurityElement keyv = root.SearchForChildByTag ("KeyValue");
if (keyv.Children.Count > 0)
_keyvalue = keyv.Children [0].ToString ();
// Note: we do not read other stuff because
// it can't be changed after key creation
}
}
private string ToXml ()
{
// note: we do not use SecurityElement here because the
// keypair is a XML string (requiring parsing)
StringBuilder xml = new StringBuilder ();
xml.AppendFormat ("<KeyPair>{0}\t<Properties>{0}\t\t<Provider ", Environment.NewLine);
if ((_params.ProviderName != null) && (_params.ProviderName.Length != 0)) {
xml.AppendFormat ("Name=\"{0}\" ", _params.ProviderName);
}
xml.AppendFormat ("Type=\"{0}\" />{1}\t\t<Container ", _params.ProviderType, Environment.NewLine);
xml.AppendFormat ("Name=\"{0}\" />{1}\t</Properties>{1}\t<KeyValue", this.ContainerName, Environment.NewLine);
if (_params.KeyNumber != -1) {
xml.AppendFormat (" Id=\"{0}\" ", _params.KeyNumber);
}
xml.AppendFormat (">{1}\t\t{0}{1}\t</KeyValue>{1}</KeyPair>{1}", this.KeyValue, Environment.NewLine);
return xml.ToString ();
}
}
}

View File

@@ -0,0 +1,67 @@
//
// MD2.cs - Message Digest 2 Abstract class
//
// Author:
// Sebastien Pouliot (spouliot@motus.com)
//
// (C) 2001-2003 Motus Technologies Inc. (http://www.motus.com)
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Security.Cryptography;
namespace Mono.Security.Cryptography {
#if !INSIDE_CORLIB
public
#endif
abstract class MD2 : HashAlgorithm {
protected MD2 ()
{
// MD2 hash length are 128 bits long
HashSizeValue = 128;
}
public static new MD2 Create ()
{
#if FULL_AOT_RUNTIME
return new MD2Managed ();
#else
// for this to work we must register ourself with CryptoConfig
return Create ("MD2");
#endif
}
public static new MD2 Create (string hashName)
{
object o = CryptoConfig.CreateFromName (hashName);
// in case machine.config isn't configured to use any MD2 implementation
if (o == null) {
o = new MD2Managed ();
}
return (MD2) o;
}
}
}

View File

@@ -0,0 +1,197 @@
//
// MD2Managed.cs - Message Digest 2 Managed Implementation
//
// Author:
// Sebastien Pouliot (sebastien@ximian.com)
//
// (C) 2001-2003 Motus Technologies Inc. (http://www.motus.com)
// Copyright (C) 2004-2005,2010 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
namespace Mono.Security.Cryptography {
// References:
// a. RFC1319: The MD2 Message-Digest Algorithm
// http://www.ietf.org/rfc/rfc1319.txt
#if !INSIDE_CORLIB
public
#endif
class MD2Managed : MD2 {
private byte[] state;
private byte[] checksum;
private byte[] buffer;
private int count;
private byte[] x;
/// <summary>
/// Permutation of 0..255 constructed from the digits of pi. It gives a
/// "random" nonlinear byte substitution operation.
/// </summary>
private static readonly byte[] PI_SUBST = {
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
31, 26, 219, 153, 141, 51, 159, 17, 131, 20 };
private byte[] Padding (int nLength)
{
if (nLength > 0) {
byte[] padding = new byte [nLength];
for (int i = 0; i < padding.Length; i++)
padding[i] = (byte) nLength;
return padding;
}
return null;
}
//--- constructor -----------------------------------------------------------
public MD2Managed () : base ()
{
// we allocate the context memory
state = new byte [16];
checksum = new byte [16];
buffer = new byte [16];
x = new byte [48];
// the initialize our context
Initialize ();
}
public override void Initialize ()
{
count = 0;
Array.Clear (state, 0, 16);
Array.Clear (checksum, 0, 16);
Array.Clear (buffer, 0, 16);
// Zeroize sensitive information
Array.Clear (x, 0, 48);
}
protected override void HashCore (byte[] array, int ibStart, int cbSize)
{
int i;
/* Update number of bytes mod 16 */
int index = count;
count = (int) (index + cbSize) & 0xf;
int partLen = 16 - index;
/* Transform as many times as possible. */
if (cbSize >= partLen) {
// MD2_memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen);
Buffer.BlockCopy (array, ibStart, buffer, index, partLen);
// MD2Transform (context->state, context->checksum, context->buffer);
MD2Transform (state, checksum, buffer, 0);
for (i = partLen; i + 15 < cbSize; i += 16) {
// MD2Transform (context->state, context->checksum, &input[i]);
MD2Transform (state, checksum, array, ibStart + i);
}
index = 0;
}
else
i = 0;
/* Buffer remaining input */
// MD2_memcpy((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
Buffer.BlockCopy (array, ibStart + i, buffer, index, (cbSize - i));
}
protected override byte[] HashFinal ()
{
// Pad out to multiple of 16.
int index = count;
int padLen = 16 - index;
// is padding needed ? required if length not a multiple of 16.
if (padLen > 0)
HashCore (Padding (padLen), 0, padLen);
// Extend with checksum
HashCore (checksum, 0, 16);
// Store state in digest
byte[] digest = (byte[]) state.Clone ();
// Zeroize sensitive information.
Initialize ();
return digest;
}
//--- private methods ---------------------------------------------------
/// <summary>
/// MD2 basic transformation. Transforms state and updates checksum
/// based on block.
/// </summary>
private void MD2Transform (byte[] state, byte[] checksum, byte[] block, int index)
{
/* Form encryption block from state, block, state ^ block. */
// MD2_memcpy ((POINTER)x, (POINTER)state, 16);
Buffer.BlockCopy (state, 0, x, 0, 16);
// MD2_memcpy ((POINTER)x+16, (POINTER)block, 16);
Buffer.BlockCopy (block, index, x, 16, 16);
// for (i = 0; i < 16; i++) x[i+32] = state[i] ^ block[i];
for (int i = 0; i < 16; i++)
x [i+32] = (byte) ((byte) state [i] ^ (byte) block [index + i]);
/* Encrypt block (18 rounds). */
int t = 0;
for (int i = 0; i < 18; i++) {
for (int j = 0; j < 48; j++ )
t = x [j] ^= PI_SUBST [t];
t = (t + i) & 0xff;
}
/* Save new state */
// MD2_memcpy ((POINTER)state, (POINTER)x, 16);
Buffer.BlockCopy (x, 0, state, 0, 16);
/* Update checksum. */
t = checksum [15];
for (int i = 0; i < 16; i++)
t = checksum [i] ^= PI_SUBST [block [index + i] ^ t];
}
}
}

View File

@@ -0,0 +1,68 @@
//
// MD4.cs - Message Digest 4 Abstract class
//
// Author:
// Sebastien Pouliot (sebastien@xamarin.com)
//
// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
// Copyright 2013 Xamarin Inc. (http://www.xamarin.com)
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Security.Cryptography;
namespace Mono.Security.Cryptography {
#if !INSIDE_CORLIB
public
#endif
abstract class MD4 : HashAlgorithm {
protected MD4 ()
{
// MD4 hash length are 128 bits long
HashSizeValue = 128;
}
public static new MD4 Create ()
{
#if FULL_AOT_RUNTIME
return new MD4Managed ();
#else
// for this to work we must register ourself with CryptoConfig
return Create ("MD4");
#endif
}
public static new MD4 Create (string hashName)
{
object o = CryptoConfig.CreateFromName (hashName);
// in case machine.config isn't configured to use any MD4 implementation
if (o == null) {
o = new MD4Managed ();
}
return (MD4) o;
}
}
}

View File

@@ -0,0 +1,284 @@
//
// MD4Managed.cs - Message Digest 4 Managed Implementation
//
// Author:
// Sebastien Pouliot (sebastien@ximian.com)
//
// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
// Copyright (C) 2004-2005,2010 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
namespace Mono.Security.Cryptography {
// References:
// a. RFC1320: The MD4 Message-Digest Algorithm
// http://www.ietf.org/rfc/rfc1320.txt
#if !INSIDE_CORLIB
public
#endif
class MD4Managed : MD4 {
private uint[] state;
private byte[] buffer;
private uint[] count;
private uint[] x;
private const int S11 = 3;
private const int S12 = 7;
private const int S13 = 11;
private const int S14 = 19;
private const int S21 = 3;
private const int S22 = 5;
private const int S23 = 9;
private const int S24 = 13;
private const int S31 = 3;
private const int S32 = 9;
private const int S33 = 11;
private const int S34 = 15;
private byte[] digest;
//--- constructor -----------------------------------------------------------
public MD4Managed ()
{
// we allocate the context memory
state = new uint [4];
count = new uint [2];
buffer = new byte [64];
digest = new byte [16];
// temporary buffer in MD4Transform that we don't want to keep allocate on each iteration
x = new uint [16];
// the initialize our context
Initialize ();
}
public override void Initialize ()
{
count [0] = 0;
count [1] = 0;
state [0] = 0x67452301;
state [1] = 0xefcdab89;
state [2] = 0x98badcfe;
state [3] = 0x10325476;
// Zeroize sensitive information
Array.Clear (buffer, 0, 64);
Array.Clear (x, 0, 16);
}
protected override void HashCore (byte[] array, int ibStart, int cbSize)
{
/* Compute number of bytes mod 64 */
int index = (int) ((count [0] >> 3) & 0x3F);
/* Update number of bits */
count [0] += (uint) (cbSize << 3);
if (count [0] < (cbSize << 3))
count [1]++;
count [1] += (uint) (cbSize >> 29);
int partLen = 64 - index;
int i = 0;
/* Transform as many times as possible. */
if (cbSize >= partLen) {
//MD4_memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen);
Buffer.BlockCopy (array, ibStart, buffer, index, partLen);
MD4Transform (state, buffer, 0);
for (i = partLen; i + 63 < cbSize; i += 64) {
// MD4Transform (context->state, &input[i]);
MD4Transform (state, array, ibStart + i);
}
index = 0;
}
/* Buffer remaining input */
//MD4_memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
Buffer.BlockCopy (array, ibStart + i, buffer, index, (cbSize-i));
}
protected override byte[] HashFinal ()
{
/* Save number of bits */
byte[] bits = new byte [8];
Encode (bits, count);
/* Pad out to 56 mod 64. */
uint index = ((count [0] >> 3) & 0x3f);
int padLen = (int) ((index < 56) ? (56 - index) : (120 - index));
HashCore (Padding (padLen), 0, padLen);
/* Append length (before padding) */
HashCore (bits, 0, 8);
/* Store state in digest */
Encode (digest, state);
// Zeroize sensitive information.
Initialize ();
return digest;
}
//--- private methods ---------------------------------------------------
private byte[] Padding (int nLength)
{
if (nLength > 0) {
byte[] padding = new byte [nLength];
padding [0] = 0x80;
return padding;
}
return null;
}
/* F, G and H are basic MD4 functions. */
private uint F (uint x, uint y, uint z)
{
return (uint) (((x) & (y)) | ((~x) & (z)));
}
private uint G (uint x, uint y, uint z)
{
return (uint) (((x) & (y)) | ((x) & (z)) | ((y) & (z)));
}
private uint H (uint x, uint y, uint z)
{
return (uint) ((x) ^ (y) ^ (z));
}
/* ROTATE_LEFT rotates x left n bits. */
private uint ROL (uint x, byte n)
{
return (uint) (((x) << (n)) | ((x) >> (32-(n))));
}
/* FF, GG and HH are transformations for rounds 1, 2 and 3 */
/* Rotation is separate from addition to prevent recomputation */
private void FF (ref uint a, uint b, uint c, uint d, uint x, byte s)
{
a += F (b, c, d) + x;
a = ROL (a, s);
}
private void GG (ref uint a, uint b, uint c, uint d, uint x, byte s)
{
a += G (b, c, d) + x + 0x5a827999;
a = ROL (a, s);
}
private void HH (ref uint a, uint b, uint c, uint d, uint x, byte s)
{
a += H (b, c, d) + x + 0x6ed9eba1;
a = ROL (a, s);
}
private void Encode (byte[] output, uint[] input)
{
for (int i = 0, j = 0; j < output.Length; i++, j += 4) {
output [j] = (byte)(input [i]);
output [j+1] = (byte)(input [i] >> 8);
output [j+2] = (byte)(input [i] >> 16);
output [j+3] = (byte)(input [i] >> 24);
}
}
private void Decode (uint[] output, byte[] input, int index)
{
for (int i = 0, j = index; i < output.Length; i++, j += 4) {
output [i] = (uint) ((input [j]) | (input [j+1] << 8) | (input [j+2] << 16) | (input [j+3] << 24));
}
}
private void MD4Transform (uint[] state, byte[] block, int index)
{
uint a = state [0];
uint b = state [1];
uint c = state [2];
uint d = state [3];
Decode (x, block, index);
/* Round 1 */
FF (ref a, b, c, d, x[ 0], S11); /* 1 */
FF (ref d, a, b, c, x[ 1], S12); /* 2 */
FF (ref c, d, a, b, x[ 2], S13); /* 3 */
FF (ref b, c, d, a, x[ 3], S14); /* 4 */
FF (ref a, b, c, d, x[ 4], S11); /* 5 */
FF (ref d, a, b, c, x[ 5], S12); /* 6 */
FF (ref c, d, a, b, x[ 6], S13); /* 7 */
FF (ref b, c, d, a, x[ 7], S14); /* 8 */
FF (ref a, b, c, d, x[ 8], S11); /* 9 */
FF (ref d, a, b, c, x[ 9], S12); /* 10 */
FF (ref c, d, a, b, x[10], S13); /* 11 */
FF (ref b, c, d, a, x[11], S14); /* 12 */
FF (ref a, b, c, d, x[12], S11); /* 13 */
FF (ref d, a, b, c, x[13], S12); /* 14 */
FF (ref c, d, a, b, x[14], S13); /* 15 */
FF (ref b, c, d, a, x[15], S14); /* 16 */
/* Round 2 */
GG (ref a, b, c, d, x[ 0], S21); /* 17 */
GG (ref d, a, b, c, x[ 4], S22); /* 18 */
GG (ref c, d, a, b, x[ 8], S23); /* 19 */
GG (ref b, c, d, a, x[12], S24); /* 20 */
GG (ref a, b, c, d, x[ 1], S21); /* 21 */
GG (ref d, a, b, c, x[ 5], S22); /* 22 */
GG (ref c, d, a, b, x[ 9], S23); /* 23 */
GG (ref b, c, d, a, x[13], S24); /* 24 */
GG (ref a, b, c, d, x[ 2], S21); /* 25 */
GG (ref d, a, b, c, x[ 6], S22); /* 26 */
GG (ref c, d, a, b, x[10], S23); /* 27 */
GG (ref b, c, d, a, x[14], S24); /* 28 */
GG (ref a, b, c, d, x[ 3], S21); /* 29 */
GG (ref d, a, b, c, x[ 7], S22); /* 30 */
GG (ref c, d, a, b, x[11], S23); /* 31 */
GG (ref b, c, d, a, x[15], S24); /* 32 */
HH (ref a, b, c, d, x[ 0], S31); /* 33 */
HH (ref d, a, b, c, x[ 8], S32); /* 34 */
HH (ref c, d, a, b, x[ 4], S33); /* 35 */
HH (ref b, c, d, a, x[12], S34); /* 36 */
HH (ref a, b, c, d, x[ 2], S31); /* 37 */
HH (ref d, a, b, c, x[10], S32); /* 38 */
HH (ref c, d, a, b, x[ 6], S33); /* 39 */
HH (ref b, c, d, a, x[14], S34); /* 40 */
HH (ref a, b, c, d, x[ 1], S31); /* 41 */
HH (ref d, a, b, c, x[ 9], S32); /* 42 */
HH (ref c, d, a, b, x[ 5], S33); /* 43 */
HH (ref b, c, d, a, x[13], S34); /* 44 */
HH (ref a, b, c, d, x[ 3], S31); /* 45 */
HH (ref d, a, b, c, x[11], S32); /* 46 */
HH (ref c, d, a, b, x[ 7], S33); /* 47 */
HH (ref b, c, d, a, x[15], S34); /* 48 */
state [0] += a;
state [1] += b;
state [2] += c;
state [3] += d;
}
}
}

View File

@@ -0,0 +1,148 @@
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
/* Transport Security Layer (TLS)
* Copyright (c) 2003-2004 Carlos Guzman Alvarez
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Security.Cryptography;
using Mono.Security.Protocol.Tls;
namespace Mono.Security.Cryptography
{
internal class MD5SHA1 : HashAlgorithm
{
#region Fields
private HashAlgorithm md5;
private HashAlgorithm sha;
private bool hashing;
#endregion
#region Constructors
public MD5SHA1() : base()
{
this.md5 = MD5.Create();
this.sha = SHA1.Create();
// Set HashSizeValue
this.HashSizeValue = this.md5.HashSize + this.sha.HashSize;
}
#endregion
#region Methods
public override void Initialize()
{
this.md5.Initialize();
this.sha.Initialize();
this.hashing = false;
}
protected override byte[] HashFinal()
{
if (!hashing)
{
this.hashing = true;
}
// Finalize the original hash
this.md5.TransformFinalBlock(new byte[0], 0, 0);
this.sha.TransformFinalBlock(new byte[0], 0, 0);
byte[] hash = new byte[36];
Buffer.BlockCopy(this.md5.Hash, 0, hash, 0, 16);
Buffer.BlockCopy(this.sha.Hash, 0, hash, 16, 20);
return hash;
}
protected override void HashCore(
byte[] array,
int ibStart,
int cbSize)
{
if (!hashing)
{
hashing = true;
}
this.md5.TransformBlock(array, ibStart, cbSize, array, ibStart);
this.sha.TransformBlock(array, ibStart, cbSize, array, ibStart);
}
public byte[] CreateSignature(RSA rsa)
{
if (rsa == null)
{
throw new CryptographicUnexpectedOperationException ("missing key");
}
RSASslSignatureFormatter f = new RSASslSignatureFormatter(rsa);
f.SetHashAlgorithm("MD5SHA1");
return f.CreateSignature(this.Hash);
}
public bool VerifySignature(RSA rsa, byte[] rgbSignature)
{
if (rsa == null)
{
throw new CryptographicUnexpectedOperationException ("missing key");
}
if (rgbSignature == null)
{
throw new ArgumentNullException ("rgbSignature");
}
RSASslSignatureDeformatter d = new RSASslSignatureDeformatter(rsa);
d.SetHashAlgorithm("MD5SHA1");
return d.VerifySignature(this.Hash, rgbSignature);
}
#endregion
}
}

View File

@@ -0,0 +1,495 @@
//
// PKCS1.cs - Implements PKCS#1 primitives.
//
// Author:
// Sebastien Pouliot <sebastien@xamarin.com>
//
// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com)
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
// Copyright 2013 Xamarin Inc. (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Security.Cryptography;
namespace Mono.Security.Cryptography {
// References:
// a. PKCS#1: RSA Cryptography Standard
// http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/index.html
#if INSIDE_CORLIB
internal
#else
public
#endif
sealed class PKCS1 {
private PKCS1 ()
{
}
private static bool Compare (byte[] array1, byte[] array2)
{
bool result = (array1.Length == array2.Length);
if (result) {
for (int i=0; i < array1.Length; i++)
if (array1[i] != array2[i])
return false;
}
return result;
}
private static byte[] xor (byte[] array1, byte[] array2)
{
byte[] result = new byte [array1.Length];
for (int i=0; i < result.Length; i++)
result[i] = (byte) (array1[i] ^ array2[i]);
return result;
}
private static byte[] emptySHA1 = { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 };
private static byte[] emptySHA256 = { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 };
private static byte[] emptySHA384 = { 0x38, 0xb0, 0x60, 0xa7, 0x51, 0xac, 0x96, 0x38, 0x4c, 0xd9, 0x32, 0x7e, 0xb1, 0xb1, 0xe3, 0x6a, 0x21, 0xfd, 0xb7, 0x11, 0x14, 0xbe, 0x07, 0x43, 0x4c, 0x0c, 0xc7, 0xbf, 0x63, 0xf6, 0xe1, 0xda, 0x27, 0x4e, 0xde, 0xbf, 0xe7, 0x6f, 0x65, 0xfb, 0xd5, 0x1a, 0xd2, 0xf1, 0x48, 0x98, 0xb9, 0x5b };
private static byte[] emptySHA512 = { 0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07, 0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, 0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce, 0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0, 0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f, 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81, 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e };
private static byte[] GetEmptyHash (HashAlgorithm hash)
{
if (hash is SHA1)
return emptySHA1;
else if (hash is SHA256)
return emptySHA256;
else if (hash is SHA384)
return emptySHA384;
else if (hash is SHA512)
return emptySHA512;
else
return hash.ComputeHash ((byte[])null);
}
// PKCS #1 v.2.1, Section 4.1
// I2OSP converts a non-negative integer to an octet string of a specified length.
public static byte[] I2OSP (int x, int size)
{
byte[] array = BitConverterLE.GetBytes (x);
Array.Reverse (array, 0, array.Length);
return I2OSP (array, size);
}
public static byte[] I2OSP (byte[] x, int size)
{
byte[] result = new byte [size];
Buffer.BlockCopy (x, 0, result, (result.Length - x.Length), x.Length);
return result;
}
// PKCS #1 v.2.1, Section 4.2
// OS2IP converts an octet string to a nonnegative integer.
public static byte[] OS2IP (byte[] x)
{
int i = 0;
while ((x [i++] == 0x00) && (i < x.Length)) {
// confuse compiler into reporting a warning with {}
}
i--;
if (i > 0) {
byte[] result = new byte [x.Length - i];
Buffer.BlockCopy (x, i, result, 0, result.Length);
return result;
}
else
return x;
}
// PKCS #1 v.2.1, Section 5.1.1
public static byte[] RSAEP (RSA rsa, byte[] m)
{
// c = m^e mod n
return rsa.EncryptValue (m);
}
// PKCS #1 v.2.1, Section 5.1.2
public static byte[] RSADP (RSA rsa, byte[] c)
{
// m = c^d mod n
// Decrypt value may apply CRT optimizations
return rsa.DecryptValue (c);
}
// PKCS #1 v.2.1, Section 5.2.1
public static byte[] RSASP1 (RSA rsa, byte[] m)
{
// first form: s = m^d mod n
// Decrypt value may apply CRT optimizations
return rsa.DecryptValue (m);
}
// PKCS #1 v.2.1, Section 5.2.2
public static byte[] RSAVP1 (RSA rsa, byte[] s)
{
// m = s^e mod n
return rsa.EncryptValue (s);
}
// PKCS #1 v.2.1, Section 7.1.1
// RSAES-OAEP-ENCRYPT ((n, e), M, L)
public static byte[] Encrypt_OAEP (RSA rsa, HashAlgorithm hash, RandomNumberGenerator rng, byte[] M)
{
int size = rsa.KeySize / 8;
int hLen = hash.HashSize / 8;
if (M.Length > size - 2 * hLen - 2)
throw new CryptographicException ("message too long");
// empty label L SHA1 hash
byte[] lHash = GetEmptyHash (hash);
int PSLength = (size - M.Length - 2 * hLen - 2);
// DB = lHash || PS || 0x01 || M
byte[] DB = new byte [lHash.Length + PSLength + 1 + M.Length];
Buffer.BlockCopy (lHash, 0, DB, 0, lHash.Length);
DB [(lHash.Length + PSLength)] = 0x01;
Buffer.BlockCopy (M, 0, DB, (DB.Length - M.Length), M.Length);
byte[] seed = new byte [hLen];
rng.GetBytes (seed);
byte[] dbMask = MGF1 (hash, seed, size - hLen - 1);
byte[] maskedDB = xor (DB, dbMask);
byte[] seedMask = MGF1 (hash, maskedDB, hLen);
byte[] maskedSeed = xor (seed, seedMask);
// EM = 0x00 || maskedSeed || maskedDB
byte[] EM = new byte [maskedSeed.Length + maskedDB.Length + 1];
Buffer.BlockCopy (maskedSeed, 0, EM, 1, maskedSeed.Length);
Buffer.BlockCopy (maskedDB, 0, EM, maskedSeed.Length + 1, maskedDB.Length);
byte[] m = OS2IP (EM);
byte[] c = RSAEP (rsa, m);
return I2OSP (c, size);
}
// PKCS #1 v.2.1, Section 7.1.2
// RSAES-OAEP-DECRYPT (K, C, L)
public static byte[] Decrypt_OAEP (RSA rsa, HashAlgorithm hash, byte[] C)
{
int size = rsa.KeySize / 8;
int hLen = hash.HashSize / 8;
if ((size < (2 * hLen + 2)) || (C.Length != size))
throw new CryptographicException ("decryption error");
byte[] c = OS2IP (C);
byte[] m = RSADP (rsa, c);
byte[] EM = I2OSP (m, size);
// split EM = Y || maskedSeed || maskedDB
byte[] maskedSeed = new byte [hLen];
Buffer.BlockCopy (EM, 1, maskedSeed, 0, maskedSeed.Length);
byte[] maskedDB = new byte [size - hLen - 1];
Buffer.BlockCopy (EM, (EM.Length - maskedDB.Length), maskedDB, 0, maskedDB.Length);
byte[] seedMask = MGF1 (hash, maskedDB, hLen);
byte[] seed = xor (maskedSeed, seedMask);
byte[] dbMask = MGF1 (hash, seed, size - hLen - 1);
byte[] DB = xor (maskedDB, dbMask);
byte[] lHash = GetEmptyHash (hash);
// split DB = lHash' || PS || 0x01 || M
byte[] dbHash = new byte [lHash.Length];
Buffer.BlockCopy (DB, 0, dbHash, 0, dbHash.Length);
bool h = Compare (lHash, dbHash);
// find separator 0x01
int nPos = lHash.Length;
while (DB[nPos] == 0)
nPos++;
int Msize = DB.Length - nPos - 1;
byte[] M = new byte [Msize];
Buffer.BlockCopy (DB, (nPos + 1), M, 0, Msize);
// we could have returned EM[0] sooner but would be helping a timing attack
if ((EM[0] != 0) || (!h) || (DB[nPos] != 0x01))
return null;
return M;
}
// PKCS #1 v.2.1, Section 7.2.1
// RSAES-PKCS1-V1_5-ENCRYPT ((n, e), M)
public static byte[] Encrypt_v15 (RSA rsa, RandomNumberGenerator rng, byte[] M)
{
int size = rsa.KeySize / 8;
if (M.Length > size - 11)
throw new CryptographicException ("message too long");
int PSLength = System.Math.Max (8, (size - M.Length - 3));
byte[] PS = new byte [PSLength];
rng.GetNonZeroBytes (PS);
byte[] EM = new byte [size];
EM [1] = 0x02;
Buffer.BlockCopy (PS, 0, EM, 2, PSLength);
Buffer.BlockCopy (M, 0, EM, (size - M.Length), M.Length);
byte[] m = OS2IP (EM);
byte[] c = RSAEP (rsa, m);
byte[] C = I2OSP (c, size);
return C;
}
// PKCS #1 v.2.1, Section 7.2.2
// RSAES-PKCS1-V1_5-DECRYPT (K, C)
public static byte[] Decrypt_v15 (RSA rsa, byte[] C)
{
int size = rsa.KeySize >> 3; // div by 8
if ((size < 11) || (C.Length > size))
throw new CryptographicException ("decryption error");
byte[] c = OS2IP (C);
byte[] m = RSADP (rsa, c);
byte[] EM = I2OSP (m, size);
if ((EM [0] != 0x00) || (EM [1] != 0x02))
return null;
int mPos = 10;
// PS is a minimum of 8 bytes + 2 bytes for header
while ((EM [mPos] != 0x00) && (mPos < EM.Length))
mPos++;
if (EM [mPos] != 0x00)
return null;
mPos++;
byte[] M = new byte [EM.Length - mPos];
Buffer.BlockCopy (EM, mPos, M, 0, M.Length);
return M;
}
// PKCS #1 v.2.1, Section 8.2.1
// RSASSA-PKCS1-V1_5-SIGN (K, M)
public static byte[] Sign_v15 (RSA rsa, HashAlgorithm hash, byte[] hashValue)
{
int size = (rsa.KeySize >> 3); // div 8
byte[] EM = Encode_v15 (hash, hashValue, size);
byte[] m = OS2IP (EM);
byte[] s = RSASP1 (rsa, m);
byte[] S = I2OSP (s, size);
return S;
}
internal static byte[] Sign_v15 (RSA rsa, string hashName, byte[] hashValue)
{
using (var hash = CreateFromName (hashName))
return Sign_v15 (rsa, hash, hashValue);
}
// PKCS #1 v.2.1, Section 8.2.2
// RSASSA-PKCS1-V1_5-VERIFY ((n, e), M, S)
public static bool Verify_v15 (RSA rsa, HashAlgorithm hash, byte[] hashValue, byte[] signature)
{
return Verify_v15 (rsa, hash, hashValue, signature, false);
}
internal static bool Verify_v15 (RSA rsa, string hashName, byte[] hashValue, byte[] signature)
{
using (var hash = CreateFromName (hashName))
return Verify_v15 (rsa, hash, hashValue, signature, false);
}
// DO NOT USE WITHOUT A VERY GOOD REASON
public static bool Verify_v15 (RSA rsa, HashAlgorithm hash, byte [] hashValue, byte [] signature, bool tryNonStandardEncoding)
{
int size = (rsa.KeySize >> 3); // div 8
byte[] s = OS2IP (signature);
byte[] m = RSAVP1 (rsa, s);
byte[] EM2 = I2OSP (m, size);
byte[] EM = Encode_v15 (hash, hashValue, size);
bool result = Compare (EM, EM2);
if (result || !tryNonStandardEncoding)
return result;
// NOTE: some signatures don't include the hash OID (pretty lame but real)
// and compatible with MS implementation. E.g. Verisign Authenticode Timestamps
// we're making this "as safe as possible"
if ((EM2 [0] != 0x00) || (EM2 [1] != 0x01))
return false;
int i;
for (i = 2; i < EM2.Length - hashValue.Length - 1; i++) {
if (EM2 [i] != 0xFF)
return false;
}
if (EM2 [i++] != 0x00)
return false;
byte [] decryptedHash = new byte [hashValue.Length];
Buffer.BlockCopy (EM2, i, decryptedHash, 0, decryptedHash.Length);
return Compare (decryptedHash, hashValue);
}
// PKCS #1 v.2.1, Section 9.2
// EMSA-PKCS1-v1_5-Encode
public static byte[] Encode_v15 (HashAlgorithm hash, byte[] hashValue, int emLength)
{
if (hashValue.Length != (hash.HashSize >> 3))
throw new CryptographicException ("bad hash length for " + hash.ToString ());
// DigestInfo ::= SEQUENCE {
// digestAlgorithm AlgorithmIdentifier,
// digest OCTET STRING
// }
byte[] t = null;
string oid = CryptoConfig.MapNameToOID (hash.ToString ());
if (oid != null)
{
ASN1 digestAlgorithm = new ASN1 (0x30);
digestAlgorithm.Add (new ASN1 (CryptoConfig.EncodeOID (oid)));
digestAlgorithm.Add (new ASN1 (0x05)); // NULL
ASN1 digest = new ASN1 (0x04, hashValue);
ASN1 digestInfo = new ASN1 (0x30);
digestInfo.Add (digestAlgorithm);
digestInfo.Add (digest);
t = digestInfo.GetBytes ();
}
else
{
// There are no valid OID, in this case t = hashValue
// This is the case of the MD5SHA hash algorithm
t = hashValue;
}
Buffer.BlockCopy (hashValue, 0, t, t.Length - hashValue.Length, hashValue.Length);
int PSLength = System.Math.Max (8, emLength - t.Length - 3);
// PS = PSLength of 0xff
// EM = 0x00 | 0x01 | PS | 0x00 | T
byte[] EM = new byte [PSLength + t.Length + 3];
EM [1] = 0x01;
for (int i=2; i < PSLength + 2; i++)
EM[i] = 0xff;
Buffer.BlockCopy (t, 0, EM, PSLength + 3, t.Length);
return EM;
}
// PKCS #1 v.2.1, Section B.2.1
public static byte[] MGF1 (HashAlgorithm hash, byte[] mgfSeed, int maskLen)
{
// 1. If maskLen > 2^32 hLen, output "mask too long" and stop.
// easy - this is impossible by using a int (31bits) as parameter ;-)
// BUT with a signed int we do have to check for negative values!
if (maskLen < 0)
throw new OverflowException();
int mgfSeedLength = mgfSeed.Length;
int hLen = (hash.HashSize >> 3); // from bits to bytes
int iterations = (maskLen / hLen);
if (maskLen % hLen != 0)
iterations++;
// 2. Let T be the empty octet string.
byte[] T = new byte [iterations * hLen];
byte[] toBeHashed = new byte [mgfSeedLength + 4];
int pos = 0;
// 3. For counter from 0 to \ceil (maskLen / hLen) - 1, do the following:
for (int counter = 0; counter < iterations; counter++) {
// a. Convert counter to an octet string C of length 4 octets
byte[] C = I2OSP (counter, 4);
// b. Concatenate the hash of the seed mgfSeed and C to the octet string T:
// T = T || Hash (mgfSeed || C)
Buffer.BlockCopy (mgfSeed, 0, toBeHashed, 0, mgfSeedLength);
Buffer.BlockCopy (C, 0, toBeHashed, mgfSeedLength, 4);
byte[] output = hash.ComputeHash (toBeHashed);
Buffer.BlockCopy (output, 0, T, pos, hLen);
pos += hLen;
}
// 4. Output the leading maskLen octets of T as the octet string mask.
byte[] mask = new byte [maskLen];
Buffer.BlockCopy (T, 0, mask, 0, maskLen);
return mask;
}
static internal string HashNameFromOid (string oid, bool throwOnError = true)
{
switch (oid) {
case "1.2.840.113549.1.1.2": // MD2 with RSA encryption
return "MD2";
case "1.2.840.113549.1.1.3": // MD4 with RSA encryption
return "MD4";
case "1.2.840.113549.1.1.4": // MD5 with RSA encryption
return "MD5";
case "1.2.840.113549.1.1.5": // SHA-1 with RSA Encryption
case "1.3.14.3.2.29": // SHA1 with RSA signature
case "1.2.840.10040.4.3": // SHA1-1 with DSA
return "SHA1";
case "1.2.840.113549.1.1.11": // SHA-256 with RSA Encryption
return "SHA256";
case "1.2.840.113549.1.1.12": // SHA-384 with RSA Encryption
return "SHA384";
case "1.2.840.113549.1.1.13": // SHA-512 with RSA Encryption
return "SHA512";
case "1.3.36.3.3.1.2":
return "RIPEMD160";
default:
if (throwOnError)
throw new CryptographicException ("Unsupported hash algorithm: " + oid);
return null;
}
}
static internal HashAlgorithm CreateFromOid (string oid)
{
return CreateFromName (HashNameFromOid (oid));
}
static internal HashAlgorithm CreateFromName (string name)
{
#if FULL_AOT_RUNTIME
switch (name) {
case "MD2":
return MD2.Create ();
case "MD4":
return MD4.Create ();
case "MD5":
return MD5.Create ();
case "SHA1":
return SHA1.Create ();
case "SHA256":
return SHA256.Create ();
case "SHA384":
return SHA384.Create ();
case "SHA512":
return SHA512.Create ();
case "RIPEMD160":
return RIPEMD160.Create ();
default:
try {
return (HashAlgorithm) Activator.CreateInstance (Type.GetType (name));
}
catch {
throw new CryptographicException ("Unsupported hash algorithm: " + name);
}
}
#else
return HashAlgorithm.Create (name);
#endif
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,87 @@
//
// RC4.cs: RC4(tm) symmetric stream cipher
// RC4 is a trademark of RSA Security
//
// Author:
// Sebastien Pouliot (sebastien@xamarin.com)
//
// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
// Copyright 2013 Xamarin Inc. (http://www.xamarin.com)
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Security.Cryptography;
namespace Mono.Security.Cryptography {
#if !INSIDE_CORLIB
public
#endif
abstract class RC4 : SymmetricAlgorithm {
private static KeySizes[] s_legalBlockSizes = {
new KeySizes (64, 64, 0)
};
private static KeySizes[] s_legalKeySizes = {
new KeySizes (40, 2048, 8)
};
public RC4()
{
KeySizeValue = 128;
BlockSizeValue = 64;
FeedbackSizeValue = BlockSizeValue;
LegalBlockSizesValue = s_legalBlockSizes;
LegalKeySizesValue = s_legalKeySizes;
}
// required for compatibility with .NET 2.0
public override byte[] IV {
get { return new byte [0]; }
set { ; }
}
new static public RC4 Create()
{
#if FULL_AOT_RUNTIME
return new ARC4Managed ();
#else
return Create ("RC4");
#endif
}
new static public RC4 Create (string algName)
{
object o = CryptoConfig.CreateFromName (algName);
// in case machine.config isn't configured to use
// any RC4 implementation
if (o == null) {
o = new ARC4Managed ();
}
return (RC4) o;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,89 @@
//
// Mono.Security.Cryptography SHA224 Class implementation
//
// Authors:
// Sebastien Pouliot <sebastien@ximian.com>
//
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System.Security.Cryptography;
namespace Mono.Security.Cryptography {
// FIXME: Remove when (or if) SHA224 moves into corlib
// (as corlib already have the required constants).
internal sealed class SHAConstants {
private SHAConstants ()
{
// Never instantiated.
}
// SHA-224/256 Constants
// Represent the first 32 bits of the fractional parts of the
// cube roots of the first sixty-four prime numbers
public readonly static uint[] K1 = {
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 abstract class SHA224 : HashAlgorithm {
public SHA224 ()
{
// SHA-224 hash length are 224 bits long
HashSizeValue = 224;
}
public static new SHA224 Create ()
{
// for this to work we must register ourself with CryptoConfig
return Create ("SHA224");
}
public static new SHA224 Create (string hashName)
{
object o = CryptoConfig.CreateFromName (hashName);
// in case machine.config isn't configured to use any SHA224 implementation
if (o == null) {
o = new SHA224Managed ();
}
return (SHA224) o;
}
}
}

View File

@@ -0,0 +1,258 @@
//
// Mono.Security.Cryptography SHA224 class implementation
// based on SHA256Managed class implementation (mscorlib.dll)
//
// Authors:
// Matthew S. Ford (Matthew.S.Ford@Rose-Hulman.Edu)
// Sebastien Pouliot <sebastien@ximian.com>
//
// (C) 2001
// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System.Security.Cryptography;
namespace Mono.Security.Cryptography {
public class SHA224Managed : SHA224 {
private const int BLOCK_SIZE_BYTES = 64;
private uint[] _H;
private ulong count;
private byte[] _ProcessingBuffer; // Used to start data when passed less than a block worth.
private int _ProcessingBufferCount; // Counts how much data we have stored that still needs processed.
private uint[] buff;
public SHA224Managed ()
{
_H = new uint [8];
_ProcessingBuffer = new byte [BLOCK_SIZE_BYTES];
buff = new uint[64];
Initialize ();
}
private uint Ch (uint u, uint v, uint w)
{
return (u&v) ^ (~u&w);
}
private uint Maj (uint u, uint v, uint w)
{
return (u&v) ^ (u&w) ^ (v&w);
}
private uint Ro0 (uint x)
{
return ((x >> 7) | (x << 25))
^ ((x >> 18) | (x << 14))
^ (x >> 3);
}
private uint Ro1 (uint x)
{
return ((x >> 17) | (x << 15))
^ ((x >> 19) | (x << 13))
^ (x >> 10);
}
private uint Sig0 (uint x)
{
return ((x >> 2) | (x << 30))
^ ((x >> 13) | (x << 19))
^ ((x >> 22) | (x << 10));
}
private uint Sig1 (uint x)
{
return ((x >> 6) | (x << 26))
^ ((x >> 11) | (x << 21))
^ ((x >> 25) | (x << 7));
}
protected override void HashCore (byte[] rgb, int start, int size)
{
int i;
State = 1;
if (_ProcessingBufferCount != 0) {
if (size < (BLOCK_SIZE_BYTES - _ProcessingBufferCount)) {
System.Buffer.BlockCopy (rgb, start, _ProcessingBuffer, _ProcessingBufferCount, size);
_ProcessingBufferCount += size;
return;
}
else {
i = (BLOCK_SIZE_BYTES - _ProcessingBufferCount);
System.Buffer.BlockCopy (rgb, start, _ProcessingBuffer, _ProcessingBufferCount, i);
ProcessBlock (_ProcessingBuffer, 0);
_ProcessingBufferCount = 0;
start += i;
size -= i;
}
}
for (i=0; i<size-size%BLOCK_SIZE_BYTES; i += BLOCK_SIZE_BYTES) {
ProcessBlock (rgb, start+i);
}
if (size%BLOCK_SIZE_BYTES != 0) {
System.Buffer.BlockCopy (rgb, size-size%BLOCK_SIZE_BYTES+start, _ProcessingBuffer, 0, size%BLOCK_SIZE_BYTES);
_ProcessingBufferCount = size%BLOCK_SIZE_BYTES;
}
}
protected override byte[] HashFinal ()
{
byte[] hash = new byte[28];
int i, j;
ProcessFinalBlock (_ProcessingBuffer, 0, _ProcessingBufferCount);
for (i=0; i<7; i++) {
for (j=0; j<4; j++) {
hash[i*4+j] = (byte)(_H[i] >> (24-j*8));
}
}
State = 0;
return hash;
}
public override void Initialize ()
{
count = 0;
_ProcessingBufferCount = 0;
_H[0] = 0xC1059ED8;
_H[1] = 0x367CD507;
_H[2] = 0x3070DD17;
_H[3] = 0xF70E5939;
_H[4] = 0xFFC00B31;
_H[5] = 0x68581511;
_H[6] = 0x64F98FA7;
_H[7] = 0xBEFA4FA4;
}
private void ProcessBlock (byte[] inputBuffer, int inputOffset)
{
uint a, b, c, d, e, f, g, h;
uint t1, t2;
int i;
uint[] K1 = SHAConstants.K1;
uint[] buff = this.buff;
count += BLOCK_SIZE_BYTES;
for (i=0; i<16; i++) {
buff[i] = (uint)(((inputBuffer[inputOffset+4*i]) << 24)
| ((inputBuffer[inputOffset+4*i+1]) << 16)
| ((inputBuffer[inputOffset+4*i+2]) << 8)
| ((inputBuffer[inputOffset+4*i+3])));
}
for (i=16; i<64; i++) {
t1 = buff[i - 15];
t1 = (((t1 >> 7) | (t1 << 25)) ^ ((t1 >> 18) | (t1 << 14)) ^ (t1 >> 3));
t2 = buff[i - 2];
t2 = (((t2 >> 17) | (t2 << 15)) ^ ((t2 >> 19) | (t2 << 13)) ^ (t2 >> 10));
buff[i] = t2 + buff[i - 7] + t1 + buff[i - 16];
}
a = _H[0];
b = _H[1];
c = _H[2];
d = _H[3];
e = _H[4];
f = _H[5];
g = _H[6];
h = _H[7];
for (i=0; i<64; i++) {
t1 = h + (((e >> 6) | (e << 26)) ^ ((e >> 11) | (e << 21)) ^ ((e >> 25) | (e << 7))) + ((e & f) ^ (~e & g)) + K1[i] + buff[i];
t2 = (((a >> 2) | (a << 30)) ^ ((a >> 13) | (a << 19)) ^ ((a >> 22) | (a << 10)));
t2 = t2 + ((a & b) ^ (a & c) ^ (b & c));
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
_H[0] += a;
_H[1] += b;
_H[2] += c;
_H[3] += d;
_H[4] += e;
_H[5] += f;
_H[6] += g;
_H[7] += h;
}
private void ProcessFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
{
ulong total = count + (ulong)inputCount;
int paddingSize = (56 - (int)(total % BLOCK_SIZE_BYTES));
if (paddingSize < 1)
paddingSize += BLOCK_SIZE_BYTES;
byte[] fooBuffer = new byte[inputCount+paddingSize+8];
for (int i=0; i<inputCount; i++) {
fooBuffer[i] = inputBuffer[i+inputOffset];
}
fooBuffer[inputCount] = 0x80;
for (int i=inputCount+1; i<inputCount+paddingSize; i++) {
fooBuffer[i] = 0x00;
}
// I deal in bytes. The algorithm deals in bits.
ulong size = total << 3;
AddLength (size, fooBuffer, inputCount+paddingSize);
ProcessBlock (fooBuffer, 0);
if (inputCount+paddingSize+8 == 128) {
ProcessBlock(fooBuffer, 64);
}
}
internal void AddLength (ulong length, byte[] buffer, int position)
{
buffer [position++] = (byte)(length >> 56);
buffer [position++] = (byte)(length >> 48);
buffer [position++] = (byte)(length >> 40);
buffer [position++] = (byte)(length >> 32);
buffer [position++] = (byte)(length >> 24);
buffer [position++] = (byte)(length >> 16);
buffer [position++] = (byte)(length >> 8);
buffer [position] = (byte)(length);
}
}
}

Some files were not shown because too many files have changed in this diff Show More