使用 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 的加密方式请查看这里