Java加密扩展 JCE

使用 RSA 加密上传文件到网易云存储,发现报错

Make sure you have the JCE unlimited strength policy files installed and configured for your JVM

原因是缺少 Java 加密扩展 JCE

解决办法

我的环境是 Java 8 ,可以去这里下载

下载后得到2个 jar 文件

我的环境是 mac 将其拷贝到

/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/jre/lib/security

再次运行程序即可。

网易云 AWS S3 RSA 加密方式上传文件代码

package awsnos.awsnos;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import com.amazonaws.ClientConfiguration;
import com.amazonaws.Protocol;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3Encryption;
import com.amazonaws.services.s3.AmazonS3EncryptionClientBuilder;
import com.amazonaws.services.s3.model.CryptoConfiguration;
import com.amazonaws.services.s3.model.CryptoMode;
import com.amazonaws.services.s3.model.CryptoStorageMode;
import com.amazonaws.services.s3.model.EncryptionMaterials;
import com.amazonaws.services.s3.model.EncryptionMaterialsProvider;
import com.amazonaws.services.s3.model.StaticEncryptionMaterialsProvider;

public class Aws3 {

    // loadKeyPair的实现方式,非对称加密algorithm = RSA
    public static KeyPair loadKeyPairRSA(String path, String algorithm)
            throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
        // read public key from file
        File filePublicKey = new File(path + "/public.key");
        FileInputStream fis = new FileInputStream(filePublicKey);
        byte[] encodedPublicKey = new byte[(int) filePublicKey.length()];
        fis.read(encodedPublicKey);
        fis.close();

        // read private key from file
        File filePrivateKey = new File(path + "/private.key");
        fis = new FileInputStream(filePrivateKey);
        byte[] encodedPrivateKey = new byte[(int) filePrivateKey.length()];
        fis.read(encodedPrivateKey);
        fis.close();

        // Convert them into KeyPair
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedPublicKey);
        PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

        PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
        PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);

        return new KeyPair(publicKey, privateKey);
    }

    // 对称加密,algorithm = AES
    public static SecretKeySpec loadKeyPairAES(String path, String algorithm) throws IOException {
        // Read private key from file.
        File keyFile = new File(path);
        FileInputStream keyfis = new FileInputStream(keyFile);
        byte[] encodedPrivateKey = new byte[(int) keyFile.length()];
        keyfis.read(encodedPrivateKey);
        keyfis.close();
        // Generate secret key.
        return new SecretKeySpec(encodedPrivateKey, algorithm);
    }

    // 生成Key的方式,非对称加密
    public static KeyPair genKeyPair(String algorithm, int bitLength) throws NoSuchAlgorithmException {
        KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance(algorithm);
        SecureRandom srand = new SecureRandom();
        keyGenerator.initialize(bitLength, srand);
        return keyGenerator.generateKeyPair();
    }

    // 生成Key的方式,对称加密
    public static SecretKey generateCMasterKey() throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
        KeyGenerator symKeyGenerator = null;
        try {
            symKeyGenerator = KeyGenerator.getInstance("AES");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        symKeyGenerator.init(256);
        return symKeyGenerator.generateKey();
    }

    // 保存Key,该key只要生成一次就好了,要妥善保管,如果该key丢失了,那么意味着通过该key加密的数据将没法解密

    // 非对称
    public static void saveKeyPair(String dir, KeyPair keyPair) throws IOException {
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();

        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey.getEncoded());
        FileOutputStream fos = new FileOutputStream(dir + "/public.key");
        fos.write(x509EncodedKeySpec.getEncoded());
        fos.close();

        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey.getEncoded());
        fos = new FileOutputStream(dir + "/private.key");
        fos.write(pkcs8EncodedKeySpec.getEncoded());
        fos.close();
    }

    // 对称
    public static void saveSymmetricKey(String path, SecretKey secretKey) throws IOException {
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(secretKey.getEncoded());
        FileOutputStream keyfos = new FileOutputStream(path);
        keyfos.write(x509EncodedKeySpec.getEncoded());
        keyfos.close();
    }

    public static void main(String[] args) throws NoSuchAlgorithmException {

        String accessKey = "";
        String secretKey = "";
        String bucketName = "cloud201411";
        // 1.生成RSA 密钥对
        // try {
        // saveKeyPair("/Users/wenjun/Downloads/rsa", genKeyPair("RSA", 1024));
        //
        // } catch (IOException e) {
        // // TODO Auto-generated catch block
        // e.printStackTrace();
        // }

        // 2.加载 RSA 文件
        String keyDir = "/Users/wenjun/Downloads/rsa";
        // 1.获取CMK,客户端主密钥,可以使用对称和分对称两种方式,下述使用的是非对称的
        KeyPair keyPair = null;
        try {
            keyPair = loadKeyPairRSA(keyDir, "RSA");
        } catch (InvalidKeySpecException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // 2. Construct an instance of AmazonS3Encryption.
        EncryptionMaterials encryptionMaterials = new EncryptionMaterials(keyPair);
        ClientConfiguration configuration = new ClientConfiguration();
        configuration.setProtocol(Protocol.HTTPS);
        CryptoConfiguration cryptoConfiguration = new CryptoConfiguration();
        // 支持EncryptionOnly,AuthenticatedEncryption,StrictAuthenticatedEncryption,默认是EncryptionOnly,StrictAuthenticatedEncryption不支持range请求
        cryptoConfiguration.setCryptoMode(CryptoMode.StrictAuthenticatedEncryption);
        // 保存加密信息的方式,有两种方式,Instruction模式和Metadata模式,由于NOS分块上传和S3支持上存在一些差异,导致metadata保存的方式大文件下载时由于找不到加密信息而不解密
        cryptoConfiguration.setStorageMode(CryptoStorageMode.InstructionFile);

        EncryptionMaterialsProvider encryptionMaterialsProvider = new StaticEncryptionMaterialsProvider(
                encryptionMaterials);

        ClientConfiguration clientConfiguration = new ClientConfiguration();
        clientConfiguration.setProtocol(Protocol.HTTPS);
        AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration(
                "nos-eastchina1.126.net", "us-east-1");
        AmazonS3Encryption encryptionClient = AmazonS3EncryptionClientBuilder.standard()
                .withCryptoConfiguration(cryptoConfiguration)
                .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey)))
                .withEncryptionMaterials(encryptionMaterialsProvider).withClientConfiguration(clientConfiguration)
                .withEndpointConfiguration(endpointConfiguration).build();


        //要上传文件的路径
        String filePath = "tomcat.zip";

        try {
            encryptionClient.putObject(bucketName,"tomcat11111.zip", new File(filePath));
        }catch (Exception e){
           System.out.println(e.getMessage());
        }
    }


}

加密后看到存储有2个文件

一个是 tomcat.zip.instruction,一个是 tomcat.zip

tomcat.zip.instruction 记录着加密文件的元信息

{"x-amz-tag-len":"128","x-amz-iv":"glBQ2qlgTn+8tJkG","x-amz-wrap-alg":"RSA/ECB/OAEPWithSHA-256AndMGF1Padding","x-amz-key-v2":"G/ZrpexIpCaRBHNaU/mBTzAVY61Dm8OlQbvV4EJea2+o4mFcZn2FZ6KXVUb3/qzaYlcol6+nc9gum9J+pNZW1x2tG5RoPJ8e743IOJ9GD7zO5evpUzvk658w4iWbLuaCxTayzha/7VDIBwRiVGClseytCJ2WusadSmFHaIRike4=","x-amz-cek-alg":"AES/GCM/NoPadding","x-amz-matdesc":"{}"}

AES 的加密方式请查看这里