I have code sample in Java and I need the same functionality in C#. Are there any alternatives to the classes, which are used for the sample?
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import javax.xml.bind.DatatypeConverter;
publicKey = publicKey.replaceAll("-----(BEGIN|END).*", "").trim();
X509EncodedKeySpec spec = new X509EncodedKeySpec(DatatypeConverter.parseBase64Binary(publicKey));
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PublicKey pKey = keyFactory.generatePublic(spec);
Signature ecdsaSign = Signature.getInstance("SHA256withECDSA");
ecdsaSign.initVerify(pKey);
ecdsaSign.update(stringToVerify.getBytes("UTF-8"));
if (ecdsaSign.verify(new BigInteger(ECDSA, 16).toByteArray())) {
// true
}
There's not anything in .NET (by itself) which can read the public key structure only. But if you can get the entirety of a certificate then you can write the following in .NET 4.6.1:
using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace Demo
{
public static class DemoClass
{
public static bool ECDsaSha256Verify(string pemCert, string data, byte[] signature)
{
using (var cert = new X509Certificate2(Encoding.ASCII.GetBytes(pemCert)))
using (ECDsa ecdsa = cert.GetECDsaPublicKey())
{
if (ecdsa == null)
{
throw new ArgumentException("Certificate does not have an ECDSA key.");
}
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
return ecdsa.VerifyData(dataBytes, signature, HashAlgorithmName.SHA256);
}
}
}
}
I wasn't sure where your BigInteger signature value was coming from, so that I have just left as a byte array.
Related
I need to verify the leaf certificate using itsparent certificate.
I got 2 certificate from bing.com, when I used the Java API it success.
But in my App, I have not got the whole certificate, Only can got the Values of the part of the certificate. When I pick up the Values of the certificates and verify by myself , it failed.
Please help me find out what's wrong with my code, here is my code:
package net.laixiong;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.net.ssl.HttpsURLConnection;
import javax.xml.bind.DatatypeConverter;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
public class certVerify {
private static Certificate CACert;
private static Certificate[] certs;
private static String TBSCertificate = "30820b42a003020102021312001f72f70a0aa155962ab9cb0000001f72f7300d06092a864886f70d01010b0500304f310b3009060355040613025553311e301c060355040a13154d6963726f736f667420436f72706f726174696f6e3120301e060355040313174d6963726f736f66742052534120544c53204341203031301e170d3231313232323031333430375a170d3232303632323031333430375a3017311530130603550403130c7777772e62696e672e636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100961baf1cb8345ab7890d195c0497b18a74dad2c684a2b9e2c5abe101712246096505fdff105dc1031f612747efddd975fb7fead9f491193d5b46832d413fe48c35a5eac160114f7e549f2e9d491a3e41b6bafa0fee55481052031f4cabfb5a0144e598b5674c91da989b7ec916e288b9fafb021fe8ff21c36fc169eedb5f908e8b02f9456ca8309cf42f12935852dac787f1df0b8544a8a7055349ca1a269ad2435e51bae1485793081b7f899d7c8d5b406bb3bab38967c32fd7b308422953fa00671766fb2b1e47f8bc491778176c98c07e83c5f7c354b510aa418cc0200dc9ac72b14e18b600b0e69687a31935ee0fdae596ff036844cfadc87433dcd4d2cd0203010001a3820965308209613082017e060a2b06010401d6790204020482016e0482016a01680076002979bef09e393921f056739f63a577e5be577d9c600af8f94d5d265c255dc7840000017ddfcf67d900000403004730450221008251d39ea76085d5428255a300a745caa1ec972c263e74bc7d9daa235e773b81022015d2d03176b33d1d637b34427530903caf207d64d0829c72d3e8cbb8fac0bc4a0077005581d4c2169036014aea0b9b573c53f0c0e43878702508172fa3aa1d0713d30c0000017ddfcf68eb0000040300483046022100c438228eadeea0cae0ca89481281178818863449889ca664e47d6bef472256ca022100bdad9c294d8a15135f1764169e8f19d825291c9aad854e6e4d7c8cd97db1b66d00750051a3b0f5fd01799c566db837788f0ca47acc1b27cbf79e88429a0dfed48b05e50000017ddfcf68f20000040300463044022077c61a666950923aa2ff338d27b115b5aa24e3a602651eb7da06e994569b239202202164db2e6b805640b8873b05e72f53ee7b4c008dfd19846cb726da194bdc41e3302706092b060104018237150a041a3018300a06082b06010505070301300a06082b06010505070302303e06092b06010401823715070431302f06272b060104018237150887da867583eed90182c9851b81b59e6185f4eb60815d85868e4187c2985002016402012730818706082b06010505070101047b3079305306082b060105050730028647687474703a2f2f7777772e6d6963726f736f66742e636f6d2f706b692f6d73636f72702f4d6963726f736f6674253230525341253230544c53253230434125323030312e637274302206082b060105050730018616687474703a2f2f6f6373702e6d736f6373702e636f6d301d0603551d0e041604149ef980a5b4eca659cefeb11b21e869aa01547ced300e0603551d0f0101ff0404030204b03082056d0603551d110482056430820560820c7777772e62696e672e636f6d8210646963742e62696e672e636f6d2e636e82132a2e706c6174666f726d2e62696e672e636f6d820a2a2e62696e672e636f6d820862696e672e636f6d821669656f6e6c696e652e6d6963726f736f66742e636f6d82132a2e77696e646f77737365617263682e636f6d8219636e2e69656f6e6c696e652e6d6963726f736f66742e636f6d82112a2e6f726967696e2e62696e672e636f6d820d2a2e6d6d2e62696e672e6e6574820e2a2e6170692e62696e672e636f6d821865636e2e6465762e7669727475616c65617274682e6e6574820d2a2e636e2e62696e672e6e6574820d2a2e636e2e62696e672e636f6d821073736c2d6170692e62696e672e636f6d821073736c2d6170692e62696e672e6e6574820e2a2e6170692e62696e672e6e6574820e2a2e62696e67617069732e636f6d820f62696e6773616e64626f782e636f6d8216666565646261636b2e6d6963726f736f66742e636f6d821b696e736572746d656469612e62696e672e6f66666963652e6e6574820e722e6261742e62696e672e636f6d82102a2e722e6261742e62696e672e636f6d82122a2e646963742e62696e672e636f6d2e636e820f2a2e646963742e62696e672e636f6d820e2a2e73736c2e62696e672e636f6d82102a2e61707065782e62696e672e636f6d82162a2e706c6174666f726d2e636e2e62696e672e636f6d820d77702e6d2e62696e672e636f6d820c2a2e6d2e62696e672e636f6d820f676c6f62616c2e62696e672e636f6d821177696e646f77737365617263682e636f6d820e7365617263682e6d736e2e636f6d82112a2e62696e6773616e64626f782e636f6d82192a2e6170692e74696c65732e646974752e6c6976652e636f6d820f2a2e646974752e6c6976652e636f6d82182a2e74302e74696c65732e646974752e6c6976652e636f6d82182a2e74312e74696c65732e646974752e6c6976652e636f6d82182a2e74322e74696c65732e646974752e6c6976652e636f6d82182a2e74332e74696c65732e646974752e6c6976652e636f6d82152a2e74696c65732e646974752e6c6976652e636f6d820b33642e6c6976652e636f6d82136170692e7365617263682e6c6976652e636f6d8214626574612e7365617263682e6c6976652e636f6d8215636e7765622e7365617263682e6c6976652e636f6d820c6465762e6c6976652e636f6d820d646974752e6c6976652e636f6d821166617265636173742e6c6976652e636f6d820e696d6167652e6c6976652e636f6d820f696d616765732e6c6976652e636f6d82116c6f63616c2e6c6976652e636f6d2e617582146c6f63616c7365617263682e6c6976652e636f6d82146c7334642e7365617263682e6c6976652e636f6d820d6d61696c2e6c6976652e636f6d82116d6170696e6469612e6c6976652e636f6d820e6c6f63616c2e6c6976652e636f6d820d6d6170732e6c6976652e636f6d82106d6170732e6c6976652e636f6d2e6175820f6d696e6469612e6c6976652e636f6d820d6e6577732e6c6976652e636f6d821c6f726967696e2e636e7765622e7365617263682e6c6976652e636f6d8216707265766965772e6c6f63616c2e6c6976652e636f6d820f7365617263682e6c6976652e636f6d8212746573742e6d6170732e6c6976652e636f6d820e766964656f2e6c6976652e636f6d820f766964656f732e6c6976652e636f6d82157669727475616c65617274682e6c6976652e636f6d820c7761702e6c6976652e636f6d82127765626d61737465722e6c6976652e636f6d82137765626d6173746572732e6c6976652e636f6d82157777772e6c6f63616c2e6c6976652e636f6d2e617582147777772e6d6170732e6c6976652e636f6d2e61753081b00603551d1f0481a83081a53081a2a0819fa0819c864d687474703a2f2f6d7363726c2e6d6963726f736f66742e636f6d2f706b692f6d73636f72702f63726c2f4d6963726f736f6674253230525341253230544c53253230434125323030312e63726c864b687474703a2f2f63726c2e6d6963726f736f66742e636f6d2f706b692f6d73636f72702f63726c2f4d6963726f736f6674253230525341253230544c53253230434125323030312e63726c30570603551d200450304e304206092b0601040182372a013035303306082b060105050702011627687474703a2f2f7777772e6d6963726f736f66742e636f6d2f706b692f6d73636f72702f6370733008060667810c010201301f0603551d23041830168014b5760c3011cec792424d4cc75c2cc8a90ce80b64301d0603551d250416301406082b0601050507030106082b06010505070302";
private static String pkInfoOfString = "30820222300d06092a864886f70d01010105000382020f003082020a0282020100aa6277cf9a63b20684f39036f499f31451abea950a3b4606fd11411ffe5b0658c9386e08fc4f4448cd3aa4f7bd1ea2e295b8be5120c5bfb270635d780c43c029cd64490996daafcefd055f2b2a91e8016e2e189b2c9cd0017f69f5ee3f53885cba056cbe2215671482f22cd2be5b6337ccaf6085e8966b6b8008a86ebe009c6b9570fce41812b11d1bb2c11331673334e625c9625b58827576f2fef23f3b16dfaa4283e3326d9b8e4326f0bd0e1fa1a73aaf2cc88ae6ea3ff9a5d2258f92aa1a08129cfeac4ac7c3eb8094ab8716d12349e7a4bbc791dfe679343f414aa73a26d2ea6f46e33873e6e5d491ae0b789e78a5ef96e373d8f79565e905bf4f5cff52a7f9cf08afa74d0999c071a3527aa53bd79b015403e3b662b05a279c30268eb64d56a117177a7b95a107ac5331b6d62e0fcd4174ecf101b2fd45bffc31e146423136431eb9aa055f847f91b18bae0fd754c3fdf064086ad39c8eea7934ec033d73e01b36d46811c75970b0877cc0dc6e45ca36ce43267702a9700de8b857544442c3fbac1b632608c2d2231f7f930b7c6f08549a2b4e5dce9fa53ed2985bd102dbf183ce3052483863f1b1fbed23d33e92b5278dd04273d79d236871ba595e0752a6964dbf7c4e6f742205c0538016d8604e97314f894e4863d8edf9e5c2d90eb20bf6694cbd4b01c9cbdd06bf3a02eb1cdd308b0d4a1460f9d5644f4344a1ed0203010001";
private static String sigValue = "35ff650af97d6a3eea1ee00f95ecae0ebd0cf43d8b3237a29bea282fb427571c3972eb0121f72d1b4a815f63c47befbe562522806834bfa40a6ac27b5d0de1b3a91f4c01cc4d78225eafcda5679689e11655dae04a88a13e665b726bc3eb0097811e2400645e53ac8a3e98bae9d492539ca5736802fbafa8a32e3a2cf49ede7a290361ef677036baf5d8dd3997297f4ad82c69b075280522deaec748fa071251986caa7ce95b4ec0ba832eaaecc2da75266fc1c534aaa4a90e2d825b87b54e74ea3fec8279d0cd352de799d3935261c0288196d7eb3121b3f8686b2e03bcaff0e2305f263e8fb2d33b28614f47d5da1432675dca8234e59f888e1cf0234891a98953b3279ffffead9d5a8efce6ab9ff7b964af24f1458e1ace76736a4024c8c83fa76995fb2bc1cee36f74db88cdbaa86a6fa5fea7acb83796a84ba73b8f2337d7f8f79dde1b1602a9bfde4fc09f7914f8187763c7baa04c602de5db5a9d6f9b6e0d805856b8e0cf3d20b598432f511e99532720c14ed74a1a86798b4acd7eddb7d107f8e8405eafffd446cf67fc78d68e6e0222415cb8d8bf1ead35f42c1bd200039623595ba3bbfc4b5ec25681354293b860bb5d90151fbd2f9f68e68930c45bb90f62a065bd813d9146709e6cdc1d10656284a83079c8f0e6a354660436f176b26f3a2c14298ec9551f2daa5979ba7cfca7059afe161958761f50ad241643";
static void sigVerify1() throws IOException, CertificateEncodingException {
URL destinationURL = new URL("https://www.bing.com");
HttpsURLConnection con = (HttpsURLConnection) destinationURL.openConnection();
con.connect();
certs = con.getServerCertificates();
X509Certificate x509cert = (X509Certificate) certs[0];
CACert = certs[1];
byte[] b = x509cert.getTBSCertificate();
b[0] = (byte) ~b[0];
try {
PublicKey pkOfCa = CACert.getPublicKey();
x509cert.verify(pkOfCa);
System.out.println("true");
} catch (GeneralSecurityException e2) {
System.out.println("false");
}
}
static void sigVerify2() throws InvalidKeySpecException {
try {
PublicKey pkOfCA = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(DatatypeConverter.parseHexBinary(pkInfoOfString)));
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, pkOfCA);
byte[] tbsHashValue1 = cipher.doFinal(DatatypeConverter.parseHexBinary(sigValue));
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
byte[] tbsHashValue2 = messageDigest.digest(DatatypeConverter.parseHexBinary(TBSCertificate));
System.out.println(Arrays.equals(tbsHashValue1, tbsHashValue2));
} catch ( NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws CertificateEncodingException, NoSuchAlgorithmException, IOException, SignatureException, InvalidKeyException, InvalidKeySpecException {
sigVerify1();
sigVerify2();
}
}
//C:\Java\jdk1.8.0_211\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJIDEACommunityEdition2020.3.1\lib\idea_rt.jar=56057:C:\Program Files\JetBrains\IntelliJIDEACommunityEdition2020.3.1\bin" -Dfile.encoding=UTF-8 -classpath C:\Java\jdk1.8.0_211\jre\lib\charsets.jar;C:\Java\jdk1.8.0_211\jre\lib\deploy.jar;C:\Java\jdk1.8.0_211\jre\lib\ext\access-bridge-64.jar;C:\Java\jdk1.8.0_211\jre\lib\ext\cldrdata.jar;C:\Java\jdk1.8.0_211\jre\lib\ext\dnsns.jar;C:\Java\jdk1.8.0_211\jre\lib\ext\jaccess.jar;C:\Java\jdk1.8.0_211\jre\lib\ext\jfxrt.jar;C:\Java\jdk1.8.0_211\jre\lib\ext\localedata.jar;C:\Java\jdk1.8.0_211\jre\lib\ext\nashorn.jar;C:\Java\jdk1.8.0_211\jre\lib\ext\sunec.jar;C:\Java\jdk1.8.0_211\jre\lib\ext\sunjce_provider.jar;C:\Java\jdk1.8.0_211\jre\lib\ext\sunmscapi.jar;C:\Java\jdk1.8.0_211\jre\lib\ext\sunpkcs11.jar;C:\Java\jdk1.8.0_211\jre\lib\ext\zipfs.jar;C:\Java\jdk1.8.0_211\jre\lib\javaws.jar;C:\Java\jdk1.8.0_211\jre\lib\jce.jar;C:\Java\jdk1.8.0_211\jre\lib\jfr.jar;C:\Java\jdk1.8.0_211\jre\lib\jfxswt.jar;C:\Java\jdk1.8.0_211\jre\lib\jsse.jar;C:\Java\jdk1.8.0_211\jre\lib\management-agent.jar;C:\Java\jdk1.8.0_211\jre\lib\plugin.jar;C:\Java\jdk1.8.0_211\jre\lib\resources.jar;C:\Java\jdk1.8.0_211\jre\lib\rt.jar;C:\myIDEAWorks\mySpecial\target\classes;C:\Users\lihong\.m2\repository\redis\clients\jedis\3.6.1\jedis-3.6.1.jar;C:\Users\lihong\.m2\repository\org\slf4j\slf4j-api\1.7.30\slf4j-api-1.7.30.jar;C:\Users\lihong\.m2\repository\org\apache\commons\commons-pool2\2.9.0\commons-pool2-2.9.0.jar;C:\Users\lihong\.m2\repository\net\sf\opencsv\opencsv\2.3\opencsv-2.3.jar;C:\Users\lihong\.m2\repository\org\apache\httpcomponents\httpcore\4.4.4\httpcore-4.4.4.jar;C:\Users\lihong\.m2\repository\org\postgresql\postgresql\9.4.1208.jre7\postgresql-9.4.1208.jre7.jar net.laixiong.certVerify
// true
// false
Added after I resolve the problem.
Thanks #dave_thompson_085, I found the corrent method in Signature API , my problem been resolved.
So the code like this :
PublicKey pkOfCA = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(DatatypeConverter.parseHexBinary(pkInfoOfString)));
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(pkOfCA);
sig.update(DatatypeConverter.parseHexBinary(TBSCertificate));
System.out.println(sig.verify(DatatypeConverter.parseHexBinary(sigValue)));
Thanks again.
Basically dupe How to use x509 public key to verify a signed/hashed Alexa request body? and more (across several Stacks) linked at https://crypto.stackexchange.com/questions/87006/why-is-data-signed-with-sha256-rsa-pkcs-and-digest-signed-with-rsa-pkcs-differen/#87022 .
First of all, the better way to verify a signature 'manually' is to use the Signature API as designed:
PublicKey pkOfCA = KeyFactory...generatePublic... // as now
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(pkOfCA);
sig.update(DatatypeConverter.parseHexBinary(TBSCertificate));
System.out.println(sig.verify(DatatypeConverter.parseHexBinary(sigValue)));
However, if you insist on doing it with the 'backwards Cipher' method, you must do the ASN.1 DigestInfo DER encoding or decoding yourself; this amounts to adding or checking and removing a prefix that depends only on the hash algorithm used, as shown in e.g. PKCS1v2.2 = RFC 8017 section 9.2 'Notes'. Specifically, either compare the 'decrypted' value to the concatenation of the appropriate prefix plus the actual hash value, or remove that prefix from the 'decrypted' value and compare only the remainder to the hash value.
I want to encrypt my password in angular side before sending it to Springboot API. My idea is to do:-
Generate public key and private key in java
Do a base64 encoding on both public key and private key
Use encoded public key in node (angular) side, this will be used for encryption
Use encoded private key in springboot rest api, this will be used for decryption
Below is my java code which generates, encrypts and decrypts password
RSAKeyPairGenerator.java
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
public class RSAKeyPairGenerator {
private static String privateKeyString = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALyR1WRqVBuvdmXmgrcZ4VMY4hIFTYt63NGEN9atlgnngNliMasvzBofnjRtk5mukezUKujtON6mPnAjKJoEDdiaw3Rk0hKvgW5MszyUBE5bLThexVLbi+nQYSf2GSvd0fjdZn6KjhgVOdbYe+JduU/iPD3/Ti5p+w3MewgZpy2RAgMBAAECgYAqWdqCXfsb6LF/u2C6PN7Faf5EK9q5q9NyXu6nkX70JIFk0U/0cZy2dUlz3vRafMGbXh9xBu5R2yaEyvCwfp6ZF26A8MbS/IaI53LMKmyclhES2f3tZLKUPkg6fntz+e6e/6oSDdQPHP3J2QrpuwzyW+UZJQmmYYj7f9sq/+dawQJBAOnkHWkLuIZNIgLzV0TuHA6fcOXrqrSlS1/Q0qLyaQEZOObocXDvWaCSP+8RXiqZSwAnMJbrGHQA5ULXLWI4GjkCQQDOZP6bfn2VV3m8JSlYL9Uz4TrRYb8Qe3/mohhMsyDB7Ua/6d9BV7JZgbYiXP0utobKVWLxD49OFMkgEs20qY4ZAkB4dJsQ9pBZ2m+hxWE0hsy8WzDxuKV504c2GX3hnaamgi7j/OIvn5UxNSDoJrGwjrIpqgVENF+rnqpz+g3Nf8dBAkBV/op+6yMUGFBmbe1eCwAAD7XcC6f6DBrsU1lgi7n4Uw6JY75bkViEJqFmi+wJjI94uj7xRZRl6g8qx+rhfUvxAkEArD1we6ZLTWz73D8z+4Boj7Su7b5LhfgvXVL5V4Zdog3X58pHK+dYppapDh5KjZZdor+y/6uz1PqIs2dmFy/xtQ==";
private static String publicKeyString = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8kdVkalQbr3Zl5oK3GeFTGOISBU2LetzRhDfWrZYJ54DZYjGrL8waH540bZOZrpHs1Cro7Tjepj5wIyiaBA3YmsN0ZNISr4FuTLM8lAROWy04XsVS24vp0GEn9hkr3dH43WZ+io4YFTnW2HviXblP4jw9/04uafsNzHsIGactkQIDAQAB";
private static PrivateKey privateKey;
private static PublicKey publicKey;
public void generateKeys() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
KeyPair pair = keyGen.generateKeyPair();
RSAKeyPairGenerator.privateKey = pair.getPrivate();
RSAKeyPairGenerator.publicKey = pair.getPublic();
}
public void readKeys() throws NoSuchAlgorithmException, InvalidKeySpecException {
KeyFactory kf = KeyFactory.getInstance("RSA");
byte [] encoded = Base64.getDecoder().decode(privateKeyString);
PKCS8EncodedKeySpec keySpec1 = new PKCS8EncodedKeySpec(encoded);
RSAKeyPairGenerator.privateKey = kf.generatePrivate(keySpec1);
encoded = Base64.getDecoder().decode(publicKeyString);
X509EncodedKeySpec keySpec2 = new X509EncodedKeySpec(encoded);
RSAKeyPairGenerator.publicKey = kf.generatePublic(keySpec2);
}
public static void main(String[] args) throws NoSuchAlgorithmException, IOException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException {
RSAKeyPairGenerator keyPairGenerator = new RSAKeyPairGenerator();
// Next line is for testing with encrypted text generated by nodejs code with genrated keys
// keyPairGenerator.generateKeys();
keyPairGenerator.readKeys();
System.out.println("-----Private----------");
System.out.println(Base64.getEncoder().encodeToString(privateKey.getEncoded()));
System.out.println("Encoding : "+ privateKey.getFormat());
System.out.println("----------------------");
System.out.println("-----Public----------");
System.out.println(Base64.getEncoder().encodeToString(publicKey.getEncoded()));
System.out.println("Encoding : "+ publicKey.getFormat());
System.out.println("----------------------");
String secretMessage = "Test";
System.out.println(secretMessage);
Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] secretMessageBytes = secretMessage.getBytes(StandardCharsets.UTF_8);
byte[] encryptedMessageBytes = encryptCipher.doFinal(secretMessageBytes);
// Next lines are for testing decryption with encrypted text generated by nodejs code with generated keys
// byte[] encryptedMessageBytes = "B��u���<⌂�lǚm0�W������1�%EN�7��‼��l��l�<�����k;�������GĦ9D8��Z��I�Oɺ♫��→P'�§�{k�Ɋ+-}?��rZ".getBytes();
// byte[] encryptedMessageBytes = Base64.getDecoder().decode("woboAUytDXJLlKm7zbqNdxVORG+kio9kZxvMPOHruQfxwNEx7SVFTsw3oeETqbRs4NZskjzO2Nzjyms73vv758Dcy0fEpjlEOKmrWuG62knOT8m6DqGDGlAn1hXpe2u6yYorLX0/6fhyWg1C/JR1sbaKPH/Xt+Fsx5ptMONX0uw=");
System.out.println(new String(encryptedMessageBytes));
Cipher decryptCipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedMessageBytes = decryptCipher.doFinal(encryptedMessageBytes);
String decryptedMessage = new String(decryptedMessageBytes, StandardCharsets.UTF_8);
System.out.println(decryptedMessage);
}
}
This gives me following output
-----Private----------
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMv+t+D6/7ZY6m+CjD97NB989P2YjmGcE2yHUokyjmxVi/SxIu9MboiVNewR+mFjTFYPGgMWHz1/XeVGlinjN/5+0fdiO/JEvEUilFmkkIF3My11I09b9NZ9RJmpCNCbqOg7NSt6VD8IC/w19N25xwcofc3qbgfEjKSs0CgxfahrAgMBAAECgYEAiyLlEBKiryDeZchJGFNULdXw07dmBbWKmg+CgAl3kvSWTQM0rLsY+Rese6OXfy1XN6t9NnW0QSHKTUNj0JYl7btKEblVHERbjwavUe83tcNIc3o0xrGoBAzma14ZicPYm70JWixTO778lm5AXKl504+oOQyVYmfgXcevPXwdIkECQQDvO3DBuu6wp5nbwR4t0736HOH9jVIjJOS8oABUARDhNt1fkb8uEptDr5EomVRMqarJMAjSMpYxrUCpvgtf4nZ5AkEA2ksDr8pbbFvZPaAe0F43LmJtFM3PvCz87S93p20YjwVMmGV17sJ5t7a26HtubgRLEWq4z6rxq2oXPv4y1lstAwJAbj9cVUtKWIrEcutqdwAPmsXYt7p60ctcxjiOLihXmRJprnNCQX89olG0eZs/qBzAofrK9eNuJ/KJzC/SmhuJMQJAAz9gc6oQCCGprrgGHVV5frAqLUgOkh8dOC4fmpcN6XrLs+y2f3HXO7t1JypG704TC9RJoZVKeSFf7Sj8+qFqnwJBALRiQc9SG5Ht5TLo12W4l3bRaxpbo597BgKRjz3hqiySdqjZA9Qe84qmEKveZ9eWehbfqwzKmCbW43I1ZEFZ95o=
Encoding : PKCS#8
----------------------
-----Public----------
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDL/rfg+v+2WOpvgow/ezQffPT9mI5hnBNsh1KJMo5sVYv0sSLvTG6IlTXsEfphY0xWDxoDFh89f13lRpYp4zf+ftH3YjvyRLxFIpRZpJCBdzMtdSNPW/TWfUSZqQjQm6joOzUrelQ/CAv8NfTduccHKH3N6m4HxIykrNAoMX2oawIDAQAB
Encoding : X.509
----------------------
Test
�N::�`��\A���ƈ�~��5s���
�0�I�C�uƹx2�Z&Kں�"ьC�$
q��K���h�^<�5�E�Ɨ0B�͒Z�{��EDbDH�.��#:�e��h~j���������q�c��R�
Test
In the Nodejs side I am using the above public to encrypt my text.
index.js
const crypto = require("crypto");
var pubkey = "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDL/rfg+v+2WOpvgow/ezQffPT9mI5hnBNsh1KJMo5sVYv0sSLvTG6IlTXsEfphY0xWDxoDFh89f13lRpYp4zf+ftH3YjvyRLxFIpRZpJCBdzMtdSNPW/TWfUSZqQjQm6joOzUrelQ/CAv8NfTduccHKH3N6m4HxIykrNAoMX2oawIDAQAB\n-----END PUBLIC KEY-----";
var plaintext = "Test"
var buffer = new Buffer.from(plaintext, "utf8");
var enc = crypto.publicEncrypt(pubkey, buffer);
var bs64 = enc.toString('base64');
console.log(enc.toString());
console.log(enc.toString('base64'));
this gives me following output
B��u���<⌂�lǚm0�W������1�%EN�7��‼��l��l�<�����k;�������GĦ9D8��Z��I�Oɺ♫��→P'�§�{k�Ɋ+-}?��rZ
woboAUytDXJLlKm7zbqNdxVORG+kio9kZxvMPOHruQfxwNEx7SVFTsw3oeETqbRs4NZskjzO2Nzjyms73vv758Dcy0fEpjlEOKmrWuG62knOT8m6DqGDGlAn1hXpe2u6yYorLX0/6fhyWg1C/JR1sbaKPH/Xt+Fsx5ptMONX0uw=
Now I tried using both the strings in java side for decryption.
When I try decoding the string, it gives me following error
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes
at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:346)
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:391)
at javax.crypto.Cipher.doFinal(Cipher.java:2168)
at com.mindtree.starr.wsr.RSAKeyPairGenerator.main(RSAKeyPairGenerator.java:90)
And, when I try decoding the base64 string, it gie me following error
Exception in thread "main" javax.crypto.BadPaddingException: Decryption error
at sun.security.rsa.RSAPadding.unpadV15(RSAPadding.java:379)
at sun.security.rsa.RSAPadding.unpad(RSAPadding.java:290)
at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:365)
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:391)
at javax.crypto.Cipher.doFinal(Cipher.java:2168)
at com.mindtree.starr.wsr.RSAKeyPairGenerator.main(RSAKeyPairGenerator.java:90)
What am I doing wrong?
The problem was clearly described in the first comment and the solution is in second comment.
Correct transformation string for Cipher instance that worked for me is RSA/ECB/OAEPWithSHA-1AndMGF1Padding
So below instantiation for decryption Cipher works perfectly.
Cipher decryptCipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
I am integrating with a .Net application which uses Symmetric encryption. My application is on Java. Following is the .Net code which was shared by the team which uses the Symmetric encryption;
public static string SymmetricEncrypt<T>(string value, string PrivateKey, string SALT_STRING) where T : SymmetricAlgorithm, new()
{
PasswordDeriveBytes rgb =
new PasswordDeriveBytes(PrivateKey ,
Encoding.Unicode.GetBytes(SALT_STRING));
SymmetricAlgorithm algorithm = new T();
byte[] rgbKey = rgb.GetBytes(algorithm.KeySize >> 3);
byte[] rgbIV = rgb.GetBytes(algorithm.BlockSize >> 3);
ICryptoTransform transform = algorithm.CreateEncryptor(rgbKey, rgbIV);
using (MemoryStream buffer = new MemoryStream())
{
using (CryptoStream stream =
new CryptoStream(buffer, transform, CryptoStreamMode.Write))
{
using (StreamWriter writer = new StreamWriter(stream, Encoding.Unicode))
{
writer.Write(value);
}
}
return Convert.ToBase64String(buffer.ToArray());
}
}
Looking at the .Net documentation, I could see that SymmetricEncrypt class by default uses Rijndael encryption. And also I have found a class similar to "PasswordDeriveBytes" implementation in bouncy castle which implements the "PKCS5S1" algorithm for key generation using the salt with an iteration count of 100. But still I am unable to generate the exact encryption to what is required by the .Net application. Following code is what i have tried so far;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import mtnsa.sorb.handler.PKCS5Test.PasswordDeriveBytes;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.encoders.Base64;
public class EncryptionHelper {
public static void main(String[] args)throws Exception {
encrypt("FTTH","HhN01vcEEtMmwdNFliM8QYg0Y89xzBOJJG7BHARC7g", "002400000480000094000000060200000024000052534131000400000100010085525e9438e9fae122f71ec7124" +
"443bf2f9f57f5f3760b3704df168493004b9ef68413f500d54fa9fa3869b42b1e2365204826e54b618d56e7e575f2" +
"7f675f0eae3ea8458a8ee1e92dc3f4bfc34fbe23851afa9d2c28fc8cd5b124f60a03a06bfb598bc3acbd8c4380ae" +
"f02cc58bdf955d140390f740a7e115c59e3b3b5758ca");
}
public static String encrypt(final String valueToEncrpt, final String saltString, final String privateKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException{
String encrptedValue = null;
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] password = privateKey.getBytes();
byte[] salt = saltString.getBytes();
PKCS5S1ParametersGenerator generator = new PasswordDeriveBytes(new SHA1Digest());
generator.init(password, salt, 100);
byte[] keyArr = ((KeyParameter)generator.generateDerivedParameters(128)).getKey();
byte[] IvArr = ((KeyParameter)generator.generateDerivedParameters(128)).getKey();
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyArr,"AES"),new IvParameterSpec(IvArr));
byte[]test = cipher.doFinal(valueToEncrpt.getBytes());
System.out.println(new String(Base64.encode(test)));
return encrptedValue;
}
}
In the Java code i have given the sample SALT key and the PRIVATE key used for testing purposes. But still I am unable to get the exact value as generated by the .Net application. Following is an example plain text and the encrypted value which i got from the .Net application which i have failed to replicate in my Java code.
Plain text value : FTTH
Encrypted value : MjgmbdT3Vg6RW/7K1BjQ/Q==
Any help on this is much appreciated as i am currently out of ideas.
Thank you everyone for the valuable comments. I have requested the .Net module authors to change their implementation to use RFC2898DeriveBytes
I am new to Android and i am working on a client server based application.Here i need to use RSA algorithm for Encryption/Decryption.
The scenario is:
1.Server has to create a Private/Public key pair (PHP) and send Public key to Client(Android Application)
2.The client should encrypt the data using that Public key and send to server
3.Now server has to decrypt using Private Key.
In PHP, i used 'PhpSecLib' to create key pair.
This is the coding :
Server.php:
<?PHP
include 'Crypt/RSA.php';
$rsa = new Crypt_RSA();
extract($rsa->createKey(1024));
echo $publickey;
?>
Generated Public Key :
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLz4yAo1FTOLc6nijBCTv5iVnW
F6MxCeM5+RxY+29AXcpMWhlM9oES3ESIfWw6OzrrENDyqwY+kVzCj2bWYnEAyJXs
WOpvqT2XSCPplwZOnQQGm+DnAYJXEeOfgU5DI63fwdiGv4M2ph1VMMe6684sBZu1
HhJHuhsX2eibBR0/lQIDAQAB
Now in Java, i successfully received this public key and stored in a String.
Coding:
protected String doInBackground(Void... params)
{
try
{
URL url=new URL("http://10.0.2.2/Samples/Server.php");
URLConnection con=url.openConnection();
con.setDoOutput(true);
BufferedReader ip=new BufferedReader(new InputStreamReader(con.getInputStream()));
String tmp,res="";
while((tmp=ip.readLine())!=null)
{
res+=tmp;
}
return res; //res contains the public key
}
catch(Exception e)
{
return new String("Exception : "+e.getMessage());
}
}
I am using Bouncy castle provider (bcprov-jdk15on-151) in java.
Now i have no idea about how to convert this string into RSA public key.
Pls suggest some code snippets? and if the code needs improvements and corrections, pls correct it.
Thanks...
Supposing that you download your key correctly, you can use your key in base 64 encoding to generate a java.security.PublicKey with the follow code:
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;
public class ParseRsaPublicKey {
public static void main(String[] args) throws Exception {
String yourKeyB64 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLz4yAo1FTOLc6nijBCTv5iVnW\n"+
"F6MxCeM5+RxY+29AXcpMWhlM9oES3ESIfWw6OzrrENDyqwY+kVzCj2bWYnEAyJXs\n"+
"WOpvqT2XSCPplwZOnQQGm+DnAYJXEeOfgU5DI63fwdiGv4M2ph1VMMe6684sBZu1\n"+
"HhJHuhsX2eibBR0/lQIDAQAB";
// create the key factory
KeyFactory kFactory = KeyFactory.getInstance("RSA", new BouncyCastleProvider());
// decode base64 of your key
byte yourKey[] = Base64.decode(yourKeyB64);
// generate the public key
X509EncodedKeySpec spec = new X509EncodedKeySpec(yourKey);
PublicKey publicKey = (PublicKey) kFactory.generatePublic(spec);
// now you can for example cipher some data with your key
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] cipherData = cipher.doFinal("someData".getBytes());
System.out.println(new String(cipherData));
}
}
Hope this helps,
I have a RSA Key and a X.509 Certificate which I use for SSL connections.
The key and certificate are stored in files in PEM format (generated by OpenSSL) and used in an Apache HTTP server environment.
Is there an easy way to validate if the key matches the certificate using only Java code (without executing the openssl binary and parsing the output), for example by using Java security and/or Bouncycastle library methods?
The following code compares the SHA-1 over the modulus within the public and private key. The modulus should be unique for each pair (unless you key pair generation mechanism or random generator is broken of course).
Note that the following code requires the key to be in unencrypted PKCS#8 format. It may be better to use PKCS#12 instead and load the binary PKCS#12 file in a KeyStore (providing the password).
openssl pkcs8 -topk8 -in key.pem -out keypk8.pem -nocrypt
And finally the Java code:
import static org.bouncycastle.util.encoders.Hex.toHexString;
import java.io.ByteArrayInputStream;
import java.io.FileReader;
import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
public class CompareCertAndKey {
/**
* Checks if the certificate and RSA private key match.
*
* #param args the path to the certificate file in args[0] and that of the private key in args[1]
*/
public static void main(String[] args) {
try {
final PemReader certReader = new PemReader(new FileReader(args[0]));
final PemObject certAsPemObject = certReader.readPemObject();
if (!certAsPemObject.getType().equalsIgnoreCase("CERTIFICATE")) {
throw new IllegalArgumentException("Certificate file does not contain a certificate but a " + certAsPemObject.getType());
}
final byte[] x509Data = certAsPemObject.getContent();
final CertificateFactory fact = CertificateFactory.getInstance("X509");
final Certificate cert = fact.generateCertificate(new ByteArrayInputStream(x509Data));
if (!(cert instanceof X509Certificate)) {
throw new IllegalArgumentException("Certificate file does not contain an X509 certificate");
}
final PublicKey publicKey = cert.getPublicKey();
if (!(publicKey instanceof RSAPublicKey)) {
throw new IllegalArgumentException("Certificate file does not contain an RSA public key but a " + publicKey.getClass().getName());
}
final RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
final byte[] certModulusData = rsaPublicKey.getModulus().toByteArray();
final MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
final byte[] certID = sha1.digest(certModulusData);
final String certIDinHex = toHexString(certID);
final PemReader keyReader = new PemReader(new FileReader(args[1]));
final PemObject keyAsPemObject = keyReader.readPemObject();
if (!keyAsPemObject.getType().equalsIgnoreCase("PRIVATE KEY")) {
throw new IllegalArgumentException("Key file does not contain a private key but a " + keyAsPemObject.getType());
}
final byte[] privateKeyData = keyAsPemObject.getContent();
final KeyFactory keyFact = KeyFactory.getInstance("RSA");
final KeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyData);
final PrivateKey privateKey = keyFact.generatePrivate(keySpec);
if (!(privateKey instanceof RSAPrivateKey)) {
throw new IllegalArgumentException("Key file does not contain an X509 encoded private key");
}
final RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) privateKey;
final byte[] keyModulusData = rsaPrivateKey.getModulus().toByteArray();
final byte[] keyID = sha1.digest(keyModulusData);
final String keyIDinHex = toHexString(keyID);
System.out.println(args[0] + " : " + certIDinHex);
System.out.println(args[1] + " : " + keyIDinHex);
if (certIDinHex.equalsIgnoreCase(keyIDinHex)) {
System.out.println("Match");
System.exit(0);
} else {
System.out.println("No match");
System.exit(-1);
}
} catch (Exception e) {
e.printStackTrace(System.err);
System.exit(-2);
}
}
}
Thank you very much for the above code snippet. Its working for me with bouncycastle version 1.51
<bcprov-jdk15on-version>1.51</bcprov-jdk15on-version>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>${bcprov-jdk15on-version}</version>
</dependency>
Many Thanks for your code snippet.