public ServerConnection(string baseUrl, Curve25519KeyPair deviceKey, string deviceUuid = null) { _client = new HttpClient(); _baseUrl = baseUrl; _deviceKey = deviceKey; _deviceUuid = deviceUuid; }
public void testUniqueSignatures() { Curve25519KeyPair keys = curve25519.generateKeyPair(); Random random = new Random(); for (int i = 1; i <= 256; i++) { byte[] message = new byte[i]; random.NextBytes(message); byte[] signature = curve25519.calculateVrfSignature(keys.getPrivateKey(), message); byte[] vrf = curve25519.verifyVrfSignature(keys.getPublicKey(), message, signature); Assert.IsFalse(curve25519.verifySignature(keys.getPublicKey(), message, signature)); message[Math.Abs(random.Next(int.MaxValue)) % message.Length] ^= 0x01; try { curve25519.verifyVrfSignature(keys.getPublicKey(), message, signature); throw new InvalidOperationException("Should have failed"); } catch (VrfSignatureVerificationFailedException e) { // good } } }
private async void OnSetUpPressed(object sender, EventArgs e) { string serverUrl = ServerEntry.Text; string devicePrivateKeyBase64 = await _secureStorageService.GetAsync("devicePrivateKey"); Curve25519KeyPair deviceKeyPair; if (devicePrivateKeyBase64 is null) { deviceKeyPair = new Curve25519KeyPair(); await _secureStorageService.SetAsync("devicePrivateKey", Convert.ToBase64String(deviceKeyPair.EdPrivateKey)); } else { deviceKeyPair = new Curve25519KeyPair(Convert.FromBase64String(devicePrivateKeyBase64), true, true); } _connection = new ServerConnection(serverUrl, deviceKeyPair); string deviceUuid = await _connection.RegisterDeviceAsync(); string userUuid = await _connection.RegisterUserAsync(EmailEntry.Text, GlobalKeyStore.Instance.IdentityKeyPair, GlobalKeyStore.Instance.SignedPreKeyPairs[0], ":)", "Non-contradictory"); await _connection.UploadOneTimePreKeysAsync(GlobalKeyStore.Instance.OneTimePreKeyPairs); await DisplayAlert("Information: ", $"Device ID: {deviceUuid}\nUser ID: {userUuid}", "Ok"); EmailEntry.Text = userUuid; }
public static async Task <Dictionary <string, RemoteAttestation> > GetAndVerifyMultiRemoteAttestation(PushServiceSocket socket, PushServiceSocket.ClientSet clientSet, string enclaveName, string mrenclave, string authorization) { Curve25519KeyPair keyPair = BuildKeyPair(); ResponsePair result = await MakeAttestationRequestAsync(socket, clientSet, authorization, enclaveName, keyPair); MultiRemoteAttestationResponse response = JsonUtil.FromJson <MultiRemoteAttestationResponse>(result.body); Dictionary <string, RemoteAttestation> attestations = new Dictionary <string, RemoteAttestation>(); if (response.Attestations !.Count == 0 || response.Attestations.Count > 3) { throw new MalformedResponseException($"Incorrect number of attestations: {response.Attestations.Count}"); } foreach (var entry in response.Attestations) { attestations.Add(entry.Key, ValidateAndBuildRemoteAttestation(entry.Value, result.cookies, keyPair, mrenclave)); } return(attestations); }
public static EcKeyPair GenerateKeyPair() { Curve25519KeyPair keyPair = Curve25519.GetInstance(Curve25519ProviderType.Best).GenerateKeyPair(); return(new EcKeyPair(new DjbEcPublicKey(keyPair.GetPublicKey()), new DjbEcPrivateKey(keyPair.GetPrivateKey()))); }
public static ECKeyPair generateKeyPair() { Curve25519KeyPair keyPair = Curve25519.getInstance(Curve25519ProviderType.BEST).generateKeyPair(); return(new ECKeyPair(new DjbECPublicKey(keyPair.getPublicKey()), new DjbECPrivateKey(keyPair.getPrivateKey()))); }
public async Task <ChatPackage> GetChatPackage(string userUuid) { HttpResponseMessage response = await PostAuthenticatedAsync($"/users/{userUuid}/package"); Dictionary <string, string> responseDict = await HandleResponse <string>(response).ConfigureAwait(false); // TODO check all keys are present in dictionary Curve25519KeyPair otherIdentityKey = new Curve25519KeyPair(Convert.FromBase64String(responseDict["identity_key"]), false, true); Curve25519KeyPair otherSignedPreKey = new Curve25519KeyPair(Convert.FromBase64String(responseDict["signed_prekey"]), false, false); byte[] otherSignedPreKeySignature = Convert.FromBase64String(responseDict["prekey_signature"]); Curve25519KeyPair otherOneTimePreKey = new Curve25519KeyPair(Convert.FromBase64String(responseDict["onetime_key"]), false, false); if (!otherIdentityKey.Verify(otherSignedPreKey.XPublicKey, otherSignedPreKeySignature)) { throw new ServerConnectionException($"The user's pre-key signature does not match their signed key: uuid = {userUuid}"); } return(new ChatPackage { OtherIdentityKey = otherIdentityKey, OtherSignedPreKey = otherSignedPreKey, OtherOneTimePreKey = otherOneTimePreKey }); }
public void testUniqueSignatureVector() { Curve25519KeyPair keys = new Curve25519KeyPair(PUBLIC_KEY, PRIVATE_KEY); byte[] signature = curve25519.calculateVrfSignature(keys.getPrivateKey(), MESSAGE); byte[] vrf = curve25519.verifyVrfSignature(keys.getPublicKey(), MESSAGE, signature); CollectionAssert.AreEqual(VRF, vrf); }
public static async Task <RemoteAttestation> GetAndVerifyRemoteAttestationAsync(PushServiceSocket socket, PushServiceSocket.ClientSet clientSet, string enclaveName, string mrenclave, string authorization) { Curve25519KeyPair keyPair = BuildKeyPair(); ResponsePair result = await MakeAttestationRequestAsync(socket, clientSet, authorization, enclaveName, keyPair); RemoteAttestationResponse response = JsonUtil.FromJson <RemoteAttestationResponse>(result.body); return(ValidateAndBuildRemoteAttestation(response, result.cookies, keyPair, mrenclave)); }
public RemoteAttestationKeys(Curve25519KeyPair keyPair, byte[] serverPublicEphemeral, byte[] serverPublicStatic) { byte[] ephemeralToEphemeral = Curve25519.getInstance(Curve25519.BEST).calculateAgreement(serverPublicEphemeral, keyPair.getPrivateKey()); byte[] ephemeralToStatic = Curve25519.getInstance(Curve25519.BEST).calculateAgreement(serverPublicStatic, keyPair.getPrivateKey()); byte[] masterSecret = ByteUtil.combine(ephemeralToEphemeral, ephemeralToStatic); byte[] publicKeys = ByteUtil.combine(keyPair.getPublicKey(), serverPublicEphemeral, serverPublicStatic); HkdfBytesGenerator generator = new HkdfBytesGenerator(new Sha256Digest()); generator.Init(new HkdfParameters(masterSecret, publicKeys, null)); generator.GenerateBytes(ClientKey, 0, ClientKey.Length); generator.GenerateBytes(ServerKey, 0, ServerKey.Length); }
public MainPage() { InitializeComponent(); Curve25519KeyPair identityKey = new Curve25519KeyPair(); Curve25519KeyPair signedPreKey = new Curve25519KeyPair(); Curve25519KeyPair oneTimePreKey = new Curve25519KeyPair(); GlobalKeyStore.Initialise(identityKey, new List <Curve25519KeyPair> { signedPreKey }, new List <Curve25519KeyPair> { oneTimePreKey }, new Dictionary <string, ChatState>()); }
private static RemoteAttestation ValidateAndBuildRemoteAttestation(RemoteAttestationResponse response, List <string> cookies, Curve25519KeyPair keyPair, string mrenclave) { RemoteAttestationKeys keys = new RemoteAttestationKeys(keyPair, response.ServerEphemeralPublic, response.ServerStaticPublic); Quote quote = new Quote(response.Quote); byte[] requestId = RemoteAttestationCipher.GetRequestId(keys, response); RemoteAttestationCipher.VerifyServerQuote(quote, response.ServerStaticPublic, mrenclave); RemoteAttestationCipher.VerifyIasSignature(response.Certificates, response.SignatureBody, response.Signature, quote); return(new RemoteAttestation(requestId, keys, cookies)); }
private static async Task <ResponsePair> MakeAttestationRequestAsync(PushServiceSocket socket, PushServiceSocket.ClientSet clientSet, string authorization, string enclaveName, Curve25519KeyPair keyPair) { RemoteAttestationRequest attestationRequest = new RemoteAttestationRequest(keyPair.getPublicKey()); HttpResponseMessage response = await socket.MakeRequestAsync(clientSet, authorization, new List <string>(), $"/v1/attestation/{enclaveName}", "PUT", JsonUtil.ToJson(attestationRequest)); HttpContent body = response.Content; if (body == null) { throw new MalformedResponseException("Empty response!"); } return(new ResponsePair(await body.ReadAsStringAsync(), ParseCookies(response))); }
public static void Initialise(Curve25519KeyPair identityKeyPair, List <Curve25519KeyPair> signedPreKeyPairs, List <Curve25519KeyPair> oneTimePreKeyPairs, Dictionary <string, ChatState> chatStates) { lock (Locker) { if (!(_instance is null)) { throw new Exception("GlobalKeyStore has already been initialised"); } _instance = new GlobalKeyStore { IdentityKeyPair = identityKeyPair, SignedPreKeyPairs = signedPreKeyPairs, OneTimePreKeyPairs = oneTimePreKeyPairs, ChatStates = chatStates }; } }
// Returns the User UUID public async Task <string> RegisterUserAsync(string email, Curve25519KeyPair userKeyPair, Curve25519KeyPair signedPreKeyPair, string nickname = null, string bio = null) { Dictionary <string, string> contentDict = new Dictionary <string, string> { { "email", email }, { "identity_key", Convert.ToBase64String(userKeyPair.EdPublicKey) }, { "signed_prekey", Convert.ToBase64String(signedPreKeyPair.XPublicKey) }, { "prekey_signature", Convert.ToBase64String(userKeyPair.Sign(signedPreKeyPair.XPublicKey)) }, { "nickname", nickname }, { "bio", bio } }; HttpResponseMessage response = await PostAuthenticatedAsync("/users/new", contentDict).ConfigureAwait(false); Dictionary <string, string> responseDict = await HandleResponse <string>(response).ConfigureAwait(false); if (!responseDict.ContainsKey("user_id")) { throw new ServerConnectionException($"User UUID not found in response content: {responseDict}"); } return(responseDict["user_id"]); }
public static MetaMessage ComposeInitialMessage(string recipientUuid, ChatPackage chatPackage, string text) { Curve25519KeyPair ephemeralKeyPair = new Curve25519KeyPair(); byte[] secretKey = CryptoUtils.DeriveX3DhSecretSender(GlobalKeyStore.Instance.IdentityKeyPair, ephemeralKeyPair, chatPackage.OtherIdentityKey, chatPackage.OtherSignedPreKey, chatPackage.OtherOneTimePreKey); Curve25519KeyPair dhSendingKeyPair = new Curve25519KeyPair(); (byte[] rootKey, byte[] sendingChainKey) = CryptoUtils.RatchetRootKey(secretKey, dhSendingKeyPair.CalculateSharedSecret(chatPackage.OtherSignedPreKey)); ChatState state = new ChatState { DhSendingKeyPair = dhSendingKeyPair, DhReceivingKey = chatPackage.OtherSignedPreKey, RootKey = rootKey, SendingChainKey = sendingChainKey, ReceivingChainKey = null, CountSent = 0, CountReceived = 0, PreviousCount = 0, MissedMessages = new Dictionary <string, (byte[], byte[])>() }; GlobalKeyStore.Instance.ChatStates[recipientUuid] = state; byte[] initialAssociatedData = CryptoUtils.CalculateInitialAssociatedData( GlobalKeyStore.Instance.IdentityKeyPair, chatPackage.OtherIdentityKey); (byte[] encryptedText, MessageHeader header) = RatchetEncrypt(state, Encoding.UTF8.GetBytes(text), initialAssociatedData); NormalTextMessage innerPayload = new NormalTextMessage { AssociatedDataBase64 = Convert.ToBase64String(initialAssociatedData), DhKeyBase64 = Convert.ToBase64String(dhSendingKeyPair.XPublicKey), EncryptedTextBase64 = Convert.ToBase64String(encryptedText), MessageNumber = header.MessageNumber, PreviousCount = header.PreviousCount }; string innerPayloadJson = JsonConvert.SerializeObject(innerPayload); InitialMessage payload = new InitialMessage { EphemeralKeyBase64 = Convert.ToBase64String(ephemeralKeyPair.XPublicKey), InnerMessagePayload = innerPayloadJson, SenderIdentityKeyBase64 = Convert.ToBase64String(GlobalKeyStore.Instance.IdentityKeyPair.EdPublicKey), RecipientSignedPreKeyBase64 = Convert.ToBase64String(chatPackage.OtherSignedPreKey.XPublicKey), RecipientOneTimePreKeyBase64 = Convert.ToBase64String(chatPackage.OtherOneTimePreKey.XPublicKey) }; string payloadJson = JsonConvert.SerializeObject(payload); return(new MetaMessage { OtherUuid = recipientUuid, Type = MessageType.InitialMessage, Payload = payloadJson }); }
private static void HandleInitialMessage(MetaMessage metaMessage) { // TODO actually do database stuff string senderUuid = metaMessage.OtherUuid; InitialMessage message = JsonConvert.DeserializeObject <InitialMessage>(metaMessage.Payload); Curve25519KeyPair otherIdentityKey = new Curve25519KeyPair(Convert.FromBase64String(message.SenderIdentityKeyBase64), false, true); Curve25519KeyPair ephemeralKey = new Curve25519KeyPair(Convert.FromBase64String(message.EphemeralKeyBase64), false, false); Curve25519KeyPair receivedSignedPreKey = new Curve25519KeyPair(Convert.FromBase64String(message.RecipientSignedPreKeyBase64), false, false); Curve25519KeyPair signedPreKeyPair = GlobalKeyStore.Instance.SignedPreKeyPairs.Find(pair => pair.XPublicKey.SequenceEqual(receivedSignedPreKey.XPublicKey)); if (signedPreKeyPair is null) { throw new Exception("Matching signed prekey pair not found"); } Curve25519KeyPair oneTimePreKeyPair; if (message.RecipientOneTimePreKeyBase64 is null) { oneTimePreKeyPair = null; } else { Curve25519KeyPair receivedOneTimePreKey = new Curve25519KeyPair(Convert.FromBase64String(message.RecipientOneTimePreKeyBase64), false, false); oneTimePreKeyPair = GlobalKeyStore.Instance.OneTimePreKeyPairs.Find(pair => pair.XPublicKey.SequenceEqual(receivedOneTimePreKey.XPublicKey)); if (oneTimePreKeyPair is null) { throw new Exception("Matching one-time prekey pair not found"); } // Remove the one-time key, never to be used again GlobalKeyStore.Instance.SignedPreKeyPairs.Remove(oneTimePreKeyPair); } byte[] secretKey = CryptoUtils.DeriveX3DhSecretReceiver(GlobalKeyStore.Instance.IdentityKeyPair, signedPreKeyPair, otherIdentityKey, ephemeralKey, oneTimePreKeyPair); GlobalKeyStore.Instance.ChatStates[senderUuid] = new ChatState { DhSendingKeyPair = signedPreKeyPair, DhReceivingKey = null, RootKey = secretKey, SendingChainKey = null, ReceivingChainKey = null, CountSent = 0, CountReceived = 0, PreviousCount = 0, MissedMessages = new Dictionary <string, (byte[], byte[])>() }; MetaMessage innerMetaMessage = new MetaMessage { OtherUuid = metaMessage.OtherUuid, Type = MessageType.NormalTextMessage, Payload = message.InnerMessagePayload, Timestamp = metaMessage.Timestamp }; NormalTextMessage innerMessage = JsonConvert.DeserializeObject <NormalTextMessage>(innerMetaMessage.Payload); string requiredAssociatedDataBase64 = Convert.ToBase64String( CryptoUtils.CalculateInitialAssociatedData(otherIdentityKey, GlobalKeyStore.Instance.IdentityKeyPair)); if (innerMessage.AssociatedDataBase64 != requiredAssociatedDataBase64) { throw new Exception($"Associated data for the initial message isn't what it should be: {innerMessage.AssociatedDataBase64} != {requiredAssociatedDataBase64}"); } HandleNormalTextMessage(innerMetaMessage); }