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

chat.dim.plugins.RSAPublicKey Maven / Gradle / Ivy

There is a newer version: 1.1.0
Show newest version
/* license: https://mit-license.org
 * ==============================================================================
 * The MIT License (MIT)
 *
 * Copyright (c) 2019 Albert Moky
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 * ==============================================================================
 */
package chat.dim.plugins;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Map;

import chat.dim.crypto.EncryptKey;
import chat.dim.format.PEM;
import chat.dim.impl.PublicKeyImpl;

/**
 *  RSA Public Key
 *
 *      keyInfo format: {
 *          algorithm: "RSA",
 *          data: "..."       // base64
 *      }
 */
public final class RSAPublicKey extends PublicKeyImpl implements EncryptKey {

    private final java.security.interfaces.RSAPublicKey publicKey;

    public RSAPublicKey(Map dictionary)
            throws NoSuchFieldException, InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException {
        super(dictionary);
        publicKey = getKey();
    }

    private int keySize() {
        // TODO: get from key

        Object size = dictionary.get("keySize");
        if (size == null) {
            return 1024 / 8; // 128
        } else  {
            return (int) size;
        }
    }

    private java.security.interfaces.RSAPublicKey getKey()
            throws NoSuchFieldException, InvalidKeySpecException, NoSuchAlgorithmException, NoSuchProviderException {
        Object data = dictionary.get("data");
        if (data == null) {
            throw new NoSuchFieldException("RSA public key data not found");
        }
        return parse((String) data);
    }

    private static java.security.interfaces.RSAPublicKey parse(String fileContent)
            throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
        PEM pemFile = new PEM(fileContent);
        byte[] publicKeyData = pemFile.publicKeyData;
        if (publicKeyData == null) {
            return null;
        }
        // X.509
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyData);
        KeyFactory factory;
        try {
            factory = KeyFactory.getInstance("RSA", "BC");
        } catch (NoSuchAlgorithmException e) {
            //e.printStackTrace();
            factory = KeyFactory.getInstance("RSA");
        }
        return (java.security.interfaces.RSAPublicKey) factory.generatePublic(keySpec);
    }

    @Override
    public byte[] getData() {
        return publicKey == null ? null : publicKey.getEncoded();
    }

    @Override
    public byte[] encrypt(byte[] plaintext) {
        if (plaintext.length > (keySize() - 11)) {
            throw new InvalidParameterException("RSA plain text length error: " + plaintext.length);
        }
        try {
            Cipher cipher;
            try {
                cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
            } catch (NoSuchAlgorithmException e) {
                //e.printStackTrace();
                cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            }
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            return cipher.doFinal(plaintext);
        } catch (NoSuchProviderException | NoSuchAlgorithmException | NoSuchPaddingException |
                InvalidKeyException |
                IllegalBlockSizeException | BadPaddingException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public boolean verify(byte[] data, byte[] signature) {
        try {
            Signature signer;
            try {
                signer = Signature.getInstance("SHA256withRSA", "BC");
            } catch (NoSuchAlgorithmException e) {
                //e.printStackTrace();
                signer = Signature.getInstance("SHA256withRSA");
            }
            signer.initVerify(publicKey);
            signer.update(data);
            return signer.verify(signature);
        } catch (NoSuchProviderException | NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
            e.printStackTrace();
            return false;
        }
    }

    static {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy