Object Storage Service (OSS) のクライアントサイド暗号化を使用すると、データを OSS にアップロードする前にローカルで暗号化できます。これにより、キーの所有者のみがデータを復号できるようになり、転送中およびストレージでのデータセキュリティが強化されます。
免責事項
クライアントサイド暗号化を使用する場合、カスタマーマスターキー (CMK) の整合性と有効性を確保する必要があります。不適切なメンテナンスによる CMK の誤用または紛失が発生した場合、復号の失敗によって生じるすべての損失と結果はお客様の責任となります。
暗号化されたデータをコピーまたは移行する場合、オブジェクトのメタデータの整合性と有効性はお客様の責任となります。不適切なメンテナンスによって暗号化されたメタデータが不正確になったり失われたりした場合、データの復号の失敗によって生じるすべての損失と結果はお客様の責任となります。
利用シーン
機密性の高いデータ:個人を特定できる情報 (PII)、金融取引記録、医療健康データなど、機密性の高い情報を含むデータについては、ローカル環境から離れる前にデータを暗号化できます。これにより、転送中にデータが傍受された場合でも、生データは保護されたままになります。
コンプライアンス要件:HIPAA や GDPR などの一部の業界や規制では、サードパーティのプラットフォームに保存されるデータに対して厳格な暗号化コントロールが要求されます。クライアントサイド暗号化は、お客様がキーを管理するため、これらのコンプライアンス要件を満たすのに役立ちます。キーはネットワーク経由で送信されたり、クラウドサービスプロバイダーによって直接制御されたりすることはありません。
より強力な自律的制御:企業や開発者は、暗号化アルゴリズムの選択、キーの管理とローテーションなど、暗号化プロセスを完全に制御したい場合があります。クライアントサイド暗号化は、このレベルの制御を提供し、承認されたユーザーのみがデータを復号してアクセスできるようにします。
リージョン間のデータ移行のセキュリティ:あるリージョンから別のリージョンにデータを移行する場合、クライアントサイド暗号化により、移行前、移行中、移行後もデータが暗号化されたままになります。これにより、インターネット経由での転送中のデータセキュリティが強化されます。
注意事項
このトピックでは、中国 (杭州) リージョンのパブリックエンドポイントを使用します。同じリージョン内の他の Alibaba Cloud サービスから OSS にアクセスするには、内部エンドポイントを使用します。サポートされているリージョンとエンドポイントの詳細については、「リージョンとエンドポイント」をご参照ください。
このトピックでは、アクセス認証情報は環境変数から取得されます。アクセス認証情報の設定方法の詳細については、「アクセス認証情報の設定」をご参照ください。
このトピックでは、OSS エンドポイントを使用して OSSClient インスタンスが作成されます。カスタムドメイン名または Security Token Service (STS) を使用して OSSClient インスタンスを作成する場合は、「一般的なシナリオの設定例」をご参照ください。
背景情報
クライアントサイド暗号化では、オブジェクトごとにランダムなデータキーが生成され、オブジェクトの対称暗号化が実行されます。クライアントは CMK を使用してランダムなデータキーを暗号化します。暗号化されたデータキーは、オブジェクトのメタデータの一部としてアップロードされ、OSS サーバーに保存されます。暗号化されたオブジェクトがダウンロードされると、クライアントは CMK を使用してランダムなデータキーを復号し、復号されたデータキーを使用してオブジェクトを復号します。データセキュリティを確保するため、CMK はクライアントでのみ使用され、ネットワーク経由で送信されたり、サーバーに保存されたりすることはありません。
クライアントサイド暗号化は、5 GB を超えるファイルのマルチパートアップロードをサポートします。マルチパートアップロードを使用する場合、ファイルの合計サイズとパートサイズを指定する必要があります。最後のパートを除き、各パートのサイズは同じでなければなりません。パートサイズは 16 の倍数である必要があります。
クライアントサイド暗号化を使用してファイルをアップロードした後、暗号化メタデータは保護されます。CopyObject を使用してオブジェクトのメタデータを変更することはできません。
暗号化方式
クライアントサイド暗号化には、2 種類の CMK を使用できます。
KMS で管理される CMK
Key Management Service (KMS) で管理される CMK をクライアントサイド暗号化に使用する場合、OSS SDK for Java に CMK ID を提供する必要があります。
独自に管理する RSA ベースの CMK
自身で管理する CMK をクライアント側の暗号化に使用する場合、CMK の公開鍵と秘密鍵をパラメーターとして OSS SDK for Python に送信する必要があります。
前述の暗号化方式を使用すると、データ漏洩を防ぎ、クライアント上のデータを保護できます。データが漏洩した場合でも、他の人がデータを復号することはできません。
暗号化メタデータ
パラメーター | 説明 | 必須 |
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 | マルチパートアップロードを使用してファイルを暗号化する場合、`init_multipart` 中に大きなファイルの合計サイズを渡す必要があります。 | はい (マルチパートアップロードの場合) |
x-oss-meta-client-side-encryption-part-size | マルチパートアップロードを使用してファイルを暗号化する場合、`init_multipart` 中にパートサイズを渡す必要があります。 重要 パートサイズは 16 の倍数である必要があります。 | はい (マルチパートアップロードの場合) |
OpenSSL ツールの説明
OpenSSL 3.x ツールは、デフォルトで PRIVATE_PKCS8_PEM を生成します。PRIVATE_PKCS1_PEM を生成するには、-traditional オプションを使用します。詳細については、「OpenSSL」をご参照ください。
暗号化クライアントの作成
RSA または KMS 暗号化クライアントを作成する場合、OSS Java SDK 3.9.1 以降を使用する必要があります。また、Bouncy Castle Java ライブラリ (bcprov-jdk15on) を Maven プロジェクトにインポートする必要もあります。
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.62</version>
</dependency>実行時に java.security.InvalidKeyException: Illegal key size or default parameters エラーが発生した場合は、Oracle JCE ファイルを JRE 環境に追加する必要があります。
ご利用の JDK バージョンに対応するファイルをダウンロードします。ファイルを解凍し、jre/lib/security ディレクトリに配置します。
RSA 暗号化クライアントの作成
RSA 暗号化クライアントを作成する前に、非対称の KeyPair オブジェクトを作成する必要があります。OSS Java SDK は、PKCS#1 または PKCS#8 PEM 形式の秘密鍵文字列を RSAPrivateKey オブジェクトに変換するメソッドを提供します。また、X.509 PEM 形式の公開鍵文字列を RSAPublicKey オブジェクトに変換するメソッドも提供します。
これらのキーの変換メソッドは次のとおりです。
RSAPrivateKey SimpleRSAEncryptionMaterials.getPrivateKeyFromPemPKCS1(String privateKeyStr);
RSAPrivateKey SimpleRSAEncryptionMaterials.getPrivateKeyFromPemPKCS8(String privateKeyStr);
RSAPublicKey SimpleRSAEncryptionMaterials.getPublicKeyFromPemX509(String publicKeyStr);
次のコードは、RSA 暗号化クライアントを作成する方法の例を示しています。
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.crypto.SimpleRSAEncryptionMaterials;
import java.security.KeyPair;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.Map;
public class Demo {
public static void main(String[] args) throws Throwable {
// エンドポイントは、例として中国 (杭州) に設定されています。実際のエンドポイントに変更してください。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 次のコマンドを使用して、秘密鍵と公開鍵の PEM ファイルを生成できます。次に、PEM ファイルから文字列をコピーして、PRIVATE_PKCS1_PEM および PUBLIC_X509_PEM 変数に貼り付けます。
// openssl genrsa -out private_key.pem 2048
// openssl rsa -in private_key.pem -out rsa_public_key.pem -pubout
// RSA 秘密鍵の文字列を指定します。OpenSSL を使用して生成できます。次の値は、RSA 秘密鍵の文字列の例です。
final String PRIVATE_PKCS1_PEM =
"-----BEGIN RSA PRIVATE KEY-----\n" +
"MIICWwIBAAKBgQCokfiAVXXf5ImFzKDw+XO/UByW6mse2QsIgz3ZwBtMNu59fR5z\n" +
"ttSx+8fB7vR4CN3bTztrP9A6bjoN0FFnhlQ3vNJC5MFO1PByrE/MNd5AAfSVba93\n" +
"I6sx8NSk5MzUCA4NJzAUqYOEWGtGBcom6kEF6MmR1EKib1Id8hpooY5xaQIDAQAB\n" +
"AoGAOPUZgkNeEMinrw31U3b2JS5sepG6oDG2CKpPu8OtdZMaAkzEfVTJiVoJpP2Y\n" +
"nPZiADhFW3e0ZAnak9BPsSsySRaSNmR465cG9tbqpXFKh9Rp/sCPo4Jq2n65yood\n" +
"JBrnGr6/xhYvNa14sQ6xjjfSgRNBSXD1XXNF4kALwgZyCAECQQDV7t4bTx9FbEs5\n" +
"36nAxPsPM6aACXaOkv6d9LXI7A0J8Zf42FeBV6RK0q7QG5iNNd1WJHSXIITUizVF\n" +
"6aX5NnvFAkEAybeXNOwUvYtkgxF4s28s6gn11c5HZw4/a8vZm2tXXK/QfTQrJVXp\n" +
"VwxmSr0FAajWAlcYN/fGkX1pWA041CKFVQJAG08ozzekeEpAuByTIOaEXgZr5MBQ\n" +
"gBbHpgZNBl8Lsw9CJSQI15wGfv6yDiLXsH8FyC9TKs+d5Tv4Cvquk0efOQJAd9OC\n" +
"lCKFs48hdyaiz9yEDsc57PdrvRFepVdj/gpGzD14mVerJbOiOF6aSV19ot27u4on\n" +
"Td/3aifYs0CveHzFPQJAWb4LCDwqLctfzziG7/S7Z74gyq5qZF4FUElOAZkz123E\n" +
"yZvADwuz/4aK0od0lX9c4Jp7Mo5vQ4TvdoBnPuGo****\n" +
"-----END RSA PRIVATE KEY-----";
// RSA 公開鍵の文字列を指定します。OpenSSL を使用して生成できます。次の値は、RSA 公開鍵の文字列の例です。
final String PUBLIC_X509_PEM =
"-----BEGIN PUBLIC KEY-----\n" +
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCokfiAVXXf5ImFzKDw+XO/UByW\n" +
"6mse2QsIgz3ZwBtMNu59fR5zttSx+8fB7vR4CN3bTztrP9A6bjoN0FFnhlQ3vNJC\n" +
"5MFO1PByrE/MNd5AAfSVba93I6sx8NSk5MzUCA4NJzAUqYOEWGtGBcom6kEF6MnR\n" +
"1EKib1Id8hpooY5xaQID****\n" +
"-----END PUBLIC KEY-----";
// RSA キーペアを作成します。
RSAPrivateKey privateKey = SimpleRSAEncryptionMaterials.getPrivateKeyFromPemPKCS1(PRIVATE_PKCS1_PEM);
RSAPublicKey publicKey = SimpleRSAEncryptionMaterials.getPublicKeyFromPemX509(PUBLIC_X509_PEM);
KeyPair keyPair = new KeyPair(publicKey, privateKey);
// RSA マスターキーの説明を作成します。説明は作成後に変更できません。マスターキーの説明とマスターキーは 1 対 1 でマッピングされます。
// すべてのオブジェクトが同じマスターキーを使用する場合、説明は空にできます。ただし、後でマスターキーを変更することはできません。
// マスターキーの説明が空の場合、クライアントは復号時にどのマスターキーがファイルの暗号化に使用されたかを判断できません。
// 各マスターキーの説明を設定します。クライアントは、マスターキーとその説明のマッピングを保存する必要があります。サーバーはこのマッピングを保存しません。
Map<String, String> matDesc = new HashMap<String, String>();
matDesc.put("desc-key", "desc-value");
// RSA 暗号化マテリアルを作成します。
SimpleRSAEncryptionMaterials encryptionMaterials = new SimpleRSAEncryptionMaterials(keyPair, matDesc);
// 他の RSA キーで暗号化されたファイルをダウンロードして復号するには、他のマスターキーとその説明を暗号化マテリアルに追加します。
// encryptionMaterials.addKeyPairDescMaterial(<otherKeyPair>, <otherKeyPairMatDesc>);
// RSA 暗号化クライアントを作成します。
// RSA 暗号化クライアントが不要になったら、shutdown メソッドを呼び出してリソースを解放します。
OSSEncryptionClient ossEncryptionClient = new OSSEncryptionClientBuilder().
build(endpoint, credentialsProvider, encryptionMaterials);
try {
// ここにビジネスコードを追加します。
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossEncryptionClient != null) {
ossEncryptionClient.shutdown();
}
}
}
}KMS 暗号化クライアントの作成
KMS 暗号化クライアントを作成する場合、Maven プロジェクトに Bouncy Castle Java ライブラリ (bcprov-jdk15on) と Alibaba Cloud KMS Java ライブラリ (kms-transfer-client) をインポートする必要があります。
<dependency>
<groupId>com.aliyun.kms</groupId>
<artifactId>kms-transfer-client</artifactId>
<version>0.1.0</version>
<scope>test</scope>
</dependency>次のコードは、KMS 暗号化クライアントを作成する方法の例を示しています。
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.crypto.ContentCryptoMaterialRW;
import com.aliyun.oss.crypto.EncryptionMaterials;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.http.FormatType;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.kms.model.v20160120.DecryptRequest;
import com.aliyuncs.kms.model.v20160120.DecryptResponse;
import com.aliyuncs.kms.model.v20160120.EncryptRequest;
import com.aliyuncs.kms.model.v20160120.EncryptResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class Demo {
public static void main(String[] args) throws Throwable {
// エンドポイントは、例として中国 (杭州) に設定されています。実際のエンドポイントに変更してください。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// カスタマーマスターキー (CMK)。例:e1935511-cf88-1123-a0f8-1be8d251****。
String cmk = "e1935511-cf88-1123-a0f8-1be8d251****";
// CMK が配置されているリージョン。例:cn-hangzhou。
String region = "cn-hangzhou";
// KMS マスターキーの説明を作成します。説明は作成後に変更できません。マスターキーの説明、リージョン、CMK は 1 対 1 でマッピングされます。
// すべてのオブジェクトが同じ CMK を使用する場合、説明は空にできます。ただし、後でマスターキーを変更することはできません。
// マスターキーの説明が空の場合、クライアントは復号時にどのマスターキーがファイルの暗号化に使用されたかを判断できません。
// 各マスターキーの説明を設定します。クライアントは、マスターキーとその説明のマッピングを保存する必要があります。サーバーはこのマッピングを保存しません。
Map<String, String> matDesc = new HashMap<String, String>();
matDesc.put("desc-key", "desc-value");
// KMS 暗号化マテリアルを作成します。
KmsEncryptionMaterialsV3 encryptionMaterials = new KmsEncryptionMaterialsV3(region, cmk, matDesc);
encryptionMaterials.setKmsCredentialsProvider(credentialsProvider);
// 他の CMK で暗号化されたファイルをダウンロードして復号するには、CMK のリージョン名と説明を KMS 暗号化マテリアルに追加します。
// encryptionMaterials.addKmsDescMaterial(<otherKmsRegion>, <otherKmsMatDesc>);
// KMS アカウントが OSS クライアントアカウントと異なる場合に、他の CMK で暗号化されたファイルをダウンロードして復号するには、KMS のリージョン名、認証情報、および説明を暗号化マテリアルに追加します。
// encryptionMaterials.addKmsDescMaterial(<otherKmsRegion>, <otherKmsCredentialsProvider>, <otherKmsMatDesc>);
// 暗号化クライアントを作成します。
// 暗号化クライアントが不要になったら、shutdown メソッドを呼び出してリソースを解放します。
OSSEncryptionClient ossEncryptionClient = new OSSEncryptionClientBuilder().
build(endpoint, credentialsProvider, encryptionMaterials);
try {
// ここにビジネスコードを追加します。
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossEncryptionClient != null) {
ossEncryptionClient.shutdown();
}
}
}
}
class KmsEncryptionMaterialsV3 implements EncryptionMaterials {
private static final String KEY_WRAP_ALGORITHM = "KMS/ALICLOUD";
private String region;
private String cmk;
CredentialsProvider credentialsProvider;
private final Map<String, String> desc;
private final LinkedHashMap<KmsEncryptionMaterialsV3.KmsClientSuite, Map<String, String>> kmsDescMaterials =
new LinkedHashMap<KmsEncryptionMaterialsV3.KmsClientSuite, Map<String, String>>();
public KmsEncryptionMaterialsV3(String region, String cmk) {
assertParameterNotNull(region, "kms region");
assertParameterNotNull(cmk, "kms cmk");
this.region = region;
this.cmk = cmk;
this.desc = new HashMap<String, String>();
}
public KmsEncryptionMaterialsV3(String region, String cmk, Map<String, String> desc) {
assertParameterNotNull(region, "kms region");
assertParameterNotNull(region, "kms cmk");
this.region = region;
this.cmk = cmk;
this.desc = (desc == null) ? new HashMap<String, String>() : new HashMap<String, String>(desc);
}
private final class KmsClientSuite {
private String region;
private CredentialsProvider credentialsProvider;
KmsClientSuite(String region, CredentialsProvider credentialsProvider) {
this.region = region;
this.credentialsProvider = credentialsProvider;
}
}
public void setKmsCredentialsProvider(CredentialsProvider credentialsProvider) {
this.credentialsProvider = credentialsProvider;
kmsDescMaterials.put(new KmsEncryptionMaterialsV3.KmsClientSuite(region, credentialsProvider), desc);
}
private DefaultAcsClient createKmsClient(String region, CredentialsProvider credentialsPorvider) {
Credentials credentials = credentialsPorvider.getCredentials();
IClientProfile profile = DefaultProfile.getProfile(region, credentials.getAccessKeyId(),
credentials.getSecretAccessKey(), credentials.getSecurityToken());
return new KmsTransferAcsClient(profile);
}
private EncryptResponse encryptPlainText(String keyId, String plainText) throws ClientException {
DefaultAcsClient kmsClient = createKmsClient(region, credentialsProvider);
final EncryptRequest encReq = new EncryptRequest();
encReq.setSysProtocol(ProtocolType.HTTPS);
encReq.setAcceptFormat(FormatType.JSON);
encReq.setSysMethod(MethodType.POST);
encReq.setKeyId(keyId);
encReq.setPlaintext(plainText);
final EncryptResponse encResponse;
try {
encResponse = kmsClient.getAcsResponse(encReq);
} catch (Exception e) {
throw new ClientException("The KMS client failed to encrypt data. " + e.getMessage(), e);
}
return encResponse;
}
private DecryptResponse decryptCipherBlob(KmsEncryptionMaterialsV3.KmsClientSuite kmsClientSuite, String cipherBlob)
throws ClientException {
final DefaultAcsClient kmsClient = createKmsClient(kmsClientSuite.region, kmsClientSuite.credentialsProvider);
final DecryptRequest decReq = new DecryptRequest();
decReq.setSysProtocol(ProtocolType.HTTPS);
decReq.setAcceptFormat(FormatType.JSON);
decReq.setSysMethod(MethodType.POST);
decReq.setCiphertextBlob(cipherBlob);
final DecryptResponse decResponse;
try {
decResponse = kmsClient.getAcsResponse(decReq);
} catch (Exception e) {
throw new ClientException("The KMS client failed to decrypt data. " + e.getMessage(), e);
}
return decResponse;
}
public void addKmsDescMaterial(String region, Map<String, String> description) {
addKmsDescMaterial(region, credentialsProvider, description);
}
public synchronized void addKmsDescMaterial(String region, CredentialsProvider credentialsProvider, Map<String, String> description) {
assertParameterNotNull(region, "region");
assertParameterNotNull(credentialsProvider, "credentialsProvider");
KmsEncryptionMaterialsV3.KmsClientSuite kmsClientSuite = new KmsEncryptionMaterialsV3.KmsClientSuite(region, credentialsProvider);
if (description != null) {
kmsDescMaterials.put(kmsClientSuite, new HashMap<String, String>(description));
} else {
kmsDescMaterials.put(kmsClientSuite, new HashMap<String, String>());
}
}
private KmsEncryptionMaterialsV3.KmsClientSuite findKmsClientSuiteByDescription(Map<String, String> desc) {
if (desc == null) {
return null;
}
for (Map.Entry<KmsEncryptionMaterialsV3.KmsClientSuite, Map<String, String>> entry : kmsDescMaterials.entrySet()) {
if (desc.equals(entry.getValue())) {
return entry.getKey();
}
}
return null;
}
private <K, V> Map.Entry<K, V> getTailByReflection(LinkedHashMap<K, V> map)
throws NoSuchFieldException, IllegalAccessException {
Field tail = map.getClass().getDeclaredField("tail");
tail.setAccessible(true);
return (Map.Entry<K, V>) tail.get(map);
}
@Override
public void encryptCEK(ContentCryptoMaterialRW contentMaterialRW) {
try {
assertParameterNotNull(contentMaterialRW, "contentMaterialRW");
assertParameterNotNull(contentMaterialRW.getIV(), "contentMaterialRW#getIV");
assertParameterNotNull(contentMaterialRW.getCEK(), "contentMaterialRW#getCEK");
byte[] iv = contentMaterialRW.getIV();
EncryptResponse encryptresponse = encryptPlainText(cmk, BinaryUtil.toBase64String(iv));
byte[] encryptedIV = BinaryUtil.fromBase64String(encryptresponse.getCiphertextBlob());
SecretKey cek = contentMaterialRW.getCEK();
encryptresponse = encryptPlainText(cmk, BinaryUtil.toBase64String(cek.getEncoded()));
byte[] encryptedCEK = BinaryUtil.fromBase64String(encryptresponse.getCiphertextBlob());
contentMaterialRW.setEncryptedCEK(encryptedCEK);
contentMaterialRW.setEncryptedIV(encryptedIV);
contentMaterialRW.setKeyWrapAlgorithm(KEY_WRAP_ALGORITHM);
contentMaterialRW.setMaterialsDescription(desc);
} catch (Exception e) {
throw new ClientException("Failed to encrypt the CEK and IV with KMS. "
+ "Check your CMK, region, AccessKey ID, and AccessKey secret." + e.getMessage(), e);
}
}
@Override
public void decryptCEK(ContentCryptoMaterialRW contentMaterialRW) {
assertParameterNotNull(contentMaterialRW, "ContentCryptoMaterialRW");
assertParameterNotNull(contentMaterialRW.getEncryptedCEK(), "ContentCryptoMaterialRW#getEncryptedCEK");
assertParameterNotNull(contentMaterialRW.getEncryptedIV(), "ContentCryptoMaterialRW#getEncryptedIV");
assertParameterNotNull(contentMaterialRW.getKeyWrapAlgorithm(), "ContentCryptoMaterialRW#getKeyWrapAlgorithm");
if (!contentMaterialRW.getKeyWrapAlgorithm().toLowerCase().equals(KEY_WRAP_ALGORITHM.toLowerCase())) {
throw new ClientException(
"Unrecognized object key wrap algorithm: " + contentMaterialRW.getKeyWrapAlgorithm());
}
try {
KmsEncryptionMaterialsV3.KmsClientSuite kmsClientSuite = findKmsClientSuiteByDescription(contentMaterialRW.getMaterialsDescription());
if (kmsClientSuite == null) {
Map.Entry<KmsEncryptionMaterialsV3.KmsClientSuite, Map<String, String>> entry = getTailByReflection(kmsDescMaterials);
kmsClientSuite = entry.getKey();
}
DecryptResponse decryptIvResp = decryptCipherBlob(kmsClientSuite,
BinaryUtil.toBase64String(contentMaterialRW.getEncryptedIV()));
byte[] iv = BinaryUtil.fromBase64String(decryptIvResp.getPlaintext());
DecryptResponse decryptCEKResp = decryptCipherBlob(kmsClientSuite,
BinaryUtil.toBase64String(contentMaterialRW.getEncryptedCEK()));
byte[] cekBytes = BinaryUtil.fromBase64String(decryptCEKResp.getPlaintext());
SecretKey cek = new SecretKeySpec(cekBytes, "");
contentMaterialRW.setCEK(cek);
contentMaterialRW.setIV(iv);
} catch (Exception e) {
throw new ClientException("Unable to decrypt the content-secured key and IV. "
+ "Check your KMS region and materials description." + e.getMessage(), e);
}
}
private void assertParameterNotNull(Object parameterValue, String errorMessage) {
if (parameterValue == null)
throw new IllegalArgumentException(errorMessage);
}
}以下のセクションでは、ファイルのアップロードとダウンロード、マルチパートアップロード、範囲ダウンロードなどのシナリオで、ユーザー管理のマスターキー (RSA) を使用する方法の完全な例を示します。
KMS マスターキーと RSA マスターキーの使用における唯一の違いは、OSSEncryptionClient の作成方法です。
ファイルのアップロードとダウンロード
次のコードは、RSA マスターキーを使用してオブジェクトをアップロードおよびダウンロードする方法の例を示しています。
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.crypto.SimpleRSAEncryptionMaterials;
import com.aliyun.oss.model.OSSObject;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.security.KeyPair;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.Map;
public class Demo {
public static void main(String[] args) throws Throwable {
// エンドポイントは、例として中国 (杭州) に設定されています。実際のエンドポイントに変更してください。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// バケット名を指定します。例:examplebucket。
String bucketName = "examplebucket";
// オブジェクトのフルパスを指定します。例:exampleobject.txt。フルパスにバケット名を含めることはできません。
String objectName = "exampleobject.txt";
String content = "Hello OSS!";
// RSA 秘密鍵の文字列を指定します。OpenSSL を使用して生成できます。次の値は、RSA 秘密鍵の文字列の例です。
final String PRIVATE_PKCS1_PEM =
"-----BEGIN RSA PRIVATE KEY-----\n" +
"MIICWwIBAAKBgQCokfiAVXXf5ImFzKDw+XO/UByW6mse2QsIgz3ZwBtMNu59fR5z\n" +
"ttSx+8fB7vR4CN3bTztrP9A6bjoN0FFnhlQ3vNJC5MFO1PByrE/MNd5AAfSVba93\n" +
"I6sx8NSk5MzUCA4NJzAUqYOEWGtGBcom6kEF6MmR1EKib1Id8hpooY5xaQIDAQAB\n" +
"AoGAOPUZgkNeEMinrw31U3b2JS5sepG6oDG2CKpPu8OtdZMaAkzEfVTJiVoJpP2Y\n" +
"nPZiADhFW3e0ZAnak9BPsSsySRaSNmR465cG9tbqpXFKh9Rp/sCPo4Jq2n65yood\n" +
"JBrnGr6/xhYvNa14sQ6xjjfSgRNBSXD1XXNF4kALwgZyCAECQQDV7t4bTx9FbEs5\n" +
"36nAxPsPM6aACXaOkv6d9LXI7A0J8Zf42FeBV6RK0q7QG5iNNd1WJHSXIITUizVF\n" +
"6aX5NnvFAkEAybeXNOwUvYtkgxF4s28s6gn11c5HZw4/a8vZm2tXXK/QfTQrJVXp\n" +
"VwxmSr0FAajWAlcYN/fGkX1pWA041CKFVQJAG08ozzekeEpAuByTIOaEXgZr5MBQ\n" +
"gBbHpgZNBl8Lsw9CJSQI15wGfv6yDiLXsH8FyC9TKs+d5Tv4Cvquk0efOQJAd9OC\n" +
"lCKFs48hdyaiz9yEDsc57PdrvRFepVdj/gpGzD14mVerJbOiOF6aSV19ot27u4on\n" +
"Td/3aifYs0CveHzFPQJAWb4LCDwqLctfzziG7/S7Z74gyq5qZF4FUElOAZkz123E\n" +
"yZvADwuz/4aK0od0lX9c4Jp7Mo5vQ4TvdoBnPuGo****\n" +
"-----END RSA PRIVATE KEY-----";
// RSA 公開鍵の文字列を指定します。OpenSSL を使用して生成できます。次の値は、RSA 公開鍵の文字列の例です。
final String PUBLIC_X509_PEM =
"-----BEGIN PUBLIC KEY-----\n" +
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCokfiAVXXf5ImFzKDw+XO/UByW\n" +
"6mse2QsIgz3ZwBtMNu59fR5zttSx+8fB7vR4CN3bTztrP9A6bjoN0FFnhlQ3vNJC\n" +
"5MFO1PByrE/MNd5AAfSVba93I6sx8NSk5MzUCA4NJzAUqYOEWGtGBcom6kEF6MnR\n" +
"1EKib1Id8hpooY5xaQID****\n" +
"-----END PUBLIC KEY-----";
// RSA キーペアを作成します。
RSAPrivateKey privateKey = SimpleRSAEncryptionMaterials.getPrivateKeyFromPemPKCS1(PRIVATE_PKCS1_PEM);
RSAPublicKey publicKey = SimpleRSAEncryptionMaterials.getPublicKeyFromPemX509(PUBLIC_X509_PEM);
KeyPair keyPair = new KeyPair(publicKey, privateKey);
// RSA マスターキーの説明を作成します。説明は作成後に変更できません。マスターキーの説明とマスターキーは 1 対 1 でマッピングされます。
// すべてのオブジェクトが同じマスターキーを使用する場合、説明は空にできます。ただし、後でマスターキーを変更することはできません。
// マスターキーの説明が空の場合、クライアントは復号時にどのマスターキーがファイルの暗号化に使用されたかを判断できません。
// 各マスターキーの説明を設定します。クライアントは、マスターキーとその説明のマッピングを保存する必要があります。サーバーはこのマッピングを保存しません。
Map<String, String> matDesc = new HashMap<String, String>();
matDesc.put("desc-key", "desc-value");
// RSA 暗号化マテリアルを作成します。
SimpleRSAEncryptionMaterials encryptionMaterials = new SimpleRSAEncryptionMaterials(keyPair, matDesc);
// 他の RSA キーで暗号化されたファイルをダウンロードして復号するには、他のマスターキーとその説明を暗号化マテリアルに追加します。
// encryptionMaterials.addKeyPairDescMaterial(<otherKeyPair>, <otherKeyPairMatDesc>);
// 暗号化クライアントを作成します。
// 暗号化クライアントが不要になったら、shutdown メソッドを呼び出してリソースを解放します。
OSSEncryptionClient ossEncryptionClient = new OSSEncryptionClientBuilder().
build(endpoint, credentialsProvider, encryptionMaterials);
try {
// ファイルを暗号化してアップロードします。
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());
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossEncryptionClient != null) {
ossEncryptionClient.shutdown();
}
}
}
}マルチパートアップロード
次のコードは、RSA マスターキーを使用してマルチパートアップロードを実行する方法の例を示しています。
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.crypto.MultipartUploadCryptoContext;
import com.aliyun.oss.crypto.SimpleRSAEncryptionMaterials;
import com.aliyun.oss.model.*;
import java.io.*;
import java.security.KeyPair;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Demo {
public static void main(String[] args) throws Throwable {
// エンドポイントは、例として中国 (杭州) に設定されています。実際のエンドポイントに変更してください。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// バケット名を指定します。例:examplebucket。
String bucketName = "examplebucket";
// オブジェクトのフルパスを指定します。例:exampleobject.txt。フルパスにバケット名を含めることはできません。
String objectName = "exampleobject.txt";
// ファイルパス。例:D:\\localpath\\examplefile.txt
String localFile = "D:\\localpath\\examplefile.txt";
// RSA 秘密鍵の文字列を指定します。OpenSSL を使用して生成できます。次の値は、RSA 秘密鍵の文字列の例です。
final String PRIVATE_PKCS1_PEM =
"-----BEGIN RSA PRIVATE KEY-----\n" +
"MIICWwIBAAKBgQCokfiAVXXf5ImFzKDw+XO/UByW6mse2QsIgz3ZwBtMNu59fR5z\n" +
"ttSx+8fB7vR4CN3bTztrP9A6bjoN0FFnhlQ3vNJC5MFO1PByrE/MNd5AAfSVba93\n" +
"I6sx8NSk5MzUCA4NJzAUqYOEWGtGBcom6kEF6MmR1EKib1Id8hpooY5xaQIDAQAB\n" +
"AoGAOPUZgkNeEMinrw31U3b2JS5sepG6oDG2CKpPu8OtdZMaAkzEfVTJiVoJpP2Y\n" +
"nPZiADhFW3e0ZAnak9BPsSsySRaSNmR465cG9tbqpXFKh9Rp/sCPo4Jq2n65yood\n" +
"JBrnGr6/xhYvNa14sQ6xjjfSgRNBSXD1XXNF4kALwgZyCAECQQDV7t4bTx9FbEs5\n" +
"36nAxPsPM6aACXaOkv6d9LXI7A0J8Zf42FeBV6RK0q7QG5iNNd1WJHSXIITUizVF\n" +
"6aX5NnvFAkEAybeXNOwUvYtkgxF4s28s6gn11c5HZw4/a8vZm2tXXK/QfTQrJVXp\n" +
"VwxmSr0FAajWAlcYN/fGkX1pWA041CKFVQJAG08ozzekeEpAuByTIOaEXgZr5MBQ\n" +
"gBbHpgZNBl8Lsw9CJSQI15wGfv6yDiLXsH8FyC9TKs+d5Tv4Cvquk0efOQJAd9OC\n" +
"lCKFs48hdyaiz9yEDsc57PdrvRFepVdj/gpGzD14mVerJbOiOF6aSV19ot27u4on\n" +
"Td/3aifYs0CveHzFPQJAWb4LCDwqLctfzziG7/S7Z74gyq5qZF4FUElOAZkz123E\n" +
"yZvADwuz/4aK0od0lX9c4Jp7Mo5vQ4TvdoBnPuGo****\n" +
"-----END RSA PRIVATE KEY-----";
// RSA 公開鍵の文字列を指定します。OpenSSL を使用して生成できます。次の値は、RSA 公開鍵の文字列の例です。
final String PUBLIC_X509_PEM =
"-----BEGIN PUBLIC KEY-----\n" +
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCokfiAVXXf5ImFzKDw+XO/UByW\n" +
"6mse2QsIgz3ZwBtMNu59fR5zttSx+8fB7vR4CN3bTztrP9A6bjoN0FFnhlQ3vNJC\n" +
"5MFO1PByrE/MNd5AAfSVba93I6sx8NSk5MzUCA4NJzAUqYOEWGtGBcom6kEF6MnR\n" +
"1EKib1Id8hpooY5xaQID****\n" +
"-----END PUBLIC KEY-----";
// RSA キーペアを作成します。
RSAPrivateKey privateKey = SimpleRSAEncryptionMaterials.getPrivateKeyFromPemPKCS1(PRIVATE_PKCS1_PEM);
RSAPublicKey publicKey = SimpleRSAEncryptionMaterials.getPublicKeyFromPemX509(PUBLIC_X509_PEM);
KeyPair keyPair = new KeyPair(publicKey, privateKey);
// RSA マスターキーの説明を作成します。説明は作成後に変更できません。マスターキーの説明とマスターキーは 1 対 1 でマッピングされます。
// すべてのオブジェクトが同じマスターキーを使用する場合、説明は空にできます。ただし、後でマスターキーを変更することはできません。
// マスターキーの説明が空の場合、クライアントは復号時にどのマスターキーがファイルの暗号化に使用されたかを判断できません。
// 各マスターキーの説明を設定します。クライアントは、マスターキーとその説明のマッピングを保存する必要があります。サーバーはこのマッピングを保存しません。
Map<String, String> matDesc = new HashMap<String, String>();
matDesc.put("desc-key", "desc-value");
// RSA 暗号化マテリアルを作成します。
SimpleRSAEncryptionMaterials encryptionMaterials = new SimpleRSAEncryptionMaterials(keyPair, matDesc);
// 他の RSA キーで暗号化されたファイルをダウンロードして復号するには、他のマスターキーとその説明を暗号化マテリアルに追加します。
// encryptionMaterials.addKeyPairDescMaterial(<otherKeyPair>, <otherKeyPairMatDesc>);
// 暗号化クライアントを作成します。
// 暗号化クライアントが不要になったら、shutdown メソッドを呼び出してリソースを解放します。
OSSEncryptionClient ossEncryptionClient = new OSSEncryptionClientBuilder().
build(endpoint, credentialsProvider, encryptionMaterials);
try {
// 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);
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossEncryptionClient != null) {
ossEncryptionClient.shutdown();
}
}
}
}再開可能なアップロード
次のコードは、RSA マスターキーを使用して再開可能なアップロードを実行する方法の例を示しています。
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.crypto.SimpleRSAEncryptionMaterials;
import com.aliyun.oss.model.*;
import java.security.KeyPair;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.Map;
public class Demo {
public static void main(String[] args) throws Throwable {
// エンドポイントは、例として中国 (杭州) に設定されています。実際のエンドポイントに変更してください。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// バケット名を指定します。例:examplebucket。
String bucketName = "examplebucket";
// オブジェクトのフルパスを指定します。例:exampleobject.txt。フルパスにバケット名を含めることはできません。
String objectName = "exampleobject.txt";
// ファイルパス。例:D:\\localpath\\examplefile.txt
String localFile = "D:\\localpath\\examplefile.txt";
// RSA 秘密鍵の文字列を指定します。OpenSSL を使用して生成できます。次の値は、RSA 秘密鍵の文字列の例です。
final String PRIVATE_PKCS1_PEM =
"-----BEGIN RSA PRIVATE KEY-----\n" +
"MIICWwIBAAKBgQCokfiAVXXf5ImFzKDw+XO/UByW6mse2QsIgz3ZwBtMNu59fR5z\n" +
"ttSx+8fB7vR4CN3bTztrP9A6bjoN0FFnhlQ3vNJC5MFO1PByrE/MNd5AAfSVba93\n" +
"I6sx8NSk5MzUCA4NJzAUqYOEWGtGBcom6kEF6MmR1EKib1Id8hpooY5xaQIDAQAB\n" +
"AoGAOPUZgkNeEMinrw31U3b2JS5sepG6oDG2CKpPu8OtdZMaAkzEfVTJiVoJpP2Y\n" +
"nPZiADhFW3e0ZAnak9BPsSsySRaSNmR465cG9tbqpXFKh9Rp/sCPo4Jq2n65yood\n" +
"JBrnGr6/xhYvNa14sQ6xjjfSgRNBSXD1XXNF4kALwgZyCAECQQDV7t4bTx9FbEs5\n" +
"36nAxPsPM6aACXaOkv6d9LXI7A0J8Zf42FeBV6RK0q7QG5iNNd1WJHSXIITUizVF\n" +
"6aX5NnvFAkEAybeXNOwUvYtkgxF4s28s6gn11c5HZw4/a8vZm2tXXK/QfTQrJVXp\n" +
"VwxmSr0FAajWAlcYN/fGkX1pWA041CKFVQJAG08ozzekeEpAuByTIOaEXgZr5MBQ\n" +
"gBbHpgZNBl8Lsw9CJSQI15wGfv6yDiLXsH8FyC9TKs+d5Tv4Cvquk0efOQJAd9OC\n" +
"lCKFs48hdyaiz9yEDsc57PdrvRFepVdj/gpGzD14mVerJbOiOF6aSV19ot27u4on\n" +
"Td/3aifYs0CveHzFPQJAWb4LCDwqLctfzziG7/S7Z74gyq5qZF4FUElOAZkz123E\n" +
"yZvADwuz/4aK0od0lX9c4Jp7Mo5vQ4TvdoBnPuGo****\n" +
"-----END RSA PRIVATE KEY-----";
// RSA 公開鍵の文字列を指定します。OpenSSL を使用して生成できます。次の値は、RSA 公開鍵の文字列の例です。
final String PUBLIC_X509_PEM =
"-----BEGIN PUBLIC KEY-----\n" +
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCokfiAVXXf5ImFzKDw+XO/UByW\n" +
"6mse2QsIgz3ZwBtMNu59fR5zttSx+8fB7vR4CN3bTztrP9A6bjoN0FFnhlQ3vNJC\n" +
"5MFO1PByrE/MNd5AAfSVba93I6sx8NSk5MzUCA4NJzAUqYOEWGtGBcom6kEF6MnR\n" +
"1EKib1Id8hpooY5xaQID****\n" +
"-----END PUBLIC KEY-----";
// RSA キーペアを作成します。
RSAPrivateKey privateKey = SimpleRSAEncryptionMaterials.getPrivateKeyFromPemPKCS1(PRIVATE_PKCS1_PEM);
RSAPublicKey publicKey = SimpleRSAEncryptionMaterials.getPublicKeyFromPemX509(PUBLIC_X509_PEM);
KeyPair keyPair = new KeyPair(publicKey, privateKey);
// RSA マスターキーの説明を作成します。説明は作成後に変更できません。マスターキーの説明とマスターキーは 1 対 1 でマッピングされます。
// すべてのオブジェクトが同じマスターキーを使用する場合、説明は空にできます。ただし、後でマスターキーを変更することはできません。
// マスターキーの説明が空の場合、クライアントは復号時にどのマスターキーがファイルの暗号化に使用されたかを判断できません。
// 各マスターキーの説明を設定します。クライアントは、マスターキーとその説明のマッピングを保存する必要があります。サーバーはこのマッピングを保存しません。
Map<String, String> matDesc = new HashMap<String, String>();
matDesc.put("desc-key", "desc-value");
// RSA 暗号化マテリアルを作成します。
SimpleRSAEncryptionMaterials encryptionMaterials = new SimpleRSAEncryptionMaterials(keyPair, matDesc);
// 他の RSA キーで暗号化されたファイルをダウンロードして復号するには、他のマスターキーとその説明を暗号化マテリアルに追加します。
// encryptionMaterials.addKeyPairDescMaterial(<otherKeyPair>, <otherKeyPairMatDesc>);
// 暗号化クライアントを作成します。
// 暗号化クライアントが不要になったら、shutdown メソッドを呼び出してリソースを解放します。
OSSEncryptionClient ossEncryptionClient = new OSSEncryptionClientBuilder().
build(endpoint, credentialsProvider, encryptionMaterials);
try {
// UploadFileRequest オブジェクトを作成します。
UploadFileRequest uploadFileRequest = new UploadFileRequest(bucketName, objectName);
// アップロードするファイルのパスを設定します。
uploadFileRequest.setUploadFile(localFile);
// アップロードのパートサイズを指定します。値は 100 KB から 5 GB の範囲である必要があります。デフォルト値はファイルサイズの 1/10,000 です。
uploadFileRequest.setPartSize(100 * 1024);
// 再開可能なアップロードを有効にします。この機能はデフォルトで無効になっています。
uploadFileRequest.setEnableCheckpoint(true);
// チェックポイントファイルを設定します。指定しない場合、デフォルト名はローカルファイルと同じディレクトリにある localfile + ".ucp" です。
// アップロードの進行状況はこのファイルに保存されます。パートのアップロードに失敗した場合、再試行すると記録されたブレークポイントからアップロードが再開されます。アップロードが完了すると、ファイルは削除されます。
uploadFileRequest.setCheckpointFile("test-upload.ucp");
// 再開可能なアップロードを開始します。
ossEncryptionClient.uploadFile(uploadFileRequest);
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossEncryptionClient != null) {
ossEncryptionClient.shutdown();
}
}
}
}再開可能なダウンロード
次のコードは、RSA マスターキーを使用して再開可能なダウンロードを実行する方法の例を示しています。
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.crypto.SimpleRSAEncryptionMaterials;
import com.aliyun.oss.model.*;
import java.security.KeyPair;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.Map;
public class Demo {
public static void main(String[] args) throws Throwable {
// エンドポイントは、例として中国 (杭州) に設定されています。実際のエンドポイントに変更してください。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// バケット名を指定します。例:examplebucket。
String bucketName = "examplebucket";
// オブジェクトのフルパスを指定します。例:exampleobject.txt。フルパスにバケット名を含めることはできません。
String objectName = "exampleobject.txt";
// RSA 秘密鍵の文字列を指定します。OpenSSL を使用して生成できます。次の値は、RSA 秘密鍵の文字列の例です。
final String PRIVATE_PKCS1_PEM =
"-----BEGIN RSA PRIVATE KEY-----\n" +
"MIICWwIBAAKBgQCokfiAVXXf5ImFzKDw+XO/UByW6mse2QsIgz3ZwBtMNu59fR5z\n" +
"ttSx+8fB7vR4CN3bTztrP9A6bjoN0FFnhlQ3vNJC5MFO1PByrE/MNd5AAfSVba93\n" +
"I6sx8NSk5MzUCA4NJzAUqYOEWGtGBcom6kEF6MmR1EKib1Id8hpooY5xaQIDAQAB\n" +
"AoGAOPUZgkNeEMinrw31U3b2JS5sepG6oDG2CKpPu8OtdZMaAkzEfVTJiVoJpP2Y\n" +
"nPZiADhFW3e0ZAnak9BPsSsySRaSNmR465cG9tbqpXFKh9Rp/sCPo4Jq2n65yood\n" +
"JBrnGr6/xhYvNa14sQ6xjjfSgRNBSXD1XXNF4kALwgZyCAECQQDV7t4bTx9FbEs5\n" +
"36nAxPsPM6aACXaOkv6d9LXI7A0J8Zf42FeBV6RK0q7QG5iNNd1WJHSXIITUizVF\n" +
"6aX5NnvFAkEAybeXNOwUvYtkgxF4s28s6gn11c5HZw4/a8vZm2tXXK/QfTQrJVXp\n" +
"VwxmSr0FAajWAlcYN/fGkX1pWA041CKFVQJAG08ozzekeEpAuByTIOaEXgZr5MBQ\n" +
"gBbHpgZNBl8Lsw9CJSQI15wGfv6yDiLXsH8FyC9TKs+d5Tv4Cvquk0efOQJAd9OC\n" +
"lCKFs48hdyaiz9yEDsc57PdrvRFepVdj/gpGzD14mVerJbOiOF6aSV19ot27u4on\n" +
"Td/3aifYs0CveHzFPQJAWb4LCDwqLctfzziG7/S7Z74gyq5qZF4FUElOAZkz123E\n" +
"yZvADwuz/4aK0od0lX9c4Jp7Mo5vQ4TvdoBnPuGo****\n" +
"-----END RSA PRIVATE KEY-----";
// RSA 公開鍵の文字列を指定します。OpenSSL を使用して生成できます。次の値は、RSA 公開鍵の文字列の例です。
final String PUBLIC_X509_PEM =
"-----BEGIN PUBLIC KEY-----\n" +
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCokfiAVXXf5ImFzKDw+XO/UByW\n" +
"6mse2QsIgz3ZwBtMNu59fR5zttSx+8fB7vR4CN3bTztrP9A6bjoN0FFnhlQ3vNJC\n" +
"5MFO1PByrE/MNd5AAfSVba93I6sx8NSk5MzUCA4NJzAUqYOEWGtGBcom6kEF6MnR\n" +
"1EKib1Id8hpooY5xaQID****\n" +
"-----END PUBLIC KEY-----";
// RSA キーペアを作成します。
RSAPrivateKey privateKey = SimpleRSAEncryptionMaterials.getPrivateKeyFromPemPKCS1(PRIVATE_PKCS1_PEM);
RSAPublicKey publicKey = SimpleRSAEncryptionMaterials.getPublicKeyFromPemX509(PUBLIC_X509_PEM);
KeyPair keyPair = new KeyPair(publicKey, privateKey);
// RSA マスターキーの説明を作成します。説明は作成後に変更できません。マスターキーの説明とマスターキーは 1 対 1 でマッピングされます。
// すべてのオブジェクトが同じマスターキーを使用する場合、説明は空にできます。ただし、後でマスターキーを変更することはできません。
// マスターキーの説明が空の場合、クライアントは復号時にどのマスターキーがファイルの暗号化に使用されたかを判断できません。
// 各マスターキーの説明を設定します。クライアントは、マスターキーとその説明のマッピングを保存する必要があります。サーバーはこのマッピングを保存しません。
Map<String, String> matDesc = new HashMap<String, String>();
matDesc.put("desc-key", "desc-value");
// RSA 暗号化マテリアルを作成します。
SimpleRSAEncryptionMaterials encryptionMaterials = new SimpleRSAEncryptionMaterials(keyPair, matDesc);
// 他の RSA キーで暗号化されたファイルをダウンロードして復号するには、他のマスターキーとその説明を暗号化マテリアルに追加します。
// encryptionMaterials.addKeyPairDescMaterial(<otherKeyPair>, <otherKeyPairMatDesc>);
// 暗号化クライアントを作成します。
// 暗号化クライアントが不要になったら、shutdown メソッドを呼び出してリソースを解放します。
OSSEncryptionClient ossEncryptionClient = new OSSEncryptionClientBuilder().
build(endpoint, credentialsProvider, encryptionMaterials);
try {
// ダウンロードリクエストを開始します。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);
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossEncryptionClient != null) {
ossEncryptionClient.shutdown();
}
}
}
}範囲ダウンロード
次のコードは、RSA マスターキーを使用して範囲ダウンロードを実行し、ダウンロードしたデータを復号する方法の例を示しています。
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.crypto.SimpleRSAEncryptionMaterials;
import com.aliyun.oss.model.*;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.security.KeyPair;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.Map;
public class Demo {
public static void main(String[] args) throws Throwable {
// エンドポイントは、例として中国 (杭州) に設定されています。実際のエンドポイントに変更してください。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// バケット名を指定します。例:examplebucket。
String bucketName = "examplebucket";
// オブジェクトのフルパスを指定します。例:exampleobject.txt。フルパスにバケット名を含めることはできません。
String objectName = "exampleobject.txt";
String content = "test-range-get-content-82042795hlnf12s8yhfs976y2nfoshhnsdfsf235bvsmnhtskbcfd!";
// RSA 秘密鍵の文字列を指定します。OpenSSL を使用して生成できます。次の値は、RSA 秘密鍵の文字列の例です。
final String PRIVATE_PKCS1_PEM =
"-----BEGIN RSA PRIVATE KEY-----\n" +
"MIICWwIBAAKBgQCokfiAVXXf5ImFzKDw+XO/UByW6mse2QsIgz3ZwBtMNu59fR5z\n" +
"ttSx+8fB7vR4CN3bTztrP9A6bjoN0FFnhlQ3vNJC5MFO1PByrE/MNd5AAfSVba93\n" +
"I6sx8NSk5MzUCA4NJzAUqYOEWGtGBcom6kEF6MmR1EKib1Id8hpooY5xaQIDAQAB\n" +
"AoGAOPUZgkNeEMinrw31U3b2JS5sepG6oDG2CKpPu8OtdZMaAkzEfVTJiVoJpP2Y\n" +
"nPZiADhFW3e0ZAnak9BPsSsySRaSNmR465cG9tbqpXFKh9Rp/sCPo4Jq2n65yood\n" +
"JBrnGr6/xhYvNa14sQ6xjjfSgRNBSXD1XXNF4kALwgZyCAECQQDV7t4bTx9FbEs5\n" +
"36nAxPsPM6aACXaOkv6d9LXI7A0J8Zf42FeBV6RK0q7QG5iNNd1WJHSXIITUizVF\n" +
"6aX5NnvFAkEAybeXNOwUvYtkgxF4s28s6gn11c5HZw4/a8vZm2tXXK/QfTQrJVXp\n" +
"VwxmSr0FAajWAlcYN/fGkX1pWA041CKFVQJAG08ozzekeEpAuByTIOaEXgZr5MBQ\n" +
"gBbHpgZNBl8Lsw9CJSQI15wGfv6yDiLXsH8FyC9TKs+d5Tv4Cvquk0efOQJAd9OC\n" +
"lCKFs48hdyaiz9yEDsc57PdrvRFepVdj/gpGzD14mVerJbOiOF6aSV19ot27u4on\n" +
"Td/3aifYs0CveHzFPQJAWb4LCDwqLctfzziG7/S7Z74gyq5qZF4FUElOAZkz123E\n" +
"yZvADwuz/4aK0od0lX9c4Jp7Mo5vQ4TvdoBnPuGo****\n" +
"-----END RSA PRIVATE KEY-----";
// RSA 公開鍵の文字列を指定します。OpenSSL を使用して生成できます。次の値は、RSA 公開鍵の文字列の例です。
final String PUBLIC_X509_PEM =
"-----BEGIN PUBLIC KEY-----\n" +
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCokfiAVXXf5ImFzKDw+XO/UByW\n" +
"6mse2QsIgz3ZwBtMNu59fR5zttSx+8fB7vR4CN3bTztrP9A6bjoN0FFnhlQ3vNJC\n" +
"5MFO1PByrE/MNd5AAfSVba93I6sx8NSk5MzUCA4NJzAUqYOEWGtGBcom6kEF6MnR\n" +
"1EKib1Id8hpooY5xaQID****\n" +
"-----END PUBLIC KEY-----";
// RSA キーペアを作成します。
RSAPrivateKey privateKey = SimpleRSAEncryptionMaterials.getPrivateKeyFromPemPKCS1(PRIVATE_PKCS1_PEM);
RSAPublicKey publicKey = SimpleRSAEncryptionMaterials.getPublicKeyFromPemX509(PUBLIC_X509_PEM);
KeyPair keyPair = new KeyPair(publicKey, privateKey);
// RSA マスターキーの説明を作成します。説明は作成後に変更できません。マスターキーの説明とマスターキーは 1 対 1 でマッピングされます。
// すべてのオブジェクトが同じマスターキーを使用する場合、説明は空にできます。ただし、後でマスターキーを変更することはできません。
// マスターキーの説明が空の場合、クライアントは復号時にどのマスターキーがファイルの暗号化に使用されたかを判断できません。
// 各マスターキーの説明を設定します。クライアントは、マスターキーとその説明のマッピングを保存する必要があります。サーバーはこのマッピングを保存しません。
Map<String, String> matDesc = new HashMap<String, String>();
matDesc.put("desc-key", "desc-value");
// RSA 暗号化マテリアルを作成します。
SimpleRSAEncryptionMaterials encryptionMaterials = new SimpleRSAEncryptionMaterials(keyPair, matDesc);
// 他の RSA キーで暗号化されたファイルをダウンロードして復号するには、他のマスターキーとその説明を暗号化マテリアルに追加します。
// encryptionMaterials.addKeyPairDescMaterial(<otherKeyPair>, <otherKeyPairMatDesc>);
// 暗号化クライアントを作成します。
// 暗号化クライアントが不要になったら、shutdown メソッドを呼び出してリソースを解放します。
OSSEncryptionClient ossEncryptionClient = new OSSEncryptionClientBuilder().
build(endpoint, credentialsProvider, encryptionMaterials);
try {
// ファイルを暗号化してアップロードします。
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 ossObject = ossEncryptionClient.getObject(getObjectRequest);
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("Range-Get plain text:" + content.substring(start, end + 1));
System.out.println("Range-Get decrypted text: " + buffer.toString());
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossEncryptionClient != null) {
ossEncryptionClient.shutdown();
}
}
}
}関連ドキュメント
クライアントサイド暗号化の完全なサンプルコードについては、「GitHub の例」をご参照ください。