The Crypto Bone

privacy and secure communication
under your control

    

SafeWebdrop: An encrypted message exchange mechanism for the CryptoBone

Dear Cryptography Mailing List,

I'd like to present SafeWebdrop, an encrypted message exchange mechanism for the CryptoBone, here for constructive criticism. Apologies for the long posting.

The protocols always reflect the latest improvements! [ 15. April 2023 ]

As we all know [1] the CryptoBone [2] simplifies the key management for users who wish to exchange always-encrypted messages but does not make any attempt to disguise the fact, that a message exchange has taken place, because the default transport mechanism is EMAIL. Today, it has become increasingly difficult to establish reliable EMAIL exchanges using standard programs on dialup devices like laptops.

Because a simple exchange of encrypted messages does not really need an ISP hosted email account, a different HTTPS-based exchange mechanism is desirable.

The basic idea behind SafeWebdrop is, that people wishing to communicate securely may have contact to a webserver administrator (think of a community or organization, ...) who can be convinced to add a minimalistic software to a server, which already provides HTTPS for other reasons (LetsEncrypt, etc.).

With the installation of three bash-scripts the server admin can establish a direct message exchange service [3], that does not interfere with the official use of the server. SafeWebdrop requires the attention of the admin only once, when a user's public key is accepted and stored in the user's safewebdrop directory (account registration). Everything else works without the admin's involvement.

Given, that a webserver admin can be found to extend their service for users, who can be contacted first hand, SafeWebdrop is minimal invasive.

So here are the three mechanisms for scrutiny in detail.

Message exchanges between a user's device and the server rely on HTTPS, already present on the server. That means, one side of the SafeWebdrop service is authenticated and encrypted (in the sense in which for instance an online bank is authenticated). What's missing is the authentication of the user-side. SSH would be the ideal solution for this part, but I do not want to burden the server administrator with the task of establishing all SafeWebdrop users as real users on the server. Minimal invasiveness means that an additional user is simply a directory with a RSA public key in it, nothing more.

The only precondition to start a secure communication between two people is the exchange of a random 20 character initial secret, preferably exchanged in person on a piece of paper.

There are three protocols, I use the notation similar to Ross Anderson's [4]


Account Registration:

A : User Alice S : Server <https> A -> S : UID, registration S -> A : hash(Nonce) # S stores IP, UID and Nonce A -> S : UID, { UID, hash(nonce) } RSAprivA, RSApubkeyA # S checks IP, challenge and UID # S verifies signature and stores Pubkey # and RegCode in a directory UID S -> A : RegCode # RegCode is 20 char random hex </https>

The registration code stored on the server must be handed over by the person, who wishes to use a new SafeWebdrop account, directly to the server administrator. The admin checks that the registration code matches the one on the server and copies the RSA public key into the directory created for the user. The admin's involvement stops here.

Of course, anyone can register a given UID. But if the UID is not in use already, providing the RegCode offline guarantees that the legitimate Pubkey, the one generated by the CryptoBone system, will be stored in the new UID directory. Any attempt to use this account will require the use of the corresponding RSA private key.


Reading SafeWebdrop Messages: (authenticated pull)

<https> A -> S : UID, NEW # server checks that UID exists and # has a public key S -> A : hash(Nonce) # S uses a new stored Nonce A -> S : UID, { UID, hash(Nonce), GET } RSAprivA # S performs the checks as in registration # S concatenates all safewebdrop messages # generates a hash and a list and sends S -> A : allsafewebdropmessages A -> S : UID, { UID, hash(Nonce), hash(allmess.) } RSAprivA # S performs checks and verifies hash # S deletes all safewebdrop messages S -> A : OK </https>


Sending SafeWebdrop Messages: (push a message)

CASE 1) unauthorized: B : any user <https> B -> S: A, B, base64(message) # S checks that A exists # S checks that message is in AES encrypted # openPGP message format # S stores message in A's directory S -> B: OK </https> CASE 2) authorized user on the same server S: C : User that is registered on S <https> C -> S: A, C, base64(message), { hash(message) } RSAprivC # S verifies C's signature as C's pubkey is on the server # after registration and checks that the hash # matches the message and proceeds as in CASE 1 S -> C: OK </https> CASE 3) registered user D on another server CROSS: D : is registered on CROSS and has exchanged an initial secret (sec) with A. (A%S is Alices full safewebdrop address) <https> # this is done by the CryptoBone, when A # enters the secret sec for D%CROSS into the # GUI A -> S : UID, ALLOW # server checks that UID exists and # has a public key so that signatures can be # verified S -> A : hash(Nonce) # S uses a new stored Nonce A -> S: A, { hash(Nonce), D%CROSS } RSAprivA, { hash(Nonce), hash(A%S, D%CROSS, sec) } RSAprivA # A tells S, that if D%CROSS sends a # public key and this hash, D%CROSS is # allowed to send safe webdrop messages # to A on S (as in CASE 2). # the submitted hash is stored on S in contacts/D%CROSS.allow S -> A : OK </https> The user who is already registered on CROSS sends a contact request for A to S: <https> D%CROSS -> S : A, D%CROSS, CONTACT S -> D%CROSS : hash(Nonce) # S uses a new stored Nonce # S stores IP, CONTACT and Nonce in A's directory D%CROSS -> S : A, { hash(Nonce), D%CROSS } RSAprivD, { hash(Nonce), hash(A%S, D%CROSS, sec) } RSAprivD, RSApubkeyD # this is done by the CryptoBone, when D # enters the secret sec for A%S into the # GUI # D%CROSS's pubkey is saved in A's directory on S # S can verify that A allows D's pubkey # to be used to check D%CROSS's messages # if the hash in contacts/D%CROSS.allow matches the signed hash # then S stores RSApubkeyD as contacts/D%CROSS.pubkey S -> D%CROSS : OK </https> D%CROSS sends the first safe webdrop message to A on S: <https> D%CROSS -> S : A, D%CROSS, base64(message), { hash(message) } RSAprivD # S can verify D's signature, as it finds # D's pubkey in A's contact subdirectory # the server admin is not involved to # authorize D on A. # S stores D's message for A as in CASE 2. S -> D%CROSS : OK </https>

It will be the sole administrator's choice whether or not he accepts unauthorized messages.
The essential part is the authorization of D on S based on the initial secret that had been exchanged between A and D first hand.


File Attachment Extension

Added to the initial proposal on 15 April 2023

The SafeWebdrop message exchange mechanism may be even more useful if exchanged messages can be extended with an encrypted file attachment. Thus I have added two more protocols to provide one encrypted file to be sent with each message.

Please note, that this message + attachment exchange mechanism can be used in every project where users and server administrator and different users can exchange registrationcodes and initial secrets in person first-hand.

Sending SafeWebdrop Messages with an Encrypted File Attachment

CASE 1) unauthorized: B : any user This is always forbidden for obvious reasons.

CASE 2) authorized user on the same server S: C : User that is registered on S

<https> C -> S: A, C, base64(message), { hash(message) } RSAprivC # S verifies C's signature as C's pubkey is on the server # after registration and checks that the hash # matches the message and finally: # S checks that A exists # S checks that message is in AES encrypted # OpenPGP message format # S stores message in A's directory using Number S -> C: Number # Server returns the number under which the message # is stored. # C uses https PUT for file-upload in the next transfer C -> S: A, C, encryptedFile, { Num, hash(encryptedFile)} RSAprivC # Server reads maxbytes from stdin, checks that the # data is in OpenPGP format, checks that less than # maxfiles are already stored in A's directory # S checks C's signature and stores the file in A's # directory using Number to identify the corresponding # message S -> C: OK </https> CASE 3) registered user D on another server CROSS: As the cross server user D is registered on S using the shared initial secret between A and D. This case can be handled exactly like CASE 2. D%CROSS's public key is in A's contacts directory and can be used in the same way as the authorized user C in CASE 2.

Reading SafeWebdrop Messages with an Encrypted File Attachment

<https> A -> S : UID, NEW # server checks that UID exists and # has a public key S -> A : hash(Nonce) # S uses a new stored Nonce A -> S : UID, { UID, hash(Nonce), GETATTACH } RSAprivA # S performs the checks as in registration # S concatenates all safewebdrop messages # prefixed with their filename and # generates a hash and a list of the messages # S concatenates all stored encrypted files # prefixed with their filename and # generates a hash2 and a list2 of the files # S stores both hashes, the Nonce and the IP in # A's request file S -> A : allsafewebdropmessages, "&", base64(allencryptedfiles) A -> S : UID, { UID, hash(Nonce), hash(allmessages), hash(allfiles) } RSAprivA # S performs checks and verifies both hashes # S deletes all safewebdrop messages and files, # if the hashes match those in the request file. S -> A : OK </https>


Any objections? Any (obvious) improvements?

--ralf

  1. https://www.metzdowd.com/pipermail/cryptography/2015-January/024194.html
  2. https://crypto-bone.com
  3. https://safewebdrop.com
  4. Ross Anderson: Security Engineering, Chapter 4 (Protocols)