Skip to content

Latest commit

 

History

History
308 lines (251 loc) · 11.7 KB

how-to-exchange-encrypted-data.md

File metadata and controls

308 lines (251 loc) · 11.7 KB

How to exchange encrypted data

  • Last Updated: 2023-08-09
  • Objective: Explain how an authenticated atSign client exchanges data with another atSign

Note When atClients send notifications to each other, the notify payloads are encrypted in the same way as is described below for the put and get operations.

Background

Some details of how the atPlatform works are not specified in detail by the atProtocol itself, but are usage conventions which are embedded in the client SDKs. As a result, building new client software, be it in a new language or building alternative client software for a language for which client software is already available, currently requires the engineer to base their efforts upon existing client libraries rather than a language-agnostic specification of the minimum functionality required.

Goals

Given a client which has access to keys from a completed onboarding, provide a detailed specification of how the client can securely exchange data with another atSign.

Non-goals

  • This document does not cover client onboarding.
    • TODO: Create such a document

Technical prerequisites

Ability to

  • create RSA encryption public/private keypairs and use them to do encryption and decryption
  • cryptographically sign data using a private key, and verify signatures using a public key
  • create AES encryption keys and use them to do encryption and decryption
  • establish a TLS socket connection, and be able to use it to send and receive data
  • base64 encoding/decoding

Specification

"Sending" atSign

Given an already-onboarded client (i.e. access to authentication private key and encryption private key) for atsign @alice

1. Lookup address of the @alice atServer

  • Establish TLS connection to root.atsign.org:64
  • Send alice\n
  • Expect response in form <someDomain.example.com>:<port>

2. Authenticate to @alice atServer

  • Establish TLS connection to the address of the @alice atServer
  • do PKAM authentication
    • Send from:@alice

    • Expect response in form data:<challengeText>

    • Create a base64-encoded SHA256 signature of challengeText using the client's PKAM private key

      • Dart code example
        var key = RSAPrivateKey.fromString(privateKey);
        var sha256signature =
          key.createSHA256Signature(utf8.encode(challengeText) as Uint8List);
        var signature = base64Encode(sha256signature);
    • Send pkam:<signature>

    • Expect response data:success (or error:<errorMessage> if the signature could not be verified by the atServer using the corresponding PKAM public key)

3a. Fetch existing shared symmetric key if it has already been created

  • Send llookup:shared_key.bob@alice // This is a copy of the symmetric key which is encrypted with @alice's public encryption key
  • If response like data:<base64EncodedEncryptedSharedKey>
    • Decode from bas64, then decrypt using our private encryption key. The result will be a symmetric key, base64-encoded. NB _Currently we use RSA asymmetric keypairs, and AES-256 symmetric keys. We will be supporting other ciphers and modes in future.
    • base64-decode the symmetric key => $sharedAESKey
  • Else if response like error:error:AT0015-key not found : @bob:shared_key@alice does not exist in keystore we need to create a symmetric key and share it wih @bob

3b. or create a new shared symmetric key

  • Create a new AES-256 symmetric key => $sharedAESKey and base64-encode it => $base64EncodedSharedAESKey
  • Save for our own use in future
    • Encrypt $base64EncodedSharedAESKey with our public encryption key and base64-encode the result => $base64EncodedEncryptedForAliceSharedAESKey
    • Store in the atServer
      • Send update:shared_key.bob@alice $base64EncodedEncryptedForAliceSharedAESKey and handle the response
  • Share with @bob
    • Fetch @bob's public encryption key
      • Send plookup:publickey@bob
      • Successful response data:<bobsBase64EncodedPublicKey>
    • Encrypt $base64EncodedSharedAESKey with bobsBase64EncodedPublicKey and base64-encode the result => $base64EncodedEncryptedForBobSharedAESKey
    • Store in the atServer
      • Send update:ttr:86400:@bob:shared_key@alice $base64EncodedEncryptedForBobSharedAESKey and handle the response

4. Encrypt some data

  • Encrypt your $data with $sharedAESKey and base64-encode the result => $base64EncodedEncryptedData
    • We currently use the CTR (aka SIC) mode of the AES cipher, with PKCS7Padding. Java example:

      public String aesEncryptToBase64(String clearText,
        String keyBase64, byte[] iv) {
          SecretKey key = _aesKeyFromBase64(keyBase64);
          Cipher cipher = Cipher.getInstance("AES/SIC/PKCS7Padding", "BC");
          cipher.init(Cipher.ENCRYPT_MODE, key, iv);
          byte[] encrypted = cipher.doFinal(clearText.getBytes());
          return Base64.getEncoder().encodeToString(encrypted);
      }

5. Share the data with @bob

  • Send update:<optional metadata attributes:>@bob:some.key_name.in.some.namespace@alice base64EncodedEncryptedData and handle the response

"Receiving" atSign

1. Lookup address of the @bob atServer

2. PKAM authenticate to @bob atServer

3. Fetch the data which @alice shared

  • Send lookup:some.key_name.in.some.namespace@alice // NB do not include @bob:
    • (Aside: What is happening here? @bob client talks to @bob atServer. @bob atServer sees that the data was created by @alice; @bob atServer connects to @alice atServer, does a server-to-server authentication, and looks up the value in @alice atServer.)
  • Successful response will be data:$base64EncodedEncryptedData

4. Fetch the symmetric key which @alice shared

  • Send lookup:shared_key@alice // NB do not include @bob:
  • Successful response will be data:$base64EncodedEncryptedForBobSharedAESKey
  • base64-decode $base64EncodedEncryptedForBobSharedAESKey => $encryptedForBobSharedAESKey
  • decrypt $encryptedForBobSharedAESKey using Bob's private encryption key
  • base64-decode the result, and construct an AES key

5. Decrypt the data using the symmetric key

  • base64-decode the $base64EncodedEncryptedData, and decrypt it using the shared symmetric key. Java example:

    public static String aesDecryptFromBase64(String cipherTextBase64,
      String keyBase64, byte[] iv) {
        SecretKey key = _aesKeyFromBase64(keyBase64);
        Cipher cipher = Cipher.getInstance("AES/SIC/PKCS7Padding", "BC");
        cipher.init(Cipher.DECRYPT_MODE, key, iv);
        byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(cipherTextBase64));
        return new String(decrypted);
    }

Key descriptions

.atKeys:

  • aesPkamPublicKey: used by the AtServer to verify the signature (unused by Client)
  • aesPkamPrivateKey: key for signing the challenge during authentication
  • aesEncryptPublicKey: key that other atSigns use to encrypt messages sent to AtSign
  • aesEncryptPrivateKey: used to decrypt messages receive by AtSign
  • selfEncryptionKey: used for encrypting AtKey specific things. E.g. A saved AES symmetric key

Other:

  • aesSymmetricalKey: Generated for each atSign that is communicated with. This is created the first time one AtSign tries to communicate with another.

Sequence diagram

Sequence diagram of the process of sending and receiving data between two AtSigns.

sequenceDiagram
    participant A as Alice
    participant AAS as Alice's AtServer
    participant D as Directory
    participant BAS as Bob's AtServer
    participant B as Bob

    Note left of A: 1. Lookup - Get the location of Alice's AtSign server
    A->>D: TLS: root.atsign.org:64
    Note over A,D: @alice
    D-->>A: Location of @alice AtServer
    Note over D,A: <someDomain.exmaple.com>:<port>

    Note left of A: 2. Authenticate with AtServer by proving we have ownership of the private key
    A->>AAS: TLS: @alice AtServer location
    Note over A,AAS: from:@alice
    AAS-->>A: Challenge
    Note over A,AAS: data:<challengeText>
    A->>AAS: sig = SHA256 of challengeText using aesPkamPrivateKey
    Note over A,AAS: pkam:<signature>
    alt success
        AAS-->>A: Challenge success
        Note over A,AAS: data:success
    else failure
        AAS-->>A: Challenge failure
        Note over A,AAS: error:<errorMessage>
    end

    Note left of A: 3. Getting symmetric key
    alt existing shared symmetric key
        A->>AAS: Look up @bob symmetric key
        Note over A,AAS: llookup:shared_key.bob@alice
        Note right of AAS: shared_key is a reserved atID
        AAS-->>A: Success. Decrypt with aesEncryptPrivateKey
        Note over A,AAS: data:encryptedSharedKey
    else Create new symmetric key
        A->>A: Create aesSymmetricalKey
        A->>AAS: Encrypt with aesEncryptPublicKey and save
        Note over A,AAS: update:shared_key.bob@alice encryptedSymKey
        A->>AAS: Get @bob public key
        Note over A,AAS: plookup:publickey@bob
        AAS-->>A: Success
        Note over A,AAS: data:<bobPublicKey>
        A->>AAS: Encrypt aesSymmetricalKey with @bob aesEncryptPublicKey and send
        Note over A,AAS: Update:ttr:86400:@bob:shared_key@alice  <encryptedSymKey>
    end

    Note left of A: 4. Send data after encrypting with newly created sym key
    A->>A: Encrypt data with aesSymmetricalKey
    A->>AAS: Share data with @bob
    Note over A,AAS: Update:<metadata>@bob:record_key.namespace@alice encryptedData

    Note right of B: 5. Fetch encrypted data shared with @bob 
    B->>BAS: Lookup data for a specific AtRecord shared by @alice
    Note over B,BAS: lookup:record_key.namespace@alice
    BAS-->>B: Success
    Note over B,BAS: data:encryptedData

    Note right of B: 6. Fetch @alice sym key
    B->>BAS: Fetch @alice aesSymmetricalKey
    Note over B,BAS: lookup:shared_key@alice
    BAS-->>B: Success
    Note over B,BAS: data:encryptedForBobSharedKey

    Note right of B: 7. Decrypt @alice sym key using @bob private key
    B->>B: Decrypt using aesEncryptPrivateKey
    Note over B: Decrypted data

    Note right of B: 8. Decrypt message using using @alice sym key
    B->>B: Decrypt using shared aesSymemtricalKey
    Note over B: Decrypted message
Loading

Other resources