mirror of
https://github.com/raphaeIl/Novaria.git
synced 2025-12-12 22:44:35 +01:00
fix dh (by plagiarism), refactor pcapparser
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Mono.Math;
|
||||
using Mono.Security.Cryptography;
|
||||
using NSec.Cryptography;
|
||||
using Org.BouncyCastle.Crypto.Engines;
|
||||
using Org.BouncyCastle.Crypto.Modes;
|
||||
@@ -24,7 +26,7 @@ namespace Novaria.Common.Crypto
|
||||
public static readonly int IVSize = 16;
|
||||
|
||||
public static byte[] PS_REQUEST_NONCE = new byte[12]; // hardcoded nonce, probably makes it easier for server idk? could also just randomly generate but me lazy
|
||||
public static byte[] PS_PUBLIC_KEY { get => DiffieHellman.Instance.ServerPublicKey.ToByteArray(); }
|
||||
//public static byte[] PS_PUBLIC_KEY { get => DiffieHellman.Instance.ServerPublicKey.GetBytes(); }
|
||||
public static string TOKEN = "seggs"; // hardcoded for now
|
||||
|
||||
public static readonly byte[] DEFAULT_SERVERLIST_KEY = new byte[] { 74, 72, 42, 67, 80, 51, 50, 57, 89, 120, 111, 103, 81, 74, 69, 120 };
|
||||
@@ -34,8 +36,9 @@ namespace Novaria.Common.Crypto
|
||||
|
||||
public static readonly byte[] IKE_KEY = Encoding.ASCII.GetBytes("3LS9&oYdsp^5wi8&ZxC#c7MZg73hbEDw");
|
||||
|
||||
private static DiffieHellmanManaged SendKey;
|
||||
private static BigInteger p = BigInteger.Parse("1552518092300708935130918131258481755631334049434514313202351194902966239949102107258669453876591642442910007680288864229150803718918046342632727613031282983744380820890196288509170691316593175367469551763119843371637221007210577919");
|
||||
private static GcmBlockCipher cipher;
|
||||
|
||||
private static AesEngine engine;
|
||||
|
||||
public delegate void AeadEncryptHandler(Span<byte> result, ReadOnlySpan<byte> key, ReadOnlySpan<byte> nonce, ReadOnlySpan<byte> data, bool needAssociatedData);
|
||||
@@ -57,6 +60,25 @@ namespace Novaria.Common.Crypto
|
||||
PS_REQUEST_NONCE[11] = 42;
|
||||
|
||||
InitAeadTool();
|
||||
InitDH();
|
||||
}
|
||||
|
||||
private static int InitDH()
|
||||
{
|
||||
int nRandom = 1;
|
||||
byte[] bytes = BitConverter.GetBytes(2);
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
Array.Reverse<byte>(bytes);
|
||||
}
|
||||
byte[] bytes2 = BitConverter.GetBytes(nRandom);
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
Array.Reverse<byte>(bytes2);
|
||||
}
|
||||
|
||||
SendKey = new DiffieHellmanManaged(p.GetBytes(), bytes, bytes2);
|
||||
return nRandom;
|
||||
}
|
||||
|
||||
public static void InitAeadTool()
|
||||
@@ -84,6 +106,24 @@ namespace Novaria.Common.Crypto
|
||||
AeadTool.cipher = new GcmBlockCipher(AeadTool.engine);
|
||||
}
|
||||
|
||||
public static void SetAeadKey(byte[] pubKey)
|
||||
{
|
||||
byte[] array = SendKey.DecryptKeyExchange(pubKey);
|
||||
|
||||
int num = array.Length;
|
||||
if (num > 32)
|
||||
{
|
||||
num = 32;
|
||||
}
|
||||
key3 = new byte[32];
|
||||
Buffer.BlockCopy(array, 0, key3, 0, num);
|
||||
}
|
||||
|
||||
public static byte[] GetPubKey()
|
||||
{
|
||||
return new BigInteger(SendKey.CreateKeyExchange()).GetBytes();
|
||||
}
|
||||
|
||||
private static void Encrypt_AESGCM_BouncyCastle(Span<byte> result, ReadOnlySpan<byte> key, ReadOnlySpan<byte> nonce, ReadOnlySpan<byte> data, bool needAssociatedData)
|
||||
{
|
||||
if (!needAssociatedData)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using Novaria.Common.Util;
|
||||
using System.Numerics;
|
||||
using Mono.Math;
|
||||
using Novaria.Common.Util;
|
||||
|
||||
namespace Novaria.Common.Crypto
|
||||
{
|
||||
public class DiffieHellman : Singleton<DiffieHellman>
|
||||
{
|
||||
private BigInteger p = BigInteger.Parse("1552518092300708935130918131258481755631334049434514313202351194902966239949102107258669453876591642442910007680288864229150803718918046342632727613031282983744380820890196288509170691316593175367469551763119843371637221007210577919");
|
||||
private System.Numerics.BigInteger old_p = System.Numerics.BigInteger.Parse("1552518092300708935130918131258481755631334049434514313202351194902966239949102107258669453876591642442910007680288864229150803718918046342632727613031282983744380820890196288509170691316593175367469551763119843371637221007210577919");
|
||||
|
||||
private BigInteger g = 2;
|
||||
|
||||
@@ -15,37 +15,49 @@ namespace Novaria.Common.Crypto
|
||||
|
||||
public DiffieHellman()
|
||||
{
|
||||
Console.WriteLine(spriv);
|
||||
//Console.WriteLine(spriv);
|
||||
//g** Spriv mod p
|
||||
ServerPublicKey = BigInteger.ModPow(g, spriv, p);
|
||||
//ServerPublicKey = this.g.ModPow(spriv, p);
|
||||
}
|
||||
|
||||
public byte[] CalculateKey(byte[] clientPubKey) // server calculates key like this
|
||||
{
|
||||
BigInteger clientPubKeyInt = new BigInteger(clientPubKey.Reverse().ToArray());
|
||||
|
||||
//Cpub**Spriv mod p
|
||||
Console.WriteLine(clientPubKeyInt.ToString());
|
||||
|
||||
var result = BigInteger.ModPow(clientPubKeyInt, spriv, p);
|
||||
// old stuff
|
||||
//System.Numerics.BigInteger clientPubKeyInt = new System.Numerics.BigInteger(clientPubKey.Reverse().ToArray());
|
||||
//var result = System.Numerics.BigInteger.ModPow(clientPubKeyInt, new System.Numerics.BigInteger(new byte[] { 1, 2, 3, 4 }), old_p);
|
||||
|
||||
//Console.WriteLine(result);
|
||||
//if (result < 0)
|
||||
//{
|
||||
// return result.ToByteArray(false, true)[..32];
|
||||
// Console.WriteLine("THIS SHOULD CRASH");
|
||||
//}
|
||||
|
||||
return result.ToByteArray(true, true)[..32];
|
||||
}
|
||||
|
||||
// this is for manual pcap parsing use only, officalServerPubKey is in the first IKE response, client priv will be in frida
|
||||
public byte[] CalculateKey(byte[] officalServerPubKey, byte[] officialClientPriv)
|
||||
{
|
||||
BigInteger officalServerPubKeyInt = new BigInteger(officalServerPubKey.Reverse().ToArray());
|
||||
BigInteger officialClientPrivInt = new BigInteger(officialClientPriv.Reverse().ToArray());
|
||||
//BigInteger bigInteger = new BigInteger(clientPubKey.Reverse().ToArray()).ModPow(this.spriv, this.p);
|
||||
|
||||
BigInteger result = BigInteger.ModPow(officalServerPubKeyInt, officialClientPrivInt, p);
|
||||
//return bigInteger.GetBytes()[..32];
|
||||
return null;
|
||||
//BigInteger clientPubKeyInt = new BigInteger(clientPubKey.Reverse().ToArray());
|
||||
|
||||
return result.ToByteArray(true, true)[..32];
|
||||
////Cpub**Spriv mod p
|
||||
//Console.WriteLine(clientPubKeyInt.ToString());
|
||||
|
||||
//var result = BigInteger.ModPow(clientPubKeyInt, spriv, p);
|
||||
|
||||
//Console.WriteLine("------------test-------------------");
|
||||
|
||||
////Utils.PrintByteArray(BigInteger.Abs());
|
||||
////if (result < 0)
|
||||
////{
|
||||
//// return result.ToByteArray(false, true)[..32];
|
||||
////}
|
||||
|
||||
//Utils.PrintByteArray(result.ToByteArray(true, true));
|
||||
|
||||
//Console.WriteLine("----------------------------------");
|
||||
|
||||
//return result.GetBytes()[..32];
|
||||
//return result.ToByteArray(true, true)[..32];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// Mono.Math.Prime.Generator.NextPrimeFinder.cs - Prime Generator
|
||||
//
|
||||
// Authors:
|
||||
// Ben Maurer
|
||||
//
|
||||
// Copyright (c) 2003 Ben Maurer. All rights reserved
|
||||
//
|
||||
|
||||
//
|
||||
// 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.Math.Prime.Generator {
|
||||
|
||||
/// <summary>
|
||||
/// Finds the next prime after a given number.
|
||||
/// </summary>
|
||||
#if INSIDE_CORLIB
|
||||
internal
|
||||
#else
|
||||
public
|
||||
#endif
|
||||
class NextPrimeFinder : SequentialSearchPrimeGeneratorBase {
|
||||
|
||||
protected override BigInteger GenerateSearchBase (int bits, object Context)
|
||||
{
|
||||
if (Context == null)
|
||||
throw new ArgumentNullException ("Context");
|
||||
|
||||
BigInteger ret = new BigInteger ((BigInteger)Context);
|
||||
ret.SetBit (0);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// Mono.Math.Prime.Generator.PrimeGeneratorBase.cs - Abstract Prime Generator
|
||||
//
|
||||
// Authors:
|
||||
// Ben Maurer
|
||||
//
|
||||
// Copyright (c) 2003 Ben Maurer. All rights reserved
|
||||
//
|
||||
|
||||
//
|
||||
// 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.Math.Prime.Generator {
|
||||
|
||||
#if INSIDE_CORLIB
|
||||
internal
|
||||
#else
|
||||
public
|
||||
#endif
|
||||
abstract class PrimeGeneratorBase {
|
||||
|
||||
public virtual ConfidenceFactor Confidence {
|
||||
get {
|
||||
#if DEBUG
|
||||
return ConfidenceFactor.ExtraLow;
|
||||
#else
|
||||
return ConfidenceFactor.Medium;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public virtual Prime.PrimalityTest PrimalityTest {
|
||||
get {
|
||||
return new Prime.PrimalityTest (PrimalityTests.RabinMillerTest);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual int TrialDivisionBounds {
|
||||
get { return 4000; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs primality tests on bi, assumes trial division has been done.
|
||||
/// </summary>
|
||||
/// <param name="bi">A BigInteger that has been subjected to and passed trial division</param>
|
||||
/// <returns>False if bi is composite, true if it may be prime.</returns>
|
||||
/// <remarks>The speed of this method is dependent on Confidence</remarks>
|
||||
protected bool PostTrialDivisionTests (BigInteger bi)
|
||||
{
|
||||
return PrimalityTest (bi, this.Confidence);
|
||||
}
|
||||
|
||||
public abstract BigInteger GenerateNewPrime (int bits);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
//
|
||||
// Mono.Math.Prime.Generator.SequentialSearchPrimeGeneratorBase.cs - Prime Generator
|
||||
//
|
||||
// Authors:
|
||||
// Ben Maurer
|
||||
//
|
||||
// Copyright (c) 2003 Ben Maurer. All rights reserved
|
||||
// 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.
|
||||
//
|
||||
|
||||
namespace Mono.Math.Prime.Generator {
|
||||
|
||||
#if INSIDE_CORLIB
|
||||
internal
|
||||
#else
|
||||
public
|
||||
#endif
|
||||
class SequentialSearchPrimeGeneratorBase : PrimeGeneratorBase {
|
||||
|
||||
protected virtual BigInteger GenerateSearchBase (int bits, object context)
|
||||
{
|
||||
BigInteger ret = BigInteger.GenerateRandom (bits);
|
||||
ret.SetBit (0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
public override BigInteger GenerateNewPrime (int bits)
|
||||
{
|
||||
return GenerateNewPrime (bits, null);
|
||||
}
|
||||
|
||||
|
||||
public virtual BigInteger GenerateNewPrime (int bits, object context)
|
||||
{
|
||||
//
|
||||
// STEP 1. Find a place to do a sequential search
|
||||
//
|
||||
BigInteger curVal = GenerateSearchBase (bits, context);
|
||||
|
||||
const uint primeProd1 = 3u* 5u * 7u * 11u * 13u * 17u * 19u * 23u * 29u;
|
||||
|
||||
uint pMod1 = curVal % primeProd1;
|
||||
|
||||
int DivisionBound = TrialDivisionBounds;
|
||||
uint[] SmallPrimes = BigInteger.smallPrimes;
|
||||
//
|
||||
// STEP 2. Search for primes
|
||||
//
|
||||
while (true) {
|
||||
|
||||
//
|
||||
// STEP 2.1 Sieve out numbers divisible by the first 9 primes
|
||||
//
|
||||
if (pMod1 % 3 == 0) goto biNotPrime;
|
||||
if (pMod1 % 5 == 0) goto biNotPrime;
|
||||
if (pMod1 % 7 == 0) goto biNotPrime;
|
||||
if (pMod1 % 11 == 0) goto biNotPrime;
|
||||
if (pMod1 % 13 == 0) goto biNotPrime;
|
||||
if (pMod1 % 17 == 0) goto biNotPrime;
|
||||
if (pMod1 % 19 == 0) goto biNotPrime;
|
||||
if (pMod1 % 23 == 0) goto biNotPrime;
|
||||
if (pMod1 % 29 == 0) goto biNotPrime;
|
||||
|
||||
//
|
||||
// STEP 2.2 Sieve out all numbers divisible by the primes <= DivisionBound
|
||||
//
|
||||
for (int p = 10; p < SmallPrimes.Length && SmallPrimes [p] <= DivisionBound; p++) {
|
||||
if (curVal % SmallPrimes [p] == 0)
|
||||
goto biNotPrime;
|
||||
}
|
||||
|
||||
//
|
||||
// STEP 2.3 Is the potential prime acceptable?
|
||||
//
|
||||
if (!IsPrimeAcceptable (curVal, context))
|
||||
goto biNotPrime;
|
||||
|
||||
//
|
||||
// STEP 2.4 Filter out all primes that pass this step with a primality test
|
||||
//
|
||||
if (PrimalityTest (curVal, Confidence))
|
||||
return curVal;
|
||||
|
||||
//
|
||||
// STEP 2.4
|
||||
//
|
||||
biNotPrime:
|
||||
pMod1 += 2;
|
||||
if (pMod1 >= primeProd1)
|
||||
pMod1 -= primeProd1;
|
||||
curVal.Incr2 ();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual bool IsPrimeAcceptable (BigInteger bi, object context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
68
Novaria.Common/Mono/Mono.Math.Prime/ConfidenceFactor.cs
Normal file
68
Novaria.Common/Mono/Mono.Math.Prime/ConfidenceFactor.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// Mono.Math.Prime.ConfidenceFactor.cs - Confidence factor for prime generation
|
||||
//
|
||||
// Authors:
|
||||
// Ben Maurer
|
||||
//
|
||||
// Copyright (c) 2003 Ben Maurer. All rights reserved
|
||||
//
|
||||
|
||||
//
|
||||
// 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.Math.Prime {
|
||||
/// <summary>
|
||||
/// A factor of confidence.
|
||||
/// </summary>
|
||||
#if INSIDE_CORLIB
|
||||
internal
|
||||
#else
|
||||
public
|
||||
#endif
|
||||
enum ConfidenceFactor {
|
||||
/// <summary>
|
||||
/// Only suitable for development use, probability of failure may be greater than 1/2^20.
|
||||
/// </summary>
|
||||
ExtraLow,
|
||||
/// <summary>
|
||||
/// Suitable only for transactions which do not require forward secrecy. Probability of failure about 1/2^40
|
||||
/// </summary>
|
||||
Low,
|
||||
/// <summary>
|
||||
/// Designed for production use. Probability of failure about 1/2^80.
|
||||
/// </summary>
|
||||
Medium,
|
||||
/// <summary>
|
||||
/// Suitable for sensitive data. Probability of failure about 1/2^160.
|
||||
/// </summary>
|
||||
High,
|
||||
/// <summary>
|
||||
/// Use only if you have lots of time! Probability of failure about 1/2^320.
|
||||
/// </summary>
|
||||
ExtraHigh,
|
||||
/// <summary>
|
||||
/// Only use methods which generate provable primes. Not yet implemented.
|
||||
/// </summary>
|
||||
Provable
|
||||
}
|
||||
}
|
||||
218
Novaria.Common/Mono/Mono.Math.Prime/PrimalityTests.cs
Normal file
218
Novaria.Common/Mono/Mono.Math.Prime/PrimalityTests.cs
Normal file
@@ -0,0 +1,218 @@
|
||||
//
|
||||
// Mono.Math.Prime.PrimalityTests.cs - Test for primality
|
||||
//
|
||||
// Authors:
|
||||
// Ben Maurer
|
||||
//
|
||||
// Copyright (c) 2003 Ben Maurer. All rights reserved
|
||||
//
|
||||
|
||||
//
|
||||
// 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.Math.Prime {
|
||||
|
||||
#if INSIDE_CORLIB
|
||||
internal
|
||||
#else
|
||||
public
|
||||
#endif
|
||||
delegate bool PrimalityTest (BigInteger bi, ConfidenceFactor confidence);
|
||||
|
||||
#if INSIDE_CORLIB
|
||||
internal
|
||||
#else
|
||||
public
|
||||
#endif
|
||||
sealed class PrimalityTests {
|
||||
|
||||
private PrimalityTests ()
|
||||
{
|
||||
}
|
||||
|
||||
#region SPP Test
|
||||
|
||||
private static int GetSPPRounds (BigInteger bi, ConfidenceFactor confidence)
|
||||
{
|
||||
int bc = bi.BitCount();
|
||||
|
||||
int Rounds;
|
||||
|
||||
// Data from HAC, 4.49
|
||||
if (bc <= 100 ) Rounds = 27;
|
||||
else if (bc <= 150 ) Rounds = 18;
|
||||
else if (bc <= 200 ) Rounds = 15;
|
||||
else if (bc <= 250 ) Rounds = 12;
|
||||
else if (bc <= 300 ) Rounds = 9;
|
||||
else if (bc <= 350 ) Rounds = 8;
|
||||
else if (bc <= 400 ) Rounds = 7;
|
||||
else if (bc <= 500 ) Rounds = 6;
|
||||
else if (bc <= 600 ) Rounds = 5;
|
||||
else if (bc <= 800 ) Rounds = 4;
|
||||
else if (bc <= 1250) Rounds = 3;
|
||||
else Rounds = 2;
|
||||
|
||||
switch (confidence) {
|
||||
case ConfidenceFactor.ExtraLow:
|
||||
Rounds >>= 2;
|
||||
return Rounds != 0 ? Rounds : 1;
|
||||
case ConfidenceFactor.Low:
|
||||
Rounds >>= 1;
|
||||
return Rounds != 0 ? Rounds : 1;
|
||||
case ConfidenceFactor.Medium:
|
||||
return Rounds;
|
||||
case ConfidenceFactor.High:
|
||||
return Rounds << 1;
|
||||
case ConfidenceFactor.ExtraHigh:
|
||||
return Rounds << 2;
|
||||
case ConfidenceFactor.Provable:
|
||||
throw new Exception ("The Rabin-Miller test can not be executed in a way such that its results are provable");
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException ("confidence");
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Test (BigInteger n, ConfidenceFactor confidence)
|
||||
{
|
||||
// Rabin-Miller fails with smaller primes (at least with our BigInteger code)
|
||||
if (n.BitCount () < 33)
|
||||
return SmallPrimeSppTest (n, confidence);
|
||||
else
|
||||
return RabinMillerTest (n, confidence);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Probabilistic prime test based on Rabin-Miller's test
|
||||
/// </summary>
|
||||
/// <param name="n" type="BigInteger.BigInteger">
|
||||
/// <para>
|
||||
/// The number to test.
|
||||
/// </para>
|
||||
/// </param>
|
||||
/// <param name="confidence" type="int">
|
||||
/// <para>
|
||||
/// The number of chosen bases. The test has at least a
|
||||
/// 1/4^confidence chance of falsely returning True.
|
||||
/// </para>
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <para>
|
||||
/// True if "this" is a strong pseudoprime to randomly chosen bases.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// False if "this" is definitely NOT prime.
|
||||
/// </para>
|
||||
/// </returns>
|
||||
public static bool RabinMillerTest (BigInteger n, ConfidenceFactor confidence)
|
||||
{
|
||||
int bits = n.BitCount ();
|
||||
int t = GetSPPRounds (bits, confidence);
|
||||
|
||||
// n - 1 == 2^s * r, r is odd
|
||||
BigInteger n_minus_1 = n - 1;
|
||||
int s = n_minus_1.LowestSetBit ();
|
||||
BigInteger r = n_minus_1 >> s;
|
||||
|
||||
BigInteger.ModulusRing mr = new BigInteger.ModulusRing (n);
|
||||
|
||||
// Applying optimization from HAC section 4.50 (base == 2)
|
||||
// not a really random base but an interesting (and speedy) one
|
||||
BigInteger y = null;
|
||||
// FIXME - optimization disable for small primes due to bug #81857
|
||||
if (n.BitCount () > 100)
|
||||
y = mr.Pow (2, r);
|
||||
|
||||
// still here ? start at round 1 (round 0 was a == 2)
|
||||
for (int round = 0; round < t; round++) {
|
||||
|
||||
if ((round > 0) || (y == null)) {
|
||||
BigInteger a = null;
|
||||
|
||||
// check for 2 <= a <= n - 2
|
||||
// ...but we already did a == 2 previously as an optimization
|
||||
do {
|
||||
a = BigInteger.GenerateRandom (bits);
|
||||
} while ((a <= 2) && (a >= n_minus_1));
|
||||
|
||||
y = mr.Pow (a, r);
|
||||
}
|
||||
|
||||
if (y == 1)
|
||||
continue;
|
||||
|
||||
for (int j = 0; ((j < s) && (y != n_minus_1)); j++) {
|
||||
|
||||
y = mr.Pow (y, 2);
|
||||
if (y == 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (y != n_minus_1)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool SmallPrimeSppTest (BigInteger bi, ConfidenceFactor confidence)
|
||||
{
|
||||
int Rounds = GetSPPRounds (bi, confidence);
|
||||
|
||||
// calculate values of s and t
|
||||
BigInteger p_sub1 = bi - 1;
|
||||
int s = p_sub1.LowestSetBit ();
|
||||
|
||||
BigInteger t = p_sub1 >> s;
|
||||
|
||||
|
||||
BigInteger.ModulusRing mr = new BigInteger.ModulusRing (bi);
|
||||
|
||||
for (int round = 0; round < Rounds; round++) {
|
||||
|
||||
BigInteger b = mr.Pow (BigInteger.smallPrimes [round], t);
|
||||
|
||||
if (b == 1) continue; // a^t mod p = 1
|
||||
|
||||
bool result = false;
|
||||
for (int j = 0; j < s; j++) {
|
||||
|
||||
if (b == p_sub1) { // a^((2^j)*t) mod p = p-1 for some 0 <= j <= s-1
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
b = (b * b) % bi;
|
||||
}
|
||||
|
||||
if (result == false)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// TODO: Implement the Lucus test
|
||||
// TODO: Implement other new primality tests
|
||||
// TODO: Implement primality proving
|
||||
}
|
||||
}
|
||||
2372
Novaria.Common/Mono/Mono.Math/BigInteger.cs
Normal file
2372
Novaria.Common/Mono/Mono.Math/BigInteger.cs
Normal file
File diff suppressed because it is too large
Load Diff
805
Novaria.Common/Mono/Mono.Security.Cryptography/CryptoConvert.cs
Normal file
805
Novaria.Common/Mono/Mono.Security.Cryptography/CryptoConvert.cs
Normal file
@@ -0,0 +1,805 @@
|
||||
//
|
||||
// CryptoConvert.cs - Crypto Convertion Routines
|
||||
//
|
||||
// Author:
|
||||
// Sebastien Pouliot <sebastien@ximian.com>
|
||||
//
|
||||
// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
|
||||
// Copyright (C) 2004-2006 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.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Mono.Security.Cryptography {
|
||||
|
||||
#if INSIDE_CORLIB
|
||||
internal
|
||||
#else
|
||||
public
|
||||
#endif
|
||||
sealed class CryptoConvert {
|
||||
|
||||
private CryptoConvert ()
|
||||
{
|
||||
}
|
||||
|
||||
static private int ToInt32LE (byte [] bytes, int offset)
|
||||
{
|
||||
return (bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset];
|
||||
}
|
||||
|
||||
static private uint ToUInt32LE (byte [] bytes, int offset)
|
||||
{
|
||||
return (uint)((bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset]);
|
||||
}
|
||||
|
||||
static private byte [] GetBytesLE (int val)
|
||||
{
|
||||
return new byte [] {
|
||||
(byte) (val & 0xff),
|
||||
(byte) ((val >> 8) & 0xff),
|
||||
(byte) ((val >> 16) & 0xff),
|
||||
(byte) ((val >> 24) & 0xff)
|
||||
};
|
||||
}
|
||||
|
||||
static private byte[] Trim (byte[] array)
|
||||
{
|
||||
for (int i=0; i < array.Length; i++) {
|
||||
if (array [i] != 0x00) {
|
||||
byte[] result = new byte [array.Length - i];
|
||||
Buffer.BlockCopy (array, i, result, 0, result.Length);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
#if INSIDE_CORLIB
|
||||
static internal bool TryImportCapiPrivateKeyBlob (byte[] blob, int offset)
|
||||
{
|
||||
try {
|
||||
var rsap = GetParametersFromCapiPrivateKeyBlob (blob, offset);
|
||||
// Since we are only checking whether this throws an exception and
|
||||
// not actually returning the `RSA` object, we can use `RSAManaged`
|
||||
// here because that's what the `RSACryptoServiceProvider` implementation
|
||||
// does internally.
|
||||
var rsa = new RSAManaged ();
|
||||
rsa.ImportParameters (rsap);
|
||||
return true;
|
||||
} catch (CryptographicException) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// convert the key from PRIVATEKEYBLOB to RSA
|
||||
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/Security/private_key_blobs.asp
|
||||
// e.g. SNK files, PVK files
|
||||
static public RSA FromCapiPrivateKeyBlob (byte[] blob)
|
||||
{
|
||||
return FromCapiPrivateKeyBlob (blob, 0);
|
||||
}
|
||||
|
||||
static public RSA FromCapiPrivateKeyBlob (byte[] blob, int offset)
|
||||
{
|
||||
RSAParameters rsap = GetParametersFromCapiPrivateKeyBlob (blob, offset);
|
||||
|
||||
#if INSIDE_CORLIB && MOBILE
|
||||
RSA rsa = RSA.Create ();
|
||||
rsa.ImportParameters (rsap);
|
||||
#else
|
||||
RSA rsa = null;
|
||||
try {
|
||||
rsa = RSA.Create ();
|
||||
rsa.ImportParameters (rsap);
|
||||
}
|
||||
catch (CryptographicException ce) {
|
||||
// this may cause problem when this code is run under
|
||||
// the SYSTEM identity on Windows (e.g. ASP.NET). See
|
||||
// http://bugzilla.ximian.com/show_bug.cgi?id=77559
|
||||
try {
|
||||
CspParameters csp = new CspParameters ();
|
||||
csp.Flags = CspProviderFlags.UseMachineKeyStore;
|
||||
rsa = new RSACryptoServiceProvider (csp);
|
||||
rsa.ImportParameters (rsap);
|
||||
}
|
||||
catch {
|
||||
// rethrow original, not the later, exception if this fails
|
||||
throw ce;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return rsa;
|
||||
}
|
||||
|
||||
static RSAParameters GetParametersFromCapiPrivateKeyBlob (byte[] blob, int offset)
|
||||
{
|
||||
if (blob == null)
|
||||
throw new ArgumentNullException ("blob");
|
||||
if (offset >= blob.Length)
|
||||
throw new ArgumentException ("blob is too small.");
|
||||
|
||||
RSAParameters rsap = new RSAParameters ();
|
||||
try {
|
||||
if ((blob [offset] != 0x07) || // PRIVATEKEYBLOB (0x07)
|
||||
(blob [offset+1] != 0x02) || // Version (0x02)
|
||||
(blob [offset+2] != 0x00) || // Reserved (word)
|
||||
(blob [offset+3] != 0x00) ||
|
||||
(ToUInt32LE (blob, offset+8) != 0x32415352)) // DWORD magic = RSA2
|
||||
throw new CryptographicException ("Invalid blob header");
|
||||
|
||||
// ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...)
|
||||
// int algId = ToInt32LE (blob, offset+4);
|
||||
|
||||
// DWORD bitlen
|
||||
int bitLen = ToInt32LE (blob, offset+12);
|
||||
|
||||
// DWORD public exponent
|
||||
byte[] exp = new byte [4];
|
||||
Buffer.BlockCopy (blob, offset+16, exp, 0, 4);
|
||||
Array.Reverse (exp);
|
||||
rsap.Exponent = Trim (exp);
|
||||
|
||||
int pos = offset+20;
|
||||
// BYTE modulus[rsapubkey.bitlen/8];
|
||||
int byteLen = (bitLen >> 3);
|
||||
rsap.Modulus = new byte [byteLen];
|
||||
Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen);
|
||||
Array.Reverse (rsap.Modulus);
|
||||
pos += byteLen;
|
||||
|
||||
// BYTE prime1[rsapubkey.bitlen/16];
|
||||
int byteHalfLen = (byteLen >> 1);
|
||||
rsap.P = new byte [byteHalfLen];
|
||||
Buffer.BlockCopy (blob, pos, rsap.P, 0, byteHalfLen);
|
||||
Array.Reverse (rsap.P);
|
||||
pos += byteHalfLen;
|
||||
|
||||
// BYTE prime2[rsapubkey.bitlen/16];
|
||||
rsap.Q = new byte [byteHalfLen];
|
||||
Buffer.BlockCopy (blob, pos, rsap.Q, 0, byteHalfLen);
|
||||
Array.Reverse (rsap.Q);
|
||||
pos += byteHalfLen;
|
||||
|
||||
// BYTE exponent1[rsapubkey.bitlen/16];
|
||||
rsap.DP = new byte [byteHalfLen];
|
||||
Buffer.BlockCopy (blob, pos, rsap.DP, 0, byteHalfLen);
|
||||
Array.Reverse (rsap.DP);
|
||||
pos += byteHalfLen;
|
||||
|
||||
// BYTE exponent2[rsapubkey.bitlen/16];
|
||||
rsap.DQ = new byte [byteHalfLen];
|
||||
Buffer.BlockCopy (blob, pos, rsap.DQ, 0, byteHalfLen);
|
||||
Array.Reverse (rsap.DQ);
|
||||
pos += byteHalfLen;
|
||||
|
||||
// BYTE coefficient[rsapubkey.bitlen/16];
|
||||
rsap.InverseQ = new byte [byteHalfLen];
|
||||
Buffer.BlockCopy (blob, pos, rsap.InverseQ, 0, byteHalfLen);
|
||||
Array.Reverse (rsap.InverseQ);
|
||||
pos += byteHalfLen;
|
||||
|
||||
// ok, this is hackish but CryptoAPI support it so...
|
||||
// note: only works because CRT is used by default
|
||||
// http://bugzilla.ximian.com/show_bug.cgi?id=57941
|
||||
rsap.D = new byte [byteLen]; // must be allocated
|
||||
if (pos + byteLen + offset <= blob.Length) {
|
||||
// BYTE privateExponent[rsapubkey.bitlen/8];
|
||||
Buffer.BlockCopy (blob, pos, rsap.D, 0, byteLen);
|
||||
Array.Reverse (rsap.D);
|
||||
}
|
||||
return rsap;
|
||||
} catch (Exception e) {
|
||||
throw new CryptographicException ("Invalid blob.", e);
|
||||
}
|
||||
}
|
||||
|
||||
static public DSA FromCapiPrivateKeyBlobDSA (byte[] blob)
|
||||
{
|
||||
return FromCapiPrivateKeyBlobDSA (blob, 0);
|
||||
}
|
||||
|
||||
static public DSA FromCapiPrivateKeyBlobDSA (byte[] blob, int offset)
|
||||
{
|
||||
if (blob == null)
|
||||
throw new ArgumentNullException ("blob");
|
||||
if (offset >= blob.Length)
|
||||
throw new ArgumentException ("blob is too small.");
|
||||
|
||||
DSAParameters dsap = new DSAParameters ();
|
||||
try {
|
||||
if ((blob [offset] != 0x07) || // PRIVATEKEYBLOB (0x07)
|
||||
(blob [offset + 1] != 0x02) || // Version (0x02)
|
||||
(blob [offset + 2] != 0x00) || // Reserved (word)
|
||||
(blob [offset + 3] != 0x00) ||
|
||||
(ToUInt32LE (blob, offset + 8) != 0x32535344)) // DWORD magic
|
||||
throw new CryptographicException ("Invalid blob header");
|
||||
|
||||
int bitlen = ToInt32LE (blob, offset + 12);
|
||||
int bytelen = bitlen >> 3;
|
||||
int pos = offset + 16;
|
||||
|
||||
dsap.P = new byte [bytelen];
|
||||
Buffer.BlockCopy (blob, pos, dsap.P, 0, bytelen);
|
||||
Array.Reverse (dsap.P);
|
||||
pos += bytelen;
|
||||
|
||||
dsap.Q = new byte [20];
|
||||
Buffer.BlockCopy (blob, pos, dsap.Q, 0, 20);
|
||||
Array.Reverse (dsap.Q);
|
||||
pos += 20;
|
||||
|
||||
dsap.G = new byte [bytelen];
|
||||
Buffer.BlockCopy (blob, pos, dsap.G, 0, bytelen);
|
||||
Array.Reverse (dsap.G);
|
||||
pos += bytelen;
|
||||
|
||||
dsap.X = new byte [20];
|
||||
Buffer.BlockCopy (blob, pos, dsap.X, 0, 20);
|
||||
Array.Reverse (dsap.X);
|
||||
pos += 20;
|
||||
|
||||
dsap.Counter = ToInt32LE (blob, pos);
|
||||
pos += 4;
|
||||
|
||||
dsap.Seed = new byte [20];
|
||||
Buffer.BlockCopy (blob, pos, dsap.Seed, 0, 20);
|
||||
Array.Reverse (dsap.Seed);
|
||||
pos += 20;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new CryptographicException ("Invalid blob.", e);
|
||||
}
|
||||
|
||||
#if INSIDE_CORLIB && MOBILE
|
||||
DSA dsa = (DSA)DSA.Create ();
|
||||
dsa.ImportParameters (dsap);
|
||||
#else
|
||||
DSA dsa = null;
|
||||
try {
|
||||
dsa = (DSA)DSA.Create ();
|
||||
dsa.ImportParameters (dsap);
|
||||
}
|
||||
catch (CryptographicException ce) {
|
||||
// this may cause problem when this code is run under
|
||||
// the SYSTEM identity on Windows (e.g. ASP.NET). See
|
||||
// http://bugzilla.ximian.com/show_bug.cgi?id=77559
|
||||
try {
|
||||
CspParameters csp = new CspParameters ();
|
||||
csp.Flags = CspProviderFlags.UseMachineKeyStore;
|
||||
dsa = new DSACryptoServiceProvider (csp);
|
||||
dsa.ImportParameters (dsap);
|
||||
}
|
||||
catch {
|
||||
// rethrow original, not the later, exception if this fails
|
||||
throw ce;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return dsa;
|
||||
}
|
||||
|
||||
static public byte[] ToCapiPrivateKeyBlob (RSA rsa)
|
||||
{
|
||||
RSAParameters p = rsa.ExportParameters (true);
|
||||
int keyLength = p.Modulus.Length; // in bytes
|
||||
byte[] blob = new byte [20 + (keyLength << 2) + (keyLength >> 1)];
|
||||
|
||||
blob [0] = 0x07; // Type - PRIVATEKEYBLOB (0x07)
|
||||
blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
|
||||
// [2], [3] // RESERVED - Always 0
|
||||
blob [5] = 0x24; // ALGID - Always 00 24 00 00 (for CALG_RSA_SIGN)
|
||||
blob [8] = 0x52; // Magic - RSA2 (ASCII in hex)
|
||||
blob [9] = 0x53;
|
||||
blob [10] = 0x41;
|
||||
blob [11] = 0x32;
|
||||
|
||||
byte[] bitlen = GetBytesLE (keyLength << 3);
|
||||
blob [12] = bitlen [0]; // bitlen
|
||||
blob [13] = bitlen [1];
|
||||
blob [14] = bitlen [2];
|
||||
blob [15] = bitlen [3];
|
||||
|
||||
// public exponent (DWORD)
|
||||
int pos = 16;
|
||||
int n = p.Exponent.Length;
|
||||
while (n > 0)
|
||||
blob [pos++] = p.Exponent [--n];
|
||||
// modulus
|
||||
pos = 20;
|
||||
byte[] part = p.Modulus;
|
||||
int len = part.Length;
|
||||
Array.Reverse (part, 0, len);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, len);
|
||||
pos += len;
|
||||
// private key
|
||||
part = p.P;
|
||||
len = part.Length;
|
||||
Array.Reverse (part, 0, len);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, len);
|
||||
pos += len;
|
||||
|
||||
part = p.Q;
|
||||
len = part.Length;
|
||||
Array.Reverse (part, 0, len);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, len);
|
||||
pos += len;
|
||||
|
||||
part = p.DP;
|
||||
len = part.Length;
|
||||
Array.Reverse (part, 0, len);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, len);
|
||||
pos += len;
|
||||
|
||||
part = p.DQ;
|
||||
len = part.Length;
|
||||
Array.Reverse (part, 0, len);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, len);
|
||||
pos += len;
|
||||
|
||||
part = p.InverseQ;
|
||||
len = part.Length;
|
||||
Array.Reverse (part, 0, len);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, len);
|
||||
pos += len;
|
||||
|
||||
part = p.D;
|
||||
len = part.Length;
|
||||
Array.Reverse (part, 0, len);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, len);
|
||||
|
||||
return blob;
|
||||
}
|
||||
|
||||
static public byte[] ToCapiPrivateKeyBlob (DSA dsa)
|
||||
{
|
||||
DSAParameters p = dsa.ExportParameters (true);
|
||||
int keyLength = p.P.Length; // in bytes
|
||||
|
||||
// header + P + Q + G + X + count + seed
|
||||
byte[] blob = new byte [16 + keyLength + 20 + keyLength + 20 + 4 + 20];
|
||||
|
||||
blob [0] = 0x07; // Type - PRIVATEKEYBLOB (0x07)
|
||||
blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
|
||||
// [2], [3] // RESERVED - Always 0
|
||||
blob [5] = 0x22; // ALGID
|
||||
blob [8] = 0x44; // Magic
|
||||
blob [9] = 0x53;
|
||||
blob [10] = 0x53;
|
||||
blob [11] = 0x32;
|
||||
|
||||
byte[] bitlen = GetBytesLE (keyLength << 3);
|
||||
blob [12] = bitlen [0];
|
||||
blob [13] = bitlen [1];
|
||||
blob [14] = bitlen [2];
|
||||
blob [15] = bitlen [3];
|
||||
|
||||
int pos = 16;
|
||||
byte[] part = p.P;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, keyLength);
|
||||
pos += keyLength;
|
||||
|
||||
part = p.Q;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, 20);
|
||||
pos += 20;
|
||||
|
||||
part = p.G;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, keyLength);
|
||||
pos += keyLength;
|
||||
|
||||
part = p.X;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, 20);
|
||||
pos += 20;
|
||||
|
||||
Buffer.BlockCopy (GetBytesLE (p.Counter), 0, blob, pos, 4);
|
||||
pos += 4;
|
||||
|
||||
part = p.Seed;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, 20);
|
||||
|
||||
return blob;
|
||||
}
|
||||
|
||||
#if INSIDE_CORLIB
|
||||
static internal bool TryImportCapiPublicKeyBlob (byte[] blob, int offset)
|
||||
{
|
||||
try {
|
||||
var rsap = GetParametersFromCapiPublicKeyBlob (blob, offset);
|
||||
// Since we are only checking whether this throws an exception and
|
||||
// not actually returning the `RSA` object, we can use `RSAManaged`
|
||||
// here because that's what the `RSACryptoServiceProvider` implementation
|
||||
// does internally.
|
||||
var rsa = new RSAManaged ();
|
||||
rsa.ImportParameters (rsap);
|
||||
return true;
|
||||
} catch (CryptographicException) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static public RSA FromCapiPublicKeyBlob (byte[] blob)
|
||||
{
|
||||
return FromCapiPublicKeyBlob (blob, 0);
|
||||
}
|
||||
|
||||
static public RSA FromCapiPublicKeyBlob (byte[] blob, int offset)
|
||||
{
|
||||
var rsap = GetParametersFromCapiPublicKeyBlob (blob, offset);
|
||||
|
||||
try {
|
||||
#if INSIDE_CORLIB && MOBILE
|
||||
RSA rsa = RSA.Create ();
|
||||
rsa.ImportParameters (rsap);
|
||||
#else
|
||||
RSA rsa = null;
|
||||
try {
|
||||
rsa = RSA.Create ();
|
||||
rsa.ImportParameters (rsap);
|
||||
}
|
||||
catch (CryptographicException) {
|
||||
// this may cause problem when this code is run under
|
||||
// the SYSTEM identity on Windows (e.g. ASP.NET). See
|
||||
// http://bugzilla.ximian.com/show_bug.cgi?id=77559
|
||||
CspParameters csp = new CspParameters ();
|
||||
csp.Flags = CspProviderFlags.UseMachineKeyStore;
|
||||
rsa = new RSACryptoServiceProvider (csp);
|
||||
rsa.ImportParameters (rsap);
|
||||
}
|
||||
#endif
|
||||
return rsa;
|
||||
} catch (Exception e) {
|
||||
throw new CryptographicException ("Invalid blob.", e);
|
||||
}
|
||||
}
|
||||
|
||||
static RSAParameters GetParametersFromCapiPublicKeyBlob (byte[] blob, int offset)
|
||||
{
|
||||
if (blob == null)
|
||||
throw new ArgumentNullException ("blob");
|
||||
if (offset >= blob.Length)
|
||||
throw new ArgumentException ("blob is too small.");
|
||||
|
||||
try {
|
||||
if ((blob [offset] != 0x06) || // PUBLICKEYBLOB (0x06)
|
||||
(blob [offset+1] != 0x02) || // Version (0x02)
|
||||
(blob [offset+2] != 0x00) || // Reserved (word)
|
||||
(blob [offset+3] != 0x00) ||
|
||||
(ToUInt32LE (blob, offset+8) != 0x31415352)) // DWORD magic = RSA1
|
||||
throw new CryptographicException ("Invalid blob header");
|
||||
|
||||
// ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...)
|
||||
// int algId = ToInt32LE (blob, offset+4);
|
||||
|
||||
// DWORD bitlen
|
||||
int bitLen = ToInt32LE (blob, offset+12);
|
||||
|
||||
// DWORD public exponent
|
||||
RSAParameters rsap = new RSAParameters ();
|
||||
rsap.Exponent = new byte [3];
|
||||
rsap.Exponent [0] = blob [offset+18];
|
||||
rsap.Exponent [1] = blob [offset+17];
|
||||
rsap.Exponent [2] = blob [offset+16];
|
||||
|
||||
int pos = offset+20;
|
||||
// BYTE modulus[rsapubkey.bitlen/8];
|
||||
int byteLen = (bitLen >> 3);
|
||||
rsap.Modulus = new byte [byteLen];
|
||||
Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen);
|
||||
Array.Reverse (rsap.Modulus);
|
||||
return rsap;
|
||||
} catch (Exception e) {
|
||||
throw new CryptographicException ("Invalid blob.", e);
|
||||
}
|
||||
}
|
||||
|
||||
static public DSA FromCapiPublicKeyBlobDSA (byte[] blob)
|
||||
{
|
||||
return FromCapiPublicKeyBlobDSA (blob, 0);
|
||||
}
|
||||
|
||||
static public DSA FromCapiPublicKeyBlobDSA (byte[] blob, int offset)
|
||||
{
|
||||
if (blob == null)
|
||||
throw new ArgumentNullException ("blob");
|
||||
if (offset >= blob.Length)
|
||||
throw new ArgumentException ("blob is too small.");
|
||||
|
||||
try {
|
||||
if ((blob [offset] != 0x06) || // PUBLICKEYBLOB (0x06)
|
||||
(blob [offset + 1] != 0x02) || // Version (0x02)
|
||||
(blob [offset + 2] != 0x00) || // Reserved (word)
|
||||
(blob [offset + 3] != 0x00) ||
|
||||
(ToUInt32LE (blob, offset + 8) != 0x31535344)) // DWORD magic
|
||||
throw new CryptographicException ("Invalid blob header");
|
||||
|
||||
int bitlen = ToInt32LE (blob, offset + 12);
|
||||
DSAParameters dsap = new DSAParameters ();
|
||||
int bytelen = bitlen >> 3;
|
||||
int pos = offset + 16;
|
||||
|
||||
dsap.P = new byte [bytelen];
|
||||
Buffer.BlockCopy (blob, pos, dsap.P, 0, bytelen);
|
||||
Array.Reverse (dsap.P);
|
||||
pos += bytelen;
|
||||
|
||||
dsap.Q = new byte [20];
|
||||
Buffer.BlockCopy (blob, pos, dsap.Q, 0, 20);
|
||||
Array.Reverse (dsap.Q);
|
||||
pos += 20;
|
||||
|
||||
dsap.G = new byte [bytelen];
|
||||
Buffer.BlockCopy (blob, pos, dsap.G, 0, bytelen);
|
||||
Array.Reverse (dsap.G);
|
||||
pos += bytelen;
|
||||
|
||||
dsap.Y = new byte [bytelen];
|
||||
Buffer.BlockCopy (blob, pos, dsap.Y, 0, bytelen);
|
||||
Array.Reverse (dsap.Y);
|
||||
pos += bytelen;
|
||||
|
||||
dsap.Counter = ToInt32LE (blob, pos);
|
||||
pos += 4;
|
||||
|
||||
dsap.Seed = new byte [20];
|
||||
Buffer.BlockCopy (blob, pos, dsap.Seed, 0, 20);
|
||||
Array.Reverse (dsap.Seed);
|
||||
pos += 20;
|
||||
|
||||
DSA dsa = (DSA)DSA.Create ();
|
||||
dsa.ImportParameters (dsap);
|
||||
return dsa;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new CryptographicException ("Invalid blob.", e);
|
||||
}
|
||||
}
|
||||
|
||||
static public byte[] ToCapiPublicKeyBlob (RSA rsa)
|
||||
{
|
||||
RSAParameters p = rsa.ExportParameters (false);
|
||||
int keyLength = p.Modulus.Length; // in bytes
|
||||
byte[] blob = new byte [20 + keyLength];
|
||||
|
||||
blob [0] = 0x06; // Type - PUBLICKEYBLOB (0x06)
|
||||
blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
|
||||
// [2], [3] // RESERVED - Always 0
|
||||
blob [5] = 0x24; // ALGID - Always 00 24 00 00 (for CALG_RSA_SIGN)
|
||||
blob [8] = 0x52; // Magic - RSA1 (ASCII in hex)
|
||||
blob [9] = 0x53;
|
||||
blob [10] = 0x41;
|
||||
blob [11] = 0x31;
|
||||
|
||||
byte[] bitlen = GetBytesLE (keyLength << 3);
|
||||
blob [12] = bitlen [0]; // bitlen
|
||||
blob [13] = bitlen [1];
|
||||
blob [14] = bitlen [2];
|
||||
blob [15] = bitlen [3];
|
||||
|
||||
// public exponent (DWORD)
|
||||
int pos = 16;
|
||||
int n = p.Exponent.Length;
|
||||
while (n > 0)
|
||||
blob [pos++] = p.Exponent [--n];
|
||||
// modulus
|
||||
pos = 20;
|
||||
byte[] part = p.Modulus;
|
||||
int len = part.Length;
|
||||
Array.Reverse (part, 0, len);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, len);
|
||||
pos += len;
|
||||
return blob;
|
||||
}
|
||||
|
||||
static public byte[] ToCapiPublicKeyBlob (DSA dsa)
|
||||
{
|
||||
DSAParameters p = dsa.ExportParameters (false);
|
||||
int keyLength = p.P.Length; // in bytes
|
||||
|
||||
// header + P + Q + G + Y + count + seed
|
||||
byte[] blob = new byte [16 + keyLength + 20 + keyLength + keyLength + 4 + 20];
|
||||
|
||||
blob [0] = 0x06; // Type - PUBLICKEYBLOB (0x06)
|
||||
blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
|
||||
// [2], [3] // RESERVED - Always 0
|
||||
blob [5] = 0x22; // ALGID
|
||||
blob [8] = 0x44; // Magic
|
||||
blob [9] = 0x53;
|
||||
blob [10] = 0x53;
|
||||
blob [11] = 0x31;
|
||||
|
||||
byte[] bitlen = GetBytesLE (keyLength << 3);
|
||||
blob [12] = bitlen [0];
|
||||
blob [13] = bitlen [1];
|
||||
blob [14] = bitlen [2];
|
||||
blob [15] = bitlen [3];
|
||||
|
||||
int pos = 16;
|
||||
byte[] part;
|
||||
|
||||
part = p.P;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, keyLength);
|
||||
pos += keyLength;
|
||||
|
||||
part = p.Q;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, 20);
|
||||
pos += 20;
|
||||
|
||||
part = p.G;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, keyLength);
|
||||
pos += keyLength;
|
||||
|
||||
part = p.Y;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, keyLength);
|
||||
pos += keyLength;
|
||||
|
||||
Buffer.BlockCopy (GetBytesLE (p.Counter), 0, blob, pos, 4);
|
||||
pos += 4;
|
||||
|
||||
part = p.Seed;
|
||||
Array.Reverse (part);
|
||||
Buffer.BlockCopy (part, 0, blob, pos, 20);
|
||||
|
||||
return blob;
|
||||
}
|
||||
|
||||
// PRIVATEKEYBLOB
|
||||
// PUBLICKEYBLOB
|
||||
static public RSA FromCapiKeyBlob (byte[] blob)
|
||||
{
|
||||
return FromCapiKeyBlob (blob, 0);
|
||||
}
|
||||
|
||||
static public RSA FromCapiKeyBlob (byte[] blob, int offset)
|
||||
{
|
||||
if (blob == null)
|
||||
throw new ArgumentNullException ("blob");
|
||||
if (offset >= blob.Length)
|
||||
throw new ArgumentException ("blob is too small.");
|
||||
|
||||
switch (blob [offset]) {
|
||||
case 0x00:
|
||||
// this could be a public key inside an header
|
||||
// like "sn -e" would produce
|
||||
if (blob [offset + 12] == 0x06) {
|
||||
return FromCapiPublicKeyBlob (blob, offset + 12);
|
||||
}
|
||||
break;
|
||||
case 0x06:
|
||||
return FromCapiPublicKeyBlob (blob, offset);
|
||||
case 0x07:
|
||||
return FromCapiPrivateKeyBlob (blob, offset);
|
||||
}
|
||||
throw new CryptographicException ("Unknown blob format.");
|
||||
}
|
||||
|
||||
static public DSA FromCapiKeyBlobDSA (byte[] blob)
|
||||
{
|
||||
return FromCapiKeyBlobDSA (blob, 0);
|
||||
}
|
||||
|
||||
static public DSA FromCapiKeyBlobDSA (byte[] blob, int offset)
|
||||
{
|
||||
if (blob == null)
|
||||
throw new ArgumentNullException ("blob");
|
||||
if (offset >= blob.Length)
|
||||
throw new ArgumentException ("blob is too small.");
|
||||
|
||||
switch (blob [offset]) {
|
||||
case 0x06:
|
||||
return FromCapiPublicKeyBlobDSA (blob, offset);
|
||||
case 0x07:
|
||||
return FromCapiPrivateKeyBlobDSA (blob, offset);
|
||||
}
|
||||
throw new CryptographicException ("Unknown blob format.");
|
||||
}
|
||||
|
||||
static public byte[] ToCapiKeyBlob (AsymmetricAlgorithm keypair, bool includePrivateKey)
|
||||
{
|
||||
if (keypair == null)
|
||||
throw new ArgumentNullException ("keypair");
|
||||
|
||||
// check between RSA and DSA (and potentially others like DH)
|
||||
if (keypair is RSA)
|
||||
return ToCapiKeyBlob ((RSA)keypair, includePrivateKey);
|
||||
else if (keypair is DSA)
|
||||
return ToCapiKeyBlob ((DSA)keypair, includePrivateKey);
|
||||
else
|
||||
return null; // TODO
|
||||
}
|
||||
|
||||
static public byte[] ToCapiKeyBlob (RSA rsa, bool includePrivateKey)
|
||||
{
|
||||
if (rsa == null)
|
||||
throw new ArgumentNullException ("rsa");
|
||||
|
||||
if (includePrivateKey)
|
||||
return ToCapiPrivateKeyBlob (rsa);
|
||||
else
|
||||
return ToCapiPublicKeyBlob (rsa);
|
||||
}
|
||||
|
||||
static public byte[] ToCapiKeyBlob (DSA dsa, bool includePrivateKey)
|
||||
{
|
||||
if (dsa == null)
|
||||
throw new ArgumentNullException ("dsa");
|
||||
|
||||
if (includePrivateKey)
|
||||
return ToCapiPrivateKeyBlob (dsa);
|
||||
else
|
||||
return ToCapiPublicKeyBlob (dsa);
|
||||
}
|
||||
|
||||
static public string ToHex (byte[] input)
|
||||
{
|
||||
if (input == null)
|
||||
return null;
|
||||
|
||||
StringBuilder sb = new StringBuilder (input.Length * 2);
|
||||
foreach (byte b in input) {
|
||||
sb.Append (b.ToString ("X2", CultureInfo.InvariantCulture));
|
||||
}
|
||||
return sb.ToString ();
|
||||
}
|
||||
|
||||
static private byte FromHexChar (char c)
|
||||
{
|
||||
if ((c >= 'a') && (c <= 'f'))
|
||||
return (byte) (c - 'a' + 10);
|
||||
if ((c >= 'A') && (c <= 'F'))
|
||||
return (byte) (c - 'A' + 10);
|
||||
if ((c >= '0') && (c <= '9'))
|
||||
return (byte) (c - '0');
|
||||
throw new ArgumentException ("invalid hex char");
|
||||
}
|
||||
|
||||
static public byte[] FromHex (string hex)
|
||||
{
|
||||
if (hex == null)
|
||||
return null;
|
||||
if ((hex.Length & 0x1) == 0x1)
|
||||
throw new ArgumentException ("Length must be a multiple of 2");
|
||||
|
||||
byte[] result = new byte [hex.Length >> 1];
|
||||
int n = 0;
|
||||
int i = 0;
|
||||
while (n < result.Length) {
|
||||
result [n] = (byte) (FromHexChar (hex [i++]) << 4);
|
||||
result [n++] += FromHexChar (hex [i++]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
147
Novaria.Common/Mono/Mono.Security.Cryptography/CryptoTools.cs
Normal file
147
Novaria.Common/Mono/Mono.Security.Cryptography/CryptoTools.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
//
|
||||
// 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)
|
||||
{
|
||||
if (transform == null)
|
||||
throw new ArgumentNullException ("transform");
|
||||
if (blockSize <= 0)
|
||||
throw new ArgumentOutOfRangeException ("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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
124
Novaria.Common/Mono/Mono.Security.Cryptography/DiffieHellman.cs
Normal file
124
Novaria.Common/Mono/Mono.Security.Cryptography/DiffieHellman.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
//
|
||||
// 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.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>
|
||||
/// 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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
if (m_P != null) m_P.Clear();
|
||||
if (m_G != null) m_G.Clear();
|
||||
if (m_X != null) 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
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -15,5 +15,9 @@
|
||||
<PackageReference Include="Serilog" Version="3.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Mono\" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
</Project>
|
||||
|
||||
75
Novaria.Common/Util/BigIntegerExtensions.cs
Normal file
75
Novaria.Common/Util/BigIntegerExtensions.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Novaria.Common.Util
|
||||
{
|
||||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
public static class BigIntegerExtensions
|
||||
{
|
||||
public static byte[] GetBytes(this BigInteger value)
|
||||
{
|
||||
if (value == 0)
|
||||
{
|
||||
return new byte[1];
|
||||
}
|
||||
|
||||
int bitCount = value.GetBitCount();
|
||||
int byteCount = bitCount >> 3;
|
||||
if ((bitCount & 7) != 0)
|
||||
{
|
||||
byteCount++;
|
||||
}
|
||||
|
||||
byte[] result = new byte[byteCount];
|
||||
int remainingBytes = byteCount & 3;
|
||||
if (remainingBytes == 0)
|
||||
{
|
||||
remainingBytes = 4;
|
||||
}
|
||||
|
||||
int byteIndex = 0;
|
||||
|
||||
// Convert BigInteger to unsigned equivalent (to match the behavior of the original code)
|
||||
BigInteger unsignedValue = BigInteger.Abs(value);
|
||||
|
||||
// Iterate through each 32-bit chunk of the BigInteger
|
||||
while (unsignedValue != 0)
|
||||
{
|
||||
uint currentWord = (uint)(unsignedValue & 0xFFFFFFFF);
|
||||
unsignedValue >>= 32;
|
||||
|
||||
for (int i = remainingBytes - 1; i >= 0; i--)
|
||||
{
|
||||
result[byteIndex + i] = (byte)(currentWord & 0xFF);
|
||||
currentWord >>= 8;
|
||||
}
|
||||
|
||||
byteIndex += remainingBytes;
|
||||
remainingBytes = 4;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Helper method to calculate the number of significant bits in a BigInteger
|
||||
private static int GetBitCount(this BigInteger value)
|
||||
{
|
||||
BigInteger unsignedValue = BigInteger.Abs(value);
|
||||
int bits = 0;
|
||||
|
||||
while (unsignedValue != 0)
|
||||
{
|
||||
unsignedValue >>= 1;
|
||||
bits++;
|
||||
}
|
||||
|
||||
return bits;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user