|
//------------------------------------------------------------------------
// (c) 2002-2004 by Per Anderson. All rights reserved.
//------------------------------------------------------------------------
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Reflection;
using System.Security.Cryptography;
using System.Collections;
namespace Bullfrog.Compress.RSA
{
/// <summary>
/// NOTE: These methods assume 1024 bit keys, the same
/// as exported from sn.exe
/// See also CryptExportKey() Win32 API
/// </summary>
public class RSA1024Util
{
public RSA1024Util()
{
// This will generate a new key
CtorFromXml(null);
}
public RSA1024Util(string xmlkey)
{
CtorFromXml(xmlkey);
}
public RSA1024Util(byte[] snkbuf)
{
CtorFromSnkBuf(snkbuf);
}
/// <summary>
/// NOTE: Passing null is allowed to generate new keys
/// </summary>
/// <param name="xmlkey"></param>
protected void CtorFromXml(string xmlkey)
{
_rsa = new RSACryptoServiceProvider(1024);
if ((xmlkey == null) || (xmlkey.Length < 1))
return;
_rsa.FromXmlString(xmlkey);
}
protected void CtorFromSnkBuf(byte[] snkbuf)
{
if ((snkbuf == null) || (snkbuf.Length < 1))
{
CtorFromXml(null);
return;
}
RSAParameters param = FigureParams(snkbuf);
// Must set KeyNumber to AT_SIGNATURE for strong
// name keypair to correctly be imported.
CspParameters cp = new CspParameters();
cp.KeyNumber = 2; // AT_SIGNATURE
_rsa = new RSACryptoServiceProvider(1024, cp);
_rsa.ImportParameters(param);
}
protected RSACryptoServiceProvider _rsa;
protected RSACryptoServiceProvider RSA
{
get
{
return _rsa;
}
}
protected Encoding _pt_enc = null;
public Encoding PlainTextEnc
{
get
{
if (_pt_enc == null)
_pt_enc = new UnicodeEncoding();
return _pt_enc;
}
set
{
_pt_enc = value;
}
}
protected SHA1CryptoServiceProvider _sha = null;
protected SHA1CryptoServiceProvider SHA
{
get
{
if (_sha == null)
_sha = new SHA1CryptoServiceProvider();
return _sha;
}
}
/// <summary>
/// NOTE: Output is bytes in UTF8 or Unicode encoding.
/// (Encoder set in PlainTextEnc)
/// </summary>
public byte[] PlainTextToByte(string s)
{
if ((s == null) || (s.Length < 1)) return null;
return PlainTextEnc.GetBytes(s);
}
/// <summary>
/// NOTE: Uses UTF8 or Unicode encoding.
/// Pass UTF8/Unicode bytes.
/// (Encoder set in PlainTextEnc)
/// </summary>
public string ByteToPlainText(byte[] bytes)
{
if ((bytes == null) || (bytes.Length < 1)) return null;
return PlainTextEnc.GetString(bytes);
}
/// <summary>
/// NOTE: Uses Base64 Encoding.
/// Pass base64 encoded string representing original bytes.
/// </summary>
public byte[] Base64StringToByte(string s)
{
if ((s == null) || (s.Length < 1)) return null;
return Convert.FromBase64String(s);
}
/// <summary>
/// NOTE: Uses Base64 Encoding.
/// Returns base64 encoded string representing passed bytes.
/// </summary>
public string ByteToBase64String(byte[] bytes)
{
if ((bytes == null) || (bytes.Length < 1)) return null;
return Convert.ToBase64String(bytes);
}
protected static byte[] BlockCopy(byte[] source, int idx, int size)
{
if ((source == null) || (source.Length < (idx + size)))
return null;
byte[] ret = new byte[size];
Buffer.BlockCopy(source, idx, ret, 0, size);
return ret;
}
public string PrivKeyXml
{
get
{
return RSA.ToXmlString(/*includepriv*/ true);
}
}
public string PubKeyXml
{
get
{
return RSA.ToXmlString(/*includepriv*/ false);
}
}
// For reading SNK Files
public static bool SnkBufIsPubLength(byte[] keypair)
{
if (keypair == null) return false;
return (keypair.Length == 160);
}
/// <summary>
/// Check that RSA1 is in header (public key only)
/// </summary>
/// <param name="keypair"></param>
/// <returns></returns>
public static bool CheckRSA1(byte[] pubkey)
{
// Check that RSA1 is in header
// R S A 1
byte[] check = new byte[] { 0x52, 0x53, 0x41, 0x31 };
return CheckMagic(pubkey, check, _magic_pub_idx);
}
/// <summary>
/// Check that RSA2 is in header (public and private key)
/// </summary>
/// <param name="keypair"></param>
/// <returns></returns>
public static bool CheckRSA2(byte[] pubkey)
{
// Check that RSA2 is in header
// R S A 2
byte[] check = new byte[] { 0x52, 0x53, 0x41, 0x32 };
return CheckMagic(pubkey, check, _magic_priv_idx);
}
protected static bool CheckMagic(byte[] keypair, byte[] check, int idx)
{
byte[] magic = BlockCopy(keypair, idx, _magic_size);
if (magic == null) return false;
for (int i = 0; i < _magic_size; i++)
{
if (check[i] != magic[i])
return false;
}
return true;
}
// Magic
// Will be RSA1 or RSA2
public const int _magic_priv_idx = 0x08;
public const int _magic_pub_idx = 0x14;
public const int _magic_size = 4;
public static RSAParameters FigureParams(
byte[] keypair)
{
RSAParameters ret = new RSAParameters();
if ((keypair == null) || (keypair.Length < 1))
return ret;
bool pubonly = SnkBufIsPubLength(keypair);
if ((pubonly) && (!CheckRSA1(keypair)))
return ret;
if ((!pubonly) && (!CheckRSA2(keypair)))
return ret;
int magic_idx = pubonly ? _magic_pub_idx : _magic_priv_idx;
// Bitlen is stored here, but note this
// class is only set up for 1024 bit length keys
int bitlen_idx = magic_idx + _magic_size;
int bitlen_size = 4; // DWORD
// Exponent
// In read file, will usually be { 1, 0, 1, 0 } or 65537
int exp_idx = bitlen_idx + bitlen_size;
int exp_size = 4;
//BYTE modulus[rsapubkey.bitlen/8]; == MOD; Size 128
int mod_idx = exp_idx + exp_size;
int mod_size = 128;
//BYTE prime1[rsapubkey.bitlen/16]; == P; Size 64
int p_idx = mod_idx + mod_size;
int p_size = 64;
//BYTE prime2[rsapubkey.bitlen/16]; == Q; Size 64
int q_idx = p_idx + p_size;
int q_size = 64;
//BYTE exponent1[rsapubkey.bitlen/16]; == DP; Size 64
int dp_idx = q_idx + q_size;
int dp_size = 64;
//BYTE exponent2[rsapubkey.bitlen/16]; == DQ; Size 64
int dq_idx = dp_idx + dp_size;
int dq_size = 64;
//BYTE coefficient[rsapubkey.bitlen/16]; == InverseQ; Size 64
int invq_idx = dq_idx + dq_size;
int invq_size = 64;
//BYTE privateExponent[rsapubkey.bitlen/8]; == D; Size 128
int d_idx = invq_idx + invq_size;
int d_size = 128;
// Figure public params
// Must reverse order (little vs. big endian issue)
ret.Exponent = BlockCopy(keypair, exp_idx, exp_size);
Array.Reverse(ret.Exponent);
ret.Modulus = BlockCopy(keypair, mod_idx, mod_size);
Array.Reverse(ret.Modulus);
if (pubonly) return ret;
// Figure private params
// Must reverse order (little vs. big endian issue)
ret.P = BlockCopy(keypair, p_idx, p_size);
Array.Reverse(ret.P);
ret.Q = BlockCopy(keypair, q_idx, q_size);
Array.Reverse(ret.Q);
ret.DP = BlockCopy(keypair, dp_idx, dp_size);
Array.Reverse(ret.DP);
ret.DQ = BlockCopy(keypair, dq_idx, dq_size);
Array.Reverse(ret.DQ);
ret.InverseQ = BlockCopy(keypair, invq_idx, invq_size);
Array.Reverse(ret.InverseQ);
ret.D = BlockCopy(keypair, d_idx, d_size);
Array.Reverse(ret.D);
return ret;
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
Per Anderson is the founder of Sunfrog Technologies LLC, http://sunfrog-tech.com .