age: mitigate multi-key attacks on ChaCha20Poly1305

It's possible to craft ChaCha20Poly1305 ciphertexts that decrypt under
multiple keys. (I know, it's wild.)

The impact is different for different recipients, but in general only
applies to Chosen Ciphertext Attacks against online decryption oracles:

* With the scrypt recipient, it lets the attacker make a recipient
  stanza that decrypts with multiple passwords, speeding up a bruteforce
  in terms of oracle queries (but not scrypt work, which can be
  precomputed) to logN by binary search.

  Limiting the ciphertext size limits the keys to two, which makes this
  acceptable: it's a loss of only one bit of security in a scenario
  (online decryption oracles) that is not recommended.

* With the X25519 recipient, it lets the attacker search for accepted
  public keys without using multiple recipient stanzas in the message.
  That lets the attacker bypass the 20 recipients limit (which was not
  actually intended to defend against deanonymization attacks).

  This is not really in the threat model for age: we make no attempt to
  provide anonymity in an online CCA scenario.

  Anyway, limiting the keys to two by enforcing short ciphertexts
  mitigates the attack: it only lets the attacker test 40 keys per
  message instead of 20.

* With the ssh-ed25519 recipient, the attack should be irrelevant, since
  the recipient stanza includes a 32-bit hash of the public key, making
  it decidedly not anonymous.

  Also to avoid breaking the abstraction in the agessh package, we don't
  mitigate the attack for this recipient, but we document the lack of
  anonymity.

This was reported by Paul Grubbs in the context of the upcoming paper
"Partitioning Oracle Attacks", USENIX Security 2021 (to appear), by
Julia Len, Paul Grubbs, and Thomas Ristenpart.
This commit is contained in:
Filippo Valsorda
2020-09-19 18:52:59 +02:00
parent 07c72f3b69
commit 2194f6962c
10 changed files with 94 additions and 28 deletions
+25 -12
View File
@@ -20,13 +20,20 @@ func TestVectors(t *testing.T) {
files, _ := filepath.Glob("testdata/*.age")
for _, f := range files {
name := strings.TrimSuffix(strings.TrimPrefix(f, "testdata/"), ".age")
expectFailure := strings.HasPrefix(name, "fail_")
t.Run(name, func(t *testing.T) {
identities, err := parseIdentitiesFile("testdata/" + name + "_key.txt")
if err != nil {
t.Fatal(err)
var identities []age.Identity
ids, err := parseIdentitiesFile("testdata/" + name + "_key.txt")
if err == nil {
identities = append(identities, ids...)
}
for _, i := range identities {
t.Logf("%s", i.Type())
password, err := ioutil.ReadFile("testdata/" + name + "_password.txt")
if err == nil {
i, err := age.NewScryptIdentity(string(password))
if err != nil {
t.Fatal(err)
}
identities = append(identities, i)
}
in, err := os.Open("testdata/" + name + ".age")
@@ -34,14 +41,20 @@ func TestVectors(t *testing.T) {
t.Fatal(err)
}
r, err := age.Decrypt(in, identities...)
if err != nil {
t.Fatal(err)
if expectFailure {
if err == nil {
t.Fatal("expected Decrypt failure")
}
} else {
if err != nil {
t.Fatal(err)
}
out, err := ioutil.ReadAll(r)
if err != nil {
t.Fatal(err)
}
t.Logf("%s", out)
}
out, err := ioutil.ReadAll(r)
if err != nil {
t.Fatal(err)
}
t.Logf("%s", out)
})
}
}
+6
View File
@@ -0,0 +1,6 @@
age-encryption.org/v1
-> scrypt qeKad+OgIkBbr/ndSa7J3Q 1
C2tmV7/uZjRafxqaQd1JhYkM2KxuHHBy3/d2dJNEZEh8rZCqYfvE/eJUXqiqZsZa
6kWgG1qa6Q6sXPz0vIIpYHGf4gzxG9oTVonMke2kHC4
--- FQeacPQobvFBd0tuIQnQDd/NEDR4G4MfylkXiq9ZqZ0
Ãù€pÛÂt€t˜Ë3qòÆ)¬ÌÈŒv´¨QÆoÌšK÷¶7ÜØ)ø%a
@@ -0,0 +1 @@
dog-old-little-breeze-novel-razor-battle-replace-lake-horse
+6
View File
@@ -0,0 +1,6 @@
age-encryption.org/v1
-> X25519 /Gt0E6JT7yuYHlwsGW5LbpEEJawOc+QMeMAS+hoOIgw
XU/4Zkz4MksDhge0kosiMTJF8tHnOP0ZSi+6aaMqLMS1PlMIs95nKz3H7JGesTwA
tsxuQrj+TuoGouNB1O0VshA9vsHGurn0Dtw5e7bkw9Q
--- jQNSF6blozj2QFYJ/2iqy0wUcPuz/8vCS7RgKH8wjNI
Þ9­¶‡yË_£§R\¯ÿm\¥û©Uv6Qȶ»ñmK»a¢©êv®©˜2
+3
View File
@@ -0,0 +1,3 @@
# created: 2020-09-19T18:42:11+02:00
# public key: age1uc8zlurjyjpenrslc2thyl28u7ylz6x8c2g9yphvjha6xm8ppf3slq0l25
AGE-SECRET-KEY-1D8JAD8SXNFVQEFHAUNNAX4QCE3K5CUKMT7YYHNGTUSSP97YGWL4STV89UH