Skip to content

Instantly share code, notes, and snippets.

@chgeuer
Last active February 28, 2018 12:16
Show Gist options
  • Save chgeuer/42b6d4369042cf0af48533d91ced0780 to your computer and use it in GitHub Desktop.
Save chgeuer/42b6d4369042cf0af48533d91ced0780 to your computer and use it in GitHub Desktop.
namespace ecdsa
{
using System;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;
using System.Linq;
class Program
{
static BigInteger BigIntegerFromSerial(byte[] serialNumber)
{
if (serialNumber == null) throw new ArgumentNullException(paramName: nameof(serialNumber));
if (serialNumber.Length != 24) throw new ArgumentException(message: "Must be 24 bytes", paramName: nameof(serialNumber));
var input = new byte[25];
Buffer.BlockCopy(serialNumber, 0, input, 0, 24);
input[24] = 0;
var i = new BigInteger(input);
if (i <= BigInteger.One)
{
throw new ArgumentException(message: $"Value must be greater than 1", paramName: nameof(serialNumber));
}
return i;
}
static bool CanBeSigned(IRsaKey key, byte[] serialNumber) => BigIntegerFromSerial(serialNumber) < key.Modulus;
static byte[] sign(IRsaKey key, byte[] serialNumber)
{
var serno = BigIntegerFromSerial(serialNumber);
if (serno >= key.Modulus)
{
throw new ArgumentException(message: "Cannot sign messages greater than the modulus", paramName: nameof(serialNumber));
}
var signature = key.PrivateKeyOperation(serno);
return signature.ToByteArray();
}
static bool verify(IRsaKey key, byte[] serialNumber, byte[] signature)
{
var serno = BigIntegerFromSerial(serialNumber);
var sigInt = new BigInteger(signature);
var signed = key.PublicKeyOperation(sigInt);
return serno == signed;
}
static void Main(string[] args)
{
// openssl genrsa -out Alice.key 192
// openssl rsa -in Alice.key - text - inform PEM - noout
var rsa = RSAPlainKey.from(
privateExponent: "46:b9:d9:27:1b:77:09:0c:5c:a9:10:f9:63:c3:ed:9e:4a:d4:3f:b9:08:de:b3:71",
modulus: "00:ba:cf:c0:f2:e1:e5:0e:45:f8:8b:78:2b:87:c5:33:fb:4e:6b:b1:eb:f1:81:a6:01",
publicExponent: new BigInteger(65537));
var signatureOf10 = rsa.PrivateKeyOperation(new BigInteger(10));
var signatureOf18 = rsa.PrivateKeyOperation(new BigInteger(18));
var signatureOf180 = signatureOf10 * signatureOf18;
var itIsHomomorphicBecauseWeHaveNoPadding = new BigInteger(180) == rsa.PublicKeyOperation(signatureOf180);
Func<byte[]> random = () => {
var original = new byte[24];
new Random((int)System.DateTime.Now.Ticks).NextBytes(original);
return original;
};
while (true)
{
var serno = random();
if (!CanBeSigned(rsa, serno))
{
continue;
}
var signature = sign(rsa, serno);
bool valid = verify(rsa, serno, signature);
if (valid)
{
Console.WriteLine($"OK {signature.ToHexString()}");
}
else
{
var errMsg = $"Error: serno {serno.ToHexString()} sig {signature.ToHexString()}";
throw new Exception(errMsg);
}
}
for (int i=1000000; i< 1000050; i++)
{
var message = new BigInteger(i);
var signature = rsa.PrivateKeyOperation(message);
var verification = rsa.PublicKeyOperation(signature);
if (verification == message)
{
Console.WriteLine($"OK serno={i} sig={signature} ver={verification}");
}
else
{
Console.WriteLine($"ERR serno = {i} sig={signature }");
}
}
var serialNumber = 64387;
var sig = rsa.CreateSignature(serialNumber);
// sig[0] = 12;
var ok = rsa.SignatureOK(serialNumber, sig) ? "" : " not";
Console.WriteLine($"serialNumber = {serialNumber}");
Console.WriteLine($"signature = {sig.ToHexString()}");
Console.WriteLine($"signature length {sig.Length} bytes, {8 * sig.Length} bits");
Console.WriteLine($"Validation was {ok} successfull");
}
}
public interface IRsaKey
{
BigInteger PrivateExponent { get; }
BigInteger Modulus { get; }
BigInteger PublicExponent { get; }
}
public class RSAPlainKey : IRsaKey
{
public BigInteger PrivateExponent { get; }
public BigInteger Modulus { get; }
public BigInteger PublicExponent { get; }
public static IRsaKey from(string privateExponent, string modulus, BigInteger publicExponent) => new RSAPlainKey(parse(privateExponent), parse(modulus), publicExponent);
private RSAPlainKey(BigInteger privateExponent, BigInteger modulus, BigInteger exponent) { this.PrivateExponent = privateExponent; this.Modulus = modulus; this.PublicExponent = exponent; }
public static BigInteger parse(string value) => new BigInteger(value.Replace(":", "").FromHex().Reverse().ToArray());
}
public class RSACryptoServiceProviderKey : IRsaKey
{
public readonly RSACryptoServiceProvider rsa;
public static RSACryptoServiceProviderKey from(RSACryptoServiceProvider rsa) => new RSACryptoServiceProviderKey(rsa);
private RSACryptoServiceProviderKey(RSACryptoServiceProvider rsa) { this.rsa = rsa; }
public BigInteger PrivateExponent => rsa.ExportParameters(true).D.AsBigInteger();
public BigInteger Modulus => rsa.ExportParameters(true).Modulus.AsBigInteger();
public BigInteger PublicExponent => rsa.ExportParameters(true).Exponent.AsBigInteger();
}
public static class RSAPrivateEncryption
{
public static byte[] CreateSignature(this IRsaKey rsa, int serial) => rsa.PrivateKeyOperation(new BigInteger(serial)).ToByteArray();
public static bool SignatureOK(this IRsaKey rsa, int serial, byte[] signature) => serial == rsa.PublicKeyOperation(new BigInteger(signature));
// signieren, oder *ent*-schlüsseln
public static BigInteger PrivateKeyOperation(this IRsaKey rsa, BigInteger data) => BigInteger.ModPow(data, rsa.PrivateExponent, rsa.Modulus);
// signatur-prüfen, oder *ver*-schlüsseln
public static BigInteger PublicKeyOperation(this IRsaKey rsa, BigInteger data) => BigInteger.ModPow(data, rsa.PublicExponent, rsa.Modulus);
public static BigInteger AsBigInteger(this byte[] data)
{
byte[] inArr = (byte[])data.Clone();
Array.Reverse(inArr);
byte[] final = new byte[inArr.Length + 1];
Array.Copy(inArr, final, inArr.Length);
return new BigInteger(final);
}
public static string ToBase64(this byte[] bytes) => Convert.ToBase64String(bytes);
public static byte[] FromBase64(this string str) => Convert.FromBase64String(str);
public static string ToHexString(this byte[] ba)
{
var hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba) { hex.AppendFormat("{0:x2}", b); }
return hex.ToString();
}
public static byte[] FromHex(this string hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2) { bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); }
return bytes;
}
}
}
namespace ecdsa
{
using System;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;
class Program
{
static void Main(string[] args)
{
var rsa = new RSACryptoServiceProvider(dwKeySize: 384);
Console.WriteLine($"{rsa.ToXmlString(includePrivateParameters: true)}");
var message = Encoding.UTF8.GetBytes("Hallo Tim".PadLeft(totalWidth: 24));
var sig = rsa.PrivareEncryption(message);
var validated = rsa.PublicDecryption(sig);
var x = Encoding.UTF8.GetString(validated);
bool OK = Convert.ToBase64String(message) == Convert.ToBase64String(validated);
}
}
public static class RSAPrivateEncryption
{
public static byte[] PrivareEncryption(this RSACryptoServiceProvider rsa, byte[] data)
{
if (data == null)
throw new ArgumentNullException("data");
if (rsa.PublicOnly)
throw new InvalidOperationException("Private key is not loaded");
int maxDataLength = (rsa.KeySize / 8) - 6;
if (data.Length > maxDataLength)
throw new ArgumentOutOfRangeException("data", string.Format(
"Maximum data length for the current key size ({0} bits) is {1} bytes (current length: {2} bytes)",
rsa.KeySize, maxDataLength, data.Length));
// Add 4 byte padding to the data, and convert to BigInteger struct
BigInteger numData = GetBig(AddPadding(data));
RSAParameters rsaParams = rsa.ExportParameters(true);
BigInteger D = GetBig(rsaParams.D);
BigInteger Modulus = GetBig(rsaParams.Modulus);
BigInteger encData = BigInteger.ModPow(numData, D, Modulus);
return encData.ToByteArray();
}
public static byte[] PublicDecryption(this RSACryptoServiceProvider rsa, byte[] cipherData)
{
if (cipherData == null)
throw new ArgumentNullException("cipherData");
BigInteger numEncData = new BigInteger(cipherData);
RSAParameters rsaParams = rsa.ExportParameters(false);
BigInteger Exponent = GetBig(rsaParams.Exponent);
BigInteger Modulus = GetBig(rsaParams.Modulus);
BigInteger decData = BigInteger.ModPow(numEncData, Exponent, Modulus);
byte[] data = decData.ToByteArray();
byte[] result = new byte[data.Length - 1];
Array.Copy(data, result, result.Length);
result = RemovePadding(result);
Array.Reverse(result);
return result;
}
private static BigInteger GetBig(byte[] data)
{
byte[] inArr = (byte[])data.Clone();
Array.Reverse(inArr); // Reverse the byte order
byte[] final = new byte[inArr.Length + 1]; // Add an empty byte at the end, to simulate unsigned BigInteger (no negatives!)
Array.Copy(inArr, final, inArr.Length);
return new BigInteger(final);
}
// Add 4 byte random padding, first bit *Always On*
private static byte[] AddPadding(byte[] data)
{
Random rnd = new Random();
byte[] paddings = new byte[4];
rnd.NextBytes(paddings);
paddings[0] = (byte)(paddings[0] | 128);
byte[] results = new byte[data.Length + 4];
Array.Copy(paddings, results, 4);
Array.Copy(data, 0, results, 4, data.Length);
return results;
}
private static byte[] RemovePadding(byte[] data)
{
byte[] results = new byte[data.Length - 4];
Array.Copy(data, results, results.Length);
return results;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment