├── signal-protocol-pcl ├── ecc │ ├── Curve25519KeyPair.cs │ ├── ECPrivateKey.cs │ ├── ECPublicKey.cs │ ├── impl │ │ ├── ICurve25519Provider.cs │ │ ├── Curve25519NativeProvider.cs │ │ └── Curve25519ManagedProvider.cs │ ├── ECKeyPair.cs │ ├── DjbECPrivateKey.cs │ ├── DjbECPublicKey.cs │ ├── Curve.cs │ └── Curve25519.cs ├── Protobuf │ ├── FingerprintProtocol.proto │ ├── Makefile.bat │ ├── WhisperTextProtocol.proto │ └── LocalStorageProtocol.proto ├── signal-protocol-pcl.nuspec ├── util │ ├── Medium.cs │ ├── Pair.cs │ └── HMAC.cs ├── StaleKeyExchangeException.cs ├── packages.config ├── DecryptionCallback.cs ├── state │ ├── SignalProtocolStore.cs │ ├── impl │ │ ├── InMemoryPreKeyStore.cs │ │ ├── InMemoryIdentityKeyStore.cs │ │ ├── InMemorySignedPreKeyStore.cs │ │ ├── InMemorySessionStore.cs │ │ └── InMemorySignalProtocolStore.cs │ ├── PreKeyStore.cs │ ├── SignedPreKeyStore.cs │ ├── PreKeyRecord.cs │ ├── IdentityKeyStore.cs │ ├── SignedPreKeyRecord.cs │ ├── SessionStore.cs │ ├── PreKeyBundle.cs │ └── SessionRecord.cs ├── kdf │ ├── HKDFv3.cs │ ├── HKDFv2.cs │ ├── DerivedRootSecrets.cs │ ├── DerivedMessageSecrets.cs │ └── HKDF.cs ├── DuplicateMessageException.cs ├── fingerprint │ ├── FingerprintParsingException.cs │ ├── FingerprintGenerator.cs │ ├── FingerprintVersionMismatchException.cs │ ├── DisplayableFingerprint.cs │ ├── Fingerprint.cs │ ├── FingerprintIdentifierMismatchException.cs │ ├── NumericFingerprintGenerator.cs │ └── ScannableFingerprint.cs ├── LegacyMessageException.cs ├── InvalidVersionException.cs ├── InvalidKeyIdException.cs ├── InvalidMacException.cs ├── Properties │ └── AssemblyInfo.cs ├── NoSessionException.cs ├── UntrustedIdentityException.cs ├── InvalidKeyException.cs ├── protocol │ ├── CiphertextMessage.cs │ ├── SenderKeyDistributionMessage.cs │ └── SenderKeyMessage.cs ├── ratchet │ ├── MessageKeys.cs │ ├── RootKey.cs │ ├── ChainKey.cs │ ├── SymmetricSignalProtocolParameters.cs │ ├── BobSignalProtocolParameters.cs │ └── AliceSignalProtocolParameters.cs ├── InvalidMessageException.cs ├── SignalProtocolAddress.cs ├── IdentityKey.cs ├── groups │ ├── ratchet │ │ ├── SenderMessageKey.cs │ │ └── SenderChainKey.cs │ ├── SenderKeyName.cs │ ├── state │ │ ├── SenderKeyStore.cs │ │ └── SenderKeyRecord.cs │ └── GroupSessionBuilder.cs └── IdentityKeyPair.cs ├── signal-protocol-tests ├── packages.config ├── DateUtil.cs ├── Properties │ └── AssemblyInfo.cs ├── TestInMemoryIdentityKeyStore.cs ├── TestInMemorySignalProtocolStore.cs ├── groups │ └── InMemorySenderKeyStore.cs ├── ratchet │ ├── RootKeyTest.cs │ └── ChainKeyTest.cs └── fingerprint │ └── NumericFingerprintGeneratorTest.cs ├── signal-protocol-pcl.sln ├── .gitattributes └── .gitignore /signal-protocol-pcl/ecc/Curve25519KeyPair.cs: -------------------------------------------------------------------------------- 1 | namespace libaxolotl_csharp.ecc 2 | { 3 | public class Curve25519KeyPair 4 | { 5 | public byte[] PublicKey; 6 | public byte[] PrivateKey; 7 | } 8 | } -------------------------------------------------------------------------------- /signal-protocol-pcl/Protobuf/FingerprintProtocol.proto: -------------------------------------------------------------------------------- 1 | message FingerprintData { 2 | optional bytes publicKey = 1; 3 | optional bytes identifier = 2; 4 | } 5 | 6 | message CombinedFingerprint { 7 | optional uint32 version = 1; 8 | optional FingerprintData localFingerprint = 2; 9 | optional FingerprintData remoteFingerprint = 3; 10 | } -------------------------------------------------------------------------------- /signal-protocol-pcl/Protobuf/Makefile.bat: -------------------------------------------------------------------------------- 1 | setlocal 2 | SET PATH=%PATH%;%USERPROFILE%\.nuget\packages\Google.ProtocolBuffers\2.4.1.555\tools 3 | ProtoGen -namespace="libsignal.state" -umbrella_classname="StorageProtos" -nest_classes=true -output_directory="../state/" LocalStorageProtocol.proto 4 | ProtoGen -namespace="libsignal.protocol" -umbrella_classname="SignalProtos" -nest_classes=true -output_directory="../protocol/" WhisperTextProtocol.proto 5 | ProtoGen -namespace="libsignal.fingerprint" -umbrella_classname="FingerprintProtos" -nest_classes=true -output_directory="../fingerprint/" FingerprintProtocol.proto 6 | -------------------------------------------------------------------------------- /signal-protocol-tests/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /signal-protocol-pcl/signal-protocol-pcl.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $id$ 5 | $version$ 6 | $title$ 7 | langboost 8 | langboost 9 | https://github.com/langboost/libsignal-protocol-pcl/blob/master/LICENSE 10 | https://github.com/langboost/libsignal-protocol-pcl 11 | https://raw.githubusercontent.com/langboost/libaxolotl-uwp/master/NuGetIcon.png 12 | false 13 | Portable implementation of the Signal protocol. 14 | Portable implementation of the Signal protocol. 15 | Copyright 2018 16 | signal pcl 17 | 18 | -------------------------------------------------------------------------------- /signal-protocol-pcl/util/Medium.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | namespace libsignal.util 19 | { 20 | public class Medium 21 | { 22 | public static uint MAX_VALUE = 0xFFFFFF; 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /signal-protocol-pcl/StaleKeyExchangeException.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace libsignal 21 | { 22 | public class StaleKeyExchangeException : Exception 23 | { 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /signal-protocol-pcl/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /signal-protocol-pcl/DecryptionCallback.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | namespace libsignal 19 | { 20 | public interface DecryptionCallback 21 | { 22 | void handlePlaintext(byte[] plaintext); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /signal-protocol-pcl/ecc/ECPrivateKey.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | namespace libsignal.ecc 19 | { 20 | public interface ECPrivateKey 21 | { 22 | byte[] serialize(); 23 | int getType(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /signal-protocol-pcl/state/SignalProtocolStore.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | namespace libsignal.state 19 | { 20 | public interface SignalProtocolStore : IdentityKeyStore, PreKeyStore, SessionStore, SignedPreKeyStore 21 | { 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /signal-protocol-pcl/kdf/HKDFv3.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | namespace libsignal.kdf 19 | { 20 | public class HKDFv3 : HKDF 21 | { 22 | protected override int getIterationStartOffset() 23 | { 24 | return 1; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /signal-protocol-pcl/ecc/ECPublicKey.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace libsignal.ecc 21 | { 22 | public interface ECPublicKey : IComparable 23 | { 24 | 25 | //int KEY_SIZE = 33; 26 | 27 | byte[] serialize(); 28 | 29 | int getType(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /signal-protocol-pcl/DuplicateMessageException.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace libsignal 21 | { 22 | public class DuplicateMessageException : Exception 23 | { 24 | public DuplicateMessageException(String s) 25 | : base(s) 26 | { 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /signal-protocol-pcl/fingerprint/FingerprintParsingException.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace org.whispersystems.libsignal.fingerprint 21 | { 22 | public class FingerprintParsingException : Exception 23 | { 24 | public FingerprintParsingException(Exception nested) : base("Fingerprint", nested) 25 | { 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /signal-protocol-pcl/LegacyMessageException.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace libsignal 21 | { 22 | public class LegacyMessageException : Exception 23 | { 24 | public LegacyMessageException() 25 | { 26 | } 27 | 28 | public LegacyMessageException(String s) 29 | : base(s) 30 | { 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /signal-protocol-pcl/kdf/HKDFv2.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace libsignal.kdf 21 | { 22 | [Obsolete("Use HKDFv3 over v2 for new work.")] 23 | public class HKDFv2 : HKDF 24 | { 25 | [Obsolete("HKDFv2 should be upgraded to v3.")] 26 | protected override int getIterationStartOffset() 27 | { 28 | return 0; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /signal-protocol-pcl/InvalidVersionException.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace libsignal 21 | { 22 | public class InvalidVersionException : Exception 23 | { 24 | public InvalidVersionException() 25 | { 26 | } 27 | 28 | public InvalidVersionException(String detailMessage) 29 | : base (detailMessage) 30 | { 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /signal-protocol-pcl/fingerprint/FingerprintGenerator.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal; 19 | 20 | namespace org.whispersystems.libsignal.fingerprint 21 | { 22 | public interface FingerprintGenerator { 23 | Fingerprint createFor(string localStableIdentifier, IdentityKey localIdentityKey, 24 | string remoteStableIdentifier, IdentityKey remoteIdentityKey); 25 | } 26 | } -------------------------------------------------------------------------------- /signal-protocol-tests/DateUtil.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace libsignal_test 21 | { 22 | class DateUtil 23 | { 24 | private static readonly DateTime Jan1st1970 = new DateTime 25 | (1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 26 | 27 | public static ulong currentTimeMillis() 28 | { 29 | return (ulong)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /signal-protocol-pcl/Protobuf/WhisperTextProtocol.proto: -------------------------------------------------------------------------------- 1 | message SignalMessage { 2 | optional bytes ratchetKey = 1; 3 | optional uint32 counter = 2; 4 | optional uint32 previousCounter = 3; 5 | optional bytes ciphertext = 4; 6 | } 7 | 8 | message PreKeySignalMessage { 9 | optional uint32 registrationId = 5; 10 | optional uint32 preKeyId = 1; 11 | optional uint32 signedPreKeyId = 6; 12 | optional bytes baseKey = 2; 13 | optional bytes identityKey = 3; 14 | optional bytes message = 4; // SignalMessage 15 | } 16 | 17 | message KeyExchangeMessage { 18 | optional uint32 id = 1; 19 | optional bytes baseKey = 2; 20 | optional bytes ratchetKey = 3; 21 | optional bytes identityKey = 4; 22 | optional bytes baseKeySignature = 5; 23 | } 24 | 25 | message SenderKeyMessage { 26 | optional uint32 id = 1; 27 | optional uint32 iteration = 2; 28 | optional bytes ciphertext = 3; 29 | } 30 | 31 | message SenderKeyDistributionMessage { 32 | optional uint32 id = 1; 33 | optional uint32 iteration = 2; 34 | optional bytes chainKey = 3; 35 | optional bytes signingKey = 4; 36 | } -------------------------------------------------------------------------------- /signal-protocol-pcl/InvalidKeyIdException.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace libsignal 21 | { 22 | public class InvalidKeyIdException : Exception 23 | { 24 | public InvalidKeyIdException(String detailMessage) 25 | :base(detailMessage) 26 | { 27 | } 28 | 29 | public InvalidKeyIdException(Exception exception) 30 | :base(exception.Message) 31 | { 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /signal-protocol-pcl/InvalidMacException.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace TextSecure.libsignal 21 | { 22 | class InvalidMacException : Exception 23 | { 24 | 25 | public InvalidMacException(String detailMessage) 26 | :base(detailMessage) 27 | { 28 | } 29 | 30 | public InvalidMacException(Exception exception) 31 | :base(exception.Message) 32 | { 33 | 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /signal-protocol-pcl/fingerprint/FingerprintVersionMismatchException.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace org.whispersystems.libsignal.fingerprint 21 | { 22 | public class FingerprintVersionMismatchException : Exception 23 | { 24 | public FingerprintVersionMismatchException() : base() 25 | { 26 | } 27 | 28 | public FingerprintVersionMismatchException(Exception e) : base("Fingerprint", e) 29 | { 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /signal-protocol-pcl/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Resources; 2 | using System.Reflection; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("signal-protocol-pcl")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("signal-protocol-pcl")] 14 | [assembly: AssemblyCopyright("Copyright 2016")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | [assembly: NeutralResourcesLanguage("en")] 18 | 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Build and Revision Numbers 27 | // by using the '*' as shown below: 28 | // [assembly: AssemblyVersion("1.0.*")] 29 | [assembly: AssemblyVersion("2.2.0.0")] 30 | [assembly: AssemblyFileVersion("2.2.0.0")] 31 | -------------------------------------------------------------------------------- /signal-protocol-pcl/NoSessionException.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace libsignal 21 | { 22 | public class NoSessionException : Exception 23 | { 24 | public NoSessionException() 25 | { 26 | } 27 | 28 | public NoSessionException(String s) 29 | : base(s) 30 | { 31 | } 32 | 33 | public NoSessionException(Exception exception) 34 | : base(exception.Message) 35 | { 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /signal-protocol-pcl/ecc/impl/ICurve25519Provider.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2015 langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | namespace libsignal.ecc.impl 19 | { 20 | /// 21 | /// If you want to expose an implementation of Curve25519 to this class library, 22 | /// implement this interface. 23 | /// 24 | public interface ICurve25519Provider 25 | { 26 | byte[] calculateAgreement(byte[] ourPrivate, byte[] theirPublic); 27 | byte[] calculateSignature(byte[] random, byte[] privateKey, byte[] message); 28 | byte[] generatePrivateKey(byte[] random); 29 | byte[] generatePublicKey(byte[] privateKey); 30 | bool isNative(); 31 | bool verifySignature(byte[] publicKey, byte[] message, byte[] signature); 32 | } 33 | } -------------------------------------------------------------------------------- /signal-protocol-pcl/UntrustedIdentityException.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace libsignal.exceptions 21 | { 22 | public class UntrustedIdentityException : Exception 23 | { 24 | private readonly String name; 25 | private readonly IdentityKey key; 26 | 27 | public UntrustedIdentityException(String name, IdentityKey key) 28 | { 29 | this.name = name; 30 | this.key = key; 31 | } 32 | 33 | public IdentityKey getUntrustedIdentity() 34 | { 35 | return key; 36 | } 37 | 38 | public String getName() 39 | { 40 | return name; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /signal-protocol-pcl/ecc/ECKeyPair.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | namespace libsignal.ecc 19 | { 20 | public class ECKeyPair 21 | { 22 | 23 | private readonly ECPublicKey publicKey; 24 | private readonly ECPrivateKey privateKey; 25 | 26 | public ECKeyPair(ECPublicKey publicKey, ECPrivateKey privateKey) 27 | { 28 | this.publicKey = publicKey; 29 | this.privateKey = privateKey; 30 | } 31 | 32 | public ECPublicKey getPublicKey() 33 | { 34 | return publicKey; 35 | } 36 | 37 | public ECPrivateKey getPrivateKey() 38 | { 39 | return privateKey; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /signal-protocol-pcl/InvalidKeyException.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace libsignal 21 | { 22 | public class InvalidKeyException : Exception 23 | { 24 | 25 | public InvalidKeyException() { } 26 | 27 | public InvalidKeyException(String detailMessage) 28 | : base(detailMessage) 29 | { 30 | 31 | } 32 | 33 | public InvalidKeyException(Exception exception) 34 | : base(exception.Message) 35 | { 36 | 37 | } 38 | 39 | public InvalidKeyException(String detailMessage, Exception exception) 40 | : base(detailMessage, exception) 41 | { 42 | 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /signal-protocol-pcl/ecc/DjbECPrivateKey.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | namespace libsignal.ecc 19 | { 20 | public class DjbECPrivateKey : ECPrivateKey 21 | { 22 | 23 | private readonly byte[] privateKey; 24 | 25 | public DjbECPrivateKey(byte[] privateKey) 26 | { 27 | this.privateKey = privateKey; 28 | } 29 | 30 | 31 | public byte[] serialize() 32 | { 33 | return privateKey; 34 | } 35 | 36 | 37 | public int getType() 38 | { 39 | return Curve.DJB_TYPE; 40 | } 41 | 42 | public byte[] getPrivateKey() 43 | { 44 | return privateKey; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /signal-protocol-pcl/kdf/DerivedRootSecrets.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal.util; 19 | 20 | namespace libsignal.kdf 21 | { 22 | public class DerivedRootSecrets 23 | { 24 | public static readonly int SIZE = 64; 25 | 26 | private readonly byte[] rootKey; 27 | private readonly byte[] chainKey; 28 | 29 | public DerivedRootSecrets(byte[] okm) 30 | { 31 | byte[][] keys = ByteUtil.split(okm, 32, 32); 32 | this.rootKey = keys[0]; 33 | this.chainKey = keys[1]; 34 | } 35 | 36 | public byte[] getRootKey() 37 | { 38 | return rootKey; 39 | } 40 | 41 | public byte[] getChainKey() 42 | { 43 | return chainKey; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /signal-protocol-pcl/protocol/CiphertextMessage.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | namespace libsignal.protocol 19 | { 20 | public abstract class CiphertextMessage 21 | { 22 | 23 | public const uint UNSUPPORTED_VERSION = 1; 24 | public const uint CURRENT_VERSION = 3; 25 | 26 | public const uint WHISPER_TYPE = 2; 27 | public const uint PREKEY_TYPE = 3; 28 | public const uint SENDERKEY_TYPE = 4; 29 | public const uint SENDERKEY_DISTRIBUTION_TYPE = 5; 30 | 31 | /// 32 | /// This should be the worst case (worse than V2). So not always accurate, but good enough for padding. 33 | /// 34 | public const uint ENCRYPTED_MESSAGE_OVERHEAD = 53; 35 | 36 | public abstract byte[] serialize(); 37 | public abstract uint getType(); 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /signal-protocol-tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("signal-protocol-tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("signal-protocol-tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("3b01684c-a5c1-4165-a384-fb9d89d10f16")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /signal-protocol-pcl.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25123.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "signal-protocol-pcl", "signal-protocol-pcl\signal-protocol-pcl.csproj", "{28969CF5-0CEC-4B94-B5CC-BDF648A66E70}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "signal-protocol-tests", "signal-protocol-tests\signal-protocol-tests.csproj", "{3B01684C-A5C1-4165-A384-FB9D89D10F16}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {28969CF5-0CEC-4B94-B5CC-BDF648A66E70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {28969CF5-0CEC-4B94-B5CC-BDF648A66E70}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {28969CF5-0CEC-4B94-B5CC-BDF648A66E70}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {28969CF5-0CEC-4B94-B5CC-BDF648A66E70}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {3B01684C-A5C1-4165-A384-FB9D89D10F16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {3B01684C-A5C1-4165-A384-FB9D89D10F16}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {3B01684C-A5C1-4165-A384-FB9D89D10F16}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {3B01684C-A5C1-4165-A384-FB9D89D10F16}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /signal-protocol-pcl/fingerprint/DisplayableFingerprint.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | namespace org.whispersystems.libsignal.fingerprint 19 | { 20 | public class DisplayableFingerprint 21 | { 22 | 23 | private readonly string localFingerprint; 24 | private readonly string remoteFingerprint; 25 | 26 | public DisplayableFingerprint(string localFingerprint, string remoteFingerprint) 27 | { 28 | this.localFingerprint = localFingerprint; 29 | this.remoteFingerprint = remoteFingerprint; 30 | } 31 | 32 | public string getDisplayText() 33 | { 34 | if (localFingerprint.CompareTo(remoteFingerprint) <= 0) 35 | { 36 | return localFingerprint + remoteFingerprint; 37 | } 38 | else 39 | { 40 | return remoteFingerprint + localFingerprint; 41 | } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /signal-protocol-tests/TestInMemoryIdentityKeyStore.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal; 19 | using libsignal.ecc; 20 | using libsignal.state.impl; 21 | using libsignal.util; 22 | 23 | namespace libsignal_test 24 | { 25 | class TestInMemoryIdentityKeyStore : InMemoryIdentityKeyStore 26 | { 27 | public TestInMemoryIdentityKeyStore() 28 | : base(generateIdentityKeyPair(), generateRegistrationId()) 29 | { } 30 | 31 | private static IdentityKeyPair generateIdentityKeyPair() 32 | { 33 | ECKeyPair identityKeyPairKeys = Curve.generateKeyPair(); 34 | 35 | return new IdentityKeyPair(new IdentityKey(identityKeyPairKeys.getPublicKey()), 36 | identityKeyPairKeys.getPrivateKey()); 37 | } 38 | 39 | private static uint generateRegistrationId() 40 | { 41 | return KeyHelper.generateRegistrationId(false); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /signal-protocol-tests/TestInMemorySignalProtocolStore.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal; 19 | using libsignal.ecc; 20 | using libsignal.state.impl; 21 | using libsignal.util; 22 | 23 | namespace libsignal_test 24 | { 25 | class TestInMemorySignalProtocolStore : InMemorySignalProtocolStore 26 | { 27 | public TestInMemorySignalProtocolStore() 28 | : base(generateIdentityKeyPair(), generateRegistrationId()) 29 | { } 30 | 31 | private static IdentityKeyPair generateIdentityKeyPair() 32 | { 33 | ECKeyPair identityKeyPairKeys = Curve.generateKeyPair(); 34 | 35 | return new IdentityKeyPair(new IdentityKey(identityKeyPairKeys.getPublicKey()), 36 | identityKeyPairKeys.getPrivateKey()); 37 | } 38 | 39 | private static uint generateRegistrationId() 40 | { 41 | return KeyHelper.generateRegistrationId(false); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /signal-protocol-pcl/ratchet/MessageKeys.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | namespace libsignal.ratchet 19 | { 20 | public class MessageKeys 21 | { 22 | 23 | private readonly byte[] cipherKey; 24 | private readonly byte[] macKey; 25 | private readonly byte[] iv; 26 | private readonly uint counter; 27 | 28 | public MessageKeys(byte[] cipherKey, byte[] macKey, byte[] iv, uint counter) 29 | { 30 | this.cipherKey = cipherKey; 31 | this.macKey = macKey; 32 | this.iv = iv; 33 | this.counter = counter; 34 | } 35 | 36 | public byte[] getCipherKey() 37 | { 38 | return cipherKey; 39 | } 40 | 41 | public byte[] getMacKey() 42 | { 43 | return macKey; 44 | } 45 | 46 | public byte[] getIv() 47 | { 48 | return iv; 49 | } 50 | 51 | public uint getCounter() 52 | { 53 | return counter; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /signal-protocol-pcl/state/impl/InMemoryPreKeyStore.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | 21 | namespace libsignal.state.impl 22 | { 23 | public class InMemoryPreKeyStore : PreKeyStore 24 | { 25 | 26 | private readonly IDictionary store = new Dictionary(); 27 | 28 | 29 | public PreKeyRecord LoadPreKey(uint preKeyId) 30 | { 31 | try 32 | { 33 | if (!store.ContainsKey(preKeyId)) 34 | { 35 | throw new InvalidKeyIdException("No such prekeyrecord!"); 36 | } 37 | byte[] record; 38 | store.TryGetValue(preKeyId, out record); // get() 39 | 40 | return new PreKeyRecord(record); 41 | } 42 | catch (Exception e) 43 | { 44 | throw new Exception(e.Message); 45 | } 46 | } 47 | 48 | 49 | public void StorePreKey(uint preKeyId, PreKeyRecord record) 50 | { 51 | store[preKeyId] = record.serialize(); 52 | } 53 | 54 | 55 | public bool ContainsPreKey(uint preKeyId) 56 | { 57 | return store.ContainsKey(preKeyId); 58 | } 59 | 60 | 61 | public void RemovePreKey(uint preKeyId) 62 | { 63 | store.Remove(preKeyId); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /signal-protocol-pcl/ecc/impl/Curve25519NativeProvider.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace libsignal.ecc.impl 21 | { 22 | class Curve25519NativeProvider : ICurve25519Provider 23 | { 24 | //private curve25519.Curve25519Native native = new curve25519.Curve25519Native(); 25 | 26 | public byte[] calculateAgreement(byte[] ourPrivate, byte[] theirPublic) 27 | { 28 | throw new NotImplementedException(); 29 | } 30 | 31 | public byte[] calculateSignature(byte[] random, byte[] privateKey, byte[] message) 32 | { 33 | throw new NotImplementedException(); 34 | } 35 | 36 | public byte[] generatePrivateKey(byte[] random) 37 | { 38 | throw new NotImplementedException(); 39 | } 40 | 41 | public byte[] generatePublicKey(byte[] privateKey) 42 | { 43 | throw new NotImplementedException(); 44 | } 45 | 46 | public bool isNative() 47 | { 48 | throw new NotImplementedException(); 49 | } 50 | 51 | public bool verifySignature(byte[] publicKey, byte[] message, byte[] signature) 52 | { 53 | throw new NotImplementedException(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /signal-protocol-pcl/fingerprint/Fingerprint.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | namespace org.whispersystems.libsignal.fingerprint 19 | { 20 | public class Fingerprint 21 | { 22 | 23 | private readonly DisplayableFingerprint displayableFingerprint; 24 | private readonly ScannableFingerprint scannableFingerprint; 25 | 26 | public Fingerprint(DisplayableFingerprint displayableFingerprint, 27 | ScannableFingerprint scannableFingerprint) 28 | { 29 | this.displayableFingerprint = displayableFingerprint; 30 | this.scannableFingerprint = scannableFingerprint; 31 | } 32 | 33 | /** 34 | * @return A text fingerprint that can be displayed and compared remotely. 35 | */ 36 | public DisplayableFingerprint getDisplayableFingerprint() 37 | { 38 | return displayableFingerprint; 39 | } 40 | 41 | /** 42 | * @return A scannable fingerprint that can be scanned anc compared locally. 43 | */ 44 | public ScannableFingerprint getScannableFingerprint() 45 | { 46 | return scannableFingerprint; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /signal-protocol-pcl/util/Pair.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace libsignal.util 21 | { 22 | public class Pair 23 | { 24 | private readonly T1 v1; 25 | private readonly T2 v2; 26 | 27 | public Pair(T1 v1, T2 v2) 28 | { 29 | this.v1 = v1; 30 | this.v2 = v2; 31 | } 32 | 33 | public T1 first() 34 | { 35 | return v1; 36 | } 37 | 38 | public T2 second() 39 | { 40 | return v2; 41 | } 42 | 43 | public bool equals(Object o) 44 | { 45 | return o is Pair && 46 | equal(((Pair)o).first(), first()) && 47 | equal(((Pair)o).second(), second()); 48 | } 49 | 50 | public int hashCode() 51 | { 52 | return first().GetHashCode() ^ second().GetHashCode(); 53 | } 54 | 55 | private bool equal(Object first, Object second) 56 | { 57 | if (first == null && second == null) return true; 58 | if (first == null || second == null) return false; 59 | return first.Equals(second); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /signal-protocol-pcl/InvalidMessageException.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | 22 | namespace libsignal 23 | { 24 | public class InvalidMessageException : Exception 25 | { 26 | 27 | public InvalidMessageException() { } 28 | 29 | public InvalidMessageException(String detailMessage) 30 | : base(detailMessage) 31 | { 32 | 33 | } 34 | 35 | public InvalidMessageException(Exception exception) 36 | : base(exception.Message) 37 | { 38 | 39 | } 40 | 41 | public InvalidMessageException(String detailMessage, Exception exception) 42 | : base(detailMessage, exception) 43 | { 44 | 45 | } 46 | 47 | public InvalidMessageException(String detailMessage, List exceptions) 48 | : base(string.Join(",", exceptions.Select(x => x.Message).ToArray())) 49 | { 50 | 51 | } 52 | public InvalidMessageException(String detailMessage, LinkedList exceptions) 53 | : base(string.Join(",", exceptions.Select(x => x.Message).ToArray())) 54 | { 55 | 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /signal-protocol-pcl/SignalProtocolAddress.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace libsignal 21 | { 22 | public class SignalProtocolAddress 23 | { 24 | 25 | private readonly String name; 26 | private readonly uint deviceId; 27 | 28 | public SignalProtocolAddress(String name, uint deviceId) 29 | { 30 | this.name = name; 31 | this.deviceId = deviceId; 32 | } 33 | 34 | public String getName() 35 | { 36 | return name; 37 | } 38 | 39 | public uint getDeviceId() 40 | { 41 | return deviceId; 42 | } 43 | 44 | public override String ToString() 45 | { 46 | return name + ":" + deviceId; 47 | } 48 | 49 | public override bool Equals(Object other) 50 | { 51 | if (other == null) return false; 52 | if (!(other is SignalProtocolAddress)) return false; 53 | 54 | SignalProtocolAddress that = (SignalProtocolAddress)other; 55 | return this.name.Equals(that.name) && this.deviceId == that.deviceId; 56 | } 57 | 58 | 59 | public override int GetHashCode() 60 | { 61 | return this.name.GetHashCode() ^ (int)this.deviceId; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /signal-protocol-tests/groups/InMemorySenderKeyStore.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal.groups; 19 | using libsignal.groups.state; 20 | using System; 21 | using System.Collections.Generic; 22 | using System.IO; 23 | 24 | namespace libsignal_test.groups 25 | { 26 | class InMemorySenderKeyStore : SenderKeyStore 27 | { 28 | private readonly Dictionary store = new Dictionary(); 29 | 30 | public void storeSenderKey(SenderKeyName senderKeyName, SenderKeyRecord record) 31 | { 32 | store[senderKeyName] = record; 33 | } 34 | 35 | public SenderKeyRecord loadSenderKey(SenderKeyName senderKeyName) 36 | { 37 | try 38 | { 39 | SenderKeyRecord record; 40 | store.TryGetValue(senderKeyName, out record); 41 | 42 | if (record == null) 43 | { 44 | return new SenderKeyRecord(); 45 | } 46 | else 47 | { 48 | return new SenderKeyRecord(record.serialize()); 49 | } 50 | } 51 | catch (IOException e) 52 | { 53 | throw new Exception(e.Message); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /signal-protocol-pcl/ratchet/RootKey.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal.ecc; 19 | using libsignal.kdf; 20 | using libsignal.util; 21 | using System.Text; 22 | 23 | namespace libsignal.ratchet 24 | { 25 | public class RootKey 26 | { 27 | 28 | private readonly HKDF kdf; 29 | private readonly byte[] key; 30 | 31 | public RootKey(HKDF kdf, byte[] key) 32 | { 33 | this.kdf = kdf; 34 | this.key = key; 35 | } 36 | 37 | public byte[] getKeyBytes() 38 | { 39 | return key; 40 | } 41 | 42 | public Pair createChain(ECPublicKey theirRatchetKey, ECKeyPair ourRatchetKey) 43 | { 44 | byte[] sharedSecret = Curve.calculateAgreement(theirRatchetKey, ourRatchetKey.getPrivateKey()); 45 | byte[] derivedSecretBytes = kdf.deriveSecrets(sharedSecret, key, Encoding.UTF8.GetBytes("WhisperRatchet"), DerivedRootSecrets.SIZE); 46 | DerivedRootSecrets derivedSecrets = new DerivedRootSecrets(derivedSecretBytes); 47 | 48 | RootKey newRootKey = new RootKey(kdf, derivedSecrets.getRootKey()); 49 | ChainKey newChainKey = new ChainKey(kdf, derivedSecrets.getChainKey(), 0); 50 | 51 | return new Pair(newRootKey, newChainKey); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /signal-protocol-pcl/state/PreKeyStore.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | namespace libsignal.state 19 | { 20 | /** 21 | * An interface describing the local storage of {@link PreKeyRecord}s. 22 | * 23 | * @author 24 | */ 25 | public interface PreKeyStore 26 | { 27 | 28 | /** 29 | * Load a local PreKeyRecord. 30 | * 31 | * @param preKeyId the ID of the local PreKeyRecord. 32 | * @return the corresponding PreKeyRecord. 33 | * @throws InvalidKeyIdException when there is no corresponding PreKeyRecord. 34 | */ 35 | PreKeyRecord LoadPreKey(uint preKeyId); 36 | 37 | /** 38 | * Store a local PreKeyRecord. 39 | * 40 | * @param preKeyId the ID of the PreKeyRecord to store. 41 | * @param record the PreKeyRecord. 42 | */ 43 | void StorePreKey(uint preKeyId, PreKeyRecord record); 44 | 45 | /** 46 | * @param preKeyId A PreKeyRecord ID. 47 | * @return true if the store has a record for the preKeyId, otherwise false. 48 | */ 49 | bool ContainsPreKey(uint preKeyId); 50 | 51 | /** 52 | * Delete a PreKeyRecord from local storage. 53 | * 54 | * @param preKeyId The ID of the PreKeyRecord to remove. 55 | */ 56 | void RemovePreKey(uint preKeyId); 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /signal-protocol-pcl/kdf/DerivedMessageSecrets.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal.util; 19 | 20 | namespace libsignal.kdf 21 | { 22 | public class DerivedMessageSecrets 23 | { 24 | 25 | public static readonly int SIZE = 80; 26 | private static readonly int CIPHER_KEY_LENGTH = 32; 27 | private static readonly int MAC_KEY_LENGTH = 32; 28 | private static readonly int IV_LENGTH = 16; 29 | 30 | private readonly byte[] cipherKey; 31 | private readonly byte[] macKey; 32 | private readonly byte[] iv; 33 | 34 | public DerivedMessageSecrets(byte[] okm) 35 | { 36 | //try 37 | //{ 38 | byte[][] keys = ByteUtil.split(okm, CIPHER_KEY_LENGTH, MAC_KEY_LENGTH, IV_LENGTH); 39 | 40 | this.cipherKey = keys[0]; 41 | this.macKey = keys[1]; 42 | this.iv = keys[2]; 43 | /*} 44 | catch (ParseException e) 45 | { 46 | throw new AssertionError(e); 47 | }*/ 48 | } 49 | 50 | public byte[] getCipherKey() 51 | { 52 | return cipherKey; 53 | } 54 | 55 | public byte[] getMacKey() 56 | { 57 | return macKey; 58 | } 59 | 60 | public byte[] getIv() 61 | { 62 | return iv; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /signal-protocol-pcl/IdentityKey.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal.ecc; 19 | using System; 20 | 21 | namespace libsignal 22 | { 23 | /** 24 | * A class for representing an identity key. 25 | * 26 | * @author Moxie Marlinspike 27 | */ 28 | 29 | public class IdentityKey 30 | { 31 | 32 | private ECPublicKey publicKey; 33 | 34 | public IdentityKey(ECPublicKey publicKey) 35 | { 36 | this.publicKey = publicKey; 37 | } 38 | 39 | public IdentityKey(byte[] bytes, int offset) 40 | { 41 | this.publicKey = Curve.decodePoint(bytes, offset); 42 | } 43 | 44 | public ECPublicKey getPublicKey() 45 | { 46 | return publicKey; 47 | } 48 | 49 | public byte[] serialize() 50 | { 51 | return publicKey.serialize(); 52 | } 53 | 54 | public String getFingerprint() 55 | { 56 | return publicKey.serialize().ToString(); //Hex 57 | } 58 | 59 | public override bool Equals(Object other) 60 | { 61 | if (other == null) return false; 62 | if (!(other is IdentityKey)) return false; 63 | 64 | return publicKey.Equals(((IdentityKey)other).getPublicKey()); 65 | } 66 | 67 | 68 | public override int GetHashCode() 69 | { 70 | return publicKey.GetHashCode(); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /signal-protocol-pcl/groups/ratchet/SenderMessageKey.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal.kdf; 19 | using libsignal.util; 20 | using System.Text; 21 | 22 | namespace libsignal.groups.ratchet 23 | { 24 | /** 25 | * The final symmetric material (IV and Cipher Key) used for encrypting 26 | * individual SenderKey messages. 27 | * 28 | * @author 29 | */ 30 | public class SenderMessageKey 31 | { 32 | 33 | private readonly uint iteration; 34 | private readonly byte[] iv; 35 | private readonly byte[] cipherKey; 36 | private readonly byte[] seed; 37 | 38 | public SenderMessageKey(uint iteration, byte[] seed) 39 | { 40 | byte[] derivative = new HKDFv3().deriveSecrets(seed, Encoding.UTF8.GetBytes("WhisperGroup"), 48); 41 | byte[][] parts = ByteUtil.split(derivative, 16, 32); 42 | 43 | this.iteration = iteration; 44 | this.seed = seed; 45 | this.iv = parts[0]; 46 | this.cipherKey = parts[1]; 47 | } 48 | 49 | public uint getIteration() 50 | { 51 | return iteration; 52 | } 53 | 54 | public byte[] getIv() 55 | { 56 | return iv; 57 | } 58 | 59 | public byte[] getCipherKey() 60 | { 61 | return cipherKey; 62 | } 63 | 64 | public byte[] getSeed() 65 | { 66 | return seed; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /signal-protocol-pcl/state/impl/InMemoryIdentityKeyStore.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | 21 | namespace libsignal.state.impl 22 | { 23 | /// 24 | /// In-memory / testing implementation of IdentityKeyStore 25 | /// 26 | public class InMemoryIdentityKeyStore : IdentityKeyStore 27 | { 28 | 29 | private readonly IDictionary trustedKeys = new Dictionary(); 30 | 31 | private readonly IdentityKeyPair identityKeyPair; 32 | private readonly uint localRegistrationId; 33 | 34 | /// 35 | /// .ctor 36 | /// 37 | public InMemoryIdentityKeyStore(IdentityKeyPair identityKeyPair, uint localRegistrationId) 38 | { 39 | this.identityKeyPair = identityKeyPair; 40 | this.localRegistrationId = localRegistrationId; 41 | } 42 | 43 | public IdentityKeyPair GetIdentityKeyPair() 44 | { 45 | return identityKeyPair; 46 | } 47 | 48 | 49 | public uint GetLocalRegistrationId() 50 | { 51 | return localRegistrationId; 52 | } 53 | 54 | public bool SaveIdentity(String name, IdentityKey identityKey) 55 | { 56 | trustedKeys[name] = identityKey; //put 57 | return true; 58 | } 59 | 60 | public bool IsTrustedIdentity(String name, IdentityKey identityKey) 61 | { 62 | IdentityKey trusted; 63 | trustedKeys.TryGetValue(name, out trusted); // get(name) 64 | return (trusted == null || trusted.Equals(identityKey)); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /signal-protocol-pcl/fingerprint/FingerprintIdentifierMismatchException.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace org.whispersystems.libsignal.fingerprint 21 | { 22 | public class FingerprintIdentifierMismatchException : Exception 23 | { 24 | 25 | private readonly string localIdentifier; 26 | private readonly string remoteIdentifier; 27 | private readonly string scannedLocalIdentifier; 28 | private readonly string scannedRemoteIdentifier; 29 | 30 | public FingerprintIdentifierMismatchException(string localIdentifier, string remoteIdentifier, 31 | string scannedLocalIdentifier, string scannedRemoteIdentifier) 32 | { 33 | this.localIdentifier = localIdentifier; 34 | this.remoteIdentifier = remoteIdentifier; 35 | this.scannedLocalIdentifier = scannedLocalIdentifier; 36 | this.scannedRemoteIdentifier = scannedRemoteIdentifier; 37 | } 38 | 39 | public string getScannedRemoteIdentifier() 40 | { 41 | return scannedRemoteIdentifier; 42 | } 43 | 44 | public string getScannedLocalIdentifier() 45 | { 46 | return scannedLocalIdentifier; 47 | } 48 | 49 | public string getRemoteIdentifier() 50 | { 51 | return remoteIdentifier; 52 | } 53 | 54 | public string getLocalIdentifier() 55 | { 56 | return localIdentifier; 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /signal-protocol-pcl/groups/SenderKeyName.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace libsignal.groups 21 | { 22 | /** 23 | * A representation of a (groupId + senderId + deviceId) tuple. 24 | */ 25 | public class SenderKeyName 26 | { 27 | 28 | private readonly String groupId; 29 | private readonly SignalProtocolAddress sender; 30 | 31 | public SenderKeyName(String groupId, SignalProtocolAddress sender) 32 | { 33 | this.groupId = groupId; 34 | this.sender = sender; 35 | } 36 | 37 | public String getGroupId() 38 | { 39 | return groupId; 40 | } 41 | 42 | public SignalProtocolAddress getSender() 43 | { 44 | return sender; 45 | } 46 | 47 | public String serialize() 48 | { 49 | return groupId + "::" + sender.getName() + "::" + sender.getDeviceId(); 50 | } 51 | 52 | 53 | public override bool Equals(Object other) 54 | { 55 | if (other == null) return false; 56 | if (!(other is SenderKeyName)) return false; 57 | 58 | SenderKeyName that = (SenderKeyName)other; 59 | 60 | return 61 | this.groupId.Equals(that.groupId) && 62 | this.sender.Equals(that.sender); 63 | } 64 | 65 | public override int GetHashCode() 66 | { 67 | return this.groupId.GetHashCode() ^ this.sender.GetHashCode(); 68 | } 69 | 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /signal-protocol-pcl/ecc/impl/Curve25519ManagedProvider.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | namespace libsignal.ecc.impl 19 | { 20 | class Curve25519ManagedProvider : ICurve25519Provider 21 | { 22 | private org.whispersystems.curve25519.Curve25519 curve; 23 | /// 24 | /// ctor 25 | /// 26 | /// Such as Curve25519.CSHARP or Curve25519.BEST 27 | public Curve25519ManagedProvider(string type) 28 | { 29 | curve = org.whispersystems.curve25519.Curve25519.getInstance(type); 30 | } 31 | 32 | public byte[] calculateAgreement(byte[] ourPrivate, byte[] theirPublic) 33 | { 34 | return curve.calculateAgreement(ourPrivate, theirPublic); 35 | } 36 | 37 | public byte[] calculateSignature(byte[] random, byte[] privateKey, byte[] message) 38 | { 39 | return curve.calculateSignature(random, privateKey, message); 40 | } 41 | 42 | public byte[] generatePrivateKey(byte[] random) 43 | { 44 | return curve.generatePrivateKey(random); 45 | } 46 | 47 | public byte[] generatePublicKey(byte[] privateKey) 48 | { 49 | return curve.generatePublicKey(privateKey); 50 | } 51 | 52 | public bool isNative() 53 | { 54 | return curve.isNative(); 55 | } 56 | 57 | public bool verifySignature(byte[] publicKey, byte[] message, byte[] signature) 58 | { 59 | return curve.verifySignature(publicKey, message, signature); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /signal-protocol-pcl/state/SignedPreKeyStore.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System.Collections.Generic; 19 | 20 | namespace libsignal.state 21 | { 22 | public interface SignedPreKeyStore 23 | { 24 | 25 | 26 | /** 27 | * Load a local SignedPreKeyRecord. 28 | * 29 | * @param signedPreKeyId the ID of the local SignedPreKeyRecord. 30 | * @return the corresponding SignedPreKeyRecord. 31 | * @throws InvalidKeyIdException when there is no corresponding SignedPreKeyRecord. 32 | */ 33 | SignedPreKeyRecord LoadSignedPreKey(uint signedPreKeyId); 34 | 35 | /** 36 | * Load all local SignedPreKeyRecords. 37 | * 38 | * @return All stored SignedPreKeyRecords. 39 | */ 40 | List LoadSignedPreKeys(); 41 | 42 | /** 43 | * Store a local SignedPreKeyRecord. 44 | * 45 | * @param signedPreKeyId the ID of the SignedPreKeyRecord to store. 46 | * @param record the SignedPreKeyRecord. 47 | */ 48 | void StoreSignedPreKey(uint signedPreKeyId, SignedPreKeyRecord record); 49 | 50 | /** 51 | * @param signedPreKeyId A SignedPreKeyRecord ID. 52 | * @return true if the store has a record for the signedPreKeyId, otherwise false. 53 | */ 54 | bool ContainsSignedPreKey(uint signedPreKeyId); 55 | 56 | /** 57 | * Delete a SignedPreKeyRecord from local storage. 58 | * 59 | * @param signedPreKeyId The ID of the SignedPreKeyRecord to remove. 60 | */ 61 | void RemoveSignedPreKey(uint signedPreKeyId); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /signal-protocol-pcl/groups/state/SenderKeyStore.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | namespace libsignal.groups.state 19 | { 20 | public interface SenderKeyStore 21 | { 22 | 23 | /** 24 | * Commit to storage the {@link org.whispersystems.libsignal.groups.state.SenderKeyRecord} for a 25 | * given (groupId + senderId + deviceId) tuple. 26 | * 27 | * @param senderKeyName the (groupId + senderId + deviceId) tuple. 28 | * @param record the current SenderKeyRecord for the specified senderKeyName. 29 | */ 30 | void storeSenderKey(SenderKeyName senderKeyName, SenderKeyRecord record); 31 | 32 | /** 33 | * Returns a copy of the {@link org.whispersystems.libsignal.groups.state.SenderKeyRecord} 34 | * corresponding to the (groupId + senderId + deviceId) tuple, or a new SenderKeyRecord if 35 | * one does not currently exist. 36 | *

37 | * It is important that implementations return a copy of the current durable information. The 38 | * returned SenderKeyRecord may be modified, but those changes should not have an effect on the 39 | * durable session state (what is returned by subsequent calls to this method) without the 40 | * store method being called here first. 41 | * 42 | * @param senderKeyName The (groupId + senderId + deviceId) tuple. 43 | * @return a copy of the SenderKeyRecord corresponding to the (groupId + senderId + deviceId tuple, or 44 | * a new SenderKeyRecord if one does not currently exist. 45 | */ 46 | 47 | SenderKeyRecord loadSenderKey(SenderKeyName senderKeyName); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /signal-protocol-pcl/ecc/DjbECPublicKey.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Linq; 20 | using libsignal.util; 21 | 22 | namespace libsignal.ecc 23 | { 24 | public class DjbECPublicKey : ECPublicKey 25 | { 26 | private readonly byte[] publicKey; 27 | 28 | public DjbECPublicKey(byte[] publicKey) 29 | { 30 | this.publicKey = publicKey; 31 | } 32 | 33 | 34 | public byte[] serialize() 35 | { 36 | byte[] type = { (byte)Curve.DJB_TYPE }; 37 | return ByteUtil.combine(type, publicKey); 38 | } 39 | 40 | 41 | public int getType() 42 | { 43 | return Curve.DJB_TYPE; 44 | } 45 | 46 | 47 | public override bool Equals(Object other) 48 | { 49 | if (other == null) return false; 50 | if (!(other is DjbECPublicKey)) return false; 51 | 52 | DjbECPublicKey that = (DjbECPublicKey)other; 53 | return Enumerable.SequenceEqual(this.publicKey, that.publicKey); 54 | } 55 | 56 | 57 | public override int GetHashCode() 58 | { 59 | return string.Join(",", publicKey).GetHashCode(); 60 | } 61 | 62 | 63 | public int CompareTo(Object another) 64 | { 65 | byte[] theirs = ((DjbECPublicKey)another).publicKey; 66 | String theirString = string.Join(",", theirs.Select(y => y.ToString())); 67 | String ourString = string.Join(",", publicKey.Select(y => y.ToString())); 68 | return ourString.CompareTo(theirString); 69 | } 70 | 71 | public byte[] getPublicKey() 72 | { 73 | return publicKey; 74 | } 75 | 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /signal-protocol-pcl/state/impl/InMemorySignedPreKeyStore.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | 21 | namespace libsignal.state.impl 22 | { 23 | public class InMemorySignedPreKeyStore : SignedPreKeyStore 24 | { 25 | 26 | private readonly IDictionary store = new Dictionary(); 27 | 28 | 29 | public SignedPreKeyRecord LoadSignedPreKey(uint signedPreKeyId) 30 | { 31 | try 32 | { 33 | if (!store.ContainsKey(signedPreKeyId)) 34 | { 35 | throw new InvalidKeyIdException("No such signedprekeyrecord! " + signedPreKeyId); 36 | } 37 | 38 | byte[] record; 39 | store.TryGetValue(signedPreKeyId, out record); // get() 40 | 41 | return new SignedPreKeyRecord(record); 42 | } 43 | catch (Exception e) 44 | { 45 | throw new Exception(e.Message); 46 | } 47 | } 48 | 49 | 50 | public List LoadSignedPreKeys() 51 | { 52 | try 53 | { 54 | List results = new List(); 55 | 56 | foreach (byte[] serialized in store.Values) //values() 57 | { 58 | results.Add(new SignedPreKeyRecord(serialized)); 59 | } 60 | 61 | return results; 62 | } 63 | catch (Exception e) 64 | { 65 | throw new Exception(e.Message); 66 | } 67 | } 68 | 69 | 70 | public void StoreSignedPreKey(uint signedPreKeyId, SignedPreKeyRecord record) 71 | { 72 | store[signedPreKeyId] = record.serialize(); 73 | } 74 | 75 | 76 | public bool ContainsSignedPreKey(uint signedPreKeyId) 77 | { 78 | return store.ContainsKey(signedPreKeyId); 79 | } 80 | 81 | 82 | public void RemoveSignedPreKey(uint signedPreKeyId) 83 | { 84 | store.Remove(signedPreKeyId); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /signal-protocol-pcl/IdentityKeyPair.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using Google.ProtocolBuffers; 19 | using libsignal.ecc; 20 | using static libsignal.state.StorageProtos; 21 | 22 | namespace libsignal 23 | { 24 | /** 25 | * Holder for public and private identity key pair. 26 | * 27 | * @author 28 | */ 29 | public class IdentityKeyPair 30 | { 31 | 32 | private readonly IdentityKey publicKey; 33 | private readonly ECPrivateKey privateKey; 34 | 35 | public IdentityKeyPair(IdentityKey publicKey, ECPrivateKey privateKey) 36 | { 37 | this.publicKey = publicKey; 38 | this.privateKey = privateKey; 39 | } 40 | 41 | public IdentityKeyPair(byte[] serialized) 42 | { 43 | try 44 | { 45 | IdentityKeyPairStructure structure = IdentityKeyPairStructure.ParseFrom(serialized); 46 | this.publicKey = new IdentityKey(structure.PublicKey.ToByteArray(), 0); 47 | this.privateKey = Curve.decodePrivatePoint(structure.PrivateKey.ToByteArray()); 48 | } 49 | catch (InvalidProtocolBufferException e) 50 | { 51 | throw new InvalidKeyException(e); 52 | } 53 | } 54 | 55 | public IdentityKey getPublicKey() 56 | { 57 | return publicKey; 58 | } 59 | 60 | public ECPrivateKey getPrivateKey() 61 | { 62 | return privateKey; 63 | } 64 | 65 | public byte[] serialize() 66 | { 67 | return IdentityKeyPairStructure.CreateBuilder() 68 | .SetPublicKey(ByteString.CopyFrom(publicKey.serialize())) 69 | .SetPrivateKey(ByteString.CopyFrom(privateKey.serialize())) 70 | .Build().ToByteArray(); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /signal-protocol-pcl/ratchet/ChainKey.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal.kdf; 19 | using libsignal.util; 20 | using System; 21 | using System.Text; 22 | 23 | namespace libsignal.ratchet 24 | { 25 | public class ChainKey 26 | { 27 | 28 | private static readonly byte[] MESSAGE_KEY_SEED = { 0x01 }; 29 | private static readonly byte[] CHAIN_KEY_SEED = { 0x02 }; 30 | 31 | private readonly HKDF kdf; 32 | private readonly byte[] key; 33 | private readonly uint index; 34 | 35 | public ChainKey(HKDF kdf, byte[] key, uint index) 36 | { 37 | this.kdf = kdf; 38 | this.key = key; 39 | this.index = index; 40 | } 41 | 42 | public byte[] getKey() 43 | { 44 | return key; 45 | } 46 | 47 | public uint getIndex() 48 | { 49 | return index; 50 | } 51 | 52 | public ChainKey getNextChainKey() 53 | { 54 | byte[] nextKey = getBaseMaterial(CHAIN_KEY_SEED); 55 | return new ChainKey(kdf, nextKey, index + 1); 56 | } 57 | 58 | public MessageKeys getMessageKeys() 59 | { 60 | byte[] inputKeyMaterial = getBaseMaterial(MESSAGE_KEY_SEED); 61 | byte[] keyMaterialBytes = kdf.deriveSecrets(inputKeyMaterial, Encoding.UTF8.GetBytes("WhisperMessageKeys"), DerivedMessageSecrets.SIZE); 62 | DerivedMessageSecrets keyMaterial = new DerivedMessageSecrets(keyMaterialBytes); 63 | 64 | return new MessageKeys(keyMaterial.getCipherKey(), keyMaterial.getMacKey(), keyMaterial.getIv(), index); 65 | } 66 | 67 | private byte[] getBaseMaterial(byte[] seed) 68 | { 69 | try 70 | { 71 | return Sign.sha256sum(key, seed); 72 | } 73 | catch (InvalidKeyException e) 74 | { 75 | throw new Exception(e.Message); 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /signal-protocol-pcl/groups/ratchet/SenderChainKey.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal.util; 19 | 20 | namespace libsignal.groups.ratchet 21 | { 22 | /** 23 | * Each SenderKey is a "chain" of keys, each derived from the previous. 24 | * 25 | * At any given point in time, the state of a SenderKey can be represented 26 | * as the current chain key value, along with its iteration count. From there, 27 | * subsequent iterations can be derived, as well as individual message keys from 28 | * each chain key. 29 | * 30 | * @author 31 | */ 32 | public class SenderChainKey 33 | { 34 | 35 | private static readonly byte[] MESSAGE_KEY_SEED = { 0x01 }; 36 | private static readonly byte[] CHAIN_KEY_SEED = { 0x02 }; 37 | 38 | private readonly uint iteration; 39 | private readonly byte[] chainKey; 40 | 41 | public SenderChainKey(uint iteration, byte[] chainKey) 42 | { 43 | this.iteration = iteration; 44 | this.chainKey = chainKey; 45 | } 46 | 47 | public uint getIteration() 48 | { 49 | return iteration; 50 | } 51 | 52 | public SenderMessageKey getSenderMessageKey() 53 | { 54 | return new SenderMessageKey(iteration, getDerivative(MESSAGE_KEY_SEED, chainKey)); 55 | } 56 | 57 | public SenderChainKey getNext() 58 | { 59 | return new SenderChainKey(iteration + 1, getDerivative(CHAIN_KEY_SEED, chainKey)); 60 | } 61 | 62 | public byte[] getSeed() 63 | { 64 | return chainKey; 65 | } 66 | 67 | private byte[] getDerivative(byte[] seed, byte[] key) 68 | { 69 | // try 70 | //{ 71 | return Sign.sha256sum(key, seed); 72 | /*} 73 | catch (NoSuchAlgorithmException | InvalidKeyException e) { 74 | throw new AssertionError(e); 75 | }*/ 76 | } 77 | 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /signal-protocol-pcl/state/PreKeyRecord.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using Google.ProtocolBuffers; 19 | using libsignal.ecc; 20 | using System; 21 | using static libsignal.state.StorageProtos; 22 | 23 | namespace libsignal.state 24 | { 25 | public class PreKeyRecord 26 | { 27 | 28 | private PreKeyRecordStructure structure; 29 | 30 | public PreKeyRecord(uint id, ECKeyPair keyPair) 31 | { 32 | this.structure = PreKeyRecordStructure.CreateBuilder() 33 | .SetId(id) 34 | .SetPublicKey(ByteString.CopyFrom(keyPair.getPublicKey() 35 | .serialize())) 36 | .SetPrivateKey(ByteString.CopyFrom(keyPair.getPrivateKey() 37 | .serialize())) 38 | .Build(); 39 | } 40 | 41 | public PreKeyRecord(byte[] serialized) 42 | { 43 | this.structure = PreKeyRecordStructure.ParseFrom(serialized); 44 | } 45 | 46 | 47 | 48 | public uint getId() 49 | { 50 | return this.structure.Id; 51 | } 52 | 53 | public ECKeyPair getKeyPair() 54 | { 55 | try 56 | { 57 | ECPublicKey publicKey = Curve.decodePoint(this.structure.PublicKey.ToByteArray(), 0); 58 | ECPrivateKey privateKey = Curve.decodePrivatePoint(this.structure.PrivateKey.ToByteArray()); 59 | 60 | return new ECKeyPair(publicKey, privateKey); 61 | } 62 | catch (InvalidKeyException e) 63 | { 64 | throw new Exception(e.Message); 65 | } 66 | } 67 | 68 | public byte[] serialize() 69 | { 70 | return this.structure.ToByteArray(); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /signal-protocol-pcl/state/IdentityKeyStore.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | 20 | namespace libsignal.state 21 | { 22 | /** 23 | * Provides an interface to identity information. 24 | * 25 | * @author 26 | */ 27 | public interface IdentityKeyStore 28 | { 29 | 30 | /** 31 | * Get the local client's identity key pair. 32 | * 33 | * @return The local client's persistent identity key pair. 34 | */ 35 | IdentityKeyPair GetIdentityKeyPair(); 36 | 37 | /** 38 | * Return the local client's registration ID. 39 | *

40 | * Clients should maintain a registration ID, a random number 41 | * between 1 and 16380 that's generated once at install time. 42 | * 43 | * @return the local client's registration ID. 44 | */ 45 | uint GetLocalRegistrationId(); 46 | 47 | /** 48 | * Save a remote client's identity key 49 | *

50 | * Store a remote client's identity key as trusted. 51 | * 52 | * @param name The name of the remote client. 53 | * @param identityKey The remote client's identity key. 54 | */ 55 | bool SaveIdentity(String name, IdentityKey identityKey); 56 | 57 | 58 | /** 59 | * Verify a remote client's identity key. 60 | *

61 | * Determine whether a remote client's identity is trusted. Convention is 62 | * that the TextSecure protocol is 'trust on first use.' This means that 63 | * an identity key is considered 'trusted' if there is no entry for the recipient 64 | * in the local store, or if it matches the saved key for a recipient in the local 65 | * store. Only if it mismatches an entry in the local store is it considered 66 | * 'untrusted.' 67 | * 68 | * @param name The name of the remote client. 69 | * @param identityKey The identity key to verify. 70 | * @return true if trusted, false if untrusted. 71 | */ 72 | bool IsTrustedIdentity(String name, IdentityKey identityKey); 73 | 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /signal-protocol-pcl/state/impl/InMemorySessionStore.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | 21 | namespace libsignal.state.impl 22 | { 23 | public class InMemorySessionStore : SessionStore 24 | { 25 | 26 | static object Lock = new object(); 27 | 28 | private IDictionary sessions = new Dictionary(); 29 | 30 | public InMemorySessionStore() { } 31 | 32 | //[MethodImpl(MethodImplOptions.Synchronized)] 33 | public SessionRecord LoadSession(SignalProtocolAddress remoteAddress) 34 | { 35 | try 36 | { 37 | if (ContainsSession(remoteAddress)) 38 | { 39 | byte[] session; 40 | sessions.TryGetValue(remoteAddress, out session); // get() 41 | 42 | return new SessionRecord(session); 43 | } 44 | else 45 | { 46 | return new SessionRecord(); 47 | } 48 | } 49 | catch (Exception e) 50 | { 51 | throw new Exception(e.Message); 52 | } 53 | } 54 | 55 | 56 | public List GetSubDeviceSessions(String name) 57 | { 58 | List deviceIds = new List(); 59 | 60 | foreach (SignalProtocolAddress key in sessions.Keys) //keySet() 61 | { 62 | if (key.getName().Equals(name) && 63 | key.getDeviceId() != 1) 64 | { 65 | deviceIds.Add(key.getDeviceId()); 66 | } 67 | } 68 | 69 | return deviceIds; 70 | } 71 | 72 | 73 | public void StoreSession(SignalProtocolAddress address, SessionRecord record) 74 | { 75 | sessions[address] = record.serialize(); 76 | } 77 | 78 | 79 | public bool ContainsSession(SignalProtocolAddress address) 80 | { 81 | return sessions.ContainsKey(address); 82 | } 83 | 84 | 85 | public void DeleteSession(SignalProtocolAddress address) 86 | { 87 | sessions.Remove(address); 88 | } 89 | 90 | 91 | public void DeleteAllSessions(String name) 92 | { 93 | foreach (SignalProtocolAddress key in sessions.Keys) // keySet() 94 | { 95 | if (key.getName().Equals(name)) 96 | { 97 | sessions.Remove(key); 98 | } 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /signal-protocol-pcl/state/SignedPreKeyRecord.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using Google.ProtocolBuffers; 19 | using libsignal.ecc; 20 | using System; 21 | using static libsignal.state.StorageProtos; 22 | 23 | namespace libsignal.state 24 | { 25 | public class SignedPreKeyRecord 26 | { 27 | 28 | private SignedPreKeyRecordStructure structure; 29 | 30 | public SignedPreKeyRecord(uint id, ulong timestamp, ECKeyPair keyPair, byte[] signature) 31 | { 32 | this.structure = SignedPreKeyRecordStructure.CreateBuilder() 33 | .SetId(id) 34 | .SetPublicKey(ByteString.CopyFrom(keyPair.getPublicKey() 35 | .serialize())) 36 | .SetPrivateKey(ByteString.CopyFrom(keyPair.getPrivateKey() 37 | .serialize())) 38 | .SetSignature(ByteString.CopyFrom(signature)) 39 | .SetTimestamp(timestamp) 40 | .Build(); 41 | } 42 | 43 | public SignedPreKeyRecord(byte[] serialized) 44 | { 45 | this.structure = SignedPreKeyRecordStructure.ParseFrom(serialized); 46 | } 47 | 48 | public uint getId() 49 | { 50 | return this.structure.Id; 51 | } 52 | 53 | public ulong getTimestamp() 54 | { 55 | return this.structure.Timestamp; 56 | } 57 | 58 | public ECKeyPair getKeyPair() 59 | { 60 | try 61 | { 62 | ECPublicKey publicKey = Curve.decodePoint(this.structure.PublicKey.ToByteArray(), 0); 63 | ECPrivateKey privateKey = Curve.decodePrivatePoint(this.structure.PrivateKey.ToByteArray()); 64 | 65 | return new ECKeyPair(publicKey, privateKey); 66 | } 67 | catch (InvalidKeyException e) 68 | { 69 | throw new Exception(e.Message); 70 | } 71 | } 72 | 73 | public byte[] getSignature() 74 | { 75 | return this.structure.Signature.ToByteArray(); 76 | } 77 | 78 | public byte[] serialize() 79 | { 80 | return this.structure.ToByteArray(); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /signal-protocol-pcl/state/SessionStore.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | 21 | namespace libsignal.state 22 | { 23 | /** 24 | * The interface to the durable store of session state information 25 | * for remote clients. 26 | * 27 | * @author 28 | */ 29 | public interface SessionStore 30 | { 31 | 32 | /** 33 | * Returns a copy of the {@link SessionRecord} corresponding to the recipientId + deviceId tuple, 34 | * or a new SessionRecord if one does not currently exist. 35 | *

36 | * It is important that implementations return a copy of the current durable information. The 37 | * returned SessionRecord may be modified, but those changes should not have an effect on the 38 | * durable session state (what is returned by subsequent calls to this method) without the 39 | * store method being called here first. 40 | * 41 | * @param address The name and device ID of the remote client. 42 | * @return a copy of the SessionRecord corresponding to the recipientId + deviceId tuple, or 43 | * a new SessionRecord if one does not currently exist. 44 | */ 45 | SessionRecord LoadSession(SignalProtocolAddress address); 46 | 47 | /** 48 | * Returns all known devices with active sessions for a recipient 49 | * 50 | * @param name the name of the client. 51 | * @return all known sub-devices with active sessions. 52 | */ 53 | List GetSubDeviceSessions(String name); 54 | 55 | /** 56 | * Commit to storage the {@link SessionRecord} for a given recipientId + deviceId tuple. 57 | * @param address the address of the remote client. 58 | * @param record the current SessionRecord for the remote client. 59 | */ 60 | void StoreSession(SignalProtocolAddress address, SessionRecord record); 61 | 62 | /** 63 | * Determine whether there is a committed {@link SessionRecord} for a recipientId + deviceId tuple. 64 | * @param address the address of the remote client. 65 | * @return true if a {@link SessionRecord} exists, false otherwise. 66 | */ 67 | bool ContainsSession(SignalProtocolAddress address); 68 | 69 | /** 70 | * Remove a {@link SessionRecord} for a recipientId + deviceId tuple. 71 | * 72 | * @param address the address of the remote client. 73 | */ 74 | void DeleteSession(SignalProtocolAddress address); 75 | 76 | /** 77 | * Remove the {@link SessionRecord}s corresponding to all devices of a recipientId. 78 | * 79 | * @param name the name of the remote client. 80 | */ 81 | void DeleteAllSessions(String name); 82 | 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /signal-protocol-pcl/Protobuf/LocalStorageProtocol.proto: -------------------------------------------------------------------------------- 1 | package textsecure; 2 | 3 | 4 | message SessionStructure { 5 | message Chain { 6 | optional bytes senderRatchetKey = 1; 7 | optional bytes senderRatchetKeyPrivate = 2; 8 | 9 | message ChainKey { 10 | optional uint32 index = 1; 11 | optional bytes key = 2; 12 | } 13 | 14 | optional ChainKey chainKey = 3; 15 | 16 | message MessageKey { 17 | optional uint32 index = 1; 18 | optional bytes cipherKey = 2; 19 | optional bytes macKey = 3; 20 | optional bytes iv = 4; 21 | } 22 | 23 | repeated MessageKey messageKeys = 4; 24 | } 25 | 26 | message PendingKeyExchange { 27 | optional uint32 sequence = 1; 28 | optional bytes localBaseKey = 2; 29 | optional bytes localBaseKeyPrivate = 3; 30 | optional bytes localRatchetKey = 4; 31 | optional bytes localRatchetKeyPrivate = 5; 32 | optional bytes localIdentityKey = 7; 33 | optional bytes localIdentityKeyPrivate = 8; 34 | } 35 | 36 | message PendingPreKey { 37 | optional uint32 preKeyId = 1; 38 | optional int32 signedPreKeyId = 3; 39 | optional bytes baseKey = 2; 40 | } 41 | 42 | optional uint32 sessionVersion = 1; 43 | optional bytes localIdentityPublic = 2; 44 | optional bytes remoteIdentityPublic = 3; 45 | 46 | optional bytes rootKey = 4; 47 | optional uint32 previousCounter = 5; 48 | 49 | optional Chain senderChain = 6; 50 | repeated Chain receiverChains = 7; 51 | 52 | optional PendingKeyExchange pendingKeyExchange = 8; 53 | optional PendingPreKey pendingPreKey = 9; 54 | 55 | optional uint32 remoteRegistrationId = 10; 56 | optional uint32 localRegistrationId = 11; 57 | 58 | optional bool needsRefresh = 12; 59 | optional bytes aliceBaseKey = 13; 60 | } 61 | 62 | message RecordStructure { 63 | optional SessionStructure currentSession = 1; 64 | repeated SessionStructure previousSessions = 2; 65 | } 66 | 67 | message PreKeyRecordStructure { 68 | optional uint32 id = 1; 69 | optional bytes publicKey = 2; 70 | optional bytes privateKey = 3; 71 | } 72 | 73 | message SignedPreKeyRecordStructure { 74 | optional uint32 id = 1; 75 | optional bytes publicKey = 2; 76 | optional bytes privateKey = 3; 77 | optional bytes signature = 4; 78 | optional fixed64 timestamp = 5; 79 | } 80 | 81 | message IdentityKeyPairStructure { 82 | optional bytes publicKey = 1; 83 | optional bytes privateKey = 2; 84 | } 85 | 86 | message SenderKeyStateStructure { 87 | message SenderChainKey { 88 | optional uint32 iteration = 1; 89 | optional bytes seed = 2; 90 | } 91 | 92 | message SenderMessageKey { 93 | optional uint32 iteration = 1; 94 | optional bytes seed = 2; 95 | } 96 | 97 | message SenderSigningKey { 98 | optional bytes public = 1; 99 | optional bytes private = 2; 100 | } 101 | 102 | optional uint32 senderKeyId = 1; 103 | optional SenderChainKey senderChainKey = 2; 104 | optional SenderSigningKey senderSigningKey = 3; 105 | repeated SenderMessageKey senderMessageKeys = 4; 106 | } 107 | 108 | message SenderKeyRecordStructure { 109 | repeated SenderKeyStateStructure senderKeyStates = 1; 110 | } -------------------------------------------------------------------------------- /signal-protocol-pcl/kdf/HKDF.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal.util; 19 | using System; 20 | using System.IO; 21 | 22 | namespace libsignal.kdf 23 | { 24 | public abstract class HKDF 25 | { 26 | 27 | private static readonly int HASH_OUTPUT_SIZE = 32; 28 | 29 | public static HKDF createFor(uint messageVersion) 30 | { 31 | switch (messageVersion) 32 | { 33 | case 2: return new HKDFv2(); 34 | case 3: return new HKDFv3(); 35 | default: throw new Exception("Unknown version: " + messageVersion); 36 | } 37 | } 38 | 39 | public byte[] deriveSecrets(byte[] inputKeyMaterial, byte[] info, int outputLength) 40 | { 41 | byte[] salt = new byte[HASH_OUTPUT_SIZE]; 42 | return deriveSecrets(inputKeyMaterial, salt, info, outputLength); 43 | } 44 | 45 | public byte[] deriveSecrets(byte[] inputKeyMaterial, byte[] salt, byte[] info, int outputLength) 46 | { 47 | byte[] prk = extract(salt, inputKeyMaterial); 48 | return expand(prk, info, outputLength); 49 | } 50 | 51 | private byte[] extract(byte[] salt, byte[] inputKeyMaterial) 52 | { 53 | try 54 | { 55 | return Sign.sha256sum(salt, inputKeyMaterial); 56 | } 57 | catch (Exception e) 58 | { 59 | throw new Exception(e.Message); 60 | } 61 | } 62 | 63 | private byte[] expand(byte[] prk, byte[] info, int outputSize) 64 | { 65 | try 66 | { 67 | int iterations = (int)Math.Ceiling((double)outputSize / (double)HASH_OUTPUT_SIZE); 68 | byte[] mixin = new byte[0]; 69 | MemoryStream results = new MemoryStream(); 70 | int remainingBytes = outputSize; 71 | 72 | for (int i = getIterationStartOffset(); i < iterations + getIterationStartOffset(); i++) 73 | { 74 | MemoryStream msg = new MemoryStream(); 75 | msg.Write(mixin, 0, mixin.Length); 76 | if (info != null) 77 | { 78 | msg.Write(info, 0, info.Length); 79 | } 80 | byte[] ib = BitConverter.GetBytes(i); 81 | msg.Write(ib, 0, 1); 82 | 83 | byte[] stepResult = Sign.sha256sum(prk, msg.ToArray()); 84 | int stepSize = Math.Min(remainingBytes, stepResult.Length); 85 | 86 | results.Write(stepResult, 0, stepSize); 87 | 88 | mixin = stepResult; 89 | remainingBytes -= stepSize; 90 | } 91 | 92 | return results.ToArray(); 93 | } 94 | catch (Exception e) 95 | { 96 | throw new Exception(e.Message); 97 | } 98 | } 99 | 100 | protected abstract int getIterationStartOffset(); 101 | 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /signal-protocol-pcl/groups/state/SenderKeyRecord.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal.ecc; 19 | using libsignal.groups.state; 20 | using libsignal.state; 21 | using System.Collections.Generic; 22 | using static libsignal.state.StorageProtos; 23 | 24 | namespace libsignal.groups 25 | { 26 | /** 27 | * A durable representation of a set of SenderKeyStates for a specific 28 | * SenderKeyName. 29 | * 30 | * @author 31 | */ 32 | public class SenderKeyRecord 33 | { 34 | private static readonly int MAX_STATES = 5; 35 | 36 | private LinkedList senderKeyStates = new LinkedList(); 37 | 38 | public SenderKeyRecord() { } 39 | 40 | public SenderKeyRecord(byte[] serialized) 41 | { 42 | SenderKeyRecordStructure senderKeyRecordStructure = SenderKeyRecordStructure.ParseFrom(serialized); 43 | 44 | foreach (StorageProtos.SenderKeyStateStructure structure in senderKeyRecordStructure.SenderKeyStatesList) 45 | { 46 | this.senderKeyStates.AddFirst(new SenderKeyState(structure)); 47 | } 48 | } 49 | 50 | public bool isEmpty() 51 | { 52 | return senderKeyStates.Count == 0; 53 | } 54 | 55 | public SenderKeyState getSenderKeyState() 56 | { 57 | if (!isEmpty()) 58 | { 59 | return senderKeyStates.First.Value; 60 | } 61 | else 62 | { 63 | throw new InvalidKeyIdException("No key state in record!"); 64 | } 65 | } 66 | 67 | public SenderKeyState getSenderKeyState(uint keyId) 68 | { 69 | foreach (SenderKeyState state in senderKeyStates) 70 | { 71 | if (state.getKeyId() == keyId) 72 | { 73 | return state; 74 | } 75 | } 76 | 77 | throw new InvalidKeyIdException("No keys for: " + keyId); 78 | } 79 | 80 | public void addSenderKeyState(uint id, uint iteration, byte[] chainKey, ECPublicKey signatureKey) 81 | { 82 | senderKeyStates.AddFirst(new SenderKeyState(id, iteration, chainKey, signatureKey)); 83 | 84 | if (senderKeyStates.Count > MAX_STATES) 85 | { 86 | senderKeyStates.RemoveLast(); 87 | } 88 | } 89 | 90 | public void setSenderKeyState(uint id, uint iteration, byte[] chainKey, ECKeyPair signatureKey) 91 | { 92 | senderKeyStates.Clear(); 93 | senderKeyStates.AddFirst(new SenderKeyState(id, iteration, chainKey, signatureKey)); 94 | } 95 | 96 | public byte[] serialize() 97 | { 98 | SenderKeyRecordStructure.Builder recordStructure = SenderKeyRecordStructure.CreateBuilder(); 99 | 100 | foreach (SenderKeyState senderKeyState in senderKeyStates) 101 | { 102 | recordStructure.AddSenderKeyStates(senderKeyState.getStructure()); 103 | } 104 | 105 | return recordStructure.Build().ToByteArray(); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /signal-protocol-pcl/state/PreKeyBundle.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal.ecc; 19 | 20 | namespace libsignal.state 21 | { 22 | /** 23 | * A class that contains a remote PreKey and collection 24 | * of associated items. 25 | * 26 | * @author Moxie Marlinspike 27 | */ 28 | public class PreKeyBundle 29 | { 30 | 31 | private uint registrationId; 32 | 33 | private uint deviceId; 34 | 35 | private uint preKeyId; 36 | private ECPublicKey preKeyPublic; 37 | 38 | private uint signedPreKeyId; 39 | private ECPublicKey signedPreKeyPublic; 40 | private byte[] signedPreKeySignature; 41 | 42 | private IdentityKey identityKey; 43 | 44 | public PreKeyBundle(uint registrationId, uint deviceId, uint preKeyId, ECPublicKey preKeyPublic, 45 | uint signedPreKeyId, ECPublicKey signedPreKeyPublic, byte[] signedPreKeySignature, 46 | IdentityKey identityKey) 47 | { 48 | this.registrationId = registrationId; 49 | this.deviceId = deviceId; 50 | this.preKeyId = preKeyId; 51 | this.preKeyPublic = preKeyPublic; 52 | this.signedPreKeyId = signedPreKeyId; 53 | this.signedPreKeyPublic = signedPreKeyPublic; 54 | this.signedPreKeySignature = signedPreKeySignature; 55 | this.identityKey = identityKey; 56 | } 57 | 58 | /** 59 | * @return the device ID this PreKey belongs to. 60 | */ 61 | public uint getDeviceId() 62 | { 63 | return deviceId; 64 | } 65 | 66 | /** 67 | * @return the unique key ID for this PreKey. 68 | */ 69 | public uint getPreKeyId() 70 | { 71 | return preKeyId; 72 | } 73 | 74 | /** 75 | * @return the public key for this PreKey. 76 | */ 77 | public ECPublicKey getPreKey() 78 | { 79 | return preKeyPublic; 80 | } 81 | 82 | /** 83 | * @return the unique key ID for this signed prekey. 84 | */ 85 | public uint getSignedPreKeyId() 86 | { 87 | return signedPreKeyId; 88 | } 89 | 90 | /** 91 | * @return the signed prekey for this PreKeyBundle. 92 | */ 93 | public ECPublicKey getSignedPreKey() 94 | { 95 | return signedPreKeyPublic; 96 | } 97 | 98 | /** 99 | * @return the signature over the signed prekey. 100 | */ 101 | public byte[] getSignedPreKeySignature() 102 | { 103 | return signedPreKeySignature; 104 | } 105 | 106 | /** 107 | * @return the {@link org.whispersystems.libsignal.IdentityKey} of this PreKeys owner. 108 | */ 109 | public IdentityKey getIdentityKey() 110 | { 111 | return identityKey; 112 | } 113 | 114 | /** 115 | * @return the registration ID associated with this PreKey. 116 | */ 117 | public uint getRegistrationId() 118 | { 119 | return registrationId; 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /signal-protocol-pcl/ecc/Curve.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | namespace libsignal.ecc 19 | { 20 | public class Curve 21 | { 22 | public const int DJB_TYPE = 0x05; 23 | 24 | public static bool isNative() 25 | { 26 | return Curve25519.getInstance(Curve25519ProviderType.BEST).isNative(); 27 | } 28 | 29 | public static ECKeyPair generateKeyPair() 30 | { 31 | Curve25519KeyPair keyPair = Curve25519.getInstance(Curve25519ProviderType.BEST).generateKeyPair(); 32 | 33 | return new ECKeyPair(new DjbECPublicKey(keyPair.getPublicKey()), 34 | new DjbECPrivateKey(keyPair.getPrivateKey())); 35 | } 36 | 37 | public static ECPublicKey decodePoint(byte[] bytes, int offset) 38 | { 39 | int type = bytes[offset] & 0xFF; 40 | 41 | switch (type) 42 | { 43 | case Curve.DJB_TYPE: 44 | byte[] keyBytes = new byte[32]; 45 | System.Buffer.BlockCopy(bytes, offset + 1, keyBytes, 0, keyBytes.Length); 46 | return new DjbECPublicKey(keyBytes); 47 | default: 48 | throw new InvalidKeyException("Bad key type: " + type); 49 | } 50 | } 51 | 52 | public static ECPrivateKey decodePrivatePoint(byte[] bytes) 53 | { 54 | return new DjbECPrivateKey(bytes); 55 | } 56 | 57 | public static byte[] calculateAgreement(ECPublicKey publicKey, ECPrivateKey privateKey) 58 | { 59 | if (publicKey.getType() != privateKey.getType()) 60 | { 61 | throw new InvalidKeyException("Public and private keys must be of the same type!"); 62 | } 63 | 64 | if (publicKey.getType() == DJB_TYPE) 65 | { 66 | return Curve25519.getInstance(Curve25519ProviderType.BEST) 67 | .calculateAgreement(((DjbECPublicKey)publicKey).getPublicKey(), 68 | ((DjbECPrivateKey)privateKey).getPrivateKey()); 69 | } 70 | else 71 | { 72 | throw new InvalidKeyException("Unknown type: " + publicKey.getType()); 73 | } 74 | } 75 | 76 | public static bool verifySignature(ECPublicKey signingKey, byte[] message, byte[] signature) 77 | { 78 | if (signingKey.getType() == DJB_TYPE) 79 | { 80 | return Curve25519.getInstance(Curve25519ProviderType.BEST) 81 | .verifySignature(((DjbECPublicKey)signingKey).getPublicKey(), message, signature); 82 | } 83 | else 84 | { 85 | throw new InvalidKeyException("Unknown type: " + signingKey.getType()); 86 | } 87 | } 88 | 89 | public static byte[] calculateSignature(ECPrivateKey signingKey, byte[] message) 90 | { 91 | if (signingKey.getType() == DJB_TYPE) 92 | { 93 | return Curve25519.getInstance(Curve25519ProviderType.BEST) 94 | .calculateSignature(((DjbECPrivateKey)signingKey).getPrivateKey(), message); 95 | } 96 | else 97 | { 98 | throw new InvalidKeyException("Unknown type: " + signingKey.getType()); 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /signal-protocol-tests/ratchet/RootKeyTest.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal.ecc; 19 | using libsignal.kdf; 20 | using libsignal.ratchet; 21 | using libsignal.util; 22 | using Microsoft.VisualStudio.TestTools.UnitTesting; 23 | 24 | namespace libsignal_test 25 | { 26 | [TestClass] 27 | public class RootKeyTest 28 | { 29 | [TestMethod, TestCategory("libsignal.ratchet")] 30 | public void testRootKeyDerivationV2() 31 | { 32 | byte[] rootKeySeed = 33 | { 34 | 0x7b, 0xa6, 0xde, 0xbc, 0x2b, 35 | 0xc1, 0xbb, 0xf9, 0x1a, 0xbb, 36 | 0xc1, 0x36, 0x74, 0x04, 0x17, 37 | 0x6c, 0xa6, 0x23, 0x09, 0x5b, 38 | 0x7e, 0xc6, 0x6b, 0x45, 0xf6, 39 | 0x02, 0xd9, 0x35, 0x38, 0x94, 40 | 0x2d, 0xcc 41 | }; 42 | 43 | byte[] alicePublic = 44 | { 45 | 0x05, 0xee, 0x4f, 0xa6, 0xcd, 46 | 0xc0, 0x30, 0xdf, 0x49, 0xec, 47 | 0xd0, 0xba, 0x6c, 0xfc, 0xff, 48 | 0xb2, 0x33, 0xd3, 0x65, 0xa2, 49 | 0x7f, 0xad, 0xbe, 0xff, 0x77, 50 | 0xe9, 0x63, 0xfc, 0xb1, 0x62, 51 | 0x22, 0xe1, 0x3a 52 | }; 53 | 54 | byte[] alicePrivate = 55 | { 56 | 0x21, 0x68, 0x22, 0xec, 0x67, 57 | 0xeb, 0x38, 0x04, 0x9e, 0xba, 58 | 0xe7, 0xb9, 0x39, 0xba, 0xea, 59 | 0xeb, 0xb1, 0x51, 0xbb, 0xb3, 60 | 0x2d, 0xb8, 0x0f, 0xd3, 0x89, 61 | 0x24, 0x5a, 0xc3, 0x7a, 0x94, 62 | 0x8e, 0x50 63 | }; 64 | 65 | byte[] bobPublic = 66 | { 67 | 0x05, 0xab, 0xb8, 0xeb, 0x29, 68 | 0xcc, 0x80, 0xb4, 0x71, 0x09, 69 | 0xa2, 0x26, 0x5a, 0xbe, 0x97, 70 | 0x98, 0x48, 0x54, 0x06, 0xe3, 71 | 0x2d, 0xa2, 0x68, 0x93, 0x4a, 72 | 0x95, 0x55, 0xe8, 0x47, 0x57, 73 | 0x70, 0x8a, 0x30 74 | }; 75 | 76 | byte[] nextRoot = 77 | { 78 | 0xb1, 0x14, 0xf5, 0xde, 0x28, 79 | 0x01, 0x19, 0x85, 0xe6, 0xeb, 80 | 0xa2, 0x5d, 0x50, 0xe7, 0xec, 81 | 0x41, 0xa9, 0xb0, 0x2f, 0x56, 82 | 0x93, 0xc5, 0xc7, 0x88, 0xa6, 83 | 0x3a, 0x06, 0xd2, 0x12, 0xa2, 84 | 0xf7, 0x31 85 | }; 86 | 87 | byte[] nextChain = 88 | { 89 | 0x9d, 0x7d, 0x24, 0x69, 0xbc, 90 | 0x9a, 0xe5, 0x3e, 0xe9, 0x80, 91 | 0x5a, 0xa3, 0x26, 0x4d, 0x24, 92 | 0x99, 0xa3, 0xac, 0xe8, 0x0f, 93 | 0x4c, 0xca, 0xe2, 0xda, 0x13, 94 | 0x43, 0x0c, 0x5c, 0x55, 0xb5, 95 | 0xca, 0x5f 96 | }; 97 | 98 | ECPublicKey alicePublicKey = Curve.decodePoint(alicePublic, 0); 99 | ECPrivateKey alicePrivateKey = Curve.decodePrivatePoint(alicePrivate); 100 | ECKeyPair aliceKeyPair = new ECKeyPair(alicePublicKey, alicePrivateKey); 101 | 102 | ECPublicKey bobPublicKey = Curve.decodePoint(bobPublic, 0); 103 | RootKey rootKey = new RootKey(HKDF.createFor(2), rootKeySeed); 104 | 105 | Pair rootKeyChainKeyPair = rootKey.createChain(bobPublicKey, aliceKeyPair); 106 | RootKey nextRootKey = rootKeyChainKeyPair.first(); 107 | ChainKey nextChainKey = rootKeyChainKeyPair.second(); 108 | 109 | CollectionAssert.AreEqual(rootKey.getKeyBytes(), rootKeySeed); 110 | CollectionAssert.AreEqual(nextRootKey.getKeyBytes(), nextRoot); 111 | CollectionAssert.AreEqual(nextChainKey.getKey(), nextChain); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /signal-protocol-pcl/state/impl/InMemorySignalProtocolStore.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | 21 | namespace libsignal.state.impl 22 | { 23 | public class InMemorySignalProtocolStore : SignalProtocolStore 24 | { 25 | 26 | private readonly InMemoryPreKeyStore preKeyStore = new InMemoryPreKeyStore(); 27 | private readonly InMemorySessionStore sessionStore = new InMemorySessionStore(); 28 | private readonly InMemorySignedPreKeyStore signedPreKeyStore = new InMemorySignedPreKeyStore(); 29 | 30 | private readonly InMemoryIdentityKeyStore identityKeyStore; 31 | 32 | public InMemorySignalProtocolStore(IdentityKeyPair identityKeyPair, uint registrationId) 33 | { 34 | this.identityKeyStore = new InMemoryIdentityKeyStore(identityKeyPair, registrationId); 35 | } 36 | 37 | 38 | public IdentityKeyPair GetIdentityKeyPair() 39 | { 40 | return identityKeyStore.GetIdentityKeyPair(); 41 | } 42 | 43 | 44 | public uint GetLocalRegistrationId() 45 | { 46 | return identityKeyStore.GetLocalRegistrationId(); 47 | } 48 | 49 | 50 | public bool SaveIdentity(String name, IdentityKey identityKey) 51 | { 52 | identityKeyStore.SaveIdentity(name, identityKey); 53 | return true; 54 | } 55 | 56 | 57 | public bool IsTrustedIdentity(String name, IdentityKey identityKey) 58 | { 59 | return identityKeyStore.IsTrustedIdentity(name, identityKey); 60 | } 61 | 62 | 63 | public PreKeyRecord LoadPreKey(uint preKeyId) 64 | { 65 | return preKeyStore.LoadPreKey(preKeyId); 66 | } 67 | 68 | 69 | public void StorePreKey(uint preKeyId, PreKeyRecord record) 70 | { 71 | preKeyStore.StorePreKey(preKeyId, record); 72 | } 73 | 74 | 75 | public bool ContainsPreKey(uint preKeyId) 76 | { 77 | return preKeyStore.ContainsPreKey(preKeyId); 78 | } 79 | 80 | 81 | public void RemovePreKey(uint preKeyId) 82 | { 83 | preKeyStore.RemovePreKey(preKeyId); 84 | } 85 | 86 | 87 | public SessionRecord LoadSession(SignalProtocolAddress address) 88 | { 89 | return sessionStore.LoadSession(address); 90 | } 91 | 92 | 93 | public List GetSubDeviceSessions(String name) 94 | { 95 | return sessionStore.GetSubDeviceSessions(name); 96 | } 97 | 98 | 99 | public void StoreSession(SignalProtocolAddress address, SessionRecord record) 100 | { 101 | sessionStore.StoreSession(address, record); 102 | } 103 | 104 | 105 | public bool ContainsSession(SignalProtocolAddress address) 106 | { 107 | return sessionStore.ContainsSession(address); 108 | } 109 | 110 | 111 | public void DeleteSession(SignalProtocolAddress address) 112 | { 113 | sessionStore.DeleteSession(address); 114 | } 115 | 116 | 117 | public void DeleteAllSessions(String name) 118 | { 119 | sessionStore.DeleteAllSessions(name); 120 | } 121 | 122 | 123 | public SignedPreKeyRecord LoadSignedPreKey(uint signedPreKeyId) 124 | { 125 | return signedPreKeyStore.LoadSignedPreKey(signedPreKeyId); 126 | } 127 | 128 | 129 | public List LoadSignedPreKeys() 130 | { 131 | return signedPreKeyStore.LoadSignedPreKeys(); 132 | } 133 | 134 | 135 | public void StoreSignedPreKey(uint signedPreKeyId, SignedPreKeyRecord record) 136 | { 137 | signedPreKeyStore.StoreSignedPreKey(signedPreKeyId, record); 138 | } 139 | 140 | 141 | public bool ContainsSignedPreKey(uint signedPreKeyId) 142 | { 143 | return signedPreKeyStore.ContainsSignedPreKey(signedPreKeyId); 144 | } 145 | 146 | 147 | public void RemoveSignedPreKey(uint signedPreKeyId) 148 | { 149 | signedPreKeyStore.RemoveSignedPreKey(signedPreKeyId); 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /signal-protocol-pcl/groups/GroupSessionBuilder.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal.groups.state; 19 | using libsignal.protocol; 20 | using libsignal.util; 21 | using System; 22 | 23 | namespace libsignal.groups 24 | { 25 | /** 26 | * GroupSessionBuilder is responsible for setting up group SenderKey encrypted sessions. 27 | * 28 | * Once a session has been established, {@link org.whispersystems.libsignal.groups.GroupCipher} 29 | * can be used to encrypt/decrypt messages in that session. 30 | *

31 | * The built sessions are unidirectional: they can be used either for sending or for receiving, 32 | * but not both. 33 | * 34 | * Sessions are constructed per (groupId + senderId + deviceId) tuple. Remote logical users 35 | * are identified by their senderId, and each logical recipientId can have multiple physical 36 | * devices. 37 | * 38 | * @author 39 | */ 40 | 41 | public class GroupSessionBuilder 42 | { 43 | 44 | private readonly SenderKeyStore senderKeyStore; 45 | 46 | public GroupSessionBuilder(SenderKeyStore senderKeyStore) 47 | { 48 | this.senderKeyStore = senderKeyStore; 49 | } 50 | 51 | /** 52 | * Construct a group session for receiving messages from senderKeyName. 53 | * 54 | * @param senderKeyName The (groupId, senderId, deviceId) tuple associated with the SenderKeyDistributionMessage. 55 | * @param senderKeyDistributionMessage A received SenderKeyDistributionMessage. 56 | */ 57 | public void process(SenderKeyName senderKeyName, SenderKeyDistributionMessage senderKeyDistributionMessage) 58 | { 59 | lock (GroupCipher.LOCK) 60 | { 61 | SenderKeyRecord senderKeyRecord = senderKeyStore.loadSenderKey(senderKeyName); 62 | senderKeyRecord.addSenderKeyState(senderKeyDistributionMessage.getId(), 63 | senderKeyDistributionMessage.getIteration(), 64 | senderKeyDistributionMessage.getChainKey(), 65 | senderKeyDistributionMessage.getSignatureKey()); 66 | senderKeyStore.storeSenderKey(senderKeyName, senderKeyRecord); 67 | } 68 | } 69 | 70 | /** 71 | * Construct a group session for sending messages. 72 | * 73 | * @param senderKeyName The (groupId, senderId, deviceId) tuple. In this case, 'senderId' should be the caller. 74 | * @return A SenderKeyDistributionMessage that is individually distributed to each member of the group. 75 | */ 76 | public SenderKeyDistributionMessage create(SenderKeyName senderKeyName) 77 | { 78 | lock (GroupCipher.LOCK) 79 | { 80 | try 81 | { 82 | SenderKeyRecord senderKeyRecord = senderKeyStore.loadSenderKey(senderKeyName); 83 | 84 | if (senderKeyRecord.isEmpty()) 85 | { 86 | senderKeyRecord.setSenderKeyState(KeyHelper.generateSenderKeyId(), 87 | 0, 88 | KeyHelper.generateSenderKey(), 89 | KeyHelper.generateSenderSigningKey()); 90 | senderKeyStore.storeSenderKey(senderKeyName, senderKeyRecord); 91 | } 92 | 93 | SenderKeyState state = senderKeyRecord.getSenderKeyState(); 94 | 95 | return new SenderKeyDistributionMessage(state.getKeyId(), 96 | state.getSenderChainKey().getIteration(), 97 | state.getSenderChainKey().getSeed(), 98 | state.getSigningKeyPublic()); 99 | 100 | } 101 | catch (Exception e) when (e is InvalidKeyIdException || e is InvalidKeyException) 102 | { 103 | throw new Exception(e.Message); 104 | } 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /signal-protocol-pcl/protocol/SenderKeyDistributionMessage.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using Google.ProtocolBuffers; 19 | using libsignal.ecc; 20 | using libsignal.util; 21 | using System; 22 | 23 | namespace libsignal.protocol 24 | { 25 | public partial class SenderKeyDistributionMessage : CiphertextMessage 26 | { 27 | 28 | private readonly uint id; 29 | private readonly uint iteration; 30 | private readonly byte[] chainKey; 31 | private readonly ECPublicKey signatureKey; 32 | private readonly byte[] serialized; 33 | 34 | public SenderKeyDistributionMessage(uint id, uint iteration, byte[] chainKey, ECPublicKey signatureKey) 35 | { 36 | byte[] version = { ByteUtil.intsToByteHighAndLow((int)CURRENT_VERSION, (int)CURRENT_VERSION) }; 37 | byte[] protobuf = WhisperProtos.SenderKeyDistributionMessage.CreateBuilder() 38 | .SetId(id) 39 | .SetIteration(iteration) 40 | .SetChainKey(ByteString.CopyFrom(chainKey)) 41 | .SetSigningKey(ByteString.CopyFrom(signatureKey.serialize())) 42 | .Build().ToByteArray(); 43 | 44 | this.id = id; 45 | this.iteration = iteration; 46 | this.chainKey = chainKey; 47 | this.signatureKey = signatureKey; 48 | this.serialized = ByteUtil.combine(version, protobuf); 49 | } 50 | 51 | public SenderKeyDistributionMessage(byte[] serialized) 52 | { 53 | try 54 | { 55 | byte[][] messageParts = ByteUtil.split(serialized, 1, serialized.Length - 1); 56 | byte version = messageParts[0][0]; 57 | byte[] message = messageParts[1]; 58 | 59 | if (ByteUtil.highBitsToInt(version) < CiphertextMessage.CURRENT_VERSION) 60 | { 61 | throw new LegacyMessageException("Legacy message: " + ByteUtil.highBitsToInt(version)); 62 | } 63 | 64 | if (ByteUtil.highBitsToInt(version) > CURRENT_VERSION) 65 | { 66 | throw new InvalidMessageException("Unknown version: " + ByteUtil.highBitsToInt(version)); 67 | } 68 | 69 | WhisperProtos.SenderKeyDistributionMessage distributionMessage = WhisperProtos.SenderKeyDistributionMessage.ParseFrom(message); 70 | 71 | if (!distributionMessage.HasId || 72 | !distributionMessage.HasIteration || 73 | !distributionMessage.HasChainKey || 74 | !distributionMessage.HasSigningKey) 75 | { 76 | throw new InvalidMessageException("Incomplete message."); 77 | } 78 | 79 | this.serialized = serialized; 80 | this.id = distributionMessage.Id; 81 | this.iteration = distributionMessage.Iteration; 82 | this.chainKey = distributionMessage.ChainKey.ToByteArray(); 83 | this.signatureKey = Curve.decodePoint(distributionMessage.SigningKey.ToByteArray(), 0); 84 | } 85 | catch (Exception e) 86 | { 87 | //InvalidProtocolBufferException | InvalidKey 88 | throw new InvalidMessageException(e); 89 | } 90 | } 91 | 92 | public override byte[] serialize() 93 | { 94 | return serialized; 95 | } 96 | 97 | 98 | public override uint getType() 99 | { 100 | return SENDERKEY_DISTRIBUTION_TYPE; 101 | } 102 | 103 | public uint getIteration() 104 | { 105 | return iteration; 106 | } 107 | 108 | public byte[] getChainKey() 109 | { 110 | return chainKey; 111 | } 112 | 113 | public ECPublicKey getSignatureKey() 114 | { 115 | return signatureKey; 116 | } 117 | 118 | public uint getId() 119 | { 120 | return id; 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /signal-protocol-pcl/ratchet/SymmetricSignalProtocolParameters.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal.ecc; 19 | using System; 20 | 21 | namespace libsignal.ratchet 22 | { 23 | public class SymmetricSignalProtocolParameters 24 | { 25 | 26 | private readonly ECKeyPair ourBaseKey; 27 | private readonly ECKeyPair ourRatchetKey; 28 | private readonly IdentityKeyPair ourIdentityKey; 29 | 30 | private readonly ECPublicKey theirBaseKey; 31 | private readonly ECPublicKey theirRatchetKey; 32 | private readonly IdentityKey theirIdentityKey; 33 | 34 | SymmetricSignalProtocolParameters(ECKeyPair ourBaseKey, ECKeyPair ourRatchetKey, 35 | IdentityKeyPair ourIdentityKey, ECPublicKey theirBaseKey, 36 | ECPublicKey theirRatchetKey, IdentityKey theirIdentityKey) 37 | { 38 | this.ourBaseKey = ourBaseKey; 39 | this.ourRatchetKey = ourRatchetKey; 40 | this.ourIdentityKey = ourIdentityKey; 41 | this.theirBaseKey = theirBaseKey; 42 | this.theirRatchetKey = theirRatchetKey; 43 | this.theirIdentityKey = theirIdentityKey; 44 | 45 | if (ourBaseKey == null || ourRatchetKey == null || ourIdentityKey == null || 46 | theirBaseKey == null || theirRatchetKey == null || theirIdentityKey == null) 47 | { 48 | throw new Exception("Null values!"); 49 | } 50 | } 51 | 52 | public ECKeyPair getOurBaseKey() 53 | { 54 | return ourBaseKey; 55 | } 56 | 57 | public ECKeyPair getOurRatchetKey() 58 | { 59 | return ourRatchetKey; 60 | } 61 | 62 | public IdentityKeyPair getOurIdentityKey() 63 | { 64 | return ourIdentityKey; 65 | } 66 | 67 | public ECPublicKey getTheirBaseKey() 68 | { 69 | return theirBaseKey; 70 | } 71 | 72 | public ECPublicKey getTheirRatchetKey() 73 | { 74 | return theirRatchetKey; 75 | } 76 | 77 | public IdentityKey getTheirIdentityKey() 78 | { 79 | return theirIdentityKey; 80 | } 81 | 82 | public static Builder newBuilder() 83 | { 84 | return new Builder(); 85 | } 86 | 87 | public class Builder 88 | { 89 | private ECKeyPair ourBaseKey; 90 | private ECKeyPair ourRatchetKey; 91 | private IdentityKeyPair ourIdentityKey; 92 | 93 | private ECPublicKey theirBaseKey; 94 | private ECPublicKey theirRatchetKey; 95 | private IdentityKey theirIdentityKey; 96 | 97 | public Builder setOurBaseKey(ECKeyPair ourBaseKey) 98 | { 99 | this.ourBaseKey = ourBaseKey; 100 | return this; 101 | } 102 | 103 | public Builder setOurRatchetKey(ECKeyPair ourRatchetKey) 104 | { 105 | this.ourRatchetKey = ourRatchetKey; 106 | return this; 107 | } 108 | 109 | public Builder setOurIdentityKey(IdentityKeyPair ourIdentityKey) 110 | { 111 | this.ourIdentityKey = ourIdentityKey; 112 | return this; 113 | } 114 | 115 | public Builder setTheirBaseKey(ECPublicKey theirBaseKey) 116 | { 117 | this.theirBaseKey = theirBaseKey; 118 | return this; 119 | } 120 | 121 | public Builder setTheirRatchetKey(ECPublicKey theirRatchetKey) 122 | { 123 | this.theirRatchetKey = theirRatchetKey; 124 | return this; 125 | } 126 | 127 | public Builder setTheirIdentityKey(IdentityKey theirIdentityKey) 128 | { 129 | this.theirIdentityKey = theirIdentityKey; 130 | return this; 131 | } 132 | 133 | public SymmetricSignalProtocolParameters create() 134 | { 135 | return new SymmetricSignalProtocolParameters(ourBaseKey, ourRatchetKey, ourIdentityKey, 136 | theirBaseKey, theirRatchetKey, theirIdentityKey); 137 | } 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | [Xx]64/ 19 | [Xx]86/ 20 | [Bb]uild/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Microsoft Azure ApplicationInsights config file 170 | ApplicationInsights.config 171 | 172 | # Windows Store app package directory 173 | AppPackages/ 174 | BundleArtifacts/ 175 | 176 | # Visual Studio cache files 177 | # files ending in .cache can be ignored 178 | *.[Cc]ache 179 | # but keep track of directories ending in .cache 180 | !*.[Cc]ache/ 181 | 182 | # Others 183 | ClientBin/ 184 | [Ss]tyle[Cc]op.* 185 | ~$* 186 | *~ 187 | *.dbmdl 188 | *.dbproj.schemaview 189 | *.pfx 190 | *.publishsettings 191 | node_modules/ 192 | orleans.codegen.cs 193 | 194 | # RIA/Silverlight projects 195 | Generated_Code/ 196 | 197 | # Backup & report files from converting an old project file 198 | # to a newer Visual Studio version. Backup files are not needed, 199 | # because we have git ;-) 200 | _UpgradeReport_Files/ 201 | Backup*/ 202 | UpgradeLog*.XML 203 | UpgradeLog*.htm 204 | 205 | # SQL Server files 206 | *.mdf 207 | *.ldf 208 | 209 | # Business Intelligence projects 210 | *.rdl.data 211 | *.bim.layout 212 | *.bim_*.settings 213 | 214 | # Microsoft Fakes 215 | FakesAssemblies/ 216 | 217 | # GhostDoc plugin setting file 218 | *.GhostDoc.xml 219 | 220 | # Node.js Tools for Visual Studio 221 | .ntvs_analysis.dat 222 | 223 | # Visual Studio 6 build log 224 | *.plg 225 | 226 | # Visual Studio 6 workspace options file 227 | *.opt 228 | 229 | # Visual Studio LightSwitch build output 230 | **/*.HTMLClient/GeneratedArtifacts 231 | **/*.DesktopClient/GeneratedArtifacts 232 | **/*.DesktopClient/ModelManifest.xml 233 | **/*.Server/GeneratedArtifacts 234 | **/*.Server/ModelManifest.xml 235 | _Pvt_Extensions 236 | 237 | # LightSwitch generated files 238 | GeneratedArtifacts/ 239 | ModelManifest.xml 240 | 241 | # Paket dependency manager 242 | .paket/paket.exe 243 | 244 | # FAKE - F# Make 245 | .fake/ 246 | /signal-porting-tool 247 | -------------------------------------------------------------------------------- /signal-protocol-pcl/fingerprint/NumericFingerprintGenerator.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal; 19 | using libsignal.util; 20 | using PCLCrypto; 21 | using System; 22 | using System.Diagnostics; 23 | using System.Text; 24 | using static PCLCrypto.WinRTCrypto; 25 | 26 | namespace org.whispersystems.libsignal.fingerprint 27 | { 28 | 29 | public class NumericFingerprintGenerator : FingerprintGenerator 30 | { 31 | 32 | private static readonly int VERSION = 0; 33 | 34 | private readonly long iterations; 35 | 36 | /** 37 | * Construct a fingerprint generator for 60 digit numerics. 38 | * 39 | * @param iterations The number of internal iterations to perform in the process of 40 | * generating a fingerprint. This needs to be constant, and synchronized 41 | * across all clients. 42 | * 43 | * The higher the iteration count, the higher the security level: 44 | * 45 | * - 1024 ~ 109.7 bits 46 | * - 1400 > 110 bits 47 | * - 5200 > 112 bits 48 | */ 49 | public NumericFingerprintGenerator(long iterations) 50 | { 51 | this.iterations = iterations; 52 | } 53 | 54 | public object MessageDigest { get; private set; } 55 | 56 | /** 57 | * Generate a scannable and displayble fingerprint. 58 | * 59 | * @param localStableIdentifier The client's "stable" identifier. 60 | * @param localIdentityKey The client's identity key. 61 | * @param remoteStableIdentifier The remote party's "stable" identifier. 62 | * @param remoteIdentityKey The remote party's identity key. 63 | * @return A unique fingerprint for this conversation. 64 | */ 65 | 66 | public Fingerprint createFor(string localStableIdentifier, IdentityKey localIdentityKey, 67 | string remoteStableIdentifier, IdentityKey remoteIdentityKey) 68 | { 69 | DisplayableFingerprint displayableFingerprint = new DisplayableFingerprint(getDisplayStringFor(localStableIdentifier, localIdentityKey), 70 | getDisplayStringFor(remoteStableIdentifier, remoteIdentityKey)); 71 | 72 | ScannableFingerprint scannableFingerprint = new ScannableFingerprint(VERSION, 73 | localStableIdentifier, localIdentityKey, 74 | remoteStableIdentifier, remoteIdentityKey); 75 | 76 | return new Fingerprint(displayableFingerprint, scannableFingerprint); 77 | } 78 | 79 | private string getDisplayStringFor(string stableIdentifier, IdentityKey identityKey) 80 | { 81 | try 82 | { 83 | IHashAlgorithmProvider digest = HashAlgorithmProvider.OpenAlgorithm(PCLCrypto.HashAlgorithm.Sha512); 84 | 85 | byte[] publicKey = identityKey.getPublicKey().serialize(); 86 | byte[] hash = ByteUtil.combine(ByteUtil.shortToByteArray(VERSION), 87 | publicKey, Encoding.UTF8.GetBytes(stableIdentifier)); 88 | 89 | for (int i = 0; i < iterations; i++) 90 | { 91 | hash = digest.HashData(ByteUtil.combine(new byte[][] { hash, publicKey })); 92 | } 93 | 94 | return getEncodedChunk(hash, 0) + 95 | getEncodedChunk(hash, 5) + 96 | getEncodedChunk(hash, 10) + 97 | getEncodedChunk(hash, 15) + 98 | getEncodedChunk(hash, 20) + 99 | getEncodedChunk(hash, 25); 100 | } 101 | catch (Exception e) 102 | { 103 | Debug.Assert(false, e.Message); 104 | throw e; 105 | } 106 | } 107 | 108 | private String getEncodedChunk(byte[] hash, int offset) 109 | { 110 | long chunk = ByteUtil.byteArray5ToLong(hash, offset) % 100000; 111 | return chunk.ToString().PadLeft(5, '0'); 112 | } 113 | 114 | } 115 | 116 | } -------------------------------------------------------------------------------- /signal-protocol-pcl/ratchet/BobSignalProtocolParameters.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal.ecc; 19 | using Strilanc.Value; 20 | using System; 21 | 22 | namespace libsignal.ratchet 23 | { 24 | public class BobSignalProtocolParameters 25 | { 26 | 27 | private readonly IdentityKeyPair ourIdentityKey; 28 | private readonly ECKeyPair ourSignedPreKey; 29 | private readonly May ourOneTimePreKey; 30 | private readonly ECKeyPair ourRatchetKey; 31 | 32 | private readonly IdentityKey theirIdentityKey; 33 | private readonly ECPublicKey theirBaseKey; 34 | 35 | BobSignalProtocolParameters(IdentityKeyPair ourIdentityKey, ECKeyPair ourSignedPreKey, 36 | ECKeyPair ourRatchetKey, May ourOneTimePreKey, 37 | IdentityKey theirIdentityKey, ECPublicKey theirBaseKey) 38 | { 39 | this.ourIdentityKey = ourIdentityKey; 40 | this.ourSignedPreKey = ourSignedPreKey; 41 | this.ourRatchetKey = ourRatchetKey; 42 | this.ourOneTimePreKey = ourOneTimePreKey; 43 | this.theirIdentityKey = theirIdentityKey; 44 | this.theirBaseKey = theirBaseKey; 45 | 46 | if (ourIdentityKey == null || ourSignedPreKey == null || ourRatchetKey == null || 47 | ourOneTimePreKey == null || theirIdentityKey == null || theirBaseKey == null) 48 | { 49 | throw new Exception("Null value!"); 50 | } 51 | } 52 | 53 | public IdentityKeyPair getOurIdentityKey() 54 | { 55 | return ourIdentityKey; 56 | } 57 | 58 | public ECKeyPair getOurSignedPreKey() 59 | { 60 | return ourSignedPreKey; 61 | } 62 | 63 | public May getOurOneTimePreKey() 64 | { 65 | return ourOneTimePreKey; 66 | } 67 | 68 | public IdentityKey getTheirIdentityKey() 69 | { 70 | return theirIdentityKey; 71 | } 72 | 73 | public ECPublicKey getTheirBaseKey() 74 | { 75 | return theirBaseKey; 76 | } 77 | 78 | public static Builder newBuilder() 79 | { 80 | return new Builder(); 81 | } 82 | 83 | public ECKeyPair getOurRatchetKey() 84 | { 85 | return ourRatchetKey; 86 | } 87 | 88 | public class Builder 89 | { 90 | private IdentityKeyPair ourIdentityKey; 91 | private ECKeyPair ourSignedPreKey; 92 | private May ourOneTimePreKey; 93 | private ECKeyPair ourRatchetKey; 94 | 95 | private IdentityKey theirIdentityKey; 96 | private ECPublicKey theirBaseKey; 97 | 98 | public Builder setOurIdentityKey(IdentityKeyPair ourIdentityKey) 99 | { 100 | this.ourIdentityKey = ourIdentityKey; 101 | return this; 102 | } 103 | 104 | public Builder setOurSignedPreKey(ECKeyPair ourSignedPreKey) 105 | { 106 | this.ourSignedPreKey = ourSignedPreKey; 107 | return this; 108 | } 109 | 110 | public Builder setOurOneTimePreKey(May ourOneTimePreKey) 111 | { 112 | this.ourOneTimePreKey = ourOneTimePreKey; 113 | return this; 114 | } 115 | 116 | public Builder setTheirIdentityKey(IdentityKey theirIdentityKey) 117 | { 118 | this.theirIdentityKey = theirIdentityKey; 119 | return this; 120 | } 121 | 122 | public Builder setTheirBaseKey(ECPublicKey theirBaseKey) 123 | { 124 | this.theirBaseKey = theirBaseKey; 125 | return this; 126 | } 127 | 128 | public Builder setOurRatchetKey(ECKeyPair ourRatchetKey) 129 | { 130 | this.ourRatchetKey = ourRatchetKey; 131 | return this; 132 | } 133 | 134 | public BobSignalProtocolParameters create() 135 | { 136 | return new BobSignalProtocolParameters(ourIdentityKey, ourSignedPreKey, ourRatchetKey, 137 | ourOneTimePreKey, theirIdentityKey, theirBaseKey); 138 | } 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /signal-protocol-pcl/ratchet/AliceSignalProtocolParameters.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal.ecc; 19 | using Strilanc.Value; 20 | using System; 21 | 22 | namespace libsignal.ratchet 23 | { 24 | public class AliceSignalProtocolParameters 25 | { 26 | 27 | private readonly IdentityKeyPair ourIdentityKey; 28 | private readonly ECKeyPair ourBaseKey; 29 | 30 | private readonly IdentityKey theirIdentityKey; 31 | private readonly ECPublicKey theirSignedPreKey; 32 | private readonly May theirOneTimePreKey; 33 | private readonly ECPublicKey theirRatchetKey; 34 | 35 | private AliceSignalProtocolParameters(IdentityKeyPair ourIdentityKey, ECKeyPair ourBaseKey, 36 | IdentityKey theirIdentityKey, ECPublicKey theirSignedPreKey, 37 | ECPublicKey theirRatchetKey, May theirOneTimePreKey) 38 | { 39 | this.ourIdentityKey = ourIdentityKey; 40 | this.ourBaseKey = ourBaseKey; 41 | this.theirIdentityKey = theirIdentityKey; 42 | this.theirSignedPreKey = theirSignedPreKey; 43 | this.theirRatchetKey = theirRatchetKey; 44 | this.theirOneTimePreKey = theirOneTimePreKey; 45 | 46 | if (ourIdentityKey == null || ourBaseKey == null || theirIdentityKey == null || 47 | theirSignedPreKey == null || theirRatchetKey == null || theirOneTimePreKey == null) 48 | { 49 | throw new Exception("Null values!"); 50 | } 51 | } 52 | 53 | public IdentityKeyPair getOurIdentityKey() 54 | { 55 | return ourIdentityKey; 56 | } 57 | 58 | public ECKeyPair getOurBaseKey() 59 | { 60 | return ourBaseKey; 61 | } 62 | 63 | public IdentityKey getTheirIdentityKey() 64 | { 65 | return theirIdentityKey; 66 | } 67 | 68 | public ECPublicKey getTheirSignedPreKey() 69 | { 70 | return theirSignedPreKey; 71 | } 72 | 73 | public May getTheirOneTimePreKey() 74 | { 75 | return theirOneTimePreKey; 76 | } 77 | 78 | public static Builder newBuilder() 79 | { 80 | return new Builder(); 81 | } 82 | 83 | public ECPublicKey getTheirRatchetKey() 84 | { 85 | return theirRatchetKey; 86 | } 87 | 88 | public class Builder 89 | { 90 | private IdentityKeyPair ourIdentityKey; 91 | private ECKeyPair ourBaseKey; 92 | 93 | private IdentityKey theirIdentityKey; 94 | private ECPublicKey theirSignedPreKey; 95 | private ECPublicKey theirRatchetKey; 96 | private May theirOneTimePreKey; 97 | 98 | public Builder setOurIdentityKey(IdentityKeyPair ourIdentityKey) 99 | { 100 | this.ourIdentityKey = ourIdentityKey; 101 | return this; 102 | } 103 | 104 | public Builder setOurBaseKey(ECKeyPair ourBaseKey) 105 | { 106 | this.ourBaseKey = ourBaseKey; 107 | return this; 108 | } 109 | 110 | public Builder setTheirRatchetKey(ECPublicKey theirRatchetKey) 111 | { 112 | this.theirRatchetKey = theirRatchetKey; 113 | return this; 114 | } 115 | 116 | public Builder setTheirIdentityKey(IdentityKey theirIdentityKey) 117 | { 118 | this.theirIdentityKey = theirIdentityKey; 119 | return this; 120 | } 121 | 122 | public Builder setTheirSignedPreKey(ECPublicKey theirSignedPreKey) 123 | { 124 | this.theirSignedPreKey = theirSignedPreKey; 125 | return this; 126 | } 127 | 128 | public Builder setTheirOneTimePreKey(May theirOneTimePreKey) 129 | { 130 | this.theirOneTimePreKey = theirOneTimePreKey; 131 | return this; 132 | } 133 | 134 | public AliceSignalProtocolParameters create() 135 | { 136 | return new AliceSignalProtocolParameters(ourIdentityKey, ourBaseKey, theirIdentityKey, 137 | theirSignedPreKey, theirRatchetKey, theirOneTimePreKey); 138 | } 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /signal-protocol-pcl/fingerprint/ScannableFingerprint.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using Google.ProtocolBuffers; 19 | using libsignal; 20 | using libsignal.util; 21 | using System.Text; 22 | using static libsignal.fingerprint.FingerprintProtos; 23 | 24 | namespace org.whispersystems.libsignal.fingerprint 25 | { 26 | 27 | public class ScannableFingerprint 28 | { 29 | 30 | private readonly CombinedFingerprint combinedFingerprint; 31 | 32 | public ScannableFingerprint(int version, 33 | string localStableIdentifier, IdentityKey localIdentityKey, 34 | string remoteStableIdentifier, IdentityKey remoteIdentityKey) 35 | { 36 | this.combinedFingerprint = CombinedFingerprint.CreateBuilder() 37 | .SetVersion((uint)version) 38 | .SetLocalFingerprint(FingerprintData.CreateBuilder() 39 | .SetIdentifier(ByteString.CopyFrom(Encoding.UTF8.GetBytes(localStableIdentifier))) 40 | .SetPublicKey(ByteString.CopyFrom(localIdentityKey.serialize()))) 41 | .SetRemoteFingerprint(FingerprintData.CreateBuilder() 42 | .SetIdentifier(ByteString.CopyFrom(Encoding.UTF8.GetBytes(remoteStableIdentifier))) 43 | .SetPublicKey(ByteString.CopyFrom(remoteIdentityKey.serialize()))) 44 | .Build(); 45 | } 46 | 47 | /** 48 | * @return A byte string to be displayed in a QR code. 49 | */ 50 | public byte[] getSerialized() 51 | { 52 | return combinedFingerprint.ToByteArray(); 53 | } 54 | 55 | /** 56 | * Compare a scanned QR code with what we expect. 57 | * 58 | * @param scannedFingerprintData The scanned data 59 | * @return True if matching, otehrwise false. 60 | * @throws FingerprintVersionMismatchException if the scanned fingerprint is the wrong version. 61 | * @throws FingerprintIdentifierMismatchException if the scanned fingerprint is for the wrong stable identifier. 62 | */ 63 | public bool compareTo(byte[] scannedFingerprintData) 64 | /* throws FingerprintVersionMismatchException, 65 | FingerprintIdentifierMismatchException, 66 | FingerprintParsingException */ 67 | { 68 | try 69 | { 70 | CombinedFingerprint scannedFingerprint = CombinedFingerprint.ParseFrom(scannedFingerprintData); 71 | 72 | if (!scannedFingerprint.HasRemoteFingerprint || !scannedFingerprint.HasLocalFingerprint || 73 | !scannedFingerprint.HasVersion || scannedFingerprint.Version != combinedFingerprint.Version) 74 | { 75 | throw new FingerprintVersionMismatchException(); 76 | } 77 | 78 | if (!combinedFingerprint.LocalFingerprint.Identifier.Equals(scannedFingerprint.RemoteFingerprint.Identifier) || 79 | !combinedFingerprint.RemoteFingerprint.Identifier.Equals(scannedFingerprint.LocalFingerprint.Identifier)) 80 | { 81 | throw new FingerprintIdentifierMismatchException(combinedFingerprint.LocalFingerprint.Identifier.ToStringUtf8(), 82 | combinedFingerprint.RemoteFingerprint.Identifier.ToStringUtf8(), 83 | scannedFingerprint.LocalFingerprint.Identifier.ToStringUtf8(), 84 | scannedFingerprint.RemoteFingerprint.Identifier.ToStringUtf8()); 85 | } 86 | 87 | return ByteUtil.isEqual(combinedFingerprint.LocalFingerprint.ToByteArray(), scannedFingerprint.RemoteFingerprint.ToByteArray()) && 88 | ByteUtil.isEqual(combinedFingerprint.RemoteFingerprint.ToByteArray(), scannedFingerprint.LocalFingerprint.ToByteArray()); 89 | } 90 | catch (InvalidProtocolBufferException e) 91 | { 92 | throw new FingerprintParsingException(e); 93 | } 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /signal-protocol-pcl/state/SessionRecord.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System.Collections.Generic; 19 | using System.Linq; 20 | using static libsignal.state.StorageProtos; 21 | 22 | namespace libsignal.state 23 | { 24 | /** 25 | * A SessionRecord encapsulates the state of an ongoing session. 26 | * 27 | * @author Moxie Marlinspike 28 | */ 29 | public class SessionRecord 30 | { 31 | 32 | private static int ARCHIVED_STATES_MAX_LENGTH = 40; 33 | 34 | private SessionState sessionState = new SessionState(); 35 | private LinkedList previousStates = new LinkedList(); 36 | private bool fresh = false; 37 | 38 | public SessionRecord() 39 | { 40 | this.fresh = true; 41 | } 42 | 43 | public SessionRecord(SessionState sessionState) 44 | { 45 | this.sessionState = sessionState; 46 | this.fresh = false; 47 | } 48 | 49 | public SessionRecord(byte[] serialized) 50 | { 51 | RecordStructure record = RecordStructure.ParseFrom(serialized); 52 | this.sessionState = new SessionState(record.CurrentSession); 53 | this.fresh = false; 54 | 55 | foreach (SessionStructure previousStructure in record.PreviousSessionsList) 56 | { 57 | previousStates.AddLast(new SessionState(previousStructure)); // add -> AddLast (java) 58 | } 59 | } 60 | 61 | public bool hasSessionState(uint version, byte[] aliceBaseKey) 62 | { 63 | if (sessionState.getSessionVersion() == version && 64 | Enumerable.SequenceEqual(aliceBaseKey, sessionState.getAliceBaseKey())) 65 | { 66 | return true; 67 | } 68 | 69 | foreach (SessionState state in previousStates) 70 | { 71 | if (state.getSessionVersion() == version && 72 | Enumerable.SequenceEqual(aliceBaseKey, state.getAliceBaseKey())) 73 | { 74 | return true; 75 | } 76 | } 77 | 78 | return false; 79 | } 80 | 81 | public SessionState getSessionState() 82 | { 83 | return sessionState; 84 | } 85 | 86 | /** 87 | * @return the list of all currently maintained "previous" session states. 88 | */ 89 | public LinkedList getPreviousSessionStates() 90 | { 91 | return previousStates; 92 | } 93 | 94 | 95 | public bool isFresh() 96 | { 97 | return fresh; 98 | } 99 | 100 | /** 101 | * Move the current {@link SessionState} into the list of "previous" session states, 102 | * and replace the current {@link org.whispersystems.libsignal.state.SessionState} 103 | * with a fresh reset instance. 104 | */ 105 | public void archiveCurrentState() 106 | { 107 | promoteState(new SessionState()); 108 | } 109 | 110 | public void promoteState(SessionState promotedState) 111 | { 112 | this.previousStates.AddFirst(sessionState); 113 | this.sessionState = promotedState; 114 | 115 | if (previousStates.Count > ARCHIVED_STATES_MAX_LENGTH) 116 | { 117 | previousStates.RemoveLast(); 118 | } 119 | } 120 | 121 | public void setState(SessionState sessionState) 122 | { 123 | this.sessionState = sessionState; 124 | } 125 | 126 | /** 127 | * @return a serialized version of the current SessionRecord. 128 | */ 129 | public byte[] serialize() 130 | { 131 | List previousStructures = new List(); 132 | 133 | foreach (SessionState previousState in previousStates) 134 | { 135 | previousStructures.Add(previousState.getStructure()); 136 | } 137 | 138 | RecordStructure record = RecordStructure.CreateBuilder() 139 | .SetCurrentSession(sessionState.getStructure()) 140 | .AddRangePreviousSessions(previousStructures) 141 | /*.AddAllPreviousSessions(previousStructures)*/ 142 | .Build(); 143 | 144 | return record.ToByteArray(); 145 | } 146 | 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /signal-protocol-pcl/util/HMAC.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | using System.Collections.Generic; 20 | using static PCLCrypto.WinRTCrypto; 21 | using PCLCrypto; 22 | 23 | namespace libsignal.util 24 | { 25 | public class Sign 26 | { 27 | public static byte[] sha256sum(byte[] key, byte[] message) 28 | { 29 | IMacAlgorithmProvider provider = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithm.HmacSha256); 30 | ICryptographicKey hmacKey = provider.CreateKey(key); 31 | byte [] hmac = CryptographicEngine.Sign(hmacKey, message); 32 | return hmac; 33 | } 34 | } 35 | 36 | public class Sha256 37 | { 38 | public static byte[] Sign(byte[] key, byte[] message) 39 | { 40 | IMacAlgorithmProvider provider = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithm.HmacSha256); 41 | ICryptographicKey hmacKey = provider.CreateKey(key); 42 | byte[] hmac = CryptographicEngine.Sign(hmacKey, message); 43 | return hmac; 44 | } 45 | 46 | public static bool Verify(byte[] key, byte[] message, byte[] signature) 47 | { 48 | IMacAlgorithmProvider provider = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithm.HmacSha256); 49 | 50 | ICryptographicKey hmacKey = provider.CreateKey(key); 51 | return CryptographicEngine.VerifySignature(hmacKey, message, signature); 52 | } 53 | } 54 | 55 | ///

56 | /// Encryption helpers 57 | /// 58 | public class Encrypt 59 | { 60 | /// 61 | /// Computes PKCS5 for the message 62 | /// 63 | /// plaintext 64 | /// PKCS5 of the message 65 | public static byte[] aesCbcPkcs5(byte[] message, byte[] key, byte[] iv) 66 | { 67 | ISymmetricKeyAlgorithmProvider objAlg = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7); // PKCS5 68 | ICryptographicKey ckey = objAlg.CreateSymmetricKey(key); 69 | byte [] result = CryptographicEngine.Encrypt(ckey, message, iv); 70 | return result; 71 | } 72 | 73 | public static byte[] aesCtr(byte[] message, byte[] key, uint counter) 74 | { 75 | ISymmetricKeyAlgorithmProvider objAlg = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7); // CRT 76 | ICryptographicKey ckey = objAlg.CreateSymmetricKey(key); 77 | 78 | byte[] ivBytes = new byte[16]; 79 | ByteUtil.intToByteArray(ivBytes, 0, (int)counter); 80 | 81 | byte [] result = CryptographicEngine.Encrypt(ckey, message, ivBytes); 82 | return result; 83 | } 84 | 85 | 86 | } 87 | 88 | /// 89 | /// Decryption helpers 90 | /// 91 | public class Decrypt 92 | { 93 | public static byte[] aesCbcPkcs5(byte[] message, byte[] key, byte[] iv) 94 | { 95 | ISymmetricKeyAlgorithmProvider objAlg = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7); 96 | ICryptographicKey ckey = objAlg.CreateSymmetricKey(key); 97 | 98 | if (message.Length % objAlg.BlockLength != 0) throw new Exception("Invalid ciphertext length"); 99 | 100 | byte [] result = CryptographicEngine.Decrypt(ckey, message, iv); 101 | return result; 102 | } 103 | 104 | public static byte[] aesCtr(byte[] message, byte[] key, uint counter) 105 | { 106 | ISymmetricKeyAlgorithmProvider objAlg = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithm.AesCbcPkcs7); 107 | ICryptographicKey ckey = objAlg.CreateSymmetricKey(key); 108 | 109 | byte[] ivBytes = new byte[16]; 110 | ByteUtil.intToByteArray(ivBytes, 0, (int)counter); 111 | 112 | byte [] result = CryptographicEngine.Decrypt(ckey, message, ivBytes); 113 | return result; 114 | } 115 | } 116 | 117 | public static class CryptoHelper 118 | { 119 | /// 120 | /// TODO: dead code? 121 | /// 122 | public static void Shuffle(this IList list) 123 | { 124 | Random rng = new Random(); 125 | int n = list.Count; 126 | while (n > 1) 127 | { 128 | n--; 129 | int k = rng.Next(n + 1); 130 | T value = list[k]; 131 | list[k] = list[n]; 132 | list[n] = value; 133 | } 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /signal-protocol-pcl/protocol/SenderKeyMessage.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using Google.ProtocolBuffers; 19 | using libsignal.ecc; 20 | using libsignal.util; 21 | using System; 22 | 23 | namespace libsignal.protocol 24 | { 25 | public partial class SenderKeyMessage : CiphertextMessage 26 | { 27 | 28 | private static readonly int SIGNATURE_LENGTH = 64; 29 | 30 | private readonly uint messageVersion; 31 | private readonly uint keyId; 32 | private readonly uint iteration; 33 | private readonly byte[] ciphertext; 34 | private readonly byte[] serialized; 35 | 36 | public SenderKeyMessage(byte[] serialized) 37 | { 38 | try 39 | { 40 | byte[][] messageParts = ByteUtil.split(serialized, 1, serialized.Length - 1 - SIGNATURE_LENGTH, SIGNATURE_LENGTH); 41 | byte version = messageParts[0][0]; 42 | byte[] message = messageParts[1]; 43 | byte[] signature = messageParts[2]; 44 | 45 | if (ByteUtil.highBitsToInt(version) < 3) 46 | { 47 | throw new LegacyMessageException("Legacy message: " + ByteUtil.highBitsToInt(version)); 48 | } 49 | 50 | if (ByteUtil.highBitsToInt(version) > CURRENT_VERSION) 51 | { 52 | throw new InvalidMessageException("Unknown version: " + ByteUtil.highBitsToInt(version)); 53 | } 54 | 55 | WhisperProtos.SenderKeyMessage senderKeyMessage = WhisperProtos.SenderKeyMessage.ParseFrom(message); 56 | 57 | if (!senderKeyMessage.HasId || 58 | !senderKeyMessage.HasIteration || 59 | !senderKeyMessage.HasCiphertext) 60 | { 61 | throw new InvalidMessageException("Incomplete message."); 62 | } 63 | 64 | this.serialized = serialized; 65 | this.messageVersion = (uint)ByteUtil.highBitsToInt(version); 66 | this.keyId = senderKeyMessage.Id; 67 | this.iteration = senderKeyMessage.Iteration; 68 | this.ciphertext = senderKeyMessage.Ciphertext.ToByteArray(); 69 | } 70 | catch (/*InvalidProtocolBufferException | Parse*/Exception e) 71 | { 72 | throw new InvalidMessageException(e); 73 | } 74 | } 75 | 76 | public SenderKeyMessage(uint keyId, uint iteration, byte[] ciphertext, ECPrivateKey signatureKey) 77 | { 78 | byte[] version = { ByteUtil.intsToByteHighAndLow((int)CURRENT_VERSION, (int)CURRENT_VERSION) }; 79 | byte[] message = WhisperProtos.SenderKeyMessage.CreateBuilder() 80 | .SetId(keyId) 81 | .SetIteration(iteration) 82 | .SetCiphertext(ByteString.CopyFrom(ciphertext)) 83 | .Build().ToByteArray(); 84 | 85 | byte[] signature = getSignature(signatureKey, ByteUtil.combine(version, message)); 86 | 87 | this.serialized = ByteUtil.combine(version, message, signature); 88 | this.messageVersion = CURRENT_VERSION; 89 | this.keyId = keyId; 90 | this.iteration = iteration; 91 | this.ciphertext = ciphertext; 92 | } 93 | 94 | public uint getKeyId() 95 | { 96 | return keyId; 97 | } 98 | 99 | public uint getIteration() 100 | { 101 | return iteration; 102 | } 103 | 104 | public byte[] getCipherText() 105 | { 106 | return ciphertext; 107 | } 108 | 109 | public void verifySignature(ECPublicKey signatureKey) 110 | { 111 | try 112 | { 113 | byte[][] parts = ByteUtil.split(serialized, serialized.Length - SIGNATURE_LENGTH, SIGNATURE_LENGTH); 114 | 115 | if (!Curve.verifySignature(signatureKey, parts[0], parts[1])) 116 | { 117 | throw new InvalidMessageException("Invalid signature!"); 118 | } 119 | 120 | } 121 | catch (InvalidKeyException e) 122 | { 123 | throw new InvalidMessageException(e); 124 | } 125 | } 126 | 127 | private byte[] getSignature(ECPrivateKey signatureKey, byte[] serialized) 128 | { 129 | try 130 | { 131 | return Curve.calculateSignature(signatureKey, serialized); 132 | } 133 | catch (InvalidKeyException e) 134 | { 135 | throw new Exception(e.Message); 136 | } 137 | } 138 | 139 | public override byte[] serialize() 140 | { 141 | return serialized; 142 | } 143 | 144 | 145 | public override uint getType() 146 | { 147 | return CiphertextMessage.SENDERKEY_TYPE; 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /signal-protocol-tests/ratchet/ChainKeyTest.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal.kdf; 19 | using libsignal.ratchet; 20 | using Microsoft.VisualStudio.TestTools.UnitTesting; 21 | 22 | namespace libsignal_test 23 | { 24 | [TestClass] 25 | public class ChainKeyTest 26 | { 27 | [TestMethod, TestCategory("libsignal.ratchet")] 28 | public void testChainKeyDerivationV2() 29 | { 30 | byte[] seed = 31 | { 32 | 0x8a, 0xb7, 0x2d, 0x6f, 0x4c, 33 | 0xc5, 0xac, 0x0d, 0x38, 0x7e, 34 | 0xaf, 0x46, 0x33, 0x78, 0xdd, 35 | 0xb2, 0x8e, 0xdd, 0x07, 0x38, 36 | 0x5b, 0x1c, 0xb0, 0x12, 0x50, 37 | 0xc7, 0x15, 0x98, 0x2e, 0x7a, 38 | 0xd4, 0x8f 39 | }; 40 | 41 | byte[] messageKey = 42 | { 43 | 0x02, 0xa9, 0xaa, 0x6c, 0x7d, 44 | 0xbd, 0x64, 0xf9, 0xd3, 0xaa, 45 | 0x92, 0xf9, 0x2a, 0x27, 0x7b, 46 | 0xf5, 0x46, 0x09, 0xda, 0xdf, 47 | 0x0b, 0x00, 0x82, 0x8a, 0xcf, 48 | 0xc6, 0x1e, 0x3c, 0x72, 0x4b, 49 | 0x84, 0xa7 50 | }; 51 | 52 | byte[] macKey = 53 | { 54 | 0xbf, 0xbe, 0x5e, 0xfb, 0x60, 55 | 0x30, 0x30, 0x52, 0x67, 0x42, 56 | 0xe3, 0xee, 0x89, 0xc7, 0x02, 57 | 0x4e, 0x88, 0x4e, 0x44, 0x0f, 58 | 0x1f, 0xf3, 0x76, 0xbb, 0x23, 59 | 0x17, 0xb2, 0xd6, 0x4d, 0xeb, 60 | 0x7c, 0x83 61 | }; 62 | 63 | byte[] nextChainKey = 64 | { 65 | 0x28, 0xe8, 0xf8, 0xfe, 0xe5, 66 | 0x4b, 0x80, 0x1e, 0xef, 0x7c, 67 | 0x5c, 0xfb, 0x2f, 0x17, 0xf3, 68 | 0x2c, 0x7b, 0x33, 0x44, 0x85, 69 | 0xbb, 0xb7, 0x0f, 0xac, 0x6e, 70 | 0xc1, 0x03, 0x42, 0xa2, 0x46, 71 | 0xd1, 0x5d 72 | }; 73 | 74 | ChainKey chainKey = new ChainKey(HKDF.createFor(2), seed, 0); 75 | 76 | Assert.AreEqual(seed, chainKey.getKey()); 77 | CollectionAssert.AreEqual(messageKey, chainKey.getMessageKeys().getCipherKey()); 78 | CollectionAssert.AreEqual(macKey, chainKey.getMessageKeys().getMacKey()); 79 | CollectionAssert.AreEqual(nextChainKey, chainKey.getNextChainKey().getKey()); 80 | Assert.AreEqual(0, chainKey.getIndex()); 81 | Assert.AreEqual(0, chainKey.getMessageKeys().getCounter()); 82 | Assert.AreEqual(1, chainKey.getNextChainKey().getIndex()); 83 | Assert.AreEqual(1, chainKey.getNextChainKey().getMessageKeys().getCounter()); 84 | } 85 | 86 | [TestMethod, TestCategory("libsignal.ratchet")] 87 | public void testChainKeyDerivationV3() 88 | { 89 | byte[] seed = 90 | { 91 | 0x8a, 0xb7, 0x2d, 0x6f, 0x4c, 92 | 0xc5, 0xac, 0x0d, 0x38, 0x7e, 93 | 0xaf, 0x46, 0x33, 0x78, 0xdd, 94 | 0xb2, 0x8e, 0xdd, 0x07, 0x38, 95 | 0x5b, 0x1c, 0xb0, 0x12, 0x50, 96 | 0xc7, 0x15, 0x98, 0x2e, 0x7a, 97 | 0xd4, 0x8f 98 | }; 99 | 100 | byte[] messageKey = 101 | { 102 | /* 0x02*/ 103 | 0xbf, 0x51, 0xe9, 0xd7, 104 | 0x5e, 0x0e, 0x31, 0x03, 0x10, 105 | 0x51, 0xf8, 0x2a, 0x24, 0x91, 106 | 0xff, 0xc0, 0x84, 0xfa, 0x29, 107 | 0x8b, 0x77, 0x93, 0xbd, 0x9d, 108 | 0xb6, 0x20, 0x05, 0x6f, 0xeb, 109 | 0xf4, 0x52, 0x17 110 | }; 111 | 112 | byte[] macKey = 113 | { 114 | 0xc6, 0xc7, 0x7d, 0x6a, 0x73, 115 | 0xa3, 0x54, 0x33, 0x7a, 0x56, 116 | 0x43, 0x5e, 0x34, 0x60, 0x7d, 117 | 0xfe, 0x48, 0xe3, 0xac, 0xe1, 118 | 0x4e, 0x77, 0x31, 0x4d, 0xc6, 119 | 0xab, 0xc1, 0x72, 0xe7, 0xa7, 120 | 0x03, 0x0b 121 | }; 122 | 123 | byte[] nextChainKey = 124 | { 125 | 0x28, 0xe8, 0xf8, 0xfe, 0xe5, 126 | 0x4b, 0x80, 0x1e, 0xef, 0x7c, 127 | 0x5c, 0xfb, 0x2f, 0x17, 0xf3, 128 | 0x2c, 0x7b, 0x33, 0x44, 0x85, 129 | 0xbb, 0xb7, 0x0f, 0xac, 0x6e, 130 | 0xc1, 0x03, 0x42, 0xa2, 0x46, 131 | 0xd1, 0x5d 132 | }; 133 | 134 | ChainKey chainKey = new ChainKey(HKDF.createFor(3), seed, 0); 135 | 136 | CollectionAssert.AreEqual(seed, chainKey.getKey()); 137 | CollectionAssert.AreEqual(messageKey, chainKey.getMessageKeys().getCipherKey()); 138 | CollectionAssert.AreEqual(macKey, chainKey.getMessageKeys().getMacKey()); 139 | CollectionAssert.AreEqual(nextChainKey, chainKey.getNextChainKey().getKey()); 140 | Assert.AreEqual(0, chainKey.getIndex()); 141 | Assert.AreEqual(0, chainKey.getMessageKeys().getCounter()); 142 | Assert.AreEqual(1, chainKey.getNextChainKey().getIndex()); 143 | Assert.AreEqual(1, chainKey.getNextChainKey().getMessageKeys().getCounter()); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /signal-protocol-pcl/ecc/Curve25519.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 smndtrl, langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using libsignal.ecc.impl; 19 | using static PCLCrypto.WinRTCrypto; 20 | 21 | namespace libsignal.ecc 22 | { 23 | /// 24 | /// Choose between various implementations of Curve25519 (native, managed, etc). 25 | /// 26 | public enum Curve25519ProviderType 27 | { 28 | /// 29 | /// Attempt to provide a native implementation. If one is not available, error out (TODO, break apart managed and native implementations in NuGet packages where we can dynamically use what is best based on the current environment). 30 | /// 31 | BEST = 0x05, 32 | /// 33 | /// Explicitly use the native implementation 34 | /// 35 | NATIVE 36 | } 37 | 38 | class Curve25519 39 | { 40 | private static Curve25519 instance; 41 | private ICurve25519Provider provider; 42 | 43 | private Curve25519() { } 44 | 45 | /// 46 | /// Accesses the currently in use Curve25519 provider, according to the type requested. 47 | /// 48 | /// Type of provider requested. 49 | /// Provider 50 | public static Curve25519 getInstance(Curve25519ProviderType type) 51 | { 52 | if (instance == null) 53 | { 54 | instance = new Curve25519(); 55 | switch (type) 56 | { 57 | case Curve25519ProviderType.NATIVE: 58 | { 59 | instance.provider = (ICurve25519Provider)new Curve25519NativeProvider(); 60 | break; 61 | } 62 | case Curve25519ProviderType.BEST: 63 | { 64 | instance.provider = (ICurve25519Provider)new Curve25519ManagedProvider( 65 | org.whispersystems.curve25519.Curve25519.BEST); 66 | break; 67 | } 68 | } 69 | } 70 | return instance; 71 | } 72 | 73 | /// 74 | /// is backed by a WinRT implementation of curve25519. Returns true for native. 75 | /// 76 | /// True. Backed by a native provider. 77 | public bool isNative() 78 | { 79 | return provider.isNative(); 80 | } 81 | 82 | /// 83 | /// Generates a Curve25519 keypair. 84 | /// 85 | /// A randomly generated Curve25519 keypair. 86 | public Curve25519KeyPair generateKeyPair() 87 | { 88 | byte[] random = CryptographicBuffer.GenerateRandom(32); 89 | byte[] privateKey = provider.generatePrivateKey(random); 90 | byte[] publicKey = provider.generatePublicKey(privateKey); 91 | 92 | return new Curve25519KeyPair(publicKey, privateKey); 93 | } 94 | 95 | /// 96 | /// Calculates an ECDH agreement. 97 | /// 98 | /// The Curve25519 (typically remote party's) public key. 99 | /// The Curve25519 (typically yours) private key. 100 | /// A 32-byte shared secret. 101 | public byte[] calculateAgreement(byte[] publicKey, byte[] privateKey) 102 | { 103 | return provider.calculateAgreement(privateKey, publicKey); 104 | } 105 | 106 | /// 107 | /// Calculates a Curve25519 signature. 108 | /// 109 | /// The private Curve25519 key to create the signature with. 110 | /// The message to sign. 111 | /// 64 byte signature 112 | public byte[] calculateSignature(byte[] privateKey, byte[] message) 113 | { 114 | 115 | byte[] random = CryptographicBuffer.GenerateRandom(64); 116 | return provider.calculateSignature(random, privateKey, message); 117 | } 118 | 119 | /// 120 | /// Verify a Curve25519 signature. 121 | /// 122 | /// The Curve25519 public key the signature belongs to. 123 | /// The message that was signed. 124 | /// The signature to verify. 125 | /// Boolean for if valid 126 | public bool verifySignature(byte[] publicKey, byte[] message, byte[] signature) 127 | { 128 | return provider.verifySignature(publicKey, message, signature); 129 | } 130 | } 131 | 132 | /// 133 | /// Curve25519 public and private key stored together. 134 | /// 135 | public class Curve25519KeyPair 136 | { 137 | 138 | private readonly byte[] publicKey; 139 | private readonly byte[] privateKey; 140 | 141 | /// 142 | /// Create a curve 25519 keypair from a public and private keys. 143 | /// 144 | /// 32 byte public key 145 | /// 32 byte private key 146 | public Curve25519KeyPair(byte[] publicKey, byte[] privateKey) 147 | { 148 | this.publicKey = publicKey; 149 | this.privateKey = privateKey; 150 | } 151 | 152 | /// 153 | /// Curve25519 public key 154 | /// 155 | /// 156 | public byte[] getPublicKey() 157 | { 158 | return publicKey; 159 | } 160 | 161 | /// 162 | /// Curve25519 private key 163 | /// 164 | /// 165 | public byte[] getPrivateKey() 166 | { 167 | return privateKey; 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /signal-protocol-tests/fingerprint/NumericFingerprintGeneratorTest.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2016 langboost 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | using System; 19 | using Microsoft.VisualStudio.TestTools.UnitTesting; 20 | using libsignal.ecc; 21 | using libsignal; 22 | 23 | namespace org.whispersystems.libsignal.fingerprint 24 | { 25 | [TestClass] 26 | public class NumericFingerprintGeneratorTest 27 | { 28 | [TestMethod] 29 | public void testMatchingFingerprints() 30 | { 31 | ECKeyPair aliceKeyPair = Curve.generateKeyPair(); 32 | ECKeyPair bobKeyPair = Curve.generateKeyPair(); 33 | 34 | IdentityKey aliceIdentityKey = new IdentityKey(aliceKeyPair.getPublicKey()); 35 | IdentityKey bobIdentityKey = new IdentityKey(bobKeyPair.getPublicKey()); 36 | 37 | NumericFingerprintGenerator generator = new NumericFingerprintGenerator(1024); 38 | Fingerprint aliceFingerprint = generator.createFor("+14152222222", aliceIdentityKey, 39 | "+14153333333", bobIdentityKey); 40 | 41 | Fingerprint bobFingerprint = generator.createFor("+14153333333", bobIdentityKey, 42 | "+14152222222", aliceIdentityKey); 43 | 44 | Assert.AreEqual(aliceFingerprint.getDisplayableFingerprint().getDisplayText(), 45 | bobFingerprint.getDisplayableFingerprint().getDisplayText()); 46 | 47 | Assert.IsTrue( 48 | aliceFingerprint.getScannableFingerprint().compareTo( 49 | bobFingerprint.getScannableFingerprint().getSerialized())); 50 | Assert.IsTrue( 51 | bobFingerprint.getScannableFingerprint().compareTo( 52 | aliceFingerprint.getScannableFingerprint().getSerialized())); 53 | 54 | Assert.AreEqual(aliceFingerprint.getDisplayableFingerprint().getDisplayText().Length, 60); 55 | } 56 | 57 | [TestMethod] 58 | public void testMismatchingFingerprints() 59 | { 60 | ECKeyPair aliceKeyPair = Curve.generateKeyPair(); 61 | ECKeyPair bobKeyPair = Curve.generateKeyPair(); 62 | ECKeyPair mitmKeyPair = Curve.generateKeyPair(); 63 | 64 | IdentityKey aliceIdentityKey = new IdentityKey(aliceKeyPair.getPublicKey()); 65 | IdentityKey bobIdentityKey = new IdentityKey(bobKeyPair.getPublicKey()); 66 | IdentityKey mitmIdentityKey = new IdentityKey(mitmKeyPair.getPublicKey()); 67 | 68 | NumericFingerprintGenerator generator = new NumericFingerprintGenerator(1024); 69 | Fingerprint aliceFingerprint = generator.createFor("+14152222222", aliceIdentityKey, 70 | "+14153333333", mitmIdentityKey); 71 | 72 | Fingerprint bobFingerprint = generator.createFor("+14153333333", bobIdentityKey, 73 | "+14152222222", aliceIdentityKey); 74 | 75 | Assert.AreNotEqual(aliceFingerprint.getDisplayableFingerprint().getDisplayText(), 76 | bobFingerprint.getDisplayableFingerprint().getDisplayText()); 77 | 78 | Assert.IsFalse(aliceFingerprint.getScannableFingerprint().compareTo(bobFingerprint.getScannableFingerprint().getSerialized())); 79 | Assert.IsFalse(bobFingerprint.getScannableFingerprint().compareTo(aliceFingerprint.getScannableFingerprint().getSerialized())); 80 | } 81 | 82 | [TestMethod] 83 | public void testMismatchingIdentifiers() 84 | { 85 | ECKeyPair aliceKeyPair = Curve.generateKeyPair(); 86 | ECKeyPair bobKeyPair = Curve.generateKeyPair(); 87 | 88 | IdentityKey aliceIdentityKey = new IdentityKey(aliceKeyPair.getPublicKey()); 89 | IdentityKey bobIdentityKey = new IdentityKey(bobKeyPair.getPublicKey()); 90 | 91 | NumericFingerprintGenerator generator = new NumericFingerprintGenerator(1024); 92 | Fingerprint aliceFingerprint = generator.createFor("+141512222222", aliceIdentityKey, 93 | "+14153333333", bobIdentityKey); 94 | 95 | Fingerprint bobFingerprint = generator.createFor("+14153333333", bobIdentityKey, 96 | "+14152222222", aliceIdentityKey); 97 | 98 | Assert.AreNotEqual(aliceFingerprint.getDisplayableFingerprint().getDisplayText(), 99 | bobFingerprint.getDisplayableFingerprint().getDisplayText()); 100 | 101 | try 102 | { 103 | ; 104 | aliceFingerprint.getScannableFingerprint().compareTo(bobFingerprint.getScannableFingerprint().getSerialized()); 105 | throw new Exception("Should mismatch!"); 106 | } 107 | catch (FingerprintIdentifierMismatchException) 108 | { 109 | // good 110 | } 111 | 112 | try 113 | { 114 | bobFingerprint.getScannableFingerprint().compareTo(aliceFingerprint.getScannableFingerprint().getSerialized()); 115 | throw new Exception("Should mismatch!"); 116 | } 117 | catch (FingerprintIdentifierMismatchException) 118 | { 119 | // good 120 | } 121 | } 122 | 123 | } 124 | } --------------------------------------------------------------------------------