聊天-libsignal的加密

libsignal加密协议
github:https://github.com/signalapp/libsignal-protocol-java

一、基础概念

PreKey

协议使用了称为“ PreKeys”的概念。PreKey是存储在服务器中的ECPublicKey和关联的唯一ID(如上图的结构)。PreKeys也可以被签名。

在安装时,客户端会生成单个已签名的PreKey以及大量未签名的PreKey,并将它们全部传输到服务器。

public class PreKeyEntity {

  @JsonProperty
  private int keyId;

  @JsonProperty
  @JsonSerialize(using = ECPublicKeySerializer.class)
  @JsonDeserialize(using = ECPublicKeyDeserializer.class)
  private ECPublicKey publicKey;

  public PreKeyEntity() {}

  public PreKeyEntity(int keyId, ECPublicKey publicKey) {
    this.keyId     = keyId;
    this.publicKey = publicKey;
  }

  public int getKeyId() {
    return keyId;
  }

  public ECPublicKey getPublicKey() {
    return publicKey;
  }

  private static class ECPublicKeySerializer extends JsonSerializer<ECPublicKey> {
    @Override
    public void serialize(ECPublicKey value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
      gen.writeString(Base64.encodeBytesWithoutPadding(value.serialize()));
    }
  }

  private static class ECPublicKeyDeserializer extends JsonDeserializer<ECPublicKey> {
    @Override
    public ECPublicKey deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
      try {
        return Curve.decodePoint(Base64.decodeWithoutPadding(p.getValueAsString()), 0);
      } catch (InvalidKeyException e) {
        throw new IOException(e);
      }
    }
  }
}

Sessions

协议是面向会话的。客户端建立一个“会话”,然后将其用于所有后续的加密/解密操作。建立会话后,无需拆除会话。

通过以下三种方式的其中一种可以建立会话:

  • PreKeyBundles。希望向收件人发送消息的客户端可以通过从服务器检索该收件人的PreKeyBundle来建立会话。
  • PreKeySignalMessages。客户端可以从收件人接收PreKeySignalMessage消息并使用它来建立会话。
  • KeyExchangeMes​​sages。两个客户端可以交换KeyExchange消息来建立会话。
/**
 * A class that contains a remote PreKey and collection
 * of associated items.
 *
 * @author Moxie Marlinspike
 */
public class PreKeyBundle {

  private int         registrationId;

  private int         deviceId;

  private int         preKeyId;
  private ECPublicKey preKeyPublic;

  private int         signedPreKeyId;
  private ECPublicKey signedPreKeyPublic;
  private byte[]      signedPreKeySignature;

  private IdentityKey identityKey;

  public PreKeyBundle(int registrationId, int deviceId, int preKeyId, ECPublicKey preKeyPublic,
                      int signedPreKeyId, ECPublicKey signedPreKeyPublic, byte[] signedPreKeySignature,
                      IdentityKey identityKey)
  {
    this.registrationId        = registrationId;
    this.deviceId              = deviceId;
    this.preKeyId              = preKeyId;
    this.preKeyPublic          = preKeyPublic;
    this.signedPreKeyId        = signedPreKeyId;
    this.signedPreKeyPublic    = signedPreKeyPublic;
    this.signedPreKeySignature = signedPreKeySignature;
    this.identityKey           = identityKey;
  }

  /**
   * @return the device ID this PreKey belongs to.
   */
  public int getDeviceId() {
    return deviceId;
  }

  /**
   * @return the unique key ID for this PreKey.
   */
  public int getPreKeyId() {
    return preKeyId;
  }

  /**
   * @return the public key for this PreKey.
   */
  public ECPublicKey getPreKey() {
    return preKeyPublic;
  }

  /**
   * @return the unique key ID for this signed prekey.
   */
  public int getSignedPreKeyId() {
    return signedPreKeyId;
  }

  /**
   * @return the signed prekey for this PreKeyBundle.
   */
  public ECPublicKey getSignedPreKey() {
    return signedPreKeyPublic;
  }

  /**
   * @return the signature over the signed  prekey.
   */
  public byte[] getSignedPreKeySignature() {
    return signedPreKeySignature;
  }

  /**
   * @return the {@link org.whispersystems.libsignal.IdentityKey} of this PreKeys owner.
   */
  public IdentityKey getIdentityKey() {
    return identityKey;
  }

  /**
   * @return the registration ID associated with this PreKey.
   */
  public int getRegistrationId() {
    return registrationId;
  }
}

State

建立的会话封装了两个客户端之间的许多状态。该状态保存在持久记录中,在会话的整个生命周期中都需要保留这些记录。

状态保存在以下位置:

  • 身份状态。客户端将需要维护自己的身份密钥对,以及从其他客户端收到的身份密钥的状态。
  • PreKey的状态。客户将需要维护其生成的PreKey的状态。
  • 已签名的PreKey状态。客户将需要维护其已签名的PreKey的状态。
  • 会话状态。客户将需要保持他们已建立的会话的状态。

二、数据记录

identities:终端的身份凭证

prekeys:随机加密密钥对

signed_prekeys:已签名的密钥对

sessions:会话记录

三、密钥交互过程

1、注册时记录生产终端身份,已签名对密钥对,然后上报给服务器

2、登录时批量生产加密密钥

3、消息发送时,获取对方的加密密钥,加密发送对文本

4、消息接收时,使用本地的密钥,解密接收到对文本。

四、加密例子

原始文本:

<message type="text" id="88AB4E8F976E6FEEF4B715C829BD5289" t="1585733956" from="923127077123@s.whatsapp.net" notify="Hassan">

<body>85572206e616d653f

</body>

</message>

已加密对文本:

<message type="text" id="28F31BE78B2F4EFC931C0F963FB3C305" to="6285268065063@s.whatsapp.net">

<enc type="msg" v="2">162330a210536c05d2b0e37ae0c7e7ad9f6999491fadb361f724ace8a97c7c46044bb931954100018002270c043e1d7ccd2dde22f6fe5157990bd28c6713eb57bc54de89356b7f2b23f3b6a326e52afd40f579a6e25b2cedb16aacfe62fba325ae3340d4b54284989b7a42169058e0aa0991c4454b71fdeb22cb81c56695f6a1260deb554ebc1c80c805f261c5264326916326f87f90859086a90e863d71ef0f9b63963

</enc>

</message>

更多相关内容可参看:
https://github.com/signalapp/libsignal-protocol-java
whatsapp协议简单分析之-端对端加密
Whatsapp传输协议调研
WhatsApp 分析
【翻译】WhatsApp 加密概述(技术白皮书)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值