[Nfd-dev] [EXT]Re: Update on NDNCERT protocol
Junxiao Shi
shijunxiao at email.arizona.edu
Mon Apr 13 05:17:41 PDT 2020
Hi Zhiyi
I'm trying to implement the protocol in NDNts. I've pasted my
implementation of the crypto operations at the end of this message.
I have unit-tested these operations and they seem to be working. Since
Node.js implements crypto via OpenSSL, this implies OpenSSL has sufficient
primitives for crypto needed by NDNCERT.
I noticed some more issues in the protocol.
Several steps specify the use of signed Interest.
They should also specify which uniqueness assurance fields are required in
the SignatureInfo: SignatureNonce, SignatureTime, SignatureSeqNum.
Several steps specify MustBeFresh in Interest, but lacks FreshnessPeriod in
Data. A Data without FreshnessPeriod cannot satisfy an Interest with
MustBeFresh.
Given signed Interests are unique, it's unnecessary to include MustBeFresh.
Several TLVs are specified as *OCTET in ABNF, but text says "human readable
string".
It also needs to specify what codec to use, such as UTF-8. If you want to
restrict to ASCII instead, specify as *CHAR.
CA profile packet should have FinalBlockId (set to the same as last name
component), so that it is compatible with segmentation convention.
NEW response uses "challenge" TLV-TYPE, but it lacks number assignment.
The AES-GCM session key is established by ECDH followed by HKDF.
WebCrypto cannot directly derive the HKDF key from ECDH. Instead, the
workflow is:
1. derive bits from ECDH
2. import bits as HKDF key
3. derive AES-GCM key from HKDF key
The protocol specifies that the AES-GCM key is 128 bits. However, it does
not specify how many bits go into the HKDF key.
Given ECDH on P-256 curve can establish a shared secret of 256 bits, I'd
recommend specifying 256 bits.
In PROBE/CHALLENGE request, parameter-value is specified as a string.
Some probe methods and challenges may natively use binary information.
Thus, this field could be defined as binary instead.
parameter-key could stay as string, and defined as *CHAR if restricted to
ASCII.
Yours, Junxiao
const ECDH_PARAMS: EcKeyGenParams & EcKeyImportParams = {
name: "ECDH",
namedCurve: "P-256",
};
export async function generateEcdhKey(): Promise<CryptoKeyPair> {
return crypto.subtle.generateKey(ECDH_PARAMS, false, ["deriveBits"]);
}
export async function importEcdhPub(raw: Uint8Array): Promise<CryptoKey> {
return crypto.subtle.importKey("raw", raw, ECDH_PARAMS, true, []);
}
export async function exportEcdhPub(key: CryptoKey): Promise<Uint8Array> {
const raw = await crypto.subtle.exportKey("raw", key);
return new Uint8Array(raw);
}
export async function makeSessionKey(
ecdhPvt: CryptoKey,
ecdhPub: CryptoKey,
salt: Uint8Array,
requestId: Uint8Array,
): Promise<CryptoKey> {
const hkdfBits = await crypto.subtle.deriveBits({ name: "ECDH", public:
ecdhPub }, ecdhPvt, 256);
const hkdfKey = await crypto.subtle.importKey("raw", hkdfBits, "HKDF",
false, ["deriveKey"]);
return crypto.subtle.deriveKey(
{
name: "HKDF",
salt,
info: requestId,
hash: "SHA-256",
} as any,
hkdfKey,
{
name: "AES-GCM",
length: 128,
},
false,
["encrypt", "decrypt"],
);
}
export interface Encrypted {
iv: Uint8Array;
ciphertext: Uint8Array;
}
export async function sessionEncrypt(key: CryptoKey, plaintext: Uint8Array
): Promise<Encrypted> {
const iv = crypto.getRandomValues(new Uint8Array(12));
const ciphertext = await crypto.subtle.encrypt({ name: "AES-GCM", iv },
key, plaintext);
return { iv, ciphertext: new Uint8Array(ciphertext) };
}
export async function sessionDecrypt(key: CryptoKey, { iv, ciphertext }:
Encrypted): Promise<Uint8Array> {
const plaintext = await crypto.subtle.decrypt({ name: "AES-GCM", iv }, key
, ciphertext);
return new Uint8Array(plaintext);
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.lists.cs.ucla.edu/pipermail/nfd-dev/attachments/20200413/cfbe630d/attachment-0001.html>
More information about the Nfd-dev
mailing list