Subject: [Openpgp-dt] Sample message encrypted using Argon2

From: NIIBE Yutaka <[email-masked]>
Date: Mon, 21 Feb 2022 16:56:34 +0900

Hello,

In my gniibe/crypto-refresh at git.gnupg.org, I started working for an
implementation which accepts inputs defined by crypto-refresh.  Initial
attempt is SKESK.

I tried by the test vectors in "Sample message encrypted using Argon2".

I think that I interpret the specification wrongly, and my experimental
implementation fails.

Could you please tell me details of the first message of AES 128 (when
you have time)?

In the example, the salt is:

    10 c9 9a c2 76 27 e6 21 ca 49 f7 ea ba 9e 94 79

When using this salt (and no additional data), Argon2 produces:

    de 22 34 42 e6 bc da ae 2f 38 e4 d5 81 45 75 e7

or

    $argon2id$v=19$m=2048,t=1,p=4$EMmawnYn5iHKSffqup6UeQ$3iI0Qua82q4vOOTVgUV15w

in PHC string format [0].

And using this result as KEK, it fails to decrypt encrypted session key
data of:

    78 47 97 da a5 89 87 00 2d 65 1f b4 4f 5f 61 6a e6

with my experimental implementation.

Do you see where I interpret the spec wrongly?

[0] https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md
--

---

From: Justus Winter <[email-masked]>
Date: Mon, 21 Feb 2022 16:09:20 +0100

Hello NIIBE :)

> I think that I interpret the specification wrongly, and my experimental

I made a mistake, I used Argon2i, whereas we agreed to use Argon2id.  I
apologize for the confusion.  I have produced new test vectors, see
below.

>     de 22 34 42 e6 bc da ae 2f 38 e4 d5 81 45 75 e7

Hm.  When I use Argon2id to derive the KEK from the original AES 128
test vector, I still see a different value:

    C87D 09E9 291E 98C3 CE27 1048 BD4B 0767

Of course, it now no longer decrypts the session key.  But, I would have
expected to come up with the same KEK as you.  So I guess there is still
a discrepancy.

Here are my new test vectors with some debugging of the config, salt,
and KEK.  I hope that these will help us get to the bottom of this:

[openpgp/src/crypto/s2k.rs:200] &config = Config {
    ad: [],
    hash_length: 16,
    lanes: 4,
    mem_cost: 2097152,
    secret: [],
    thread_mode: Parallel,
    time_cost: 1,
    variant: Argon2id,
    version: Version13,
}
[openpgp/src/crypto/s2k.rs:201] crate::fmt::hex::encode_pretty(salt) = "9C52 F83C 27F9 5E50 D535 440E CDFF 3136"
[openpgp/src/crypto/s2k.rs:206] crate::fmt::hex::encode_pretty(&kek) = "84A3 643C 39D5 F550 526D 1939 E857 FA66"

[openpgp/src/crypto/s2k.rs:200] &config = Config {
    ad: [],
    hash_length: 24,
    lanes: 4,
    mem_cost: 2097152,
    secret: [],
    thread_mode: Parallel,
    time_cost: 1,
    variant: Argon2id,
    version: Version13,
}
[openpgp/src/crypto/s2k.rs:201] crate::fmt::hex::encode_pretty(salt) = "E14C AC47 1534 5918 A962 DCA3 47E1 43F8"
[openpgp/src/crypto/s2k.rs:206] crate::fmt::hex::encode_pretty(&kek) = "F542 476D 2B9F F435 1585 1811 212D E949 7F1B FE1A 3D08 D707"

[openpgp/src/crypto/s2k.rs:200] &config = Config {
    ad: [],
    hash_length: 32,
    lanes: 4,
    mem_cost: 2097152,
    secret: [],
    thread_mode: Parallel,
    time_cost: 1,
    variant: Argon2id,
    version: Version13,
}
[openpgp/src/crypto/s2k.rs:201] crate::fmt::hex::encode_pretty(salt) = "B878 9520 206F F799 C688 2C42 45A6 627C"
[openpgp/src/crypto/s2k.rs:206] crate::fmt::hex::encode_pretty(&kek) = "4ED7 EB27 434F 6DF6 23CE E3AC 08B7 63C4 AF79 DFDE 5FDC 92DD 1D88 1C6C 9993 8B4F"

Thanks,
Justus

---

From: NIIBE Yutaka <[email-masked]>
Date: Tue, 22 Feb 2022 10:45:07 +0900

Hello, Justus, thanks a lot for your prompt reply.

>     C87D 09E9 291E 98C3 CE27 1048 BD4B 0767

Ah, I see the discrepancy; That's the interpretation of the parameter of
memory cost, M.  I managed to get this KEK, with memory cost 2097152
KiB.  (I thought it were 2097152 byte.)

That is: I had interpreted M as byte, which _is_ wrong. 

In the PHC string format, this is:

$argon2id$v=19$m=2097152,t=1,p=4$EMmawnYn5iHKSffqup6UeQ$yH0J6SkemMPOJxBIvUsHZw
               ^^^^^^^^^

while the one in the last message of mine was:

			*	*	*

> and KEK.  I hope that these will help us get to the bottom of this:

Thank you.  It helps me.  Now, my experiment works with those new test
vectors.

Then, I found a possible improvement here.

For the S2K specifier Argon2 {{s2k-argon2}}, now, it defines:

      Octet  0:        0x04
      Octets 1-16:     16-octet salt value
      Octet  17:       one-octet number of passes t
      Octet  18:       one-octet degree of parallelism p
      Octet  19:       one-octet exponent indicating the memory size m
      [...]
      04 XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX
      XX 01 04 15

I think that it is better (for parsing/building/debugging packet):

      Octet  0:        0x04
      Octet  1:        one-octet number of passes t
      Octet  2:        one-octet degree of parallelism p
      Octet  3:        one-octet exponent indicating the memory size m
      Octets 4-19:     16-octet salt value
      [...]
      04 01 04 15 XX XX XX XX XX XX XX XX XX XX XX XX
      XX XX XX XX

Possibly allowing different salt size.

This is minor thing, I can stand with current spec.
--

---

From: Stephen Farrell <[email-masked]>
Date: Tue, 22 Feb 2022 01:49:11 +0000

Hi all,

On 22/02/2022 01:45, NIIBE Yutaka wrote:
> Justus Winter<[email-masked]>  wrote:
> That is: I had interpreted M as byte, which_is_  wrong.

Great to see this clarified - wherever you end up, if we can
craft some text to help other implementers that'd be great,
even if it seems a bit OTT. I'm always worried that all the
variations and parameters of argon2 make these kinds of issue
fairly likely.

Cheers,
S.

---

From: Paul Wouters <[email-masked]>
Date: Mon, 21 Feb 2022 20:59:05 -0500 (EST)

> Possibly allowing different salt size.

Wouldn't we need a length specification for the salt in that case? Let's
say someone wants to use a 32-octet salt, how would they be able to see
if the salt is 16 or 32?

Paul

---

From: NIIBE Yutaka <[email-masked]>
Date: Wed, 23 Feb 2022 20:18:32 +0900

> say someone wants to use a 32-octet salt, how would they be able to see

Ah, yes.  I thought as if S2K specifier were a packet.

Since it is not a packet, if we allow different salt size for S2K, we
need length information.  (Deducing from surrounding packet could be
possible, but that's complicated and not my idea.)
--

---

From: Daniel Kahn Gillmor <[email-masked]>
Date: Wed, 23 Feb 2022 15:37:00 -0500

> variations and parameters of argon2 make these kinds of issue

good call, Stephen.

I've opened:

  https://gitlab.com/openpgp-wg/rfc4880bis/-/merge_requests/140

hope this helps.

  --dkg