How to split 3DES key and calculate KCV in C#? - c#

I have a 128 bit 3DES key 1915372928A30803A25B0659A4DD6525, how could I split the key into 3 components and calculate the KCV for each component? I'd like to do similarly to the online tool below
https://www.emvlab.org/keyshares/?combined=1915372928A30803A25B0659A4DD6525&combined_kcv=2082A4&one=B9FFAF926385DBED0FBC087F5DC674C3&one_kcv=C69561&two=EA3CD5B063E0BF73F6C5ECB5F7D32080&two_kcv=33D908&three=4AD64D0B28C66C9D5B22E2930EC83166&three_kcv=03DCA8&numcomp=three&parity=ignore&action=Generate+128+bit
The code i used to generate 3DES key
public byte[] GenerateThreeDesKey()
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] tripleDesKey = new byte[16];
rng.GetBytes(tripleDesKey);
for (var i = 0; i < tripleDesKey.Length; ++i)
{
int keyByte = tripleDesKey[i] & 0xFE;
var parity = 0;
for (int b = keyByte; b != 0; b >>= 1)
parity ^= b & 1;
tripleDesKey[i] = (byte)(keyByte | (parity == 0 ? 1 : 0));
}
return tripleDesKey;
}
After getting the key, how to split the key into 3 components and calculate the KCV?

Generate two separate DES 128 bit keys the same way as you are doing now, these are components 1 and 2. Then XOR these keys together with your current (master key). The result is the third component. You can adjust the parity of that key as well if you want.
To calculate the KCV's, simply use the generated components to encrypt a block of 8 bytes set to zero. You can use ECB mode or CBC mode (without padding) if a direct block encrypt is not available. For CBC you need to set the IV to all zeros as well. Then take the leftmost bytes of the result and encode as hexadecimals.

1- to calculate the KCV you have to encrypt 16 bytes of zero's with generated key
(data: 00000000000000000000000000000000, key: 404142434445464748494A4B4C4D4E4F) = 8BAF473F2F8FD0948BAF473F2F8FD094 (last three bytes is KCV (8BAF47))
2- to split key into 3 component
Start with the Key 404142434445464748494A4B4C4D4E4F
create 2 random number of the same length (16 bytes in this example):
Rand 1 : 988A59D7273186B8C9C9922B6D40BA75 and Rand 2: 8936E5269ADFABE7D4829B2EFB3BF5D9
(the random numbers will become Component1 and Component2)
now XOR the 3 numbers. i.e. XOR Key1, Component1 and Component2 together:
XOR(0123456789ABCDEFFEDCBA9876543210, 988A59D7273186B8C9C9922B6D40BA75, 8936E5269ADFABE7D4829B2EFB3BF5D9) = 109FF9963445E0B0E397B39DE02F7DBC (the result will be key Component3)

Related

Generate a unique, random friend code from a user ID algorithmically

I am looking for a way to generate a random, unique 9 digit friend code for a user from a sequential user ID. The idea behind this is so people can't enumerate users by searching the friend codes one by one. If there are 1000 possible codes and 100 registered users, searching a random code should have a 10% chance of finding a user.
A possible way to do this is to generate a code randomly, check if the code is already in use, and if it is, try again. I am looking for an approach (mostly out of curiosity) where the friend code is generated algorithmically and is guarenteed to be unique for that user ID first try.
Specifically, given a range of numbers (1 to 999,999,999), running the function on this number should return another number in the same range, which is paired and unique to the input number. This pairing should only differ if the range changes and/or an input seed to the randomness changes.
An individual should ideally not be able to easily reverse engineer the user ID from the friend ID without knowing the seed and algorithm (or having a very large pool of samples and a lot of time - this does not need to be cryptographically secure), so simply subtracting the user ID from the maximum range is not a valid solution.
Here is some c# code that accomplishes what I am after by generating the entire range of numbers, shuffling the list, then retrieving a friend ID by treating the user ID as the list index:
int start = 1; // Starting number (inclusive)
int end = 999999999; // End number (inclusive)
Random random = new Random(23094823); // Random with a given seed
var friendCodeList = new List<int>();
friendCodeList.AddRange(Enumerable.Range(start, end + 1)); // Populate list
int n = friendCodeList.Count;
// Shuffle the list, this should be the same for a given start, end and seed
while (n > 1)
{
n--;
int k = random.Next(n + 1);
int value = friendCodeList[k];
friendCodeList[k] = friendCodeList[n];
friendCodeList[n] = value;
}
// Retrieve friend codes from the list
var userId = 1;
Console.WriteLine($"User ID {userId}: {friendCodeList[userId]:000,000,000}");
userId = 99999999;
Console.WriteLine($"User ID {userId}: {friendCodeList[userId]:000,000,000}");
userId = 123456;
Console.WriteLine($"User ID {userId}: {friendCodeList[userId]:000,000,000}");
User ID 1: 054,677,867
User ID 99999999: 237,969,637
User ID 123456: 822,632,399
Unfortunately, this is unsuitable for large ranges - this program takes 8GB of RAM to run, with a 10 or 12 digit friend code it would not be feasible to pre-generate the list either in memory or a database. I am looking for a solution that does not require this pre-generation step.
I am interested in solutions that use either a seeded random number generator or bitwise trickery to achieve this, if it is possible. The above function is reversible (by searching the values of the list) but the solution does not need to be.
Quick mathematics lesson!
You're thinking of developing a way to map one integer value (the original "secret" UserId value) to another (the (encrypted) "public" value) and back again. This is exactly what a block-cipher does (except each "block" is usually 16 bytes big instead of being a single character or integer value). So in other words, you want to create your own cryptosystem.
(Note that even if you're thinking of converting UserId 123 into a string instead of an integer, for example, a YouTube Video Id like "dQw4w9WgXcQ") - it's still an integer: because every scalar value stored in a computer, including strings, can be represented as an integer - hence the "illegal primes" problem back in the late-1990s).
And the biggest, most important take-away from any undergraduate-level computer-science class on cryptography is never create your own cryptosystem!.
With that out of the way...
Provided that security is not a top-concern...
...and you're only concerned with preventing disclosure of incrementing integer Id values (e.g. so your visitors and users don't see how many database records you really have) then use a Hashids library: https://hashids.org/
For .NET, use this NuGet package: https://www.nuget.org/packages/Hashids.net/
Overview for .NET: https://hashids.org/net/
Project page: https://github.com/ullmark/hashids.net
In your code, construct a single Hashids object (I'd use a public static readonly field or property - or better yet: a singleton injectable service) and use the .Encode method to convert any integer int/Int32 value into a string value.
To convert the string value back to the original int/Int32, use the .Decode method.
As an aside, I don't like how the library is called "Hashids" when hashes are meant to be one-way functions - because the values are still reversible - albeit by using a secret "salt" value (why isn't it called a "key"?) it isn't really a hash, imo.
If security really matters...
Then you need to treat each integer value as a discrete block in a block cipher (not a stream-cipher, because each value needs to be encrypted and decrypted independently by itself).
For the purposes of practicality, you need to use a symmetric block cipher with a small block-size. Unfortunately many block ciphers with small block sizes aren't very good (TripleDES has a block size of 64-bits - but it's weak today), so let's stick with AES.
AES has a block-size of 128 bits (16 bytes) - that's the same as two Int64 integers concatenated with each other. Assuming you use base64url encoding on a 16-byte value then your output will be 22 characters long (as Base64 uses 6 bits per character). If you're comfortable with strings of this length then you're all set. The shortest URL-safe string you can generate from a 128-bit value is 21 (hardly an improvement at all) because Base-73 is the most you can safely use in a URL that will survive all modern URL-transmission systems (never automatically assume Unicode is supported anywhere when dealing with plaintext).
It is possible to adapt AES to generate smaller output block-sizes, but it won't work in this case because using techniques like CTR Mode mean that the generated output needs to include extra state information (IV, counter, etc) which will end-up taking up the same amount of space as was gained.
Here's the code:
Very important notes:
This uses CBC Mode - which means the same input results in the same output (that's required by-design!). CBC is useful when encrypting blocks independently.
This re-uses the same IV - this is intentional and actually desirable for this application - but generally speaking do not reuse IVs when using AES for any other purpose and make sure you understand what you're doing.
*
private static readonly Byte[] _key = new Byte[] { }. // Must be 128, 192 or 256 bits (16, 24, or 32 bytes) in length.
private static readonly Byte[] _iv = new Byte[8]; // You could use the default all-zeroes.
// Note that this method works with Int32 arguments.
private static Byte[] ProcessBlock( Byte[] inputBlock, Boolean encrypt )
{
Byte[] outputBlock;
using( Aes aes = Aes.Create() )
{
aes.Key = _key;
aes.IV = _iv;
using( ICryptoTransform xform = encrypt ? aes.CreateEncryptor() : aes.CreateDecryptor() )
{
outputBlock = xform.TransformFinalBlock( inputBlock, 0, inputBlock.Length );
}
}
}
public static Byte[] EncryptInteger( Int64 value )
{
Byte[] inputBlock = new Byte[16];
inputBlock[0] = (Byte)(value >> 0 & 0xFF);
inputBlock[1] = (Byte)(value >> 8 & 0xFF);
inputBlock[2] = (Byte)(value >> 16 & 0xFF);
inputBlock[3] = (Byte)(value >> 24 & 0xFF);
inputBlock[4] = (Byte)(value >> 32 & 0xFF);
inputBlock[5] = (Byte)(value >> 40 & 0xFF);
inputBlock[6] = (Byte)(value >> 48 & 0xFF);
inputBlock[7] = (Byte)(value >> 56 & 0xFF);
return ProcessBlock( inputBlock, encrypt: true );
}
public static Int64 DecryptInteger( Byte[] block )
{
Byte[] outputBlock = ProcessInteger( value, encrypt: false );
return
(Int64)outputBlock[0] << 0 |
(Int64)outputBlock[1] << 8 |
(Int64)outputBlock[2] << 16 |
(Int64)outputBlock[3] << 24 |
(Int64)outputBlock[4] << 32 |
(Int64)outputBlock[5] << 40 |
(Int64)outputBlock[6] << 48 |
(Int64)outputBlock[7] << 56;
};
public static String EncryptIntegerToString( Int64 value ) => Convert.ToBase64String( EncryptInteger( value ) ).Replace( '+', '-' ).Replace( '/', '_' );
public static Int64 DecryptIntegerFromString( String base64Url )
{
if( String.IsNullOrWhiteSpace( base64Url ) ) throw new ArgumentException( message: "Invalid string.", paramName: nameof(base64Url) );
// Convert Base64Url to Base64:
String base64 = base64Url.Replace( '-', '+' ).Replace( '_', '/' );
Byte[] block = Convert.FromBase64String( base64 );
return DecryptInteger( block );
}
A simple method like this can produce a long sequence of numbers provided you get the constants right.
ulong Next(ulong current)
{
unchecked
{
return (999_999_937L * current + 383_565_383L) % 999_999_999L;
}
};
From memory, this kind of function can produce a sequence of 999_999_999 digits if the values in the function are chosen correctly.
My test code shows that this method can produce 500_499 numbers without repeating.
My computer can produce the entire sequence in just under 9 milliseconds so it is a fairly fast algorithm.
The first ten elements of this sequence (with leading '0's padded) is:
383565383, 602511613, 027845340, 657154301, 639998680, 703647183, 757439993, 422285770, 201847617, 869013116
5_960_464 * current + 383_565_383L gives a sequence length of 1_000_998 before repetition.

Raw RSA encryption (aka ECB/NoPadding) under .NET?

I consider feasibility and performance under .NET (using C#) of the verification part of a standard RSA signature scheme that is not directly supported. Towards that goals, I need the raw RSA public-key encryption function x → (x65537) mod N (where x is a byte array as wide as the public modulus N is, like 256 bytes).
On other platforms, the standard technique is to implement that function using RSA encryption with no padding (Java's Cipher with "RSA/ECB/NoPadding"). But I can't find how to perform this under .NET. What are my options?
.NET doesn't provide this functionality inbox. If you're just doing public key operations then you can use the BigInteger class without having security liabilities. (Don't use it for private key operations, because a) it'll have your private key fairly obviously in memory and b) it doesn't have a Montgomery Ladder based ModPow, so it would leak the Hamming Weight of your private key)
RSA existingKey = HoweverYouWereGettingAKey();
RSAParameters rsaParams = existingKey.ExportParameters(false);
BigInteger n = PrepareBigInteger(rsaParams.Modulus);
BigInteger e = PrepareBigInteger(rsaParams.Exponent);
BigInteger sig = PrepareBigInteger(signature);
BigInteger paddedMsgVal = BigInteger.ModPow(sig, e, n);
byte[] paddedMsg = paddedMsgVal.ToArray();
if (paddedMsg[paddedMsg.Length - 1] == 0)
{
Array.Resize(ref paddedMsg, paddedMsg.Length - 1);
}
Array.Reverse(paddedMsg);
// paddedMsg is now ready.
private static BigInteger PrepareBigInteger(byte[] unsignedBigEndian)
{
// Leave an extra 0x00 byte so that the sign bit is clear
byte[] tmp = new byte[unsignedBigEndian.Length + 1];
Buffer.BlockCopy(unsignedBigEndian, 0, tmp, 1, unsignedBigInteger.Length);
Array.Reverse(tmp);
return new BigInteger(tmp);
}

trying to implement Speck32/64 block Cipher

I am trying to implement Speck 32/64 block Cipher in c# I'm stuck at encryption decryption algorithm. i know that i should split the plain text in to 2 word according to algorithm
x,y = plaintext words
--------------------------- key expansion --------------------------
for i = 0..T-2
[i+m-1] ← (k[i] + S−α
[i]) ⊕ i
k[i+1] ← S
β k[i] ⊕ `[i+m-1]
end for
---------------------------- encryption ----------------------------
for i = 0..T-1
x ← (S−α x + y) ⊕ k[i]
y ← S
βy ⊕ x
end for
References
The SIMON and SPECK Families of Lightweight Block Ciphers
https://eprint.iacr.org/2013/404
my question is the plaintext should be string then i convert to binary or what and use it in the above algo?
the algorithm didnot say the type of plaintext and there is example encryption
Key: 1918 1110 0908 0100
Plaintext: 6574 694c
Ciphertext: a868 42f2
SPECK 32/64 cipher expects 4 bytes as the input.
Plaintext: 6574 694c
means
byte[] plaintext = new byte[] {0x65, 0x74, 0x69, 0x4C};
where each byte is specified as hexadecimal value using the 0x prefix.
You will divide the plaintext in the first step:
byte[] x = new byte[] {plaintext[0], plaintext[1]};
byte[] y = new byte[] {plaintext[2], plaintext[3]};
Note: use some more clever array manipulation to speed up your cipher, the example above is for educational purposes only.
Note 2: handling input as a uint might be a good approach, it could be much faster than arrays with a little of bitwise magic:
uint plaintext = 0x6574694C;
ushort x = (ushort) (plaintext >> 16);
ushort y = (ushort) plaintext;

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.

Why RSA encryption can return different results with C# and Java?

I using:
c#: RSACryptoServiceProvider
JAVA: KeyFactory.getInstance("RSA")+Cipher
I sending public key (exponent + modulus) as byte array from java to c#. It's ok, there is the same bytes. But when i try to encrypt some data with one key in Java and c# - there is different results.
Java Key Generation:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize( Config.CRYPTO_KEY_NUM_BITS );
m_KeyPair = keyGen.genKeyPair();
m_PublicKey = KeyFactory.getInstance("RSA").generatePublic(
newX509EncodedKeySpec(m_KeyPair.getPublic().getEncoded()));
byte[] exponent = m_PublicKey.getPublicExponent().toByteArray();
byte[] modulus = m_PublicKey.getModulus().toByteArray(); // then sending...
C# Key Recieve:
// Recieved...
m_ExternKey = new RSAParameters();
m_ExternKey.Exponent = exponent;
m_ExternKey.Modulus = modulus;
m_RsaExtern = new RSACryptoServiceProvider();
m_RsaExtern.ImportParameters(m_ExternKey);
byte[] test = m_RsaExtern.Encrypt(bytesToEncrypt, true);
and problem is that encrypted bytes is different.
Thank you.
RSA encryption is randomized. For a given public key and a given message, each attempt at encryption yields a distinct sequence of bytes. This is normal and expected; random bytes are injected as part of the padding phase, and not injecting random bytes would result in a weak encryption system. During decryption, the padding bytes are located and removed, and the original message is recovered unscathed.
Hence it is expected that you will get distinct encrypted messages with Java and C#, but also if you run your Java or C# code twice.
RSA Encription mustn't return diffferent values with simular keys - its standardized algorithm. Check your keys.
RSA Parameters contains more parameters than modulus and exponent if i remember correctly. You need fully initialized rsa parameters to get the encryption correct (in .net).
Moreover, your private and private key is not even set in .net
i hope this is helpful , in C# lough code
byte[] rsaExp = rsaParameters.Exponent.ToByteArray();
byte[] Modulus = rsaParameters.Modulus.ToByteArray();
// Microsoft RSAParameters modulo wants leading zero's removed so create new array with leading zero's removed
int Pos = 0;
for (int i = 0; i < Modulus.Length; i++)
{
if (Modulus[i] == 0)
{
Pos++;
}
else
{
break;
}
}
byte[] rsaMod = new byte[Modulus.Length - Pos];
Array.Copy(Modulus, Pos, rsaMod, 0, Modulus.Length - Pos);

Categories