I am new to RSA and Cryptography and i need to encrypt and decrypt data using RSA, I have a java program which generates a key pair and save them in a .key files with XML format (It is absolutely OK and it was tested by encrypting and decrypting data ), then I want to use them in .NET application , I am importing the keys to be used for encrypt and decrypt. The public key is OK and encryption getting done without problem but the private key Import fails with the following exception message
Bad data (CryptographicException.ThrowCryptogaphicException(Int32 hr))
This is the encoded public key:
<RSAKeyValue>
<Modulus>iFouk9viRs5dcvJCvDM1vXC4sBuSB9SPcdJhRyFLoNW/pka6MNAiu4cOksFRejiuM1ZswyJMy+ow
lmLflJ/XrfnUQxLwLp61oij4CrzHKl9jjHorqIA7uEQKY8RBiUjZ7kbO5nFaIWs1NWMVks8Srdhv
8pVd1sLKKUs66c/ndAk=</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
and this is the encoded public key:
<RSAKeyValue>
<Modulus>iFouk9viRs5dcvJCvDM1vXC4sBuSB9SPcdJhRyFLoNW/pka6MNAiu4cOksFRejiuM1ZswyJMy+ow
lmLflJ/XrfnUQxLwLp61oij4CrzHKl9jjHorqIA7uEQKY8RBiUjZ7kbO5nFaIWs1NWMVks8Srdhv
8pVd1sLKKUs66c/ndAk=</Modulus>
<Exponent>AQAB</Exponent>
<P>AO9WnDNOt9Xewnoy8KTed56Z+3Nfto6J8wCXKzX3LhuuiKNUBe8qFoinrteQJq/9NAEXnNCafxDW
ThIkr9GtMxE=</P>
<Q>AJHYMk0bOEGZlQbaJk3VDovvOJuRt5NI3WtXWl1v5VUW6aQQO3rV3+3GSN6Xa3hTKXtCVVL26Awy
OkDykUPjQXk=</Q>
<DP>KIHsJfLowlXVbIE6oWzVqg49tKU6bJ2Ed1Eeix+uuhisH5iU+ImTDsXynaFUKu0b5CNu8w9y+hKL
XB7BcydxQQ==</DP>
<DQ>di267NIersF1idzhZvY62FdbBmx4VaeYi+93sPkH2wA7CI+CsxF1Z6XhzETkd9bjaRaiLx0VgTR+
Eby8y0bt+Q==</DQ>
<InverseQ>HYF8gahVyzsz0IotzKI2Oh53sJMZWVxsvzkhqGlDtY1THFGZE5j8kl/UK0+FSN6yOYxBIuKNZ7om
MgLQEMK1PQ==</InverseQ>
<D>DERQvGyjxsr6DUVOS7AvvYNOmklgseOlpA/RQJz2ONoCC+uBBLM07LoRzZImymAfC+9SiZukXRQM
mvr6MlzPAm04NWyZNzbjhLvmn1gmvDclDZ9X9bhYp8MBftPWU5PFBALOjVpD+mlbI2lTYCugf6pJ
MHEMe17mNJ0eWCerfAE=</D>
</RSAKeyValue>
Please help me to understand what is happening and what's wrong with the private key.
this is the code that is working ok after solving the problem :
private String getPublicKeyXml(RSAPublicKey pk) throws UnsupportedEncodingException {
StringBuilder builder = new StringBuilder();
builder.append("<RSAKeyValue>\n");
byte[] m = pk.getModulus().toByteArray();
byte[] mm = stripLeadingZeros(m);
write(builder, "Modulus", mm);
write(builder, "Exponent", pk.getPublicExponent());
builder.append("</RSAKeyValue>");
return builder.toString();
}
private String getPrivateKeyXml(PrivateKey pk) throws UnsupportedEncodingException {
RSAPrivateCrtKey privKey = (RSAPrivateCrtKey) pk;
BigInteger n = privKey.getModulus();
BigInteger e = privKey.getPublicExponent();
BigInteger d = privKey.getPrivateExponent();
BigInteger p = privKey.getPrimeP();
BigInteger q = privKey.getPrimeQ();
BigInteger dp = privKey.getPrimeExponentP();
BigInteger dq = privKey.getPrimeExponentQ();
BigInteger inverseQ = privKey.getCrtCoefficient();
StringBuilder builder = new StringBuilder();
builder.append("<RSAKeyValue>\n");
write(builder, "Modulus", stripLeadingZeros(n.toByteArray()));
write(builder, "Exponent", stripLeadingZeros(e.toByteArray()));
write(builder, "P", stripLeadingZeros(p.toByteArray()));
write(builder, "Q", stripLeadingZeros(q.toByteArray()));
write(builder, "DP", stripLeadingZeros(dp.toByteArray()));
write(builder, "DQ", stripLeadingZeros(dq.toByteArray()));
write(builder, "InverseQ", stripLeadingZeros(inverseQ.toByteArray()));
write(builder, "D", stripLeadingZeros(d.toByteArray()));
builder.append("</RSAKeyValue>");
return builder.toString();
}
private void write(StringBuilder builder, String tag, byte[] bigInt) throws UnsupportedEncodingException {
builder.append("\t<");
builder.append(tag);
builder.append(">");
builder.append(encode(bigInt).trim());
builder.append("</");
builder.append(tag);
builder.append(">\n");
}
private void write(StringBuilder builder, String tag, BigInteger bigInt) throws UnsupportedEncodingException {
builder.append("\t<");
builder.append(tag);
builder.append(">");
builder.append(encode(bigInt));
builder.append("</");
builder.append(tag);
builder.append(">\n");
}
private static String encode(BigInteger bigInt) throws UnsupportedEncodingException {
return new String(new sun.misc.BASE64Encoder().encode(bigInt.toByteArray()));
}
private static String encode(byte[] bigInt) throws UnsupportedEncodingException {
return new String(new sun.misc.BASE64Encoder().encode(bigInt));
}
private byte[] stripLeadingZeros(byte[] a) {
int lastZero = -1;
for (int i = 0; i < a.length; i++) {
if (a[i] == 0) {
lastZero = i;
} else {
break;
}
}
lastZero++;
byte[] result = new byte[a.length - lastZero];
System.arraycopy(a, lastZero, result, 0, result.length);
return result;
}
The public key is OK and encryption getting done without problem but the private key Import fails with the following exception message
Bad data (CryptographicException.ThrowCryptogaphicException(Int32 hr))
Take a look at Cryptographic Interoperability: Keys under "Common Errors" sections. The ones that still remain engrained in my mind:
Wrong KeyNumber or KeyUsage
Wrong Cryptographic Service Provider
Correct Cryptographic Service Provider, wrong ProviderType
Cryptographic Service Provider does not support the key size
Leaging 0's in the byte array such that the array has one too many octets
Related
I’m encrypting sensitive data using the C# AES class, Aes.Create() method before saving to an SQLite DB. My base round trip is:
*Saving/retrieving each Byte[ ] without converting threw “The specified key is not a valid size for this algorithm.” when decrypting.
The process leverages the MSDN example and is working well:
I’m concerned, however, that cipher, key & IV values must all be stored/retrieved together and am attempting to disguise the values stored in the DB. I’ve tried three procedures to disguise/revert the relevant string values. Unfortunately adding a disguise/revert procedure throws the following error when decrypting:
System.Security.Cryptography.CryptographicException
HResult=0x80131430 Message=Padding is invalid and cannot be removed.
Source=System.Core
I've tried:
switching from Aes.Create to AesManaged; result: no change
setting Padding = PaddingMode.None; result: threw "'System.Security.Cryptography.CryptographicException' occurred in mscorlib.dll 'Length of the data to encrypt is invalid.'"
setting Padding = PaddingMode.Zeros; result: ran with no error but round trips returned incorrect & unreadable values (see image):
A number of posts (of the many, most of the issues are base process round trip failures) in this forum regarding this error state that the Padding error can be thrown for a variety of reasons only one of which is actually a Padding error. One post ( Padding is invalid and cannot be removed?, 4th reply sorted by Trending) states:
If the same key and initialization vector are used for encoding and
decoding, this issue does not come from data decoding but from data
encoding.
Since my keys & IVs are the same this looked hopeful. However, as the above image implies if I'm interpreting it correctly, changing encoding doesn't seem to help.
Since my base processs by itself works I suspect my case fall into the "not really a Padding error" category.
The disguise/revert procedures
First procedure
Remove the “=” character(s) at the end of each string since it’s a blatant indicator of “something important”
Split cipher, key & IV strings based on a random number into two halves
Swap the two halves’ positions and insert unique random text of random length between the halves
Create a random length “reversion code” capturing randomized split indices and resultant string lengths
Second procedure: same as the first but leave “=” character(s) intact.
Third procedure
Split the random text of three different random length strings
“Wrap” them around the cipher, key & IV strings
Create the “reversion code”
For all three procedures: upon retrieval from the DB reverse the process using the “reversion code”. In the third procedure the original strings should, theoretically, be “untouched”.
In all three cases output indicates Original and Reverted are identical (single run testing output sample):
The disguise/revert code
Code for the third procedure since it probably has the greatest probability of working. The Encrypt & Decrypt methods are included in case they're relevant:
private static string _cipherText = "", _keyText = "", _vectorText = "";
// Prior to saving: third procedure
public static void SaveSensitivePrep(string input, bool parent)
{
input = "secretID";
Console.WriteLine($"\nOriginal: {input}");
string startString = default, extractor = default;
int disguiseLen = 0, startStringLen = 0, doneStringLen = 0;
for (int i = 0; i < 3; i++)
{
using (Aes toEncrypt = Aes.Create())
{
byte[] cypherBytes = Encrypt(input, toEncrypt.Key, toEncrypt.IV);
string cipherText = Convert.ToBase64String(cypherBytes);
string keyText = Convert.ToBase64String(toEncrypt.Key);
string vectorText = Convert.ToBase64String(toEncrypt.IV);
if (i == 0) _cipherText = startString = cipherText;
else if (i == 1) _keyText = startString = keyText;
else if (i == 2) _vectorText = startString = vectorText;
int disguiseSelector = new Random().Next(101);
string disguiseTxt = default;
List<Disguises> disguise_DB = DBconnect.Disguises_Load();
for (int c = 0; c < disguise_DB.Count; c++)
{
if (c == disguiseSelector) { disguiseTxt = disguise_DB[c].Linkages; break; }
}
disguiseLen = disguiseTxt.Length;
int disguiseSplitIndex = new Random().Next(10, 22);
string startTxt = disguiseTxt.Substring(0, disguiseSplitIndex);
string endTxt = disguiseTxt.Substring(disguiseSplitIndex);
string doneString = $"{startTxt}{startString}{endTxt}";
doneStringLen = doneString.Length;
extractor = $"{disguiseSplitIndex}{disguiseLen}{startStringLen}" +
$"{disguiseSelector + new Random().Next(5000000)}";
if (i == 0) DBconnect.Encrypted_Update_CT(Host, extractor, doneString);
else if (i == 1) DBconnect.Encrypted_Update_CK(Host, extractor, doneString);
else if (i == 2) DBconnect.Encrypted_Update_CV(Host, extractor, doneString);
}
}
}
// After retrieval: third procedure
public static string LoadSensitive(string input, bool parent)
{
string cipherText = "", keyText = "", vectorText = "";
for (int i = 0; i < 3; i++)
{
string extractor = "";
int disguiseLeft, disguiseRight;
List<EncryptedClass> host = DBconnect.Encrypted_Load(Host);
string doneString = "";
if (i == 0) { extractor = host[0].RCC; doneString = host[0].cipherText; }
else if (i == 1) { extractor = host[0].RCK; doneString = host[0].keyText; }
else if (i == 2) { extractor = host[0].RCV; doneString = host[0].vectorText; }
string disguiseSplitter = extractor.Substring(0, 2);
string disguiseLen_t = extractor.Substring(2, 2);
string startStringLen_t = extractor.Substring(4, 2);
int.TryParse(disguiseSplitter, out int indx);
int.TryParse(disguiseLen_t, out int disguiseLen);
int.TryParse(startStringLen_t, out int startStringLen);
disguiseRight = disguiseLen - indx;
disguiseLeft = disguiseLen - disguiseRight;
string e_extrctd = doneString.Substring(disguiseLeft, startStringLen);
if (i == 0) cipherTxt = revertedString;
else if (i == 1) keyTxt = revertedString;
else vectorTxt = revertedString;
}
byte[] cypher = Convert.FromBase64String(cipherText);
byte[] key = Convert.FromBase64String(keyText);
byte[] vector = Convert.FromBase64String(vectorText);
return Decrypt(cypher, key, vector);
}
static byte[] Encrypt(string input, byte[] key, byte[] iv)
{
// NULL/Length > 0 checks.
byte[] encrypted;
using (Aes input_e = Aes.Create())
{
input_e.Key = key;
input_e.IV = iv;
ICryptoTransform ict = input_e.CreateEncryptor(input_e.Key, input_e.IV);
using (MemoryStream msInput = new MemoryStream())
{
using (CryptoStream csInput = new CryptoStream(msInput, ict, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csInput))
{
swEncrypt.Write(input);
}
encrypted = msInput.ToArray();
}
}
}
return encrypted;
}
static string Decrypt(byte[] cipherText, byte[] keyText, byte[] vectorText)
{
// NULL/Length > 0 checks.
string roundtrip = null;
using (Aes output_e = Aes.Create())
{
output_e.Key = keyText;
output_e.IV = vectorText;
ICryptoTransform ict = output_e.CreateDecryptor(output_e.Key, output_e.IV);
using (MemoryStream msOutput = new MemoryStream(cipherText))
{
using (CryptoStream csOutput = new CryptoStream(msOutput, ict, CryptoStreamMode.Read))
{
using (StreamReader srOutput = new StreamReader(csOutput))
{
roundtrip = srOutput.ReadToEnd();
}
}
}
}
return roundtrip;
}
Any guidance on how/why the disguise/revert is getting deformed will be appreciated.
EDIT: scope clarification: the security functionality in this instance is for a Winforms/SQLite app which has an FTP component (WinSCP). The app's high level objective is a desktop tool streamlining TLS/SSL Certificate request/issuance via Let's Encrypt. The primary security objective is protecting FTP session credentials should an unauthorized & semi-knowledgeable person gain access to the DB. The secondary security objective is to keep it as simple as possible.
I have this binary content of file it's RSA public key generated with Java.
¬í sr java.math.BigIntegerŒüŸ©;û I bitCountI bitLengthI firstNonzeroByteNumI lowestSetBitI signum[ magnitudet [Bxr java.lang.Number†¬•”à‹ xpÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþ ur [B¬óøTà xp °^¾ùŠÖÂá}ÈþŽ–†ÁÃêsÀ»púŒaré…íè8NKŒ lH réöˆMj'cmQë>À?y‘Ǩj£ã<ʇ²ÞƒÕ4<Qga÷£#I“’[ØÜ€äºbwYòEûŸ1™àô©ñº…ýÙ£?³â+¶E #>ò̆ëÜ"nàú¾Ñt”²:r {
gÁ:ÿò¶ÌHZ`®âàtG;÷ŠzýIô÷c×ä5—Mx¾+Ë3Û#3>c¶jŒ GvbD¿SGI.˜ã;™sC¾ÝÇôôJ õ½-‹î”2ò÷…®‡¢ZƒtÃÑ#âÉÑ/|¹²5ñ’µZcxsq ~ ÿÿÿÿÿÿÿÿÿÿÿþÿÿÿþ uq ~ x
how to get Modulus and exponent from this content using c# and dotnet framework (not core).
Yes, It is a Java public key. I could not found any function to read this key and get thye RSAparameters.
I used this Java code to get the Modulus and exponenet with success. but when use it in c# to create public key I always get "Parameter Incorrect" on windows 2012 server.
Java Code
BigInteger modulo = null, exposant = null;
try {
ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(nomFichier)));
modulo = (BigInteger) ois.readObject();
exposant = (BigInteger) ois.readObject();
} catch(IOException e) {
System.err.println("Erreur lors de la lecture de la clé : " + e);
System.exit(-1);
} catch(ClassNotFoundException e) {
System.err.println("Fichier de clé incorrect : " + e);
System.exit(-1);
}
PublicKey clePublique = null;
try {
RSAPublicKeySpec specification = new RSAPublicKeySpec(modulo, exposant);
KeyFactory usine = KeyFactory.getInstance("RSA");
clePublique = usine.generatePublic(specification);
} catch(NoSuchAlgorithmException e) {
System.err.println("Algorithme RSA inconnu : " + e);
System.exit(-1);
} catch(InvalidKeySpecException e) {
System.err.println("Spécification incorrecte : " + e);
System.exit(-1);
}
return clePublique;
c# code
CspParameters parms = new CspParameters();
parms.Flags = CspProviderFlags.NoFlags;
parms.KeyContainerName = Guid.NewGuid().ToString().ToUpperInvariant();
parms.ProviderType = ((Environment.OSVersion.Version.Major > 5) || ((Environment.OSVersion.Version.Major == 5) && (Environment.OSVersion.Version.Minor >= 1))) ? 0x18 : 1;
// Modulus and Exponent are from Java
BigInteger modulusInt = BigInteger.Parse("22264662665581503581958564757951433642071042765180847835607911485241107337546440921333481060699040617948699619143852514883961242740412934026407809467632924273132875711353979878192151539324021302381664216461707890134565390428705286450284770084749935209949622966373476605854194876749604260497977835251836811598929536162941397609744200129752240619098969605506158549850626894587090735501922815967991426385372742427057780208805955531394006831299305270496208054419166650641070163691999735656859181256967560193451396805797552205282299420633106177676710034732661564145564177377055134205294304271572837276495701834203634424419");
BigInteger ExponentInt = BigInteger.Parse("65537");
csp = new RSACryptoServiceProvider(parms);
_publicKey = new RSAParameters();
_publicKey = csp.ExportParameters(false);
byte[] exponent = ExponentInt.ToByteArray();
byte[] modulus = modulusInt.ToByteArray();
_publicKey.Modulus = modulus;
_publicKey.Exponent = exponent;
csp.PersistKeyInCsp = true;
csp.ImportParameters(_publicKey);
byte[] token = csp.Encrypt(Convert.FromBase64String(txtPrivateKey.Text), true);
Could you please help me to read the binary Java key and import parameters to my RSA with c# (because the key every month will be changed).
this is Modulus and exponenet Base64
Modulus key: Y1q1kvE1srkafC/RyeJA0cN0GRqDWqKHrguF9/IylO6LLb31AEr0DvTHARl/3b5Dcw6ZO+OYLklHU79EYnZHCYxqtgtjPjMOI9sYM8srvnhNlzXk12P39En9eor3O0d04JDirmBaSMwBtoHy/zrBZyANe6ByOrKUdNG++uBuItwd64bM8j4RQBUgRbYr4rM/o9n9hbrxqfTgmTGf+0XyWRt3YrrkgNwX2FuSGpNJI6MR939hZ1E8NNWDj96yh8oDPOOjagKox5F5P4/APutRbWMnak2I9ulyIEhsCRiMS0446O2F6XJhF4z6cLvAc+rDwYaWAo7+yH3hwtaK+b5esAA=
Exponent key: AQAB
the error I got it on the Windows server 2012 R2 is from here
csp.ImportParameters(_publicKey);
this function work on Windows 10
I'm a newbie in jwt and after read a lot of web pages I've not found examples of how to generate a token (signed and encrypted) with keypairs generated from this website https://mkjwk.org/. I think it can't be very difficult. I think this is the way to generate the signed token (I don't know if it's correct):
RSACryptoServiceProvider rsaCrypto = new RSACryptoServiceProvider();
var payload = new Dictionary<string, object>()
{
{"jti", "ORIGEN_" + Guid.NewGuid().ToString()},
{"iat", DateTime.UtcNow},
{"exp", DateTime.UtcNow.AddYears(1)},
{"login", "USER" },
{"password", "PASSWORD" },
{"origen", "ORIGEN" }
};
// Contains both public and private keys to sign
var headers = new Dictionary<string, object>()
{
{ "kty", "RSA" },
{ "d", "A7Q8cttv_CSG4CJkX_xlU5lUoeRrCPZpyZx9eVaD7zi-tE7wDPKNmJPRP6uR_LA2YVXMmfY9w8q1_v_MiYxkYnFgZqNZlKdwucSQUlnfX5Tt806qh_323h5NnHrKweL-98_d8R4RuZXCWEQ3X0QDCVfccaLVVqLJy8S5zlx0aAVuBJxLxBHFRO700qdUN-RaMjHULoOnE1KbwmfKPfGlLL0YWPHQ9t-qIBh6OSZsDZh30K4VLF8sRXkGgn81_Byp4hK9tCfG98R6fWUM2_FCQrC9R1hO-KTsLffRzMboWe-2ymZGQfZKO-gtFaQH7_AjdVnQYMyKhSSCGYAAroSZAQ"},
{ "e", "AQAB" },
{ "use", "enc"},
{ "kid", "RPA" },
{ "alg", "RS256" },
{ "n", "qJPwMcHtb7xFGGczn20IiEtrPVehquyT6lxIJa_e4vcZE33uM6myVZWocTZWzTDmrNT3bJghEpLOhrgYatT3QnJIiTM9KAD01kYPc5cP5yo6Wmu0YjivqL3Rj7dUvi2pvl7juwYxt1_8zfdnBN5GpBIYcaY3ulVo_OSL7TOxJrua5IMhilQz6kqta3-Rgz3GSglOs94RHRvorYxMyHPQ6KhwSlh_zLzJQZ-0-AZ4yaMPdVwEaaEJpL-odYmRudX4E0t42dExLf_q1rpRfvTcdFSwfsJ7FmQcOtlc340WUgr4BHJfwrNIE4i-TFqrB4zSQJVKHlBfLeGKiYZQPD7igw" }
};
string tokenSigned = JWT.Encode(payload, rsaCrypto, JwsAlgorithm.RS256, headers);
I get a token (I think is signed) but if I put this token in this web site https://jwt.io/, I get an error "Invalid Signature".
Also I would like to encrypt this token with the public key. So I do this:
// Another public key to encrypt
headers = new Dictionary<string, object>()
{
{ "kty", "RSA" },
{ "e", "AQAB" },
{ "use", "enc"},
{ "alg", "RS256" },
{ "n", "ldMvqNDlz8-ABqEhqjtT0qvjKKbJMQ4J6GEi-7QrY-EUtyjCE7cOriHrYmbjt3o3zXwUTyOp0-twnF5j1HXFwVk7_XNsZz7LUmGNtmnqgB2iw2xhS7LAicN0RRgIbxWRDLOaaZ-49QumX6_r_jLNtIspKiFiuUNf2s0ipeAjWBFquiiqTMBd98z3pS-vC5y0CfzPbTSLSinikrHkIW2uO4FNHWZpoo8npn7vwWtAJjknWhaFi2s9P5kzUk4Mpbdx4DxUJ9ZvUi9SmdvH2vUzwGe0lxyvlw0DAMMWAT9TmsiKzBeXTY6rQ1-2Edn4F9S5kkPNOh1NqJoebz50-Bpl6w" }
};
string tokenEncrypted = JWT.Encode(payload, tokenSigned , JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM, extraHeaders: headers);
But I always get the error "RsaKeyManagement alg expects key to be of RSACryptoServiceProvider type.". I've already search about this error but I don't have anything clear.
Please, anyone can help me? I'm not sure if I'm on the right way.
I use jose-jwt for .net because I've read that the library System.IdentityModel.Tokens.Jwt can't encrypt.
Thank you.
Regards.
In this case I had a jwk and I wanted to sign it with my private key and encrypt it with a customer public key with c# jose-jwt library. This jwk is the same all the time, so I only need to generate it once. To do that, you need to create an RSA object and then use the Encode method of the library to sign and encrypt.
A jwk has severals parameters:
JSON Web Key (JWK): A JSON object that represents a cryptographic key.
The members of the object represent properties of the key, including
its value.
These are some of the parameters:
p = 'RSA secret prime';
kty = 'Key Type';
q = 'RSA secret prime';
d = 'RSA secret exponent';
e = 'RSA public exponent';
kid = 'Key ID';
n = 'RSA public modulus';
use = 'Public Key Use';
alg = 'Algorithm'
But in my case I only had some of them: d, e, n, kty, use, kid, alg. The problem is that if you have e and d parameters, you also need p and q, because you can't construct private key with .NET without primes (P and Q).
The solution was to part the problem in two parts:
JAVA part: create a complete jwk with the Nimbus JOSE+JWT JAVA library:
C# parts:
Use the previous jwk to create an RSA object in C# with c# jose-jwt library. Like this:
var js = new JavaScriptSerializer();
// json is the result returned by java
var jwk = js.Deserialize<IDictionary<string, string>>(json);
byte[] p = Base64Url.Decode(jwk["p"]);
byte[] q = Base64Url.Decode(jwk["q"]);
byte[] d = Base64Url.Decode(jwk["d"]);
byte[] e = Base64Url.Decode(jwk["e"]);
byte[] qi = Base64Url.Decode(jwk["qi"]);
byte[] dq = Base64Url.Decode(jwk["dq"]);
byte[] dp = Base64Url.Decode(jwk["dp"]);
byte[] n = Base64Url.Decode(jwk["n"]);
RSA key = RSA.Create();
RSAParameters keyParams = new RSAParameters();
keyParams.P = p;
keyParams.Q = q;
keyParams.D = d;
keyParams.Exponent = e;
keyParams.InverseQ = qi;
keyParams.DP = dp;
keyParams.DQ = dq;
keyParams.Modulus = n;
key.ImportParameters(keyParams);
Once you have an RSA object, you can sign it:
var payload = new Dictionary<string, object>()
{
{"user", USER },
{"password", PASSWORD }
};
string tokenSigned = JWT.Encode(payload, key, JwsAlgorithm.RS256);
You can find the original solution in the library author web page.
Regards.
I don't have deep information about cryptography ,but as I gathered some information,as an asymmetric solution I want to use RSA and here is the code which I found,I want to store an encrypted password into database and decrypt it whenever I want to get the user information,I mean these two actions don't happen respectively and whenever I like I can select from database and decrypt the previously save data.I know that there is something wrong with the generated keys,but because of low knowledge on this subject I cannot handle it.
I get the following Exception on decryption.
The parameter is incorrect.
at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
at System.Security.Cryptography.RSACryptoServiceProvider.DecryptKey(SafeKeyHandle pKeyContext, Byte[] pbEncryptedKey, Int32 cbEncryptedKey, Boolean fOAEP, ObjectHandleOnStack ohRetDecryptedKey)
at System.Security.Cryptography.RSACryptoServiceProvider.Decrypt(Byte[] rgb, Boolean fOAEP)
Encryption Class:
public static class AsymmetricEncryption
{
private static bool _optimalAsymmetricEncryptionPadding = false;
public static void GenerateKeys(int keySize, out string publicKey, out string publicAndPrivateKey)
{
using (var provider = new RSACryptoServiceProvider(keySize))
{
publicKey = provider.ToXmlString(false);
publicAndPrivateKey = provider.ToXmlString(true);
}
}
public static string EncryptText(string text, int keySize, string publicKeyXml)
{
var encrypted = Encrypt(Encoding.UTF8.GetBytes(text), keySize, publicKeyXml);
return Convert.ToBase64String(encrypted);
}
public static byte[] Encrypt(byte[] data, int keySize, string publicKeyXml)
{
if (data == null || data.Length == 0) throw new ArgumentException("Data are empty", "data");
int maxLength = GetMaxDataLength(keySize);
if (data.Length > maxLength) throw new ArgumentException(String.Format("Maximum data length is {0}", maxLength), "data");
if (!IsKeySizeValid(keySize)) throw new ArgumentException("Key size is not valid", "keySize");
if (String.IsNullOrEmpty(publicKeyXml)) throw new ArgumentException("Key is null or empty", "publicKeyXml");
using (var provider = new RSACryptoServiceProvider(keySize))
{
provider.FromXmlString(publicKeyXml);
return provider.Encrypt(data, _optimalAsymmetricEncryptionPadding);
}
}
public static string DecryptText(string text, int keySize, string publicAndPrivateKeyXml)
{
var decrypted = Decrypt(Convert.FromBase64String(text), keySize, publicAndPrivateKeyXml);
return Encoding.UTF8.GetString(decrypted);
}
public static byte[] Decrypt(byte[] data, int keySize, string publicAndPrivateKeyXml)
{
if (data == null || data.Length == 0) throw new ArgumentException("Data are empty", "data");
if (!IsKeySizeValid(keySize)) throw new ArgumentException("Key size is not valid", "keySize");
if (String.IsNullOrEmpty(publicAndPrivateKeyXml)) throw new ArgumentException("Key is null or empty", "publicAndPrivateKeyXml");
using (var provider = new RSACryptoServiceProvider(keySize))
{
provider.FromXmlString(publicAndPrivateKeyXml);
return provider.Decrypt(data, _optimalAsymmetricEncryptionPadding);
}
}
public static int GetMaxDataLength(int keySize)
{
if (_optimalAsymmetricEncryptionPadding)
{
return ((keySize - 384) / 8) + 7;
}
return ((keySize - 384) / 8) + 37;
}
public static bool IsKeySizeValid(int keySize)
{
return keySize >= 384 &&
keySize <= 16384 &&
keySize % 8 == 0;
}
}
Encrypt usage:
const int keySize = 1024;
string publicAndPrivateKey;
string publicKey;
AsymmetricEncryption.GenerateKeys(keySize, out publicKey, out publicAndPrivateKey);
string text = "text for encryption";
string encrypted = AsymmetricEncryption.EncryptText(text, keySize, publicKey);
Decrypt usage:
const int keySize = 1024;
string publicAndPrivateKey;
string publicKey;
AsymmetricEncryption.GenerateKeys(keySize, out publicKey, out publicAndPrivateKey);
string text = "text for encryption";
string encrypted = AsymmetricEncryption.DecryptText(text, keySize, publicKey);
I read the encrypted text from a table.And I like to decrypt it.
Please help me solve this issue.
Thanks in advance
Snippet link
Let me stop you right here, before you actually figure out the exception.
IT IS A HORRIBLE IDEA TO STORE PASSWORDS REVERSIBLY, regardless what encryption you use. There are memory scrubbers and a million other problems with that scheme.
Passwords are to be HASHED, NOT ENCRYPTED. The difference is that hashes are hard to reverse if implemented properly. Use BCrypt or SHA2 or SHA3 or some other good hashing algorithms, use proper salt.
Here's an example, but consult someone knowledgeable before using in production, I may have bugs, the methods are coded for simplicity and may be too simple:
public string GetHash(string secret, string salt = null)
{
var hasher = SHA256Managed.Create();
salt = salt ?? Guid.NewGuid().ToString("N"); // 128 bit salt
var hashResult = hasher.ComputeHash(Encoding.UTF8.GetBytes(salt+"|"+what));
return "SHA256|" + salt + "|" + Convert.ToBase64String(hashResult);
}
Now you can store the string you get from this function in your DB and the next time a password comes in (over HTTPS, I hope) you can check it by getting the salt from the string stored in DB:
public bool CheckSecretHash(string secret, string hashFromDB){
var hashParts = hashFromDB.Split('|'); // string[3]
var rehash = GetHash(secret, hashParts[1]);
return hashFromDB == rehash;
}
Bonus points: challenge-response. ALWAYS USE HTTPS.
I need to pass the public key and private key in string format for encryption and decryption in pgp. I've generated the keys like this but I am not able to use those. So can anyone tell me how to get the public key and private key in string format from this. And also the rsakeygenerator has not given the passphrase for private key. So where do I get passphrase for private key?
private void button2_Click(object sender, EventArgs e)
{
// keyPair = createASymRandomCipher();
//CipherPublicKey publicKey = getCipherPublicKey(keyPair);
AsymmetricCipherKeyPair keyPair = createASymRandomCipher();
Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters pubkey = (Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters)keyPair.Public;
Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters privkey = (Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters)keyPair.Private;
CipherPublicKey pbkey = getCipherPublicKey(pubkey);
CipherPrivateKey prvkey = getCipherPrivateKey(privkey);
}
private static AsymmetricCipherKeyPair createASymRandomCipher()
{
RsaKeyPairGenerator r = new RsaKeyPairGenerator();
r.Init(new KeyGenerationParameters(new SecureRandom(),
1024));
AsymmetricCipherKeyPair keys = r.GenerateKeyPair();
return keys;
}
[Serializable]
private struct CipherPrivateKey
{
public byte[] modulus;
public byte[] publicExponent;
public byte[] privateExponent;
public byte[] p;
public byte[] q;
public byte[] dP;
public byte[] dQ;
public byte[] qInv;
}
[Serializable]
private struct CipherPublicKey
{
public bool isPrivate;
public byte[] modulus;
public byte[] exponent;
}
private static CipherPublicKey getCipherPublicKey(Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters cPublic)
{
CipherPublicKey cpub = new CipherPublicKey(); cpub.modulus = cPublic.Modulus.ToByteArray();
cpub.exponent = cPublic.Exponent.ToByteArray();
return cpub;
}
private static CipherPrivateKey getCipherPrivateKey(Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters cPrivate)
{
CipherPrivateKey cpri = new CipherPrivateKey();
cpri.dP = cPrivate.DP.ToByteArray();
cpri.dQ = cPrivate.DQ.ToByteArray();
cpri.modulus = cPrivate.Modulus.ToByteArray();
cpri.p = cPrivate.P.ToByteArray();
cpri.privateExponent = cPrivate.Exponent.ToByteArray();
cpri.publicExponent = cPrivate.PublicExponent.ToByteArray();
cpri.q = cPrivate.Q.ToByteArray();
cpri.qInv = cPrivate.QInv.ToByteArray();
return cpri;
}
You need to ask the user for the passphrase. The whole point of having a passphrase is that you won't be able to work out the private key without it, and only the user can supply it.
(I haven't looked at the rest of your code, not being familiar with the BouncyCastle API. I do question the wisdom of a mutable struct with lots of byte arrays though...)
The answer to just your converting question is to convert them to Base64Strings
If you want it in hex (so a user can enter it easier), you can use the System.Runtime.Remoting.Metadata.W3cXsd2001 namespace to get convert to/from a HEX rep. Here is an example in C#.
I will also say that there may be a security flaw in your though process, but I am not sure that I am qualified to address it. (See Jon's post)