All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.wavesplatform.crypto.rsa.RsaKeyPair Maven / Gradle / Ivy

package com.wavesplatform.crypto.rsa;

import com.wavesplatform.crypto.base.Base58;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.*;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Arrays;
import java.util.Objects;

/**
 * Pair of RSA private and public keys to encrypt/decrypt or signing data.
 *
 * RSA signatures are supported in Ride language.
 */
@SuppressWarnings("WeakerAccess")
public class RsaKeyPair {

    /**
     * Create key pair from the known RSA private key.
     *
     * @param privateKeyBytes bytes of the private key
     * @return pair of RSA private and public keys
     */
    public static RsaKeyPair from(byte[] privateKeyBytes) {
        return new RsaKeyPair(privateKeyBytes);
    }

    /**
     * Create pair of random RSA private and public keys.
     *
     * @return random RSA key pair
     */
    public static RsaKeyPair random() {
        return new RsaKeyPair();
    }

    private final BouncyCastleProvider bcp;
    private final PrivateKey privateKey;
    private final PublicKey publicKey;

    /**
     * Create key pair from the known RSA private key.
     *
     * @param privateKeyBytes bytes of the private key
     */
    public RsaKeyPair(byte[] privateKeyBytes) {
        this.bcp = new BouncyCastleProvider();
        PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(privateKeyBytes);
        try {
            KeyFactory kf = KeyFactory.getInstance("RSA");
            this.privateKey = kf.generatePrivate(ks);
            RSAPrivateCrtKey privateCrtKey = (RSAPrivateCrtKey) this.privateKey;
            RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(privateCrtKey.getModulus(), privateCrtKey.getPublicExponent());
            this.publicKey = kf.generatePublic(publicKeySpec);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Create pair of random RSA private and public keys.
     */
    public RsaKeyPair() {
        this.bcp = new BouncyCastleProvider();

        KeyPairGenerator gen;
        try {
            gen = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
        gen.initialize(2048, new SecureRandom());

        KeyPair keys = gen.generateKeyPair();
        this.privateKey = keys.getPrivate();
        this.publicKey = keys.getPublic();
    }

    /**
     * Get the RSA private key.
     *
     * @return the private key
     */
    public byte[] privateKey() {
        return this.privateKey.getEncoded();
    }

    /**
     * Get the RSA public key.
     *
     * @return the public key
     */
    public byte[] publicKey() {
        return this.publicKey.getEncoded();
    }

    /**
     * Sign the message by the RSA private key with specified hashing algorithm.
     *
     * @param alg hashing algorithm
     * @param message message to sign
     * @return RSA signature
     * @see HashAlg
     */
    public byte[] sign(HashAlg alg, byte[] message) {
        try {
            Signature sig = initJSignature(alg);
            sig.initSign(this.privateKey);
            sig.update(message);
            return sig.sign();
        } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Check if the message is actually signed by the RSA private key with the specified hashing algorithm.
     *
     * @param alg hashing algorithm
     * @param message message bytes
     * @param signature signature to validate
     * @return true if the signature is valid
     * @see HashAlg
     */
    public boolean isSignatureValid(HashAlg alg, byte[] message, byte[] signature) {
        try {
            Signature sig = initJSignature(alg);
            sig.initVerify(this.publicKey);
            sig.update(message);
            return sig.verify(signature);
        } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
            throw new RuntimeException(e);
        }
    }

    private Signature initJSignature(HashAlg alg) throws NoSuchAlgorithmException {
        return Signature.getInstance(alg.value() + "withRSA", bcp);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        RsaKeyPair keyPair = (RsaKeyPair) o;
        return Arrays.equals(this.privateKey(), keyPair.privateKey()) &&
                Arrays.equals(this.publicKey(), keyPair.publicKey());
    }

    @Override
    public int hashCode() {
        return Objects.hash(this.privateKey(), this.publicKey());
    }

    @Override
    public String toString() {
        return "RsaKeyPair{" +
                "privateKey=" + Base58.encode(this.privateKey()) +
                ", publicKey=" + Base58.encode(this.publicKey()) +
                '}';
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy