In have integrated oauth1.0. i am using sha1-rsa signature method. i have generated oauth signature. i got 200 status but i did not get any value in service provider. my doubt is signature generation. how to generate the oauth signature using sha1-rsa in java? i have mentioned link what am using.
`private static KeyPair getKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024, new SecureRandom());
return kpg.genKeyPair();
}`
public static String sign(PrivateKey privateKey) throws Exception {
Signature privateSignature = Signature.getInstance(" ");
privateSignature.initSign(privateKey);
//privateSignature.update(plainText.getBytes(UTF_8));
byte[] signature = privateSignature.sign();
System.out.println(Base64.encodeBase64String(signature));
return Base64.encodeBase64String(signature);
//encodeToString(signature);
}
thanks in advance,
Below snippets generate a valid signature, i.e. signs the input data using an RSA Private Key string i.e. creates a private key from contents of a .pkcs8 private key file. This is in Groovy (works with Java with minimal syntax changes:
import java.security.SignatureException;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.Signature;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
//-------- generate RSA-SHA1 signature from request data
def encryptUsingRSASHA1(String data, String key) throws
java.security.SignatureException
{
String result
try {
// get an rsa_sha1 key from the raw key bytes
//SHA1withRSA
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initSign(getPrivateKey(key));
signature.update(data.getBytes("UTF-8"));
byte[] rawRSAsigned = signature.sign();
result= rawRSAsigned.encodeBase64()
} catch (Exception e) {
throw new SignatureException("Failed to generate Signature : " +
e.getMessage());
}
return result
}
//get PrivateKey from key string
def getPrivateKey(String privateKey) throws NoSuchAlgorithmException,
InvalidKeySpecException {
String privateKeyPEM = privateKey.replace("-----BEGIN PRIVATE KEY-----\n",
"").replace("-----END PRIVATE KEY-----", "").replaceAll("\n","");
byte[] privateKeyBytes = privateKeyPEM.decodeBase64();
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(keySpec);
}
Related
I am trying to calculate the performance of ECDSA signature verification in Java for secp521r1 curve.
I am getting around 3000 signature verification per second.
Adding my other work also, I tested with openssl speed command for secp521r1 curve, there I got around 9000 verification on my machine (40 cores). I tested with Golang also but the performance with secp521r1 is not good, though the performance with secp256r1 is great(28000 verification per second). I reached out to Golang community and found 256 is hand optimized but other curves are not.
I also tested with nodeJs to verify signature, there I got 9000 verification per second which is similar to Openssl. By checking the source code of nodeJs crypto module implementation, I found they are using openssl like implementation.
But I have to work on Java only, so reaching out to the community. Is this the usual result in Java or do we have any openssl like implementation in Java as well?
Dummy Code==========================
package dummy;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import org.bouncycastle.asn1.DERInteger;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.json.JSONObject;
public class DSA {
static JSONObject ob = new JSONObject();
static byte[] strByte = null;
static byte[] realSig;
static String str = "a";//"{\"type\":\"issueTx\",\"userId\":1,\"transaction\":{\"amount\":1000}}"; /a
static byte[] sigdata;
static String sigEdata;
static X509Certificate c;
static String sigTestSigneddata;
public static void main(String[] args)
throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException {
try {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
keyGen.initialize(new ECGenParameterSpec("secp521r1"), new SecureRandom());
KeyPair pair = keyGen.generateKeyPair();
PrivateKey priv = pair.getPrivate();
PublicKey pub = pair.getPublic();
FileWriter fw = new FileWriter("MyKeys/n.pem");
PemWriter writer = new PemWriter(fw);
writer.writeObject(new PemObject("PUBLIC KEY", pub.getEncoded()));
writer.close();
FileWriter fw2 = new FileWriter("MyKeys/n_sk");
PemWriter writer2 = new PemWriter(fw2);
writer2.writeObject(new PemObject("PRIVATE KEY ", priv.getEncoded()));
writer2.close();
Security.addProvider(new BouncyCastleProvider());
Signature ecdsa;
ecdsa = Signature.getInstance("SHA256withECDSA"); // SHA512WITHECDSA SHA512withECDSA
ecdsa.initSign(getPrivate("MyKeys/n_sk"));
strByte = str.getBytes("UTF-8");
ecdsa.update(strByte);
realSig = ecdsa.sign();
sigEdata = Base64.getEncoder().encodeToString(realSig);
Thread.sleep(1000);
verify();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void verify() throws Exception {
verifySignature();
}
private static void verifySignature() throws Exception {
Signature sig = Signature.getInstance("SHA256withECDSA", "BC"); // SHA256withECDSA // SHA512withECDSA
// sig.initVerify(c.getPublicKey()); to verify using digi cert
sig.initVerify(getPublic("MyKeys/n.pem"));
sig.update(str.getBytes());
System.out.println(sig.verify(Base64.getDecoder().decode(sigEdata)));
// sig.verify(sigEdata.getBytes(Charset.defaultCharset()));
System.out.println(str);
}
private static PrivateKey getPrivate(String filename) throws Exception {
PemReader reader = new PemReader(new FileReader(filename));
PemObject pemObject = reader.readPemObject();
byte[] content = pemObject.getContent();
reader.close();
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(content);
KeyFactory kf = KeyFactory.getInstance("EC");
return kf.generatePrivate(spec);
}
private static PublicKey getPublic(String filename) throws Exception {
PemReader reader = new PemReader(new FileReader(filename));
PemObject pemObject = reader.readPemObject();
byte[] content = pemObject.getContent();
reader.close();
X509EncodedKeySpec spec = new X509EncodedKeySpec(content);
KeyFactory kf = KeyFactory.getInstance("EC");
return kf.generatePublic(spec);
}
}
I am wanting generate a keypair once and reuse it.
public static KeyPair generateKeyPair() throws Exception {
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048, new SecureRandom());
KeyPair pair = generator.generateKeyPair();
return pair;
}
How do I go about this?
There is a bit of a problem here: Java's focus is almost entirely on TLS and the cryptography required to implement TLS. For TLS a private key and a certificate is required. So you get into a situation where you:
have to generate a (bogus) self signed certificate to go with your public key or;
have to find another way of storing the private key without a certificate.
However, with (2.) you quickly get a method that isn't very compatible. If you want to go that way, you could create a PKCS#8 encrypted private key that is encrypted using PBE / CBC.
So here's some code to create a self signed certificate and use that to store the key. Note the expiration date, you could set it to 100 years to be on the safe side (or you could actually do some key management).
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStore.Entry;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.UnrecoverableEntryException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Calendar;
import java.util.Date;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
public class StoreKeyPair {
public static KeyPair generateKeyPair() throws Exception {
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048, new SecureRandom());
KeyPair pair = generator.generateKeyPair();
return pair;
}
public static Certificate selfSign(KeyPair keyPair, String subjectDN)
throws OperatorCreationException, CertificateException, IOException
{
Provider bcProvider = new BouncyCastleProvider();
Security.addProvider(bcProvider);
long now = System.currentTimeMillis();
Date startDate = new Date(now);
X500Name dnName = new X500Name(subjectDN);
// Using the current timestamp as the certificate serial number
BigInteger certSerialNumber = new BigInteger(Long.toString(now));
Calendar calendar = Calendar.getInstance();
calendar.setTime(startDate);
// 1 Yr validity
calendar.add(Calendar.YEAR, 1);
Date endDate = calendar.getTime();
// Use appropriate signature algorithm based on your keyPair algorithm.
String signatureAlgorithm = "SHA256WithRSA";
SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair
.getPublic().getEncoded());
X509v3CertificateBuilder certificateBuilder = new X509v3CertificateBuilder(dnName,
certSerialNumber, startDate, endDate, dnName, subjectPublicKeyInfo);
ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).setProvider(
bcProvider).build(keyPair.getPrivate());
X509CertificateHolder certificateHolder = certificateBuilder.build(contentSigner);
Certificate selfSignedCert = new JcaX509CertificateConverter()
.getCertificate(certificateHolder);
return selfSignedCert;
}
public static void main(String[] args) throws Exception {
KeyPair generatedKeyPair = generateKeyPair();
String filename = "test_gen_self_signed.pkcs12";
char[] password = "test".toCharArray();
storeToPKCS12(filename, password, generatedKeyPair);
KeyPair retrievedKeyPair = loadFromPKCS12(filename, password);
// you can validate by generating a signature and verifying it or by
// comparing the moduli by first casting to RSAPublicKey, e.g.:
RSAPublicKey pubKey = (RSAPublicKey) generatedKeyPair.getPublic();
RSAPrivateKey privKey = (RSAPrivateKey) retrievedKeyPair.getPrivate();
System.out.println(pubKey.getModulus().equals(privKey.getModulus()));
}
private static KeyPair loadFromPKCS12(String filename, char[] password)
throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
FileNotFoundException, IOException, UnrecoverableEntryException {
KeyStore pkcs12KeyStore = KeyStore.getInstance("PKCS12");
try (FileInputStream fis = new FileInputStream(filename);) {
pkcs12KeyStore.load(fis, password);
}
KeyStore.ProtectionParameter param = new KeyStore.PasswordProtection(password);
Entry entry = pkcs12KeyStore.getEntry("owlstead", param);
if (!(entry instanceof PrivateKeyEntry)) {
throw new KeyStoreException("That's not a private key!");
}
PrivateKeyEntry privKeyEntry = (PrivateKeyEntry) entry;
PublicKey publicKey = privKeyEntry.getCertificate().getPublicKey();
PrivateKey privateKey = privKeyEntry.getPrivateKey();
return new KeyPair(publicKey, privateKey);
}
private static void storeToPKCS12(
String filename, char[] password,
KeyPair generatedKeyPair) throws KeyStoreException, IOException,
NoSuchAlgorithmException, CertificateException, FileNotFoundException,
OperatorCreationException {
Certificate selfSignedCertificate = selfSign(generatedKeyPair, "CN=owlstead");
KeyStore pkcs12KeyStore = KeyStore.getInstance("PKCS12");
pkcs12KeyStore.load(null, null);
KeyStore.Entry entry = new PrivateKeyEntry(generatedKeyPair.getPrivate(),
new Certificate[] { selfSignedCertificate });
KeyStore.ProtectionParameter param = new KeyStore.PasswordProtection(password);
pkcs12KeyStore.setEntry("owlstead", entry, param);
try (FileOutputStream fos = new FileOutputStream(filename)) {
pkcs12KeyStore.store(fos, password);
}
}
}
Note that I was too lazy to properly handle the exceptions.
This code uses a slightly altered version of this answer, see my comments for why I changed the code.
The public key can of course be stored separately as well. Just call getEncoded and store the resulting SubjectPublicKeyInfo structure.
We are using phpseclib for Public key signing of data and android java is used for Public key verification. But it repeatedtly failed.
PHP Code For generating keys and signing by private key
include_once("phpseclib/autoload.php");
function getKeys($keysize=2048){
$rsa = new Crypt_RSA();
//$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_OPENSSH);
//$rsa->setPublicKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$d = $rsa->createKey($keysize);
return array("publickey"=>$d['publickey'], "privatekey"=>$d['privatekey']);
}
function encryptdata($message, $encryptionKey){
$rsa = new Crypt_RSA();
//$rsa->setPublicKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
//$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_OPENSSH);
$rsa->loadKey($encryptionKey); // public key
return $rsa->encrypt($message);
}
function decryptdata($message, $decryptionKey){
$rsa = new Crypt_RSA();
// $rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_OPENSSH);
// $rsa->setPublicKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$rsa->loadKey($decryptionKey); // private key
return $rsa->decrypt($message);
}
$keys = getKeys();
file_put_contents("key.pub", $keys["publickey"]);
file_put_contents("key.priv", $keys["privatekey"]);
$publickey = file_get_contents("key.pub");
$privatekey = file_get_contents("key.priv");
//print_r($keys);
$string = "Hi I m here";
$hash = hash("sha256", $string);
$encdata = encryptdata($hash, $privatekey);
echo $base_encdata = base64_encode($encdata);
JAVA Code
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.io.UnsupportedEncodingException;
import org.apache.commons.codec.binary.Base64;
import java.security.spec.X509EncodedKeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.KeyFactory;
import java.security.Signature;
import java.security.PublicKey;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.lang.String;
class PubCheck {
public static boolean verify(String message, String signature, PublicKey publicKey) throws SignatureException{
try {
Signature sign = Signature.getInstance("SHA1withRSA");
sign.initVerify(publicKey);
sign.update(message.getBytes("UTF-8"));
return sign.verify(Base64.decodeBase64(signature.getBytes("UTF-8")));
} catch (Exception ex) {
throw new SignatureException(ex);
}
}
public static void main(String[] args)
throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeySpecException, SignatureException
{
String plainData = "Hi I m here";
String pkey = "MIIBCgKCAQEA2tF2g/muNw9xKTVcIkjUMvMhygtIW49yo1PgbwqDQ/w9MSfEARtYYF6Tenfz0twaR/eI14GXmlIffflORe4eaSuMBhwQFOIKU/1+v1BV3RLqGGblvHTVaMVm49AGiqxNnh1LBbcSrC5UhMqlL/HGiku0oYsbjLzwcLc5ac6aBQVD60wWGNm1g26lRQGRbCLqxVfcWKT3AMvEQK3cEx/En7/5Vg1V8xnJraNMrO8UGnaX8LLJFzYJiSCEShh7F+pMHbf4MaBekw7Aaf5hPJtczNsR137R92Be3OP4idI5NLmTV+Pi1DWlxhjEhswKH88SP+gsW31gS7B/ddECUqewQwIDAQAB";
String data = "aP0nuYYA1hE5odsCkR/DcdRbBvO2Z8IOlqXf/bKZJiG8HELIop90Vno1dKC1qyHEAOXy0gtH7GtJamzoBjDZmHPT6eto9EZP/xE7xZ8L05kjp0z2thLqO7on4C6DrG++TK1j+E3T7V0UeU874WIB0AEVzu1XUKFW6aeuU67a/gdn8N2n7N/WXtlyNSVZXg8f4PeUhGvFJrhINZT7BuMMZj1gZs4wMJPAICwfvVeg02RPH0N3Ybf2iVgRuZlmtQXGTyBlCxe9ybdHzuQM6nXghpLNmaOzCypb+yVs3Da7E0b3/fKQ7JqPSquWex2ERZbIMSTC6oCzc1rOF6iKVAd92Q==";
byte[] encodedPublicKey = pkey.getBytes( "utf-8" );
//System.out.println(new String(encodedPublicKey, "UTF-8") + "\n");
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec( encodedPublicKey );
//PKCS8EncodedKeySpec publicKeySpec = new PKCS8EncodedKeySpec(encodedPublicKey);
KeyFactory keyFactory = KeyFactory.getInstance( "RSA" );
PublicKey publicKey = keyFactory.generatePublic( publicKeySpec );
boolean retvar = verify(plainData, data, publicKey);
// 3 - verifying content with signature and content :
/*Signature sig = Signature.getInstance( "SHA256withRSA" );
sig.initVerify( publicKey );
sig.update( data.getBytes( ) );
ret = sig.verify( sign.getBytes( ) );*/
//byte[] decoded = Base64.decodeBase64(data);
}
}
I compiled java code by
javac -cp commons-codec-1.10.jar:. PubCheck.java
java -cp commons-codec-1.10.jar:. PubCheck
Then found following exception
Exception in thread "main" java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:205)
at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
at PubCheck.main(PubCheck.java:67)
Caused by: java.security.InvalidKeyException: invalid key format
at sun.security.x509.X509Key.decode(X509Key.java:387)
at sun.security.x509.X509Key.decode(X509Key.java:403)
at sun.security.rsa.RSAPublicKeyImpl.<init>(RSAPublicKeyImpl.java:83)
at sun.security.rsa.RSAKeyFactory.generatePublic(RSAKeyFactory.java:298)
at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:201)
... 2 more
Disclaimer : I have zero knowledge about java. all the code I try found from net.
UPDATE : Issue finally solved and java code able to verify by help from Maarten Bodewes. Code he provided works with one change I need to pass PKCS1 from phpseclib So I changed
Signature sig = Signature.getInstance( "SHA256withRSAandMGF1");
to
Signature sig = Signature.getInstance( "SHA256withRSA");
PHP Code need changes for using sign instead of manually encrypt/hashing.
function getKeys($keysize=2048){
$rsa = new Crypt_RSA();
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$d = $rsa->createKey($keysize);
return array("publickey"=>$d['publickey'], "privatekey"=>$d['privatekey']);
}
$string = "Hi I m here";
/*
$keys = getKeys();
file_put_contents("key1.pub", $keys["publickey"]);
file_put_contents("key1.priv", $keys["privatekey"]);
die;*/
$publickey = file_get_contents("key1.pub");
$privatekey = file_get_contents("key1.priv");
$hash = new Crypt_Hash('sha256');
$rsa = new Crypt_RSA();
$rsa->loadKey($privatekey);
$rsa->setSignatureMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->setHash('sha256');
$signature = $rsa->sign($string);
echo base64_encode($signature);
PKCS#1 keys are almost but not completely the same as X.509 keys.
The following snippet will create a Java JCA compliant public key. It will then try and perform the (default) OAEP decryption.
package nl.owlstead.stackoverflow;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.security.Signature;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import java.util.Base64;
import java.util.Base64.Decoder;
import javax.crypto.Cipher;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class PKCS1PublicKey {
public static RSAPublicKey fromPKCS1Encoding(byte[] pkcs1EncodedPublicKey) {
// --- parse public key ---
org.bouncycastle.asn1.pkcs.RSAPublicKey pkcs1PublicKey;
try {
pkcs1PublicKey = org.bouncycastle.asn1.pkcs.RSAPublicKey
.getInstance(pkcs1EncodedPublicKey);
} catch (Exception e) {
throw new IllegalArgumentException(
"Could not parse BER PKCS#1 public key structure", e);
}
// --- convert to JCE RSAPublicKey
RSAPublicKeySpec spec = new RSAPublicKeySpec(
pkcs1PublicKey.getModulus(), pkcs1PublicKey.getPublicExponent());
KeyFactory rsaKeyFact;
try {
rsaKeyFact = KeyFactory.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("RSA KeyFactory should be available", e);
}
try {
return (RSAPublicKey) rsaKeyFact.generatePublic(spec);
} catch (InvalidKeySpecException e) {
throw new IllegalArgumentException(
"Invalid RSA public key, modulus and/or exponent invalid", e);
}
}
public static void main(String[] args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
String pkey = "MIIBCgKCAQEA2tF2g/muNw9xKTVcIkjUMvMhygtIW49yo1PgbwqDQ/w9MSfEARtYYF6Tenfz0twaR/eI14GXmlIffflORe4eaSuMBhwQFOIKU/1+v1BV3RLqGGblvHTVaMVm49AGiqxNnh1LBbcSrC5UhMqlL/HGiku0oYsbjLzwcLc5ac6aBQVD60wWGNm1g26lRQGRbCLqxVfcWKT3AMvEQK3cEx/En7/5Vg1V8xnJraNMrO8UGnaX8LLJFzYJiSCEShh7F+pMHbf4MaBekw7Aaf5hPJtczNsR137R92Be3OP4idI5NLmTV+Pi1DWlxhjEhswKH88SP+gsW31gS7B/ddECUqewQwIDAQAB";
Decoder decoder = Base64.getDecoder();
byte[] dpkey = decoder.decode(pkey);
RSAPublicKey publicKey = fromPKCS1Encoding(dpkey);
String plainData = "Hi I m here";
String data = "aP0nuYYA1hE5odsCkR/DcdRbBvO2Z8IOlqXf/bKZJiG8HELIop90Vno1dKC1qyHEAOXy0gtH7GtJamzoBjDZmHPT6eto9EZP/xE7xZ8L05kjp0z2thLqO7on4C6DrG++TK1j+E3T7V0UeU874WIB0AEVzu1XUKFW6aeuU67a/gdn8N2n7N/WXtlyNSVZXg8f4PeUhGvFJrhINZT7BuMMZj1gZs4wMJPAICwfvVeg02RPH0N3Ybf2iVgRuZlmtQXGTyBlCxe9ybdHzuQM6nXghpLNmaOzCypb+yVs3Da7E0b3/fKQ7JqPSquWex2ERZbIMSTC6oCzc1rOF6iKVAd92Q==";
byte[] ciphertext = decoder.decode(data);
// this will fail of course if the "signature" was generated using OAEP - use PSS signatures instead (see comments below)
verifyBC(publicKey, plainData, ciphertext);
System.out.flush();
decryptBC(publicKey, plainData, ciphertext);
System.out.flush();
decryptSun(publicKey, plainData, ciphertext);
System.out.flush();
}
private static void decryptBC(RSAPublicKey publicKey, String plainData,
byte[] ciphertext) throws Exception {
Cipher oaep = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding", "BC");
// this *should* fail
oaep.init(Cipher.DECRYPT_MODE, publicKey);
byte[] plaintext = oaep.doFinal(ciphertext);
System.out.println(new String(plaintext, UTF_8));
}
private static void decryptSun(RSAPublicKey publicKey, String plainData,
byte[] ciphertext) throws Exception {
Cipher oaep = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding", "SunJCE");
// this fails beautifully
oaep.init(Cipher.DECRYPT_MODE, publicKey);
byte[] plaintext = oaep.doFinal(ciphertext);
System.out.println(new String(plaintext, UTF_8));
}
private static void verifyBC(RSAPublicKey publicKey, String plainData,
byte[] ciphertext) throws Exception {
// what should work (for PKCS#1 v1.5 signatures), requires Bouncy Castle provider
Signature sig = Signature.getInstance( "SHA256withRSAandMGF1");
sig.initVerify(publicKey);
sig.update(plainData.getBytes(UTF_8));
System.out.println(sig.verify(ciphertext));
}
}
The SunJCE implementation of OAEP will fail because it will not accept the public key for signature verification:
OAEP cannot be used to sign or verify signatures
Now that has to be one of the most clear and informative exceptions I've met in a cryptography API. You can also use the Bouncy Castle provider and this one will "decrypt" the hash value. That's however not how OAEP should be used, you should be using PSS to verify signatures.
You should be using the PHP RSA sign method instead, using setHash to setup SHA-256.
Although Martin's answer works there's another way to get rid of the InvalidKeySpecException exception.
In your original code pkey is a PKCS1 formatted RSA private key. It needs to be a PKCS8 formatted private key to work with X509EncodedKeySpec (which corresponds to an X509 cert's SubjectPublicKeyInfo). It also needs to be base64 decoded.
So in your PHP code you wouldn't do $rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1) - you'd do $rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS8).
I converted your PKCS1 key to PKCS8 myself and got this:
String pkey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2tF2g/muNw9xKTVcIkjU" +
"MvMhygtIW49yo1PgbwqDQ/w9MSfEARtYYF6Tenfz0twaR/eI14GXmlIffflORe4e" +
"aSuMBhwQFOIKU/1+v1BV3RLqGGblvHTVaMVm49AGiqxNnh1LBbcSrC5UhMqlL/HG" +
"iku0oYsbjLzwcLc5ac6aBQVD60wWGNm1g26lRQGRbCLqxVfcWKT3AMvEQK3cEx/E" +
"n7/5Vg1V8xnJraNMrO8UGnaX8LLJFzYJiSCEShh7F+pMHbf4MaBekw7Aaf5hPJtc" +
"zNsR137R92Be3OP4idI5NLmTV+Pi1DWlxhjEhswKH88SP+gsW31gS7B/ddECUqew" +
"QwIDAQAB";
byte[] encodedPublicKey = Base64.decodeBase64(pkey);
You'd, of course, need to remove your existing pkey and encodedPublicKey assignments.
Also, you could do return $d instead of return array("publickey"=>$d['publickey'], "privatekey"=>$d['privatekey']) in your PHP code..
I have an RSA private key that I am trying to decrypt another files contents that has an AES key in it. So far all I can seem to get to return from the processes is jargon. Not really sure what I am doing wrong in the below code. I have looked on google and have seen this done at least a 100 different ways.
import java.io.*;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.GeneralSecurityException;
import java.security.spec.PKCS8EncodedKeySpec;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
public class RsaEncryption {
private Cipher _pkCipher;
public RsaEncryption() throws GeneralSecurityException {
// create RSA public key cipher
_pkCipher = Cipher.getInstance("RSA");
}
public String loadKey(File in, String privateKey) throws GeneralSecurityException, IOException, Exception {
privateKey = privateKey.replaceAll("-+.*?-+", "");
byte[] encodedKey = Base64.decodeBase64(privateKey);
// create private key
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPrivateKey pk = (RSAPrivateKey) kf.generatePrivate(privateKeySpec);
// read AES key
_pkCipher.init(Cipher.DECRYPT_MODE, pk);
byte[] encryptedBytes = FileUtils.readFileToByteArray(in);
ByteArrayInputStream fileIn = new ByteArrayInputStream(encryptedBytes);
CipherInputStream cis = new CipherInputStream(fileIn, _pkCipher);
DataInputStream dis = new DataInputStream(cis);
byte[] decryptedData = new byte[32];
dis.read(decryptedData);
String key = new String(decryptedData);
return key;
}
}
UPDATE
New way with bouncy castles pem converter still not working
import java.io.StringReader;
import java.io.File;
import java.io.IOException;
import java.security.KeyPair;
import java.security.interfaces.RSAPrivateKey;
import java.security.GeneralSecurityException;
import java.security.interfaces.RSAPublicKey;
import javax.crypto.Cipher;
import org.apache.commons.io.FileUtils;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
public class RsaEncryption {
private Cipher _pkCipher;
private RSAPrivateKey _PrivateKey;
private RSAPublicKey _PublicKey;
public RsaEncryption(String privateKey) throws GeneralSecurityException, IOException {
loadKey(privateKey);
// create RSA public key cipher
_pkCipher = Cipher.getInstance("RSA/None/PKCS1Padding", "BC");
}
private void loadKey(String privateKey) throws IOException {
PEMParser pemParser = new PEMParser(new StringReader(privateKey));
PEMKeyPair pemKeyPair = (PEMKeyPair) pemParser.readObject();
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
KeyPair keyPair = converter.getKeyPair(pemKeyPair);
_PrivateKey = (RSAPrivateKey) keyPair.getPrivate();
_PublicKey = (RSAPublicKey) keyPair.getPublic();
pemParser.close();
}
public String decrypt(File in) throws GeneralSecurityException , IOException{
_pkCipher.init(Cipher.DECRYPT_MODE, _PrivateKey);
byte[] encryptedBytes = FileUtils.readFileToByteArray(in);
String key = new String(_pkCipher.doFinal(encryptedBytes));
System.out.println(key);
return key;
}
public RSAPrivateKey getPrivateKey() { return _PrivateKey; }
public RSAPublicKey getPublicKey() { return _PublicKey; }
}
RSA can only encrypt a small amount of data which must be processed as a chunk. You don't need a stream for that. Simply call
byte[] aesKey = _pkCipher.doFinal(FileUtils.readFileToByteArray(in));
to get the AES key.
JCE jars where in the wrong directory worked just fine once they got put in the correct directory.
How can I get the signature of a string using SHA1withRSA if I already have the Private Key as byte[] or String?
I guess what you say is you know the key pair before hand and want to sign/verify with that.
Please see the following code.
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
import sun.misc.BASE64Encoder;
public class MainClass {
public static void main(String[] args) throws Exception {
KeyPair keyPair = getKeyPair();
byte[] data = "test".getBytes("UTF8");
Signature sig = Signature.getInstance("SHA1WithRSA");
sig.initSign(keyPair.getPrivate());
sig.update(data);
byte[] signatureBytes = sig.sign();
System.out.println("Signature:" + new BASE64Encoder().encode(signatureBytes));
sig.initVerify(keyPair.getPublic());
sig.update(data);
System.out.println(sig.verify(signatureBytes));
}
private static KeyPair getKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
return kpg.genKeyPair();
}
}
Here you need to change the method getKeyPair() to supply your known key pair. You may load it from a java key store [JKS].
You can't just have an arbitrary byte array either as your public key or private key. They should be generated in relation.
public static String sign(String plainText, PrivateKey privateKey) throws Exception {
Signature privateSignature = Signature.getInstance("SHA256withRSA");
privateSignature.initSign(privateKey);
privateSignature.update(plainText.getBytes(UTF_8));
byte[] signature = privateSignature.sign();
return Base64.getEncoder().encodeToString(signature);
}
public static boolean verify(String plainText, String signature, PublicKey publicKey) throws Exception {
Signature publicSignature = Signature.getInstance("SHA256withRSA");
publicSignature.initVerify(publicKey);
publicSignature.update(plainText.getBytes(UTF_8));
byte[] signatureBytes = Base64.getDecoder().decode(signature);
return publicSignature.verify(signatureBytes);
}
I use bouncy-castle to sign data and verify it.
you should add maven dependency:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.56</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.56</version>
</dependency>
Load RSA private or public key from a disk file into a Java object
First, we need to be able to load RSA private or public key from a disk file into a Java object of a proper class from Bouncy Castle
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.commons.lang3.Validate;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.crypto.util.PublicKeyFactory;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
public class KeyUtil {
public static AsymmetricKeyParameter loadPublicKey(InputStream is) {
SubjectPublicKeyInfo spki = (SubjectPublicKeyInfo) readPemObject(is);
try {
return PublicKeyFactory.createKey(spki);
} catch (IOException ex) {
throw new RuntimeException("Cannot create public key object based on input data", ex);
}
}
public static AsymmetricKeyParameter loadPrivateKey(InputStream is) {
PEMKeyPair keyPair = (PEMKeyPair) readPemObject(is);
PrivateKeyInfo pki = keyPair.getPrivateKeyInfo();
try {
return PrivateKeyFactory.createKey(pki);
} catch (IOException ex) {
throw new RuntimeException("Cannot create private key object based on input data", ex);
}
}
private static Object readPemObject(InputStream is) {
try {
Validate.notNull(is, "Input data stream cannot be null");
InputStreamReader isr = new InputStreamReader(is, "UTF-8");
PEMParser pemParser = new PEMParser(isr);
Object obj = pemParser.readObject();
if (obj == null) {
throw new Exception("No PEM object found");
}
return obj;
} catch (Throwable ex) {
throw new RuntimeException("Cannot read PEM object from input data", ex);
}
}
}
Creation of an RSA digital signature
// GIVEN: InputStream prvKeyInpStream
AsymmetricKeyParameter privKey = KeyUtil.loadPrivateKey(prvKeyInpStream);
// GIVEN: byte[] messageBytes = ...
RSADigestSigner signer = new RSADigestSigner(new SHA512Digest());
signer.init(true, privKey);
signer.update(messageBytes, 0, messageBytes.length);
try {
byte[] signature = signer.generateSignature();
} catch (Exception ex) {
throw new RuntimeException("Cannot generate RSA signature. " + ex.getMessage(), ex);
}
Verification of an RSA digital signature
// GIVEN: InputStream pubKeyInpStream
AsymmetricKeyParameter publKey = KeyUtil.loadPublicKey(pubKeyInpStream);
// GIVEN: byte[] messageBytes
RSADigestSigner signer = new RSADigestSigner(new SHA512Digest());
signer.init(false, publKey);
signer.update(messageBytes, 0, messageBytes.length);
// GIVEN: byte[] signature - see code sample above
boolean isValidSignature = signer.verifySignature(signature);
public static String sign(String samlResponseString, String keystoreFile, String keyStorePassword, String privateKeyPassword, String alias)
throws NoSuchAlgorithmException, UnsupportedEncodingException,
InvalidKeyException, SignatureException {
PrivateKey pkey=getPrivateKey( keystoreFile, keyStorePassword, privateKeyPassword, alias);
String signedString = null;
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(pkey);
signature.update(samlResponseString.getBytes());
byte[] signatureBytes = signature.sign();
byte[] encryptedByteValue = Base64.encodeBase64(signatureBytes);
signedString = new String(encryptedByteValue, "UTF-8");
System.out.println(signedString);
return signedString;
}
You first must create a public key from array of bytes
byte publicKeyBytes[] = .... your public key in bytes ...
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes));
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
and after using the publicKey to encrypt
String data = "... data to be encrypted ....";
String alg = "RSA/ECB/PKCS1Padding";
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte encryptedBytes[] = cipher.doFinal(data.getBytes());
Now only who have the privateKey can read your data
#rczajka: a publicKey is a key. You can use it to sign somethig that only the owner (that have the privateKey) can read.