Skip to content

Commit

Permalink
provide examples to define the crypto bits much more clearly
Browse files Browse the repository at this point in the history
  • Loading branch information
quartzjer committed Aug 8, 2013
1 parent e354450 commit 98e528d
Showing 1 changed file with 84 additions and 5 deletions.
89 changes: 84 additions & 5 deletions org/v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,26 +102,105 @@ Once a line is established, all packets sent thereafter within a line will conta
<a name="open" />
## `open` - Establishing a Line

When a packet is of `"type":"open"` it must also contain an `"open":"TYtmBdke6QWx..."`, `"sig":"mj2vNXh0b45a..."`, and `"iv":"d211ae4a2d5d..."` along with it. These are used to establish a temporary session between any two hashnames, called a "line".
A packet of `"type":"open"` is used to establish a temporary encrypted session between any two hashnames, this session is called a "line". Every open packet requires the JSON keys of "open", "iv", and "sig", here's an example of the JSON part of the packet:
```js
{
"type":"open",
"open":"ZkQklgyD91XQaih07VBUGeQmAM9tnR5qMGMavZ9TNqQMCVfTW8TxDr9y37cgB8g6r9dngWLjXuRKe+nYNAG/1ZU4XK+GiR2vUBS8VTcAMzBcUls+GIfZU6WO/zEIu4ra1I1vI8qnYY5MqS/FQ/kMXk9RyzERaD38IWZLk3DYhn8VYPnVnQX62mE5u20usMWQt99F8ITLy972nOhdx5y9RUnnSrtc1SD9xr8O0rco22NtOEWC3uAISwC9xuihT+U7OEcvSKolScFI4oSpRu+DQWl19EAuG9ACqhs5+X3qNeBRMSH8w5+ThOVHaAWKGfFs/FNMdAte3ki8rFesMtfhXQ==",
"iv":"60aa6514ef28178f816d701b9d81a29d",
"sig":"o6buYor8o3YXkPIDJjufn9udfWDJt5hrgnVtKtvZI2ObOPlPSqlb2AdH6QsC7CuwtboGlt6eMbE7Ep6Js2CXeksXTCSZOJ99US7TH0kZ1H1aDqxYpQlM6BADOjG6YOcW+EhniotNUBiw3r02Xt4ohSm0wXxQ97JM95ntFBRnWr1vG25d+5pJQE4LyN2TwB4uApu9zeUoTPhF7daJQOcIMn9en+XxyuBsG61oR/x29bpaoZJGnKrk2DGH1jDnI5GpxIKUbT/Pa7QOlrICUCjGDgxy2TMQ+fiip5sIflxtFUPM/BV9mh4K7/ZaekJXTFfG2FKvJFytQkWbisDVy5EbEA=="
}
And the BODY will be a binary encrypted blob, the contents of which (after decryption) is another packet with the sender's RSA public key as the BODY attachment and the JSON being:
```js
{
"to":"dc375b4fc180d03fee8748ee71c2ec5c4d90bb63",
"at":1375983687346,
"line":"c4e9b78d6bf2732d9f8532193102e6dfe5410f62"
}
```
The string value of the "open" key is created by generating a new elliptic (ECC) public key using the nistp256 curve, and encrypting it *to* the recipients RSA public key, using RSA PKCS1 OAEP padding and base64 encoding. The recipient can then decrypt this using their RSA private key and get the sender's temporary elliptic (ECC) public key. That ECC key (binary) is then hashed using SHA256 resulting in 32 bytes which are used as the AES key along with the random 16 bytes decoded from the hex value of the "iv" from the json as the initialization vector to decipher the included binary body using AES-256-CTR, and once unencrypted it is decoded as another packet.
The original open packet's required values are defined as:

The string value of the "sig" key is an RSA HMAC-SHA256 signature encoded as base64, and that is created by the sender signing the binary/encrypted body. To verify, first decrypt the body using the secret (above), and after decoding the enclosed packet, it's BODY will be the sender's public key. Using that the signature value can be validated.
* `open` - a base64 string value that is is created by generating a new elliptic (ECC) public key using the nistp256 curve, and using RSA to encrypt it (PKCS OAEP padding) *to* the recipients RSA public key.
* `iv` - 16 random bytes hex encoded
* `sig` - a base64 string created using the sender's RSA public key to sign (HMAC-SHA256) the attached (encrypted) binary body.
Once the decoded packet's signature is verified, it MUST also contain the following three fields in the JSON:
And the attached packet's required values are defined as:

* `to` - which hashname this line is being created to
* `line` - the unique id the recipient must use for sending any line packets, a 40 length hex value (SHA1)
* `at` - an integer timestamp of when it was sent, used to another open request is newer

To process an open packet, the recipient must first decrypt the "open" value using their RSA private key, and the binary result of that decryption will be the sender's temporary elliptic curve public key. That ECC key is then hashed using SHA256, these resulting 32 bytes are then used as the AES key along with the random 16 bytes decoded from the hex value of the "iv" from the JSON as the initialization vector to decipher the included binary body using AES-256-CTR.
Once the attached BODY is unencrypted, it is then decoded as another packet with the JSON values above and a BODY of the sender's RSA public key. That RSA public key is then used to validate the value of the "sig" in the open packet.

With the decrypted and verified information, the recipient can now also return an open packet (if it hasn't already sent one) and use Diffie-Hellman to derive a shared secret (ECDHE) from the elliptic key it generated for this line along with the public elliptic key it received.
Example open packet generation logic in node (simplified):
```js
var eccSession = new eccKey("nistp256");
var attached = {js:{}, body:myRSAPublicKey};
attached.js.to = recipientHashname;
attached.js.at = Date.now();
attached.js.line = crypto.randomBytes(20).toString("hex");
var attachedRaw = packetEncode(attached);
var open = {js:{type:"open"}};
open.js.open = rsa(recipientRSAPublicKey).encrypt(eccSession.PublicKey, "PKCS1_OAEP_PADDING").toString("base64");
var aesKey = crypto.createHash('sha256').update(eccSession.PublicKey).digest();
var aesIV = crypto.randomBytes(16);
var aesCipher = crypto.createCipheriv("AES-256-CTR", aesKey, aesIV);
open.body = Buffer.concat([aesCipher.update(attachedRaw), aesCipher.final()]);
open.js.iv = aesIV.toString("hex");
open.js.sig = crypto.createSign("RSA-SHA256").update(open.body).sign(myRSAPrivateKey, "base64");
var openRaw = packetEncode(open);
```
Example open packet validation logic in node (simplified):
```js
// generate these to identify the line being created for each sender
var myEccSession = new eccKey("nistp256");
var myLineId = crypto.randomBytes(20).toString("hex");
var packet = packetDecode(openRaw);
var open = rsa(myRSAPrivateKey).decrypt(packet.js.open, "base64", "PKCS1_OAEP_PADDING");
var senderEccPublicKey = new eccKey("nistp256", open);
var aesKey = crypto.createHash('sha256').update(open).digest();
var aesIV = new Buffer(packet.js.iv, "hex");
var aesDecipher = crypto.createDecipheriv("AES-256-CTR", aesKey, aesIV);
var attached = packetDecode(Buffer.concat([aesDecipher.update(packet.body), aesDecipher.final()]));
if(attached.js.to !== self.hashname) return; // must match recipients hashname
var senderRSAPublicKey = deciphered.body.toString("utf8");
var valid = crypto.createVerify("RSA-SHA256").update(packet.body).verify(senderRSAPublicKey, packet.js.sig, "base64");
// generate the aes session key used for all of the line encryption
var ecdheSecret = myEccSession.deriveSharedSecret(senderEccPublicKey);
var lineEncryptKey = crypto.createHash("sha256")
.update(ecdheSecret)
.update(new Buffer(myLineId, "hex"))
.update(new Buffer(attached.js.line, "hex"))
.digest();
var lineDecryptKey = crypto.createHash("sha256")
.update(ecdheSecret)
.update(new Buffer(attached.js.line, "hex"))
.update(new Buffer(myLineId, "hex"))
.digest();
```
<a name="line" />
## `line` - Packet Encryption
A packet with a `"type":"line"` is only sent/valid after an open has been exchanged, and is required to have a `"line":"3ec1e50ad96e1895a3ed640c908ec78546e29816"` with the value being the same as the recipient sent in it's open and a random `"iv":"9c23429f8156..."` used for the AES encryption. This ensures that no line packets can be received without being invited in an open. Any unknown ones are just ignored.

The BODY is a binary encoded encrypted packet using AES-256-CTR with the key being the 32 byte result of a SHA256 hash combining the binary shared secret (ECDHE) + the sender's line id + the recipients line id (both line ids being converted to the original binary 20 byte sha1 hash first), and the 16-byte initialization vector decoded from the included "iv" hex value. Once decrypted, the recipient then processes it as a normal packet (LENGTH/JSON/BODY) from the sending hashname. All decrypted packets must contain a `"stream":"2588f32b66ac88cb4d02a78d62d1671814b18b82"` value as defined below.
The BODY is a binary encoded encrypted packet using AES-256-CTR with the key that was generated for the line and the 16-byte initialization vector decoded from the included "iv" hex value. Once decrypted, the recipient then processes it as a normal packet (LENGTH/JSON/BODY) from the sending hashname. All decrypted packets must contain a `"stream":"2588f32b66ac88cb4d02a78d62d1671814b18b82"` value as defined below.

<a name="stream" />
## `stream` - Content Transport
Expand Down

0 comments on commit 98e528d

Please sign in to comment.