Check for small subgroup components when using the EdwardsPoint group for the OPRF

A malicious attacker sending a small point could lead the server / user to leak private information.

The check avoiding mixed order points (rather than just small) is prohibitively expensive, and I don't know how an attacker would extract any data from that => we focus on a small order check.

Fixes #34.
This commit is contained in:
François Garillot
2020-08-24 14:50:29 -04:00
parent c2edb2d95e
commit 29ba1b93b5
3 changed files with 74 additions and 2 deletions
Generated
+7
View File
@@ -1,5 +1,11 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "anyhow"
version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b"
[[package]]
name = "atty"
version = "0.2.14"
@@ -451,6 +457,7 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
name = "opaque-ke"
version = "0.1.0"
dependencies = [
"anyhow",
"base64",
"criterion",
"curve25519-dalek",
+1
View File
@@ -31,6 +31,7 @@ x25519-dalek = { version = "0.6.0", default-features = false, features = ["std"]
zeroize = "1.1"
[dev-dependencies]
anyhow = "1.0.32"
base64 = "0.12.3"
criterion = "0.3.3"
hex = "0.4.2"
+66 -2
View File
@@ -131,9 +131,14 @@ impl Group for EdwardsPoint {
fn from_element_slice(
element_bits: &GenericArray<u8, Self::ElemLen>,
) -> Result<Self, InternalPakeError> {
CompressedEdwardsY::from_slice(element_bits)
let point = CompressedEdwardsY::from_slice(element_bits)
.decompress()
.ok_or_else(|| InternalPakeError::PointError)
.ok_or_else(|| InternalPakeError::PointError)?;
if point.is_small_order() {
return Err(InternalPakeError::SubGroupError);
}
Ok(point)
}
// serialization of a group element
fn to_arr(&self) -> GenericArray<u8, Self::ElemLen> {
@@ -164,3 +169,62 @@ impl Group for EdwardsPoint {
.mul_by_cofactor()
}
}
#[cfg(test)]
mod tests {
use super::*;
use anyhow::{anyhow, Result};
const EIGHT_TORSION: [[u8; 32]; 8] = [
[
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,
],
[
199, 23, 106, 112, 61, 77, 216, 79, 186, 60, 11, 118, 13, 16, 103, 15, 42, 32, 83, 250,
44, 57, 204, 198, 78, 199, 253, 119, 146, 172, 3, 122,
],
[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 128,
],
[
38, 232, 149, 143, 194, 178, 39, 176, 69, 195, 244, 137, 242, 239, 152, 240, 213, 223,
172, 5, 211, 198, 51, 57, 177, 56, 2, 136, 109, 83, 252, 5,
],
[
236, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127,
],
[
38, 232, 149, 143, 194, 178, 39, 176, 69, 195, 244, 137, 242, 239, 152, 240, 213, 223,
172, 5, 211, 198, 51, 57, 177, 56, 2, 136, 109, 83, 252, 133,
],
[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,
],
[
199, 23, 106, 112, 61, 77, 216, 79, 186, 60, 11, 118, 13, 16, 103, 15, 42, 32, 83, 250,
44, 57, 204, 198, 78, 199, 253, 119, 146, 172, 3, 250,
],
];
fn deserialize_point(pt: &[u8]) -> Result<EdwardsPoint> {
let mut bytes = [0u8; 32];
bytes.copy_from_slice(&pt[..32]);
curve25519_dalek::edwards::CompressedEdwardsY(bytes)
.decompress()
.ok_or_else(|| anyhow!("Point decompression failed!"))
}
#[test]
fn test_small_subgroup_edwards() {
for i in 0..8 {
let pt = &EIGHT_TORSION[i][..];
assert!(deserialize_point(&pt).is_ok());
assert!(EdwardsPoint::from_element_slice(GenericArray::from_slice(&pt)).is_err());
}
}
}