How to sign string with private key
How can I get the signature of a string us开发者_StackOverflowing 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.
精彩评论