How can I get the signature of a string using SHA1withRSA
if I already have the Private Key as byte[]
or String
?
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;
}
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 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.
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);
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.