エンドツーエンド暗号化チャットの実装:Virgil E3KitとTencent Chat SDKを使用した開発者ガイド

10 分読む
Feb 18, 2025

シナリオ概要

このソリューションは、バージンセキュリティのE3KitとChat SDKに基づいて顧客のアプリケーションによって実装される必要があります。E3Kitドキュメントリンク: Virtual gild E3Kit|Virtual gild Security

GroupEncryption-End-to-End-Encryption-E3Kit|Virtual Security ドキュメントを読む前に、特にJWTトークン(JSON Web Token)、チャンネルの作成/グループの作成、メッセージの暗号化と復号化について学んでください。

使用する前に、バージンセキュリティコンソールでアプリケーションを開いてください。この製品は有料製品です。具体的な価格についてはPricing|Virgin Securityをご覧ください。

Virgin Security Console App Keys Page

Description: The image shows the Virgin Security console interface

以下の図は、高レベルの通信フローを示しています:

High-level communication flow diagram illustrating the interaction between users, their server, Tencent Server

適用された製品

チャット

基本的な統合ガイドライン

1.Chat SDKの初期化。

// 1. チャットコンソールから`SDKAppID`を取得します。
// 2. `config`オブジェクトを初期化します。
V2TIMSDKConfig config = new V2TIMSDKConfig();
// 3. ログ出力レベルを指定します。
config.setLogLevel(V2TIMSDKConfig.V2TIM_LOG_INFO);
// 4. `V2TIMSDKListener`イベントリスナーを追加します。`sdkListener`は`V2TIMSDKListener`の実装クラスです。IM SDKイベントを聞く必要がない場合は、このステップをスキップしてください。
V2TIMManager.getInstance().addIMSDKListener(sdkListener);
// 5. IM SDKを初期化します。このAPIを呼び出すとすぐにログインAPIを呼び出すことができます。
V2TIMManager.getInstance().initSDK(context, sdkAppID, config);

2.E3Kitの初期化、コンソールの設定情報を渡し、jwtを生成します。対応する操作ドキュメントリンク: GenerateClientTokens-GetStarted-E3Kit | VirgilSecurity

サーバーがjwttokenを生成し、クライアントに送信します。

// jwtの生成
// アプリキー(このキーはVirgil Dashboardで取得しました)
String appKeyBase64 = "MC4CAQAwBQYDK2VwBCIEINlK4BhgsijAbNmUqU6us0ZU9MGi+HxdYCA6TdZeHjR4";
byte[] appKeyData = ConvertionUtils.base64ToBytes(appKeyBase64);

// 暗号ライブラリが鍵ペアをインポート
VirgilCrypto crypto = new VirgilCrypto();
VirgilKeyPair keyPair = crypto.importPrivateKey(appKeyData);

// ユーザーのJWTを署名するためのアクセストークンサイナーを初期化
VirgilAccessTokenSigner accessTokenSigner = new VirgilAccessTokenSigner();

// Virgil Dashboardで取得したアプリ資格情報を使用:
String appId = "be00e10e4e1f4bf58f9b4dc85d79c77a";
String appKeyId = "70b447e321f3a0fd";
TimeSpan ttl = TimeSpan.fromTime(1, TimeUnit.HOURS); // 1時間 - JWTの有効期間

// 必要なパラメータでJWTジェネレーターを設定:
JwtGenerator jwtGenerator =
    new JwtGenerator(appId, keyPair.getPrivateKey(), appKeyId, ttl, accessTokenSigner);

// ユーザーのJWTを生成
// 各ユーザーにユニークなJWTを提供する必要があります。
// 各JWTにはユニークなユーザーのアイデンティティが含まれています(この場合はアリス)。
// アイデンティティは任意の値を取ることができます:名前、メールアドレス、いくつかのIDなど。
String identity = "Alice";
Jwt aliceJwt = jwtGenerator.generateToken(identity);

// 結果として、ユーザーのJWTが得られます。これは次のようになります:"eyJraWQiOiI3MGI0NDdlMzIxZjNhMGZkIiwidHlwIjoiSldUIiwiYWxnIjoiVkVEUzUxMiIsImN0eSI6InZpcmdpbC1qd3Q7dj0xIn0.eyJleHAiOjE1MTg2OTg5MTcsImlzcyI6InZpcmdpbC1iZTAwZTEwZTRlMWY0YmY1OGY5YjRkYzg1ZDc5Yzc3YSIsInN1YiI6ImlkZW50aXR5LUFsaWNlIiwiaWF0IjoxNTE4NjEyNTE3fQ.MFEwDQYJYIZIAWUDBAIDBQAEQP4Yo3yjmt8WWJ5mqs3Yrqc_VzG6nBtrW2KIjP-kxiIJL_7Wv0pqty7PDbDoGhkX8CJa6UOdyn3rBWRvMK7p7Ak"。
// ユーザー登録または認証ステップでユーザーにJWTを提供できます。
// JWTをクライアント側に送信します。
String jwtString = aliceJwt.stringRepresentation();

AndroidクライアントがE3Kitを初期化します。tokenCallbackは、上記のサーバーから返されたjwttokenであり、User1はユーザーIDです。

// E3Kitの初期化
// アイデンティティ、tokenCallback、およびコンテキストなどの必須パラメータを持つEThreeParamsを作成
EThreeParams params = new EThreeParams("User1",
   tokenCallback,context);
// EThreeParamsでE3Kitを初期化
EThree ethree = new EThree(params);

シナリオ特有の実装

ユーザーログイン

1.Chat Sdkのログインメソッドを呼び出してアカウントにログインします。

String userID = "your user id";
// UserSigを生成
String userSig = "userSig from your server";
V2TIMManager.getInstance().login(userID, userSig, new V2TIMCallback() {
   @Override
   public void onSuccess() {
       Log.i("imsdk", "成功");
   }
    @Override
   public void onError(int code, String desc) {
       // 次のエラーコードは、`userSig`が期限切れであることを示しており、再度ログインするために新しいものを生成する必要があります。
       // 1. ERR_USER_SIG_EXPIRED (6206)
       // 2. ERR_SVR_ACCOUNT_USERSIG_EXPIRED (70001)
       // 注意:他のエラーコードの場合はログインAPIを呼び出さないでください。そうでないと、IM SDKが無限ループに入る可能性があります。
       Log.i("imsdk", "失敗, コード:" + code + ", 説明:" + desc);
   }
});

2.eThree.registerメソッドを呼び出してユーザーをvirgilSecurityに登録します。対応する操作ドキュメントリンク: UserAuthentication-E3Kit | VirgilSecurity。

注意:im_IDのユーザーとvirgilsecurity_に登録されたユーザーのIDは一致している必要があります。

1対1のチャットを開始する

1.E3Kitのethree.createRatchetChannelメソッドを呼び出して1対1のセッション(User1とUser2)を作成します。対応する操作ドキュメントリンク: https://developer.virgilsecurity.com/docs/e3kit/end-to-end-encryption/double-ratchet/#create-channel

User1がUser2とのチャンネルを作成します。

// 1対1のチャンネルを作成
ethree.createRatchetChannel(users.get("User2"))
      .addCallback(new OnResultListener<RatchetChannel>() {
          @Override public void onSuccess(RatchetChannel ratchetChannel) {
              // チャンネルが作成され、ローカルに保存されました!
          }

          @Override public void onError(@NotNull Throwable throwable) {
              // エラーハンドリング
          }
      });

User2はチャンネルに参加できます。

// チャンネルに参加
ethree.joinRatchetChannel(users.get("User1"))
      .addCallback(new OnResultListener<RatchetChannel>() {
    @Override public void onSuccess(RatchetChannel ratchetChannel) {
        // チャンネルに参加し、ローカルに保存されました!
    }

    @Override public void onError(@NotNull Throwable throwable) {
        // エラーハンドリング
    }
});

1対1のチャットメッセージの暗号化と復号化

1.上記で作成したチャンネルを使用してメッセージを暗号化し、リンクドキュメント:https://developer.virgilsecurity.com/docs/e3kit/end-to-end-encryption/double-ratchet/?#encrypt-and-decrypt-messages.

// 1対1のチャットメッセージの暗号化
// メッセージを準備する
String messageToEncrypt = "こんにちは、User2!";

String encrypted = channel.encrypt(messageToEncrypt);

2.暗号化されたメッセージ内容はChat Sdkに送信され、カスタマイズされたメッセージと共に送信されます。

// APIから返された`msgID`をオンデマンドで使用
String msgID = V2TIMManager.getInstance().sendC2CCustomMessage("virgil encrypted msg", "receiver_userID", new V2TIMValueCallback<V2TIMMessage>() {
@Override
public void onSuccess(V2TIMMessage message) {
    // 1対1のテキストメッセージが正常に送信されました
}
    @Override
public void onError(int code, String desc) {
    // 1対1のテキストメッセージの送信に失敗しました
}
});

3.受信者はカスタマイズされたメッセージを受け取ります。

// イベントリスナーを設定
V2TIMManager.getInstance().addSimpleMsgListener(simpleMsgListener);

/**
* カスタムの1対1メッセージを受信
* @param msgID メッセージID
* @param sender 送信者情報
* @param customData 送信された内容
*/
public void onRecvC2CCustomMessage(String msgID, V2TIMUserInfo sender, byte[] customData) {
Log.i("onRecvC2CCustomMessage", "msgID:" + msgID + ", from:" + sender.getNickName() + ", content:" + new String(customData));
//E3Kitを呼び出してメッセージを復号化します
}

4.受信者はE3Kitを呼び出して復号化し、表示します。次のようにします:

// メッセージを復号化
String decrypted = channel.decrypt(encrypted);

チャンネル(グループ)を開始する

1.ethree.createGroupを呼び出してグループを作成します。ドキュメントリンク:https://developer.virgilsecurity.com/docs/e3kit/end-to-end-encryption/group-chat/?#create-group-chat.

// グループを作成
ethree.createGroup(groupId, users).addCallback(new OnResultListener<Group>() {
    @Override public void onSuccess(Group group) {
        // グループが作成され、ローカルに保存されました!
    }

    @Override public void onError(@NotNull Throwable throwable) {
        // エラーハンドリング
    }
});

2.グループメンバーを追加する必要がある場合、次のコードを呼び出します。removeメソッドを呼び出してグループメンバーを削除できます。ドキュメントリンク:https://developer.virgilsecurity.com/docs/e3kit/end-to-end-encryption/group-chat/?#add-new-participant.

// グループメンバーを追加
group.add(users.get("Den")).addCallback(new OnCompleteListener() {
    @Override public void onSuccess() {
        // Denが追加されました!
    }

    @Override public void onError(@NotNull Throwable throwable) {
        // エラーハンドリング
    }
});

3.Chat SdkのcreateGroupを呼び出してグループを作成し、joinGroupまたはinviteUserToGroupを呼び出してグループメンバーを追加します。

V2TIMManager.getInstance().createGroup(V2TIMManager.GROUP_TYPE_WORK, null, "groupA", new V2TIMValueCallback<String>() {
 @Override
 public void onSuccess(String s) {
     // グループが正常に作成されました
 }
  @Override
 public void onError(int code, String desc) {
     // グループの作成に失敗しました
 }
});
// グループ作成通知を待機します
V2TIMManager.getInstance().addGroupListener(new V2TIMGroupListener() {
 @Override
 public void onGroupCreated(String groupID) {
     // グループが作成されました。`groupID`は作成されたグループのIDです。
 }
});
// `userA`ユーザーを`groupA`グループに招待します
List<String> userIDList = new ArrayList<>();
userIDList.add("userA");
V2TIMManager.getGroupManager().inviteUserToGroup("groupA", userIDList, new V2TIMValueCallback<List<V2TIMGroupMemberOperationResult>>() {
 @Override
 public void onSuccess(List<V2TIMGroupMemberOperationResult> v2TIMGroupMemberOperationResults) {
     // ユーザーをグループに招待しました
 }
  @Override
 public void onError(int code, String desc) {
     // ユーザーをグループに招待するのに失敗しました
 }
});
// グループ招待イベントを待機します
V2TIMManager.getInstance().addGroupListener(new V2TIMGroupListener() {
 @Override
 public void onMemberInvited(String groupID, V2TIMGroupMemberInfo opUser, List<V2TIMGroupMemberInfo> memberList) {
     // ユーザーがグループに招待されました。このコールバックにはUIのヒントが含まれる場合があります。
 }
});

グループチャットメッセージの暗号化と復号化

1.上記で作成したグループを使用してメッセージを暗号化し、リンクドキュメント:https://developer.virgilsecurity.com/docs/e3kit/end-to-end-encryption/group-chat/?#encrypt-and-decrypt-messages.

// グループメッセージの暗号化
// メッセージを準備する
String messageToEncrypt = "こんにちは、ボブとキャロル!";

String encrypted = group.encrypt(messageToEncrypt);

2.暗号化されたメッセージ内容はTencent Chat Sdkに送信され、カスタマイズされたメッセージと共に送信されます。

String msgID = V2TIMManager.getInstance().sendGroupCustomMessage("virgil encrypted msg ".getBytes(), "groupID", V2TIMMessage.V2TIM_PRIORITY_NORMAL, new V2TIMValueCallback<V2TIMMessage>() {
@Override
public void onSuccess(V2TIMMessage message) {
    // カスタムグループメッセージが正常に送信されました
}

3.Tencent Cloud Chat Sdkがカスタマイズされたメッセージを受信した後、

// イベントリスナーを設定
V2TIMManager.getInstance().addSimpleMsgListener(simpleMsgListener);

/**
* カスタムグループメッセージを受信
* @param msgID メッセージID
* @param groupID グループID
* @param sender 送信者のグループメンバー情報
* @param customData 送信された内容
*/
public void onRecvGroupCustomMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, byte[] customData) {
Log.i("onRecvGroupCustomMessage", "msgID:" + msgID + ", groupID:" + groupID + ", from:" + sender.getNickName() + ", content:" + new String(customData));
//E3Kitを呼び出してメッセージを復号化します
}

4.受信者は復号化して表示します。次のようにします:

// グループメッセージの復号化
String decrypted = group.decrypt(encrypted, users.get("Alice"));

注意:このエンドツーエンド暗号化スキームを使用すると、imsdkのローカルチャット記録検索機能は利用できなくなります。

今すぐ注文

こちらをクリックして、購入ページに迅速に移動して注文します。