客户端加密是指将数据发送到OSS之前在用户本地进行加密。

免责声明

  • 使用客户端加密功能时,您需要对主密钥的完整性和正确性负责。因您维护不当导致主密钥用错或丢失,从而导致加密数据无法解密所引起的一切损失和后果均由您自行承担。
  • 在对加密数据进行复制或者迁移时,您需要对加密元信息的完整性和正确性负责。因您维护不当导致加密元信息出错或丢失,从而导致加密数据无法解密所引起的一切损失和后果均由您自行承担。

背景信息

使用客户端加密时,会为每个Object生成一个随机密钥,用该随机密钥对Object的数据进行对称加密。主密钥用于对该随机的对称密钥进行加密,加密后的内容会当作Object的meta信息保存在服务端。解密时先用主密钥将加密后的随机密钥解密出来,再用解密出来的随机密钥解密Object的数据。主密钥只参与客户端本地计算,不会在网络上进行传输或保存在服务端,以保证主密钥的数据安全。

注意
  • 客户端加密支持分片上传超过5 GB的文件。在使用分片方式上传文件时,需要指定上传文件的总大小和分片大小, 除了最后一个分片外,每个分片的大小要一致,且分片大小目前必须是16的整数倍。
  • 调用客户端加密上传文件后,加密元数据会被保护,无法通过CopyObject修改object meta信息。

加密方式

对于主密钥的使用,目前支持如下两种方式:

  • 使用KMS托管用户主密钥

    当使用KMS托管用户主密钥用于客户端数据加密时,需要将KMS用户主密钥ID(即CMK ID)传递给SDK。

  • 使用用户自主管理的主密钥(RSA)

    主密钥信息由用户提供,需要用户将主密钥的公钥、私钥信息当做参数传递给SDK。

使用以上两种加密方式能够有效地避免数据泄漏,保护客户端数据安全。即使数据泄漏,其他人也无法解密得到原始数据。

加密元信息

参数 描述 是否必需
x-oss-meta-client-side-encryption-key 加密后的密钥。 经过主秘钥加密后再经过base64编码的字符串。
x-oss-meta-client-side-encryption-start 随机产生的用于加密数据的初始值 。经过主秘钥加密后再经过base64编码的字符串。
x-oss-meta-client-side-encryption-cek-alg 数据的加密算法。
x-oss-meta-client-side-encryption-wrap-alg 数据密钥的加密算法。
x-oss-meta-client-side-encryption-matdesc 主秘钥的描述信息。JSON格式。
警告 强烈建议为每个主秘钥都配置描述信息,并保存好主秘钥和描述信息之间的对应关系。否则不支持更换主秘钥进行加密。
x-oss-meta-client-side-encryption-unencrypted-content-length 加密前的数据长度。如未指定content-length则不生成该参数。
x-oss-meta-client-side-encryption-unencrypted-content-md5 加密前数据的MD5。如未指定MD5,则不生成该参数。
x-oss-meta-client-side-encryption-data-size 若加密Multipart文件需要在init_multipart时传入整个大文件的总大小。 是(分片上传)
x-oss-meta-client-side-encryption-part-size 若加密Multipart文件需要在init_multipart时传入分片大小。
说明 目前分片大小必须是16的整数倍。
是(分片上传)

创建加密客户端

说明 使用客户端加密时,你需要在工程里添加 Bouncy Castle Crypto 包,例如在pom.xml 中加入如下依赖。
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.62</version>
</dependency>
  • 创建RSA加密客户端

    创建RSA加密客户端之前,需要创建非对称密钥KeyPair对象。OSS Java SDK提供了从PKCS1编码或PKCS8编码的pem格式私钥字符串到RSAPrivateKey对象的转换方法,以及从X509编码pem格式公钥字符串到RSAPublicKey对象的转换,如果您使用的密钥符合上述情况可以使用如下方法转换:

    RSAPrivateKey SimpleRSAEncryptionMaterials.getPrivateKeyFromPemPKCS1(String privateKeyStr);

    RSAPrivateKey SimpleRSAEncryptionMaterials.getPrivateKeyFromPemPKCS8(String privateKeyStr);

    RSAPublicKey SimpleRSAEncryptionMaterials.getPublicKeyFromPemX509(String publicKeyStr);

    创建RSA加密客户端示例代码如下:

    // Endpoint以杭州为例,其它Region请按实际情况填写。
    String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
    // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
    String accessKeyId = "<yourAccessKeyId>";
    String accessKeySecret = "<yourAccessKeySecret>";
    
    // 填写您的RSA私钥字符串。
    final String PRIVATE_PKCS1_PEM = "<yourPrivateKeyWithPKCS1PemString>";
    // 填写您的RSA公钥字符串。
    final String PUBLIC_X509_PEM = "<yourPublicKeyWithX509PemString>";
    
    // 创建一个RSA密钥对。
    RSAPrivateKey privateKey = SimpleRSAEncryptionMaterials.getPrivateKeyFromPemPKCS1(PRIVATE_PKCS1_PEM);
    RSAPublicKey publicKey = SimpleRSAEncryptionMaterials.getPublicKeyFromPemX509(PUBLIC_X509_PEM);
    KeyPair keyPair = new KeyPair(publicKey, privateKey);
    
    // 创建主密钥RSA的描述信息,创建后不允许修改。主密钥描述信息和主密钥一一对应。
    // 如果所有的object都使用相同的主密钥,主密钥描述信息可以为空, 但后续不支持更换主密钥。
    // 如果主密钥描述信息为空,解密时无法判断文件使用的是哪个主密钥进行加密。
    // 强烈建议为每个主密钥都配置描述信息, 由客户端保存主密钥和描述信息之间的对应关系(服务端不保存两者之间的对应关系)。
    Map<String, String> matDesc = new HashMap<String, String>();
    matDesc.put("<yourDescriptionKey>", "<yourDescriptionValue>");
    
    // 创建RSA加密材料。
    SimpleRSAEncryptionMaterials encryptionMaterials = new SimpleRSAEncryptionMaterials(keyPair, matDesc);
    // 如果要下载并解密其他RSA密钥加密的文件,请将其他主密钥及其描述信息添加到加密材料中。
    // encryptionMaterials.addKeyPairDescMaterial(<otherKeyPair>, <otherKeyPairMatDesc>);
    
    // 创建RSA加密客户端。
    OSSEncryptionClient ossEncryptionClient = new OSSEncryptionClientBuilder().
                            build(endpoint, accessKeyId, accessKeySecret, encryptionMaterials);
  • 创建KMS加密客户端

    创建KMS加密客户端示例代码如下:

    // Endpoint以杭州为例,其它Region请按实际情况填写。
    String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
    // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
    String accessKeyId = "<yourAccessKeyId>";
    String accessKeySecret = "<yourAccessKeySecret>";
    // 用户主密钥。
    String cmk = "<yourCmkId>";
    // cmk所在的region。
    String region = "<yourKmsRegion>";
    
    
    // 创建主密钥KMS的描述信息,创建后不允许修改。主密钥描述信息、region以及用户主密钥(cmk)是一一对应关系。
    // 如果所有的object都使用相同的cmk, 主密钥描述信息可以为空,但后续不支持更换主密钥。
    // 如果主密钥描述信息为空,解密时无法判断文件使用的是哪个主密钥进行加密。
    // 强烈建议为每个主密钥都配置主密钥描述信息, 由客户端保存主密钥和描述信息之间的对应关系(服务端不保存两者之间的对应关系)。
    Map<String, String> matDesc = new HashMap<String, String>();
    matDesc.put("<yourDescriptionKey>", "<yourDescriptionValue>");
    
    // 创建KMS加密材料。
    KmsEncryptionMaterials encryptionMaterials = new KmsEncryptionMaterials(region, cmk, matDesc); 
    
    // 如果要下载并解密其他cmk加密的文件,请把cmk的region名称以及描述信息添加到KMS加密材料中。
    // encryptionMaterials.addKmsDescMaterial(<otherKmsRegion>, <otherKmsMatDesc>);
    // 如果要下载并解密其他cmk加密的文件,并且kms的账号不同于OSS客户端账号,请把Kms的region名称、凭证以及描述信息添加到加密材料中。
    // encryptionMaterials.addKmsDescMaterial(<otherKmsRegion>, <otherKmsCredentialsProvider>, <otherKmsMatDesc>);
    
    // 创建加密客户端。
    OSSEncryptionClient ossEncryptionClient = new OSSEncryptionClientBuilder().
                        build(endpoint, accessKeyId, accessKeySecret, encryptionMaterials);

以下提供了如何使用用户自主管理的主秘钥(RSA)方式普通上传和下载文件、分片上传、范围下载等场景的完整示例代码。

说明 使用主密钥KMS与使用主密钥RSA的方式,区别仅在于OSSEncryptionClient的创建过程。

普通上传和下载文件

使用主密钥RSA普通上传和下载Object示例代码如下:

// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String bucketName = "<yourBucketName>";
String objectName = "<yourObjectName>";
String content = "Hello OSS!";

// 填写您的RSA私钥字符串。
final String PRIVATE_PKCS1_PEM = "<yourPrivateKeyWithPKCS1PemString>";
// 填写您的RSA公钥字符串。
final String PUBLIC_X509_PEM = "<yourPublicKeyWithX509PemString>";

// 创建一个RSA密钥对。
RSAPrivateKey privateKey = SimpleRSAEncryptionMaterials.getPrivateKeyFromPemPKCS1(PRIVATE_PKCS1_PEM);
RSAPublicKey publicKey = SimpleRSAEncryptionMaterials.getPublicKeyFromPemX509(PUBLIC_X509_PEM);
KeyPair keyPair = new KeyPair(publicKey, privateKey);

// 创建主密钥RSA的描述信息。创建后不允许修改。主密钥描述信息和主密钥一一对应。
// 如果所有的object都使用相同的主密钥,主密钥描述信息可以为空, 但后续不支持更换主密钥。
// 如果主密钥描述信息为空,解密时无法判断文件使用的是哪个主密钥进行加密。
// 强烈建议为每个主密钥都配置描述信息, 由客户端保存主密钥和描述信息之间的对应关系(服务端不保存两者之间的对应关系)
Map<String, String> matDesc = new HashMap<String, String>();
matDesc.put("<yourDescriptionKey>", "<yourDescriptionValue>");

// 创建RSA加密材料。
SimpleRSAEncryptionMaterials encryptionMaterials = new SimpleRSAEncryptionMaterials(keyPair, matDesc);
// 如果要下载并解密其他Rsa密钥加密的文件,请将其他主密钥及其描述信息添加到加密材料中。
// encryptionMaterials.addKeyPairDescMaterial(<otherKeyPair>, <otherKeyPairMatDesc>);

// 创建加密客户端。
OSSEncryptionClient ossEncryptionClient = new OSSEncryptionClientBuilder().
                        build(endpoint, accessKeyId, accessKeySecret, encryptionMaterials);
// 加密上传文件。
ossEncryptionClient.putObject(bucketName, objectName, new ByteArrayInputStream(content.getBytes()));

// 下载文件时自动解密。
OSSObject ossObject = ossEncryptionClient.getObject(bucketName, objectName);
BufferedReader reader = new BufferedReader(new InputStreamReader(ossObject.getObjectContent()));
StringBuffer buffer = new StringBuffer();
String line;
while ((line = reader.readLine()) != null) {
    buffer.append(line);
}
reader.close();

// 查看解密后的内容是否与上传的明文一致。
System.out.println("Put plain text: " + content);
System.out.println("Get and decrypted text: " + buffer.toString());

分片上传

使用主密钥RSA分片上传的示例代码如下:

// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String bucketName = "<yourBucketName>";
String objectName = "<yourObjectName>";
String localFile = "<yourLocalFilePath>";

// 填写您的RSA私钥字符串。
final String PRIVATE_PKCS1_PEM = "<yourPrivateKeyWithPKCS1PemString>";
// 填写您的RSA公钥字符串。
final String PUBLIC_X509_PEM = "<yourPublicKeyWithX509PemString>";

// 创建一个RSA密钥对。
RSAPrivateKey privateKey = SimpleRSAEncryptionMaterials.getPrivateKeyFromPemPKCS1(PRIVATE_PKCS1_PEM);
RSAPublicKey publicKey = SimpleRSAEncryptionMaterials.getPublicKeyFromPemX509(PUBLIC_X509_PEM);
KeyPair keyPair = new KeyPair(publicKey, privateKey);


// 创建主密钥RSA的描述信息,创建后不允许修改。主密钥描述信息和主密钥一一对应。
// 如果所有的object都使用相同的主密钥,主密钥描述信息可以为空, 但后续不支持更换主密钥。
// 如果主密钥描述信息为空,解密时无法判断文件使用的是哪个主密钥进行加密。
// 强烈建议为每个主密钥都配置描述信息, 由客户端保存主密钥和描述信息之间的对应关系(服务端不保存两者之间的对应关系)。
Map<String, String> matDesc = new HashMap<String, String>();
matDesc.put("<yourDescriptionKey>", "<yourDescriptionValue>");

// 创建RSA加密材料。
SimpleRSAEncryptionMaterials encryptionMaterials = new SimpleRSAEncryptionMaterials(keyPair, matDesc);
// 如果要下载并解密其他RSA密钥加密的文件,请将其他主密钥及其描述信息添加到加密材料中。
// encryptionMaterials.addKeyPairDescMaterial(<otherKeyPair>, <otherKeyPairMatDesc>);

// 创建加密客户端。
OSSEncryptionClient ossEncryptionClient = new OSSEncryptionClientBuilder().
                        build(endpoint, accessKeyId, accessKeySecret, encryptionMaterials);

// 创建MultipartUploadCryptoContext对象,指定分片大小与文件大小。分片大小需16字节对齐。
File file = new File(localFile);
long fileLength = file.length();
final long partSize = 100 * 1024L;   // 100K
MultipartUploadCryptoContext context = new MultipartUploadCryptoContext();
context.setPartSize(partSize);
context.setDataSize(fileLength);

// 初始化一个分片上传事件。
InitiateMultipartUploadRequest initiateMultipartUploadRequest = new InitiateMultipartUploadRequest(bucketName, objectName);
// 传入MultipartUploadCryptoContext对象。
InitiateMultipartUploadResult upresult = ossEncryptionClient.initiateMultipartUpload(initiateMultipartUploadRequest, context);
String uploadId = upresult.getUploadId();

// 创建PartETag的集合。PartETag由分片的ETag和分片号组成。
List<PartETag> partETags =  new ArrayList<PartETag>();
int partCount = (int) (fileLength / partSize);
if (fileLength % partSize != 0) {
    partCount++;
}

// 遍历分片上传。
for (int i = 0; i < partCount; i++) {
    long startPos = i * partSize;
    long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
    InputStream instream = new FileInputStream(file);
    instream.skip(startPos);
    UploadPartRequest uploadPartRequest = new UploadPartRequest();
    uploadPartRequest.setBucketName(bucketName);
    uploadPartRequest.setKey(objectName);
    uploadPartRequest.setUploadId(uploadId);
    uploadPartRequest.setInputStream(instream);
    uploadPartRequest.setPartSize(curPartSize);
    uploadPartRequest.setPartNumber( i + 1);
    // 传入MultipartUploadCryptoContext对象。
    UploadPartResult uploadPartResult = ossEncryptionClient.uploadPart(uploadPartRequest, context);
    partETags.add(uploadPartResult.getPartETag());
}

// 完成分片上传。
CompleteMultipartUploadRequest completeMultipartUploadRequest =
        new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);
ossEncryptionClient.completeMultipartUpload(completeMultipartUploadRequest);

// 关闭OSSEncryptionClient。
ossEncryptionClient.shutdown();

断点续传上传

使用主密钥RSA断点续传上传的示例代码如下:

// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String bucketName = "<yourBucketName>";
String objectName = "<yourObjectName>";
String localFile = "<yourLocalFilePath>";

// 填写您的RSA私钥字符串,可以使用OpenSSL工具生成。
final String PRIVATE_PKCS1_PEM = "<yourPrivateKeyWithPKCS1PemString>";
// 填写您的RSA公钥字符串,可以使用OpenSSL工具生成。
final String PUBLIC_X509_PEM = "<yourPublicKeyWithX509PemString>";

// 创建一个RSA密钥对。
RSAPrivateKey privateKey = SimpleRSAEncryptionMaterials.getPrivateKeyFromPemPKCS1(PRIVATE_PKCS1_PEM);
RSAPublicKey publicKey = SimpleRSAEncryptionMaterials.getPublicKeyFromPemX509(PUBLIC_X509_PEM);
KeyPair keyPair = new KeyPair(publicKey, privateKey);

// 创建主密钥RSA的描述信息,创建后不允许修改。主密钥描述信息和主密钥一一对应。
// 如果所有的object都使用相同的主密钥,主密钥描述信息可以为空, 但后续不支持更换主密钥。
// 如果主密钥描述信息为空,解密时无法判断文件使用的是哪个主密钥进行加密。
// 强烈建议为每个主密钥都配置描述信息, 由客户端保存主密钥和描述信息之间的对应关系(服务端不保存两者之间的对应关系)。
Map<String, String> matDesc = new HashMap<String, String>();
matDesc.put("<yourDescriptionKey>", "<yourDescriptionValue>");

// 创建RSA加密材料。
SimpleRSAEncryptionMaterials encryptionMaterials = new SimpleRSAEncryptionMaterials(keyPair, matDesc);
// 如果要下载并解密其他Rsa密钥加密的文件,请把它以及其描述信息添加到加密材料里。
// encryptionMaterials.addKeyPairDescMaterial(<otherKeyPair>, <otherKeyPairMatDesc>);

// 创建加密客户端。
OSSEncryptionClient ossEncryptionClient = new OSSEncryptionClientBuilder().
                        build(endpoint, accessKeyId, accessKeySecret, encryptionMaterials);

// 创建UploadFileRequest对象。   
UploadFileRequest uploadFileRequest = new UploadFileRequest(bucketName, key);

// 设置要上传的文件的路径。
uploadFileRequest.setUploadFile(localFile));
// 指定上传的分片大小,范围为100KB~5GB,默认为文件大小/10000。
uploadFileRequest.setPartSize(100 * 1024);
// 开启断点续传,默认关闭。
uploadFileRequest.setEnableCheckpoint(true);
// 设置断点记录文件。不指定的话,默认名称为localfile + ".ucp",与localfile同目录。
// 上传过程中的进度信息会保存在该文件中,如果某一分片上传失败,再次上传时会根据文件中记录的点继续上传。上传完成后,该文件会被删除。
uploadFileRequest.setCheckpointFile("test-upload.ucp");

// 开始断点续传上传。
ossEncryptionClient.uploadFile(uploadFileRequest);

// 关闭OSSEncryptionClient。
ossEncryptionClient.shutdown();

断点续传下载

使用主密钥RSA断点续传下载的示例代码如下:

// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String bucketName = "<yourBucketName>";
String objectName = "<yourObjectName>";

// 填写您的RSA私钥字符串,可以使用OpenSSL工具生成。
final String PRIVATE_PKCS1_PEM = "<yourPrivateKeyWithPKCS1PemString>";
// 填写您的RSA公钥字符串,可以使用OpenSSL工具生成。
final String PUBLIC_X509_PEM = "<yourPublicKeyWithX509PemString>";

// 创建一个RSA密钥对。
RSAPrivateKey privateKey = SimpleRSAEncryptionMaterials.getPrivateKeyFromPemPKCS1(PRIVATE_PKCS1_PEM);
RSAPublicKey publicKey = SimpleRSAEncryptionMaterials.getPublicKeyFromPemX509(PUBLIC_X509_PEM);
KeyPair keyPair = new KeyPair(publicKey, privateKey);

// 创建主密钥RSA的描述信息,创建后不允许修改。主密钥描述信息和主密钥一一对应。
// 如果所有的object都使用相同的主密钥,主密钥描述信息可以为空, 但后续不支持更换主密钥。
// 如果主密钥描述信息为空,解密时无法判断文件使用的是哪个主密钥进行加密。
// 强烈建议为每个主密钥都配置描述信息, 由客户端保存主密钥和描述信息之间的对应关系(服务端不保存两者之间的对应关系)。
Map<String, String> matDesc = new HashMap<String, String>();
matDesc.put("<yourDescriptionKey>", "<yourDescriptionValue>");

// 创建RSA加密材料。
SimpleRSAEncryptionMaterials encryptionMaterials = new SimpleRSAEncryptionMaterials(keyPair, matDesc);
// 如果要下载并解密其他Rsa密钥加密的文件,请把它以及其描述信息添加到加密材料里。
// encryptionMaterials.addKeyPairDescMaterial(<otherKeyPair>, <otherKeyPairMatDesc>);

// 创建加密客户端。
OSSEncryptionClient ossEncryptionClient = new OSSEncryptionClientBuilder().
                        build(endpoint, accessKeyId, accessKeySecret, encryptionMaterials);

// 下载请求,10个任务并发下载,启动断点续传下载。
DownloadFileRequest downloadFileRequest = new DownloadFileRequest(bucketName, objectName);
downloadFileRequest.setDownloadFile("<yourDownloadFile>");
downloadFileRequest.setPartSize(1 * 1024 * 1024);
downloadFileRequest.setTaskNum(10);
downloadFileRequest.setEnableCheckpoint(true);
downloadFileRequest.setCheckpointFile("<yourCheckpointFile>");

// 开始断点续传下载。
DownloadFileResult downloadRes = ossEncryptionClient.downloadFile(downloadFileRequest);

// 关闭OSSEncryptionClient。
ossEncryptionClient.shutdown();

范围下载

使用主密钥RSA解密范围下载的文件示例代码如下:

// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
String bucketName = "<yourBucketName>";
String objectName = "<yourObjectName>";
String content = "test-range-get-content-82042795hlnf12s8yhfs976y2nfoshhnsdfsf235bvsmnhtskbcfd!";

// 填写您的RSA私钥字符串。
final String PRIVATE_PKCS1_PEM = "<yourPrivateKeyWithPKCS1PemString>";
// 填写您的RSA公钥字符串。
final String PUBLIC_X509_PEM = "<yourPublicKeyWithX509PemString>";

// 创建一个RSA密钥对。
RSAPrivateKey privateKey = SimpleRSAEncryptionMaterials.getPrivateKeyFromPemPKCS1(PRIVATE_PKCS1_PEM);
RSAPublicKey publicKey = SimpleRSAEncryptionMaterials.getPublicKeyFromPemX509(PUBLIC_X509_PEM);
KeyPair keyPair = new KeyPair(publicKey, privateKey);

// 创建主密钥RSA的描述信息,创建后不允许修改。主密钥描述信息和主密钥一一对应。
// 如果所有的object都使用相同的主密钥,主密钥描述信息可以为空, 但后续不支持更换主密钥。
// 如果主密钥描述信息为空,解密时无法判断文件使用的是哪个主密钥进行加密。
// 强烈建议为每个主密钥都配置描述信息, 由客户端保存主密钥和描述信息之间的对应关系(服务端不保存两者之间的对应关系)。
Map<String, String> matDesc = new HashMap<String, String>();
matDesc.put("<yourDescriptionKey>", "<yourDescriptionValue>");

// 创建RSA加密材料。
SimpleRSAEncryptionMaterials encryptionMaterials = new SimpleRSAEncryptionMaterials(keyPair, matDesc);
// 如果要下载并解密其他RSA密钥加密的文件,请将其他主密钥及其描述信息添加到加密材料中。
// encryptionMaterials.addKeyPairDescMaterial(<otherKeyPair>, <otherKeyPairMatDesc>);

// 创建加密客户端。
OSSEncryptionClient ossEncryptionClient = new OSSEncryptionClientBuilder().
                        build(endpoint, accessKeyId, accessKeySecret, encryptionMaterials);
// 加密上传文件。
ossEncryptionClient.putObject(bucketName, objectName, new ByteArrayInputStream(content.getBytes()));

// 范围下载。
int start = 17;
int end = 35;
GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, objectName);
getObjectRequest.setRange(start, end);
ossObject = ossEncryptionClient.getObject(getObjectRequest);
reader = new BufferedReader(new InputStreamReader(ossObject.getObjectContent()));
buffer = new StringBuffer();
while ((line = reader.readLine()) != null) {
    buffer.append(line);
}
reader.close();

// 查看范围下载结果。
System.out.println("Range-Get plain text:" + content.substring(start, end + 1));
System.out.println("Range-Get decrypted text: " + buffer.toString());

// 关闭OSSEncryptionClient。
ossEncryptionClient.shutdown();