def initializeSessionsV2(self, aliceSessionState, bobSessionState): aliceIdentityKeyPair = Curve.generateKeyPair() aliceIdentityKey = IdentityKeyPair(IdentityKey(aliceIdentityKeyPair.getPublicKey()), aliceIdentityKeyPair.getPrivateKey()) aliceBaseKey = Curve.generateKeyPair() aliceEphemeralKey = Curve.generateKeyPair() bobIdentityKeyPair = Curve.generateKeyPair() bobIdentityKey = IdentityKeyPair(IdentityKey(bobIdentityKeyPair.getPublicKey()), bobIdentityKeyPair.getPrivateKey()) bobBaseKey = Curve.generateKeyPair() bobEphemeralKey = bobBaseKey aliceParameters = AliceAxolotlParameters.newBuilder()\ .setOurIdentityKey(aliceIdentityKey)\ .setOurBaseKey(aliceBaseKey)\ .setTheirIdentityKey(bobIdentityKey.getPublicKey())\ .setTheirSignedPreKey(bobEphemeralKey.getPublicKey())\ .setTheirRatchetKey(bobEphemeralKey.getPublicKey())\ .setTheirOneTimePreKey(None)\ .create() bobParameters = BobAxolotlParameters.newBuilder()\ .setOurIdentityKey(bobIdentityKey)\ .setOurOneTimePreKey(None)\ .setOurRatchetKey(bobEphemeralKey)\ .setOurSignedPreKey(bobBaseKey)\ .setTheirBaseKey(aliceBaseKey.getPublicKey())\ .setTheirIdentityKey(aliceIdentityKey.getPublicKey())\ .create() RatchetingSession.initializeSessionAsAlice(aliceSessionState, 2, aliceParameters) RatchetingSession.initializeSessionAsBob(bobSessionState, 2, bobParameters)
def test_badSignedPreKeySignature(self): aliceStore = InMemoryAxolotlStore() aliceSessionBuilder = SessionBuilder(aliceStore, aliceStore, aliceStore, aliceStore, self.__class__.BOB_RECIPIENT_ID, 1) bobIdentityKeyStore = InMemoryIdentityKeyStore() bobPreKeyPair = Curve.generateKeyPair() bobSignedPreKeyPair = Curve.generateKeyPair() bobSignedPreKeySignature = Curve.calculateSignature(bobIdentityKeyStore.getIdentityKeyPair().getPrivateKey(), bobSignedPreKeyPair.getPublicKey().serialize()) for i in range(0, len(bobSignedPreKeySignature) * 8): modifiedSignature = bytearray(bobSignedPreKeySignature[:]) modifiedSignature[int(i/8)] ^= 0x01 << (i % 8) bobPreKey = PreKeyBundle(bobIdentityKeyStore.getLocalRegistrationId(), 1, 31337, bobPreKeyPair.getPublicKey(), 22, bobSignedPreKeyPair.getPublicKey(), modifiedSignature, bobIdentityKeyStore.getIdentityKeyPair().getPublicKey()) try: aliceSessionBuilder.processPreKeyBundle(bobPreKey) except Exception: pass #good bobPreKey = PreKeyBundle(bobIdentityKeyStore.getLocalRegistrationId(), 1, 31337, bobPreKeyPair.getPublicKey(), 22, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature, bobIdentityKeyStore.getIdentityKeyPair().getPublicKey()) aliceSessionBuilder.processPreKeyBundle(bobPreKey)
def test_randomAgreements(self): for i in range(0, 50): alice = Curve.generateKeyPair() bob = Curve.generateKeyPair() sharedAlice = Curve.calculateAgreement(bob.getPublicKey(), alice.getPrivateKey()) sharedBob = Curve.calculateAgreement(alice.getPublicKey(), bob.getPrivateKey()) self.assertEqual(sharedAlice, sharedBob)
def encryptParams(self, params, key): """ :param params: :type params: list :param key: :type key: ECPublicKey :return: :rtype: list """ keypair = Curve.generateKeyPair() encodedparams = self.urlencodeParams(params) cipher = AESGCM(Curve.calculateAgreement(key, keypair.privateKey)) ciphertext = cipher.encrypt(b'\x00\x00\x00\x00' + struct.pack('>Q', 0), encodedparams.encode(), b'') payload = base64.b64encode(keypair.publicKey.serialize()[1:] + ciphertext) return [('ENC', payload)]
def test_signature(self): aliceIdentityPrivate = bytearray([0xc0, 0x97, 0x24, 0x84, 0x12, 0xe5, 0x8b, 0xf0, 0x5d, 0xf4, 0x87, 0x96, 0x82, 0x05, 0x13, 0x27, 0x94, 0x17, 0x8e, 0x36, 0x76, 0x37, 0xf5, 0x81, 0x8f, 0x81, 0xe0, 0xe6, 0xce, 0x73, 0xe8, 0x65]) aliceIdentityPublic = bytearray([0x05, 0xab, 0x7e, 0x71, 0x7d, 0x4a, 0x16, 0x3b, 0x7d, 0x9a, 0x1d, 0x80, 0x71, 0xdf, 0xe9, 0xdc, 0xf8, 0xcd, 0xcd, 0x1c, 0xea, 0x33, 0x39, 0xb6, 0x35, 0x6b, 0xe8, 0x4d, 0x88, 0x7e, 0x32, 0x2c, 0x64]) aliceEphemeralPublic = bytearray([0x05, 0xed, 0xce, 0x9d, 0x9c, 0x41, 0x5c, 0xa7, 0x8c, 0xb7, 0x25, 0x2e, 0x72, 0xc2, 0xc4, 0xa5, 0x54, 0xd3, 0xeb, 0x29, 0x48, 0x5a, 0x0e, 0x1d, 0x50, 0x31, 0x18, 0xd1, 0xa8, 0x2d, 0x99, 0xfb, 0x4a]) aliceSignature = bytearray([0x5d, 0xe8, 0x8c, 0xa9, 0xa8, 0x9b, 0x4a, 0x11, 0x5d, 0xa7, 0x91, 0x09, 0xc6, 0x7c, 0x9c, 0x74, 0x64, 0xa3, 0xe4, 0x18, 0x02, 0x74, 0xf1, 0xcb, 0x8c, 0x63, 0xc2, 0x98, 0x4e, 0x28, 0x6d, 0xfb, 0xed, 0xe8, 0x2d, 0xeb, 0x9d, 0xcd, 0x9f, 0xae, 0x0b, 0xfb, 0xb8, 0x21, 0x56, 0x9b, 0x3d, 0x90, 0x01, 0xbd, 0x81, 0x30, 0xcd, 0x11, 0xd4, 0x86, 0xce, 0xf0, 0x47, 0xbd, 0x60, 0xb8, 0x6e, 0x88]) alicePrivateKey = Curve.decodePrivatePoint(aliceIdentityPrivate) alicePublicKey = Curve.decodePoint(aliceIdentityPublic, 0) aliceEphemeral = Curve.decodePoint(aliceEphemeralPublic, 0) res = Curve.verifySignature(alicePublicKey, aliceEphemeral.serialize(), bytes(aliceSignature)) self.assertTrue(res)
def getSignature(self, signatureKey, serialized): """ :type signatureKey: ECPrivateKey :type serialized: bytearray """ try: return Curve.calculateSignature(signatureKey, serialized) except InvalidKeyException as e: raise AssertionError(e)
def __init__(self, id = None, iteration = None, chainKey = None, signatureKey = None, serialized = None): """ :type id: int :type iteration: int :type chainKey: bytearray :type signatureKey: ECPublicKey """ assert bool(id is not None and iteration is not None and chainKey is not None and signatureKey is not None)\ ^ bool(serialized),\ "Either pass arguments or serialized data" if serialized: try: messageParts = ByteUtil.split(serialized, 1, len(serialized)- 1) version = messageParts[0][0] message = messageParts[1] if ByteUtil.highBitsToInt(version) < 3: raise LegacyMessageException("Legacy message: %s" % ByteUtil.highBitsToInt(version)) if ByteUtil.highBitsToInt(version) > self.__class__.CURRENT_VERSION: raise InvalidMessageException("Unknown version: %s" % ByteUtil.highBitsToInt(version)) distributionMessage = whisperprotos.SenderKeyDistributionMessage() distributionMessage.ParseFromString(message) if distributionMessage.id is None or distributionMessage.iteration is None\ or distributionMessage.chainKey is None or distributionMessage.signingKey is None: raise InvalidMessageException("Incomplete message") self.serialized = serialized self.id = distributionMessage.id self.iteration = distributionMessage.iteration self.chainKey = distributionMessage.chainKey self.signatureKey = Curve.decodePoint(bytearray(distributionMessage.signingKey), 0) except Exception as e: raise InvalidMessageException(e) else: version = [ByteUtil.intsToByteHighAndLow(self.__class__.CURRENT_VERSION, self.__class__.CURRENT_VERSION)] self.id = id self.iteration = iteration self.chainKey = chainKey self.signatureKey = signatureKey message = whisperprotos.SenderKeyDistributionMessage() message.id = id message.iteration = iteration message.chainKey= bytes(chainKey) message.signingKey = signatureKey.serialize() message = message.SerializeToString() self.serialized = bytes(ByteUtil.combine(version, message))
def verifySignature(self, signatureKey): """ :type signatureKey: ECPublicKey """ try: parts = ByteUtil.split(self.serialized, len(self.serialized)- self.__class__.SIGNATURE_LENGTH, self.__class__.SIGNATURE_LENGTH) if not Curve.verifySignature(signatureKey, parts[0], parts[1]): raise InvalidMessageException("Invalid signature!") except InvalidKeyException as e: raise InvalidMessageException(e)
def test_agreement(self): alicePublic = bytearray([0x05, 0x1b, 0xb7, 0x59, 0x66, 0xf2, 0xe9, 0x3a, 0x36, 0x91, 0xdf, 0xff, 0x94, 0x2b, 0xb2, 0xa4, 0x66, 0xa1, 0xc0, 0x8b, 0x8d, 0x78, 0xca, 0x3f, 0x4d, 0x6d, 0xf8, 0xb8, 0xbf, 0xa2, 0xe4, 0xee, 0x28]) alicePrivate = bytearray([0xc8, 0x06, 0x43, 0x9d, 0xc9, 0xd2, 0xc4, 0x76, 0xff, 0xed, 0x8f, 0x25, 0x80, 0xc0, 0x88, 0x8d, 0x58, 0xab, 0x40, 0x6b, 0xf7, 0xae, 0x36, 0x98, 0x87, 0x90, 0x21, 0xb9, 0x6b, 0xb4, 0xbf, 0x59]) bobPublic = bytearray([0x05, 0x65, 0x36, 0x14, 0x99, 0x3d, 0x2b, 0x15, 0xee, 0x9e, 0x5f, 0xd3, 0xd8, 0x6c, 0xe7, 0x19, 0xef, 0x4e, 0xc1, 0xda, 0xae, 0x18, 0x86, 0xa8, 0x7b, 0x3f, 0x5f, 0xa9, 0x56, 0x5a, 0x27, 0xa2, 0x2f]) bobPrivate = bytearray([0xb0, 0x3b, 0x34, 0xc3, 0x3a, 0x1c, 0x44, 0xf2, 0x25, 0xb6, 0x62, 0xd2, 0xbf, 0x48, 0x59, 0xb8, 0x13, 0x54, 0x11, 0xfa, 0x7b, 0x03, 0x86, 0xd4, 0x5f, 0xb7, 0x5d, 0xc5, 0xb9, 0x1b, 0x44, 0x66]) shared = bytearray([0x32, 0x5f, 0x23, 0x93, 0x28, 0x94, 0x1c, 0xed, 0x6e, 0x67, 0x3b, 0x86, 0xba, 0x41, 0x01, 0x74, 0x48, 0xe9, 0x9b, 0x64, 0x9a, 0x9c, 0x38, 0x06, 0xc1, 0xdd, 0x7c, 0xa4, 0xc4, 0x77, 0xe6, 0x29]) alicePublicKey = Curve.decodePoint(alicePublic, 0) alicePrivateKey = Curve.decodePrivatePoint(alicePrivate) bobPublicKey = Curve.decodePoint(bobPublic, 0) bobPrivateKey = Curve.decodePrivatePoint(bobPrivate) sharedOne = Curve.calculateAgreement(alicePublicKey, bobPrivateKey) sharedTwo = Curve.calculateAgreement(bobPublicKey, alicePrivateKey) self.assertEqual(sharedOne, shared) self.assertEqual(sharedTwo, shared)
def __init__(self, messageVersion = None, sequence = None, flags=None, baseKey = None, baseKeySignature = None, ratchetKey = None, identityKey = None, serialized = None): """ :type messageVersion: int :type sequence: int :type flags:int :type baseKey: ECPublicKey :type baseKeySignature: bytearray :type ratchetKey: ECPublicKey :type identityKey: IdentityKey :type serialized: bytearray """ if serialized: try: parts = ByteUtil.split(serialized, 1, len(serialized)- 1) self.version = ByteUtil.highBitsToInt(parts[0][0]) self.supportedVersion = ByteUtil.lowBitsToInt(parts[0][0]) if self.version <= CiphertextMessage.UNSUPPORTED_VERSION: raise LegacyMessageException("Unsupportmessageed legacy version: %s" % self.version) if self.version > CiphertextMessage.CURRENT_VERSION: raise InvalidVersionException("Unkown version: %s" % self.version) message = whisperprotos.KeyExchangeMessage() message.ParseFromString(bytes(parts[1])) if not message.HasField("id") or not message.HasField("baseKey")\ or not message.HasField("ratchetKey") or not message.HasField("identityKey")\ or (self.version >= 3 and not message.HasField("baseKeySignature")): raise InvalidMessageException("Some required fields are missing!") self.sequence = message.id >> 5 self.flags = message.id & 0x1f self.serialized = serialized self.baseKey = Curve.decodePoint(bytearray(message.baseKey), 0) self.baseKeySignature = message.baseKeySignature self.ratchetKey = Curve.decodePoint(bytearray(message.ratchetKey), 0) self.identityKey = IdentityKey(message.identityKey, 0) except InvalidKeyException as e: raise InvalidMessageException(e) else: self.supportedVersion = CiphertextMessage.CURRENT_VERSION self.version = messageVersion self.sequence = sequence self.flags = flags self.baseKey = baseKey self.baseKeySignature = baseKeySignature self.ratchetKey = ratchetKey self.identityKey = identityKey version = [ByteUtil.intsToByteHighAndLow(self.version, self.supportedVersion)] keyExchangeMessage = whisperprotos.KeyExchangeMessage() keyExchangeMessage.id = (self.sequence << 5) | self.flags keyExchangeMessage.baseKey = baseKey.serialize() keyExchangeMessage.ratchetKey = ratchetKey.serialize() keyExchangeMessage.identityKey = identityKey.serialize() if messageVersion >= 3: keyExchangeMessage.baseKeySignature = baseKeySignature self.serialized = ByteUtil.combine(version, keyExchangeMessage.SerializeToString())
def __init__(self): self.trustedKeys = {} identityKeyPairKeys = Curve.generateKeyPair() self.identityKeyPair = IdentityKeyPair(IdentityKey(identityKeyPairKeys.getPublicKey()), identityKeyPairKeys.getPrivateKey()) self.localRegistrationId = KeyHelper.generateRegistrationId()
def test_basicPreKeyV3(self): aliceStore = InMemoryAxolotlStore() aliceSessionBuilder = SessionBuilder(aliceStore, aliceStore, aliceStore, aliceStore, self.__class__.BOB_RECIPIENT_ID, 1) bobStore = InMemoryAxolotlStore() bobPreKeyPair = Curve.generateKeyPair() bobSignedPreKeyPair = Curve.generateKeyPair() bobSignedPreKeySignature = Curve.calculateSignature(bobStore.getIdentityKeyPair().getPrivateKey(), bobSignedPreKeyPair.getPublicKey().serialize()) bobPreKey = PreKeyBundle(bobStore.getLocalRegistrationId(), 1, 31337, bobPreKeyPair.getPublicKey(), 22, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature, bobStore.getIdentityKeyPair().getPublicKey()) aliceSessionBuilder.processPreKeyBundle(bobPreKey) self.assertTrue(aliceStore.containsSession(self.__class__.BOB_RECIPIENT_ID, 1)) self.assertTrue(aliceStore.loadSession(self.__class__.BOB_RECIPIENT_ID, 1).getSessionState().getSessionVersion() == 3) originalMessage = "L'homme est condamné à être libre" aliceSessionCipher = SessionCipher(aliceStore, aliceStore, aliceStore, aliceStore, self.__class__.BOB_RECIPIENT_ID, 1) outgoingMessage = aliceSessionCipher.encrypt(originalMessage) self.assertTrue(outgoingMessage.getType() == CiphertextMessage.PREKEY_TYPE) incomingMessage = PreKeyWhisperMessage(serialized=outgoingMessage.serialize()) bobStore.storePreKey(31337, PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair)) bobStore.storeSignedPreKey(22, SignedPreKeyRecord(22, int(time.time() * 1000), bobSignedPreKeyPair, bobSignedPreKeySignature)) bobSessionCipher = SessionCipher(bobStore, bobStore, bobStore, bobStore, self.__class__.ALICE_RECIPIENT_ID, 1) plaintext = bobSessionCipher.decryptPkmsg(incomingMessage) self.assertEqual(originalMessage, plaintext) # @@TODO: in callback assertion # self.assertFalse(bobStore.containsSession(self.__class__.ALICE_RECIPIENT_ID, 1)) self.assertTrue(bobStore.containsSession(self.__class__.ALICE_RECIPIENT_ID, 1)) self.assertTrue(bobStore.loadSession(self.__class__.ALICE_RECIPIENT_ID, 1).getSessionState().getSessionVersion() == 3) self.assertTrue(bobStore.loadSession(self.__class__.ALICE_RECIPIENT_ID, 1).getSessionState().getAliceBaseKey() != None) self.assertEqual(originalMessage, plaintext) bobOutgoingMessage = bobSessionCipher.encrypt(originalMessage) self.assertTrue(bobOutgoingMessage.getType() == CiphertextMessage.WHISPER_TYPE) alicePlaintext = aliceSessionCipher.decryptMsg(WhisperMessage(serialized=bobOutgoingMessage.serialize())) self.assertEqual(alicePlaintext, originalMessage) self.runInteraction(aliceStore, bobStore) aliceStore = InMemoryAxolotlStore() aliceSessionBuilder = SessionBuilder(aliceStore, aliceStore, aliceStore, aliceStore, self.__class__.BOB_RECIPIENT_ID, 1) aliceSessionCipher = SessionCipher(aliceStore, aliceStore, aliceStore, aliceStore, self.__class__.BOB_RECIPIENT_ID, 1) bobPreKeyPair = Curve.generateKeyPair() bobSignedPreKeyPair = Curve.generateKeyPair() bobSignedPreKeySignature = Curve.calculateSignature(bobStore.getIdentityKeyPair().getPrivateKey(), bobSignedPreKeyPair.getPublicKey().serialize()) bobPreKey = PreKeyBundle(bobStore.getLocalRegistrationId(), 1, 31338, bobPreKeyPair.getPublicKey(), 23, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature, bobStore.getIdentityKeyPair().getPublicKey()) bobStore.storePreKey(31338, PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair)) bobStore.storeSignedPreKey(23, SignedPreKeyRecord(23, int(time.time() * 1000), bobSignedPreKeyPair, bobSignedPreKeySignature)) aliceSessionBuilder.processPreKeyBundle(bobPreKey) outgoingMessage = aliceSessionCipher.encrypt(originalMessage) try: plaintext = bobSessionCipher.decryptPkmsg(PreKeyWhisperMessage(serialized=outgoingMessage)) raise AssertionError("shouldn't be trusted!") except Exception: bobStore.saveIdentity(self.__class__.ALICE_RECIPIENT_ID, PreKeyWhisperMessage(serialized=outgoingMessage.serialize()).getIdentityKey()) plaintext = bobSessionCipher.decryptPkmsg(PreKeyWhisperMessage(serialized=outgoingMessage.serialize())) self.assertEqual(plaintext, originalMessage) bobPreKey = PreKeyBundle(bobStore.getLocalRegistrationId(), 1, 31337, Curve.generateKeyPair().getPublicKey(), 23, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature, aliceStore.getIdentityKeyPair().getPublicKey()) try: aliceSessionBuilder.process(bobPreKey) raise AssertionError("shouldn't be trusted!") except Exception: #good pass
def getSigningKeyPublic(self): return Curve.decodePoint(bytearray(self.senderKeyStateStructure.senderSigningKey.public), 0)
def test_rootKeyDerivationV2(self): rootKeySeed = bytearray( [ 0x7B, 0xA6, 0xDE, 0xBC, 0x2B, 0xC1, 0xBB, 0xF9, 0x1A, 0xBB, 0xC1, 0x36, 0x74, 0x04, 0x17, 0x6C, 0xA6, 0x23, 0x09, 0x5B, 0x7E, 0xC6, 0x6B, 0x45, 0xF6, 0x02, 0xD9, 0x35, 0x38, 0x94, 0x2D, 0xCC, ] ) alicePublic = bytearray( [ 0x05, 0xEE, 0x4F, 0xA6, 0xCD, 0xC0, 0x30, 0xDF, 0x49, 0xEC, 0xD0, 0xBA, 0x6C, 0xFC, 0xFF, 0xB2, 0x33, 0xD3, 0x65, 0xA2, 0x7F, 0xAD, 0xBE, 0xFF, 0x77, 0xE9, 0x63, 0xFC, 0xB1, 0x62, 0x22, 0xE1, 0x3A, ] ) alicePrivate = bytearray( [ 0x21, 0x68, 0x22, 0xEC, 0x67, 0xEB, 0x38, 0x04, 0x9E, 0xBA, 0xE7, 0xB9, 0x39, 0xBA, 0xEA, 0xEB, 0xB1, 0x51, 0xBB, 0xB3, 0x2D, 0xB8, 0x0F, 0xD3, 0x89, 0x24, 0x5A, 0xC3, 0x7A, 0x94, 0x8E, 0x50, ] ) bobPublic = bytearray( [ 0x05, 0xAB, 0xB8, 0xEB, 0x29, 0xCC, 0x80, 0xB4, 0x71, 0x09, 0xA2, 0x26, 0x5A, 0xBE, 0x97, 0x98, 0x48, 0x54, 0x06, 0xE3, 0x2D, 0xA2, 0x68, 0x93, 0x4A, 0x95, 0x55, 0xE8, 0x47, 0x57, 0x70, 0x8A, 0x30, ] ) nextRoot = bytearray( [ 0xB1, 0x14, 0xF5, 0xDE, 0x28, 0x01, 0x19, 0x85, 0xE6, 0xEB, 0xA2, 0x5D, 0x50, 0xE7, 0xEC, 0x41, 0xA9, 0xB0, 0x2F, 0x56, 0x93, 0xC5, 0xC7, 0x88, 0xA6, 0x3A, 0x06, 0xD2, 0x12, 0xA2, 0xF7, 0x31, ] ) nextChain = bytearray( [ 0x9D, 0x7D, 0x24, 0x69, 0xBC, 0x9A, 0xE5, 0x3E, 0xE9, 0x80, 0x5A, 0xA3, 0x26, 0x4D, 0x24, 0x99, 0xA3, 0xAC, 0xE8, 0x0F, 0x4C, 0xCA, 0xE2, 0xDA, 0x13, 0x43, 0x0C, 0x5C, 0x55, 0xB5, 0xCA, 0x5F, ] ) alicePublicKey = Curve.decodePoint(alicePublic, 0) alicePrivateKey = Curve.decodePrivatePoint(alicePrivate) aliceKeyPair = ECKeyPair(alicePublicKey, alicePrivateKey) bobPublicKey = Curve.decodePoint(bobPublic, 0) rootKey = RootKey(HKDF.createFor(2), rootKeySeed) rootKeyChainKeyPair = rootKey.createChain(bobPublicKey, aliceKeyPair) nextRootKey = rootKeyChainKeyPair[0] nextChainKey = rootKeyChainKeyPair[1] self.assertEqual(rootKey.getKeyBytes(), rootKeySeed) self.assertEqual(nextRootKey.getKeyBytes(), nextRoot) self.assertEqual(nextChainKey.getKey(), nextChain)
def test_ratchetingSessionAsBob(self): bobPublic = bytearray([0x05, 0x2c, 0xb4, 0x97, 0x76, 0xb8, 0x77, 0x02, 0x05, 0x74, 0x5a, 0x3a, 0x6e, 0x24, 0xf5, 0x79, 0xcd, 0xb4, 0xba, 0x7a, 0x89, 0x04, 0x10, 0x05, 0x92, 0x8e, 0xbb, 0xad, 0xc9, 0xc0, 0x5a, 0xd4, 0x58]) bobPrivate = bytearray([0xa1, 0xca, 0xb4, 0x8f, 0x7c, 0x89, 0x3f, 0xaf, 0xa9, 0x88, 0x0a, 0x28, 0xc3, 0xb4, 0x99, 0x9d, 0x28, 0xd6, 0x32, 0x95, 0x62, 0xd2, 0x7a, 0x4e, 0xa4, 0xe2, 0x2e, 0x9f, 0xf1, 0xbd, 0xd6, 0x5a]) bobIdentityPublic = bytearray([0x05, 0xf1, 0xf4, 0x38, 0x74, 0xf6, 0x96, 0x69, 0x56, 0xc2, 0xdd, 0x47, 0x3f, 0x8f, 0xa1, 0x5a, 0xde, 0xb7, 0x1d, 0x1c, 0xb9, 0x91, 0xb2, 0x34, 0x16, 0x92, 0x32, 0x4c, 0xef, 0xb1, 0xc5, 0xe6, 0x26]) bobIdentityPrivate = bytearray([0x48, 0x75, 0xcc, 0x69, 0xdd, 0xf8, 0xea, 0x07, 0x19, 0xec, 0x94, 0x7d, 0x61, 0x08, 0x11, 0x35, 0x86, 0x8d, 0x5f, 0xd8, 0x01, 0xf0, 0x2c, 0x02, 0x25, 0xe5, 0x16, 0xdf, 0x21, 0x56, 0x60, 0x5e]) aliceBasePublic = bytearray([0x05, 0x47, 0x2d, 0x1f, 0xb1, 0xa9, 0x86, 0x2c, 0x3a, 0xf6, 0xbe, 0xac, 0xa8, 0x92, 0x02, 0x77, 0xe2, 0xb2, 0x6f, 0x4a, 0x79, 0x21, 0x3e, 0xc7, 0xc9, 0x06, 0xae, 0xb3, 0x5e, 0x03, 0xcf, 0x89, 0x50]) aliceEphemeralPublic = bytearray([0x05, 0x6c, 0x3e, 0x0d, 0x1f, 0x52, 0x02, 0x83, 0xef, 0xcc, 0x55, 0xfc, 0xa5, 0xe6, 0x70, 0x75, 0xb9, 0x04, 0x00, 0x7f, 0x18, 0x81, 0xd1, 0x51, 0xaf, 0x76, 0xdf, 0x18, 0xc5, 0x1d, 0x29, 0xd3, 0x4b]) aliceIdentityPublic = bytearray([0x05, 0xb4, 0xa8, 0x45, 0x56, 0x60, 0xad, 0xa6, 0x5b, 0x40, 0x10, 0x07, 0xf6, 0x15, 0xe6, 0x54, 0x04, 0x17, 0x46, 0x43, 0x2e, 0x33, 0x39, 0xc6, 0x87, 0x51, 0x49, 0xbc, 0xee, 0xfc, 0xb4, 0x2b, 0x4a]) senderChain = bytearray([0xd2, 0x2f, 0xd5, 0x6d, 0x3f, 0xec, 0x81, 0x9c, 0xf4, 0xc3, 0xd5, 0x0c, 0x56, 0xed, 0xfb, 0x1c, 0x28, 0x0a, 0x1b, 0x31, 0x96, 0x45, 0x37, 0xf1, 0xd1, 0x61, 0xe1, 0xc9, 0x31, 0x48, 0xe3, 0x6b]) bobIdentityKeyPublic = IdentityKey(bobIdentityPublic, 0) bobIdentityKeyPrivate = Curve.decodePrivatePoint(bobIdentityPrivate) bobIdentityKey = IdentityKeyPair(bobIdentityKeyPublic, bobIdentityKeyPrivate) bobEphemeralPublicKey = Curve.decodePoint(bobPublic, 0) bobEphemeralPrivateKey = Curve.decodePrivatePoint(bobPrivate) bobEphemeralKey = ECKeyPair(bobEphemeralPublicKey, bobEphemeralPrivateKey) bobBaseKey = bobEphemeralKey aliceBasePublicKey = Curve.decodePoint(aliceBasePublic, 0) aliceEphemeralPublicKey = Curve.decodePoint(aliceEphemeralPublic, 0) aliceIdentityPublicKey = IdentityKey(aliceIdentityPublic, 0) parameters = BobAxolotlParameters.newBuilder()\ .setOurIdentityKey(bobIdentityKey)\ .setOurSignedPreKey(bobBaseKey)\ .setOurRatchetKey(bobEphemeralKey)\ .setOurOneTimePreKey(None)\ .setTheirIdentityKey(aliceIdentityPublicKey)\ .setTheirBaseKey(aliceBasePublicKey)\ .create() session = SessionState() RatchetingSession.initializeSessionAsBob(session, 2, parameters) self.assertEqual(session.getLocalIdentityKey(), bobIdentityKey.getPublicKey()) self.assertEqual(session.getRemoteIdentityKey(), aliceIdentityPublicKey) self.assertEqual(session.getSenderChainKey().getKey(), senderChain)
class WARequest(object): OK = 200 ENC_PUBKEY = Curve.decodePoint( bytearray([ 5, 142, 140, 15, 116, 195, 235, 197, 215, 166, 134, 92, 108, 60, 132, 56, 86, 176, 97, 33, 204, 232, 234, 119, 77, 34, 251, 111, 18, 37, 18, 48, 45 ])) def __init__(self, config): """ :type method: str :param config: :type config: yowsup.config.v1.config.Config """ self.pvars = [] self.port = 443 self.type = "GET" self.parser = None self.params = [] self.headers = {} self.sent = False self.response = None self._config = config self._p_in = str(config.phone)[len(str(config.cc)):] self._axolotlmanager = AxolotlManagerFactory() \ .get_manager(self._config.phone) # type: yowsup.axolotl.manager.Axolotlmanager if config.expid is None: config.expid = WATools.generateDeviceId() if config.fdid is None: config.fdid = WATools.generatePhoneId() if config.client_static_keypair is None: config.client_static_keypair = WATools.generateKeyPair() self.addParam("cc", config.cc) self.addParam("in", self._p_in) self.addParam("lg", "en") self.addParam("lc", "GB") self.addParam("mistyped", "6") self.addParam("authkey", self.b64encode(config.client_static_keypair.public.data)) self.addParam( "e_regid", self.b64encode( struct.pack('>I', self._axolotlmanager.registration_id))) self.addParam("e_keytype", self.b64encode(b"\x05")) self.addParam( "e_ident", self.b64encode( self._axolotlmanager.identity.publicKey.serialize()[1:])) signedprekey = self._axolotlmanager.load_latest_signed_prekey( generate=True) self.addParam( "e_skey_id", self.b64encode(struct.pack('>I', signedprekey.getId())[1:])) self.addParam( "e_skey_val", self.b64encode( signedprekey.getKeyPair().publicKey.serialize()[1:])) self.addParam("e_skey_sig", self.b64encode(signedprekey.getSignature())) self.addParam("fdid", config.fdid) self.addParam("expid", self.b64encode(config.expid)) self.addParam("network_radio_type", "1") self.addParam("simnum", "1") self.addParam("hasinrc", "1") self.addParam("pid", int(random.uniform(100, 9999))) self.addParam("rc", 0) if self._config.id: self.addParam("id", self._config.id) def setParsableVariables(self, pvars): self.pvars = pvars def onResponse(self, name, value): if name == "status": self.status = value elif name == "result": self.result = value def addParam(self, name, value): self.params.append((name, value)) def removeParam(self, name): for i in range(0, len(self.params)): if self.params[i][0] == name: del self.params[i] def addHeaderField(self, name, value): self.headers[name] = value def clearParams(self): self.params = [] def getUserAgent(self): return YowsupEnv.getCurrent().getUserAgent() def send(self, parser=None, encrypt=True, preview=False): logger.debug( "send(parser=%s, encrypt=%s, preview=%s)" % (None if parser is None else "[omitted]", encrypt, preview)) if self.type == "POST": return self.sendPostRequest(parser) return self.sendGetRequest(parser, encrypt, preview=preview) def setParser(self, parser): if isinstance(parser, ResponseParser): self.parser = parser else: logger.error("Invalid parser") def getConnectionParameters(self): if not self.url: return "", "", self.port try: url = self.url.split("://", 1) url = url[0] if len(url) == 1 else url[1] host, path = url.split('/', 1) except ValueError: host = url path = "" path = "/" + path return host, self.port, path def encryptParams(self, params, key): """ :param params: :type params: list :param key: :type key: ECPublicKey :return: :rtype: list """ keypair = Curve.generateKeyPair() encodedparams = self.urlencodeParams(params) cipher = AESGCM(Curve.calculateAgreement(key, keypair.privateKey)) ciphertext = cipher.encrypt(b'\x00\x00\x00\x00' + struct.pack('>Q', 0), encodedparams.encode(), b'') payload = base64.b64encode(keypair.publicKey.serialize()[1:] + ciphertext) return [('ENC', payload)] def sendGetRequest(self, parser=None, encrypt_params=True, preview=False): logger.debug( "sendGetRequest(parser=%s, encrypt_params=%s, preview=%s)" % (None if parser is None else "[omitted]", encrypt_params, preview)) self.response = None if encrypt_params: logger.debug("Encrypting parameters") if logger.level <= logging.DEBUG: logger.debug("pre-encrypt (encoded) parameters = \n%s", (self.urlencodeParams(self.params))) params = self.encryptParams(self.params, self.ENC_PUBKEY) else: ## params will be logged right before sending params = self.params parser = parser or self.parser or ResponseParser() headers = dict( list({ "User-Agent": self.getUserAgent(), "Accept": parser.getMeta() }.items()) + list(self.headers.items())) host, port, path = self.getConnectionParameters() self.response = WARequest.sendRequest(host, port, path, headers, params, "GET", preview=preview) if preview: logger.info( "Preview request, skip response handling and return None") return None if not self.response.status == WARequest.OK: logger.error("Request not success, status was %s" % self.response.status) return {} data = self.response.read() logger.info(data) self.sent = True return parser.parse(data.decode(), self.pvars) def sendPostRequest(self, parser=None): self.response = None params = self.params # [param.items()[0] for param in self.params]; parser = parser or self.parser or ResponseParser() headers = dict( list({ "User-Agent": self.getUserAgent(), "Accept": parser.getMeta(), "Content-Type": "application/x-www-form-urlencoded" }.items()) + list(self.headers.items())) host, port, path = self.getConnectionParameters() self.response = WARequest.sendRequest(host, port, path, headers, params, "POST") if not self.response.status == WARequest.OK: logger.error("Request not success, status was %s" % self.response.status) return {} data = self.response.read() logger.info(data) self.sent = True return parser.parse(data.decode(), self.pvars) def b64encode(self, value): return base64.urlsafe_b64encode(value).replace(b'=', b'') @classmethod def urlencode(cls, value): if type(value) not in (str, bytes): value = str(value) out = "" for char in value: if type(char) is int: char = bytearray([char]) quoted = urllib_quote(char, safe='') out += quoted if quoted[0] != '%' else quoted.lower() return out \ .replace('-', '%2d') \ .replace('_', '%5f') \ .replace('~', '%7e') @classmethod def urlencodeParams(cls, params): merged = [] for k, v in params: merged.append("%s=%s" % (k, cls.urlencode(v))) return "&".join(merged) @classmethod def sendRequest(cls, host, port, path, headers, params, reqType="GET", preview=False): logger.debug( "sendRequest(host=%s, port=%s, path=%s, headers=%s, params=%s, reqType=%s, preview=%s)" % (host, port, path, headers, params, reqType, preview)) params = cls.urlencodeParams(params) path = path + "?" + params if reqType == "GET" and params else path if not preview: logger.debug("Opening connection to %s" % host) conn = httplib.HTTPSConnection( host, port) if port == 443 else httplib.HTTPConnection( host, port) else: logger.debug( "Should open connection to %s, but this is a preview" % host) conn = None if not preview: logger.debug("Sending %s request to %s" % (reqType, path)) conn.request(reqType, path, params, headers) else: logger.debug( "Should send %s request to %s, but this is a preview" % (reqType, path)) return None response = conn.getresponse() return response
def getSigningKeyPrivate(self): return Curve.decodePrivatePoint(self.senderKeyStateStructure.senderSigningKey.private)