[Nfd-dev] [EXT]Re: Update on NDNCERT protocol

Davide Pesavento davidepesa at gmail.com
Mon Apr 13 12:28:57 PDT 2020


On Mon, Apr 13, 2020 at 8:18 AM Junxiao Shi via Nfd-dev
<nfd-dev at lists.cs.ucla.edu> wrote:
>
> 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.

I would NOT recommend to restrict ourselves to ASCII, it's 2020...

> 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:
>
> derive bits from ECDH
> import bits as HKDF key
> 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.

I'm not sure why this needs to be specified. The ECDH shared secret is
normally the X coordinate of the calculated point, i.e. 32 bytes with
NIST P-256. By saying that one must run HKDF with the ECDH shared
secret as input, it's pretty obvious that you use the entire secret,
nothing more, nothing less. I don't think there's any ambiguity here.

>
>
> 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);
> }
>
> _______________________________________________
> Nfd-dev mailing list
> Nfd-dev at lists.cs.ucla.edu
> http://www.lists.cs.ucla.edu/mailman/listinfo/nfd-dev


More information about the Nfd-dev mailing list