Last active
February 28, 2018 12:16
-
-
Save chgeuer/42b6d4369042cf0af48533d91ced0780 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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