Signal 协议是一种基于双棘轮技术的前向保密协议。可应用于在同步和异步这两种消息传递环境。
接口库开源地址: https://github.com/signalapp/libsignal-protocol-java
Signal 协议中应用了预共享密钥(PreKey)概念。预共享密钥包括一个公钥和一个对应的惟一ID。
准备数据时,客户端生成一个已签名的预共享密钥,以及一组未签名的预共享密钥的列表,并将它们全部传输到服务器上存储,以供查询。预共享密钥也可以签名。
Signal 协议是面向会话的。客户端建立一个“会话”,用于后续的加密/解密操作。一旦建立了一个会话,通信过程中就不必再拆掉它。
会话可以通过以下三种方式建立:
已建立的会话封装了两个客户端之间的许多状态。这些状态与会话同生命周期,保存在记录中:
准备数据时,libsignal客户端需要生成其身份认证密钥、注册id和预共享密钥。以下代码是以bob端为例:
// 构建bob的数据内容 int bobId = 0x10203040; // bob 的地址 SignalProtocolAddress bobAddress = new SignalProtocolAddress("BobName", bobId); // IKP-B,身份认证密钥对 IdentityKeyPair bobIdentityKeyPair = KeyHelper.generateIdentityKeyPair(); // 注册编号, int bobRegistrationId = KeyHelper.generateRegistrationId(false); // 预共享密钥 List<PreKeyRecord> bobPreKeys = KeyHelper.generatePreKeys(bobId, 100); // 已签名预共享密钥SPK-B ID int bobSignedPreKeyId = 1; // 已签名预共享密钥 SignedPreKeyRecord bobSignedPreKey = KeyHelper.generateSignedPreKey(bobIdentityKeyPair, bobSignedPreKeyId); // 获取到的,bob的某一个预共享的密钥包 // 一次性预共享密钥OPK-B ID int bobPreKeyId = 1; // 一次性预共享密钥OPK-B公钥 ECPublicKey bobPreKeyPublic = bobPreKeys.get(bobPreKeyId).getKeyPair().getPublicKey(); // 已签名预共享密钥SPK-B公钥 ECPublicKey bobSignedPreKeyPublic = bobSignedPreKey.getKeyPair().getPublicKey(); // 预共享密钥签名Sig(IK-B,Encode(SPK-B)) byte[] bobSignedPreKeySignature = Curve.calculateSignature(bobIdentityKeyPair.getPrivateKey(), bobSignedPreKeyPublic.serialize()); // 身份认证公钥IK-B IdentityKey bobIdentityKey = bobIdentityKeyPair.getPublicKey(); // 组建预共享密钥包 PreKeyBundle bobProKeyBundle = new PreKeyBundle(bobRegistrationId, bobRegistrationId, bobPreKeyId,bobPreKeyPublic, bobSignedPreKeyId, bobSignedPreKeyPublic, bobSignedPreKeySignature, bobIdentityKey); //发送预共享密钥包到服务器...
应用接口库的客户端需要实现四个接口:IdentityKeyStore、PreKeyStore、SignedPreKeyStore和SessionStore。它们将用于管理身份认证密钥、预共享密钥、已签名预共享密钥和会话状态的加载和存储。
通过这些构建会话就相当简单:
// IKP-A,身份认证密钥对 IdentityKeyPair aliceIdentityKeyPair = KeyHelper.generateIdentityKeyPair(); // 注册编号, int aliceRegistrationId = KeyHelper.generateRegistrationId(false); // 会话存储 SessionStore aliceSessionStore = new InMemorySessionStore(); // 预共享存储 PreKeyStore alicePreKeyStore = new InMemoryPreKeyStore(); // 已签名预共享密钥 SignedPreKeyStore aliceSignedPreKeyStore = new InMemorySignedPreKeyStore(); // 身份认证密钥对 IdentityKeyStore aliceIdentityStore = new InMemoryIdentityKeyStore(aliceIdentityKeyPair, aliceRegistrationId); // 创建会话处理器 SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceSessionStore, alicePreKeyStore, aliceSignedPreKeyStore, aliceIdentityStore, bobAddress); // 从服务器获取bob的预共享密钥包,初始化会话 aliceSessionBuilder.process(bobProKeyBundle); //创建消息加解密器 SessionCipher sessionCipher = new SessionCipher(aliceSessionStore, alicePreKeyStore, aliceSignedPreKeyStore,aliceIdentityStore, bobAddress); // 组建初始消息 CiphertextMessage message = sessionCipher.encrypt("Hello world!".getBytes("UTF-8")); //将消息内容发送到bob...
bob端收到后可通过PreKeySignalMessage的方式初始化会话。
//SessionBuilder以及各种store的创建,类似alice端 bobSessionBuilder.process(sessionRecord ,(PreKeySignalMessage) message);