ElGamal signature not verified - c#

I want to implement an ElGamal encryption from this link https://csharp.hotexamples.com/examples/Portable.Licensing.Security.Cryptography.ElGamal/ElGamalKeyStruct/-/php-elgamalkeystruct-class-examples.html
This is what I have tried so far and have no luck
string lic = "abcdefghijklmnopqrstuvwxyz";
byte[] licenseKey = Encoding.UTF8.GetBytes(lic);
ElGamalKeyStruct key = new ElGamalKeyStruct();
key.P = new BigInteger(123567890);
key.G = new BigInteger(1234567890);
key.Y = new BigInteger(1234567890);
key.X = new BigInteger(0); //zero
byte[] signature = CreateSignature(licenseKey, key);
bool verified = VerifySignature(licenseKey, signature, key);
The VerifySignature always returns false.

P must be prime. See here (that is the ebook from which the code you use was taken):
Create a random prime number, p. This number is the ElGamal "modulus." The number of bits required to represent p is the size of the public key, so that if p is represented using 1024 bits, then the key created by following the protocol is a 1024-bit key. We will select 607 as our example value.
If you look in the text then there is code to generate El Gamal keys (the CreateKeyPair() method)

Related

Why does my RSA signing implementation work on some messages, but not on others?

I am trying to implement a simple RSA signature algorithm in C#, by only using BigInteger, and no built-in crypto tools. To sign a message, I encrypt it with the private key, and to verify it, I decrypt it with the public key. In the code below, I have noticed a very strange behavior. For some input strings, (e.g. "Test"), it successfully validates the signature, but for other strings (e.g. "Test1"), it fails.
What I've noticed is, that it only fails, when the m variable (the hash of the message) is a negative number, and this causes the decrypted ver variable to become an extremely large number and the code prints 'Wrong Signature'.
// Generating RSA keys
var random = new Random();
var p = new BigInteger(256, 100, random);
var q = new BigInteger(256, 100, random);
var n = p.Multiply(q);
var phi = p.Subtract(BigInteger.One).Multiply(q.Subtract(BigInteger.One));
var e = new BigInteger("65537");
var d = e.ModInverse(phi);
// Preparing the message
var messageHash = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes("Test"));
var m = new BigInteger(messageHash);
// Signing the message
var signature = m.ModPow(d, n);
// Verifying the message
var ver = signature.ModPow(e, n);
Console.Out.WriteLine(m);
Console.Out.WriteLine(ver);
if(ver.Equals(m))
Console.Out.WriteLine("Valid Signature");
else
Console.Out.WriteLine("Wrong Signature");
I'm using BouncyCastle for the BigInteger type.
Example output for the message "Test":
16928957987407306249184430693954511195
16928957987407306249184430693954511195
Valid Signature
Example output for the message "Test1":
-40249184872970767997805928798048797124
10061048024793920770364189111057222210443355984675629704584018449091407182950576678391694061743052292040531884029654111183675927763342349593675935744009443
Wrong Signature
I believe that the error is somewhere in the signing process, and not in the verification. Maybe I shouldn't try to encrypt negative numbers? What should I do if the hash is negative? How can I fix this code so it works reliably on any input string?
#Topaco helped me solve my problem.
The RSA algorithm requires 0 <= m < n for a message m and modulus n, here . To prevent negative numbers, var m = new BigInteger(1, messageHash); could be used, which creates the corresponding unsigned value instead of the signed value

Use public key in RSA algorithm

I have desktop C# code (console, wpf etc) which generate key from base64 string and encrypt by it.
string b64Key = "";
byte[] decoded = Convert.FromBase64String(b64Key);
int modLength = BitConverter.ToInt32(decoded.Take(4).Reverse().ToArray(), 0);
byte[] mod = decoded.Skip(4).Take(modLength).ToArray();
int expLength = BitConverter.ToInt32(decoded.Skip(modLength + 4).Take(4).Reverse().ToArray(), 0);
byte[] exponent = decoded.Skip(modLength + 8).Take(expLength).ToArray();
RSAParameters key = new RSAParameters();
key.Modulus = mod;
key.Exponent = exponent;
var provider = new RSACryptoServiceProvider();
provider.ImportParameters(key);
var encrypted = provider.Encrypt(Encoding.UTF8.GetBytes("string"), true);
I must reuse this part of code for UWP project.
I tried many ways but every time I catch an exception when I am trying to import public key:
// try to use DESKTOP key for understanding
byte[] mod = key.Modulus;
byte[] exponent = key.Exponent;
// this method concat arrays
var buf = this.Combine(mod, exponent);
// try to create key buffer from array
IBuffer keyBuffer = CryptographicBuffer.CreateFromByteArray(buf);
// try to create key buffer from base64 string
keyBuffer = CryptographicBuffer.DecodeFromBase64String("base64 string");
var provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
var publicKey = provider.ImportPublicKey(keyBuffer, CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey);
// I tried all values in 'CryptographicPublicKeyBlobType' enum
var encryptData = CryptographicEngine.Encrypt(publicKey, CryptographicBuffer.ConvertStringToBinary("string", BinaryStringEncoding.Utf8), null);
How can I import key correctly for the UWP project?
Thanks!
At the first - I have only correct modulus and all. My base64 string is not correct public key (key in this string but there are a lot of other items).
After that I found only one right way to generate public key from modulus and exponent -> combine them. But I was still had exception. After that I tried to generate default key and change modulus part in it -> and it worked!
var provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaOaepSha1);
// create custom (random) key with size '1024'
var standardKeyPair = provider.CreateKeyPair(1024);
// export publick key to this default key
var standardBuffer = standardKeyPair.ExportPublicKey(CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey);
// copy it to bytes array
byte[] standardKey;
CryptographicBuffer.CopyToByteArray(standardBuffer, out standardKey);
// change part of the key to our modules
// I DON'T KNOW WHY, but starndart key has 7 bytes in prefix and 5 in suffix (nail)
// we have 128 bytes in modulus and 140 in default key -> so we must make 140 bytes from our modulus
Array.Copy(modulus, 0, standardKey, 7, modulus.Length);

RSA Public exponent defaults to 65537. What should this value be? What are the impacts of my choices?

I'm creating unit tests for software that may encounter different exponent sizes. (see section 3.3.1 of this RFC)
How can I use Bouncy Castle, or any other C# library to generate a RSA key pair that doesn't have a key size of 65537.
If the answer is that I can directly modify this, as long as I update the private key as well, what specific changes (or re-computation) should I make for the public and private key?
Here is the sample code that I'm using to create the key with the exponent of 65537:
// Create key
RsaKeyPairGenerator generator = new RsaKeyPairGenerator();
var param = new KeyGenerationParameters(new SecureRandom(), 1024);
generator.Init(param);
AsymmetricCipherKeyPair keyPair= generator.GenerateKeyPair();
// Save to export format
SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public);
byte[] ret = info.GetEncoded();
string ovalue1 = Convert.ToBase64String(ret);
// Read from export format
byte[] publicKeyBytes = Convert.FromBase64String(ovalue1);
AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(publicKeyBytes);
RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
RSAParameters rsaParameters = new RSAParameters();
rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArray();
rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArray();
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParameters);
Thanks to #BrettHale I was able to solve the issue.
This is how to create a key pair in Bouncy Castle
// Create key
RsaKeyPairGenerator generator = new RsaKeyPairGenerator();
/*
* This value should be a Fermat number. 0x10001 (F4) is current recommended value. 3 (F1) is known to be safe also.
* 3, 5, 17, 257, 65537, 4294967297, 18446744073709551617,
*
* Practically speaking, Windows does not tolerate public exponents which do not fit in a 32-bit unsigned integer. Using e=3 or e=65537 works "everywhere".
*/
BigInteger exponentBigInt = new BigInteger(exponent.ToString());
var param = new RsaKeyGenerationParameters(
exponentBigInt, // new BigInteger("10001", 16) publicExponent
new SecureRandom(), // SecureRandom.getInstance("SHA1PRNG"),//prng
keyStrength, //strength
certaninty);//certainty
generator.Init(param);
Additional links that relate to his recommendation to use RSAKeyGenerationParameters include:
Why is exponent value 65537 used, what are the alternatives and impacts?
What is certainty, and what is the correct value for this (hint: it depends on key length)

Encrypt a number to another number of the same length

I need a way to take a 12 digit number and encrypt it to a different 12 digit number (no characters other than 0123456789). Then at a later point I need to be able to decrypt the encrypted number back to the original number.
It is important that it isn't obvious if 2 encrypted numbers are in order. So for instance if I encrypt 0000000000001 it should look totally different when encrypted than 000000000002. It doesn't have to be the most secure thing in the world, but the more secure the better.
I've been looking around a lot but haven't found anything that seems to be a perfect fit. From what I've seen some type of XOR might be the easiest way to go, but I'm not sure how to do this.
Thanks,
Jim
I ended up solving this thanks to you guys using "FPE from a prefix cipher" from the wikipedia page http://en.wikipedia.org/wiki/Format-preserving_encryption. I'll give the basic steps below to hopefully be helpful for someone in the future.
NOTE - I'm sure any expert will tell you this is a hack. The numbers seemed random and it was secure enough for what I needed, but if security is a big concern use something else. I'm sure experts can point to holes in what I did. My only goal for posting this is because I would have found it useful when doing my search for an answer to the problem. Also only use this in situations where it couldn't be decompiled.
I was going to post steps, but its too much to explain. I'll just post my code. This is my proof of concept code I still need to clean up, but you'll get the idea. Note my code is specific to a 12 digit number, but adjusting for others should be easy. Max is probably 16 with the way I did it.
public static string DoEncrypt(string unencryptedString)
{
string encryptedString = "";
unencryptedString = new string(unencryptedString.ToCharArray().Reverse().ToArray());
foreach (char character in unencryptedString.ToCharArray())
{
string randomizationSeed = (encryptedString.Length > 0) ? unencryptedString.Substring(0, encryptedString.Length) : "";
encryptedString += GetRandomSubstitutionArray(randomizationSeed)[int.Parse(character.ToString())];
}
return Shuffle(encryptedString);
}
public static string DoDecrypt(string encryptedString)
{
// Unshuffle the string first to make processing easier.
encryptedString = Unshuffle(encryptedString);
string unencryptedString = "";
foreach (char character in encryptedString.ToCharArray().ToArray())
unencryptedString += GetRandomSubstitutionArray(unencryptedString).IndexOf(int.Parse(character.ToString()));
// Reverse string since encrypted string was reversed while processing.
return new string(unencryptedString.ToCharArray().Reverse().ToArray());
}
private static string Shuffle(string unshuffled)
{
char[] unshuffledCharacters = unshuffled.ToCharArray();
char[] shuffledCharacters = new char[12];
shuffledCharacters[0] = unshuffledCharacters[2];
shuffledCharacters[1] = unshuffledCharacters[7];
shuffledCharacters[2] = unshuffledCharacters[10];
shuffledCharacters[3] = unshuffledCharacters[5];
shuffledCharacters[4] = unshuffledCharacters[3];
shuffledCharacters[5] = unshuffledCharacters[1];
shuffledCharacters[6] = unshuffledCharacters[0];
shuffledCharacters[7] = unshuffledCharacters[4];
shuffledCharacters[8] = unshuffledCharacters[8];
shuffledCharacters[9] = unshuffledCharacters[11];
shuffledCharacters[10] = unshuffledCharacters[6];
shuffledCharacters[11] = unshuffledCharacters[9];
return new string(shuffledCharacters);
}
private static string Unshuffle(string shuffled)
{
char[] shuffledCharacters = shuffled.ToCharArray();
char[] unshuffledCharacters = new char[12];
unshuffledCharacters[0] = shuffledCharacters[6];
unshuffledCharacters[1] = shuffledCharacters[5];
unshuffledCharacters[2] = shuffledCharacters[0];
unshuffledCharacters[3] = shuffledCharacters[4];
unshuffledCharacters[4] = shuffledCharacters[7];
unshuffledCharacters[5] = shuffledCharacters[3];
unshuffledCharacters[6] = shuffledCharacters[10];
unshuffledCharacters[7] = shuffledCharacters[1];
unshuffledCharacters[8] = shuffledCharacters[8];
unshuffledCharacters[9] = shuffledCharacters[11];
unshuffledCharacters[10] = shuffledCharacters[2];
unshuffledCharacters[11] = shuffledCharacters[9];
return new string(unshuffledCharacters);
}
public static string DoPrefixCipherEncrypt(string strIn, byte[] btKey)
{
if (strIn.Length < 1)
return strIn;
// Convert the input string to a byte array
byte[] btToEncrypt = System.Text.Encoding.Unicode.GetBytes(strIn);
RijndaelManaged cryptoRijndael = new RijndaelManaged();
cryptoRijndael.Mode =
CipherMode.ECB;//Doesn't require Initialization Vector
cryptoRijndael.Padding =
PaddingMode.PKCS7;
// Create a key (No IV needed because we are using ECB mode)
ASCIIEncoding textConverter = new ASCIIEncoding();
// Get an encryptor
ICryptoTransform ictEncryptor = cryptoRijndael.CreateEncryptor(btKey, null);
// Encrypt the data...
MemoryStream msEncrypt = new MemoryStream();
CryptoStream csEncrypt = new CryptoStream(msEncrypt, ictEncryptor, CryptoStreamMode.Write);
// Write all data to the crypto stream to encrypt it
csEncrypt.Write(btToEncrypt, 0, btToEncrypt.Length);
csEncrypt.Close();
//flush, close, dispose
// Get the encrypted array of bytes
byte[] btEncrypted = msEncrypt.ToArray();
// Convert the resulting encrypted byte array to string for return
return (Convert.ToBase64String(btEncrypted));
}
private static List<int> GetRandomSubstitutionArray(string number)
{
// Pad number as needed to achieve longer key length and seed more randomly.
// NOTE I didn't want to make the code here available and it would take too longer to clean, so I'll tell you what I did. I basically took every number seed that was passed in and prefixed it and postfixed it with some values to make it 16 characters long and to get a more unique result. For example:
// if (number.Length = 15)
// number = "Y" + number;
// if (number.Length = 14)
// number = "7" + number + "z";
// etc - hey I already said this is a hack ;)
// We pass in the current number as the password to an AES encryption of each of the
// digits 0 - 9. This returns us a set of values that we can then sort and get a
// random order for the digits based on the current state of the number.
Dictionary<string, int> prefixCipherResults = new Dictionary<string, int>();
for (int ndx = 0; ndx < 10; ndx++)
prefixCipherResults.Add(DoPrefixCipherEncrypt(ndx.ToString(), Encoding.UTF8.GetBytes(number)), ndx);
// Order the results and loop through to build your int array.
List<int> group = new List<int>();
foreach (string key in prefixCipherResults.Keys.OrderBy(k => k))
group.Add(prefixCipherResults[key]);
return group;
}
One more way for simple encryption, you can just substruct each number from 10.
For example
initial numbers: 123456
10-1 = 9
10-2 = 8
10-3 = 7
etc.
and you will get
987654
You can combine it with XOR for more secure encryption.
What you're talking about is kinda like a one-time pad. A key the same length as the plaintext and then doing some modulo math on each individual character.
A xor B = C
C xor B = A
or in other words
A xor B xor B = A
As long as you don't use the same key B on multiple different inputs (e.g. B has to be unique, every single time you encrypt), then in theory you can never recover the original A without knowing what B was. If you use the same B multiple times, then all bets are off.
comment followup:
You shouldn't end up with more bits aftewards than you started with. xor just flips bits, it doesn't have any carry functionality. Ending up with 6 digits is just odd... As for code:
$plaintext = array(digit1, digit2, digit3, digit4, digit5, digit6);
$key = array(key1, key2, key3, key4, key5, key6);
$ciphertext = array()
# encryption
foreach($plaintext as $idx => $char) {
$ciphertext[$idx] = $char xor $key[$idx];
}
# decryption
foreach($ciphertext as $idx => $char) {
$decrypted[$idx] = $char xor $key[$idx];
}
Just doing this as an array for simplicity. For actual data you'd work on a per-byte or per-word basis, and just xor each chunk in sequence. You can use a key string shorter than the input, but that makes it easier to reverse engineer the key. In theory, you could use a single byte to do the xor'ing, but then you've just basically achieved the bit-level equivalent of rot-13.
For example you can add digits of your number with digits some const (214354178963...whatever) and apply "~" operator (reverse all bits) this is not safely but ensure you can decrypt your number allways.
anyone with reflector or ildasm will be able to hack such an encryption algorithm.
I don't know what is your business requirement but you have to know that.
If there's enough wriggle-room in the requirements that you can accept 16 hexadecimal digits as the encrypted side, just interpret the 12 digit decimal number as a 64bit plaintext and use a 64 bit block cipher like Blowfish, Triple-DES or IDEA.

Generate random RSA keys with RSACryptoServiceProvider

How do I generate random RSA public and private keys (RSAParameters) using RSACryptoServiceProvider class?
Each time I create a new instance of RSACryptoServiceProvider, I end up exporting the same keys.
Thanks
I did some test on the following code, and the exported parameters are always different:
var rsaAlgo1 = new RSACryptoServiceProvider();
var rsaAlgo2 = new RSACryptoServiceProvider();
var xml1 = rsaAlgo1.ToXmlString(true);
var xml2 = rsaAlgo2.ToXmlString(true);
if (xml1 != xml2)
{
// it always goes here...
}
Using the following code you should never get all the same keys out
var rsa = new RSACryptoServiceProvider();
var rsaParams = rsa.ExportParameters(true);
However you should note that the Exponent key can be the same and if often is 65537(0x010001)
"Choose an integer e such that 1 < e < φ(n) and gcd(e, φ(n)) = 1; i.e., e and φ(n) are coprime.
e is released as the public key exponent.
e having a short bit-length and small Hamming weight results in more efficient encryption – most commonly 216 + 1 = 65,537. However, much smaller values of e (such as 3) have been shown to be less secure in some settings."
RSA wiki

Categories