开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜