Skip to content

Commit ab87b8d

Browse files
committed
rust: add tink-prf crate
Adapted from go/prf/*.
1 parent 90a61ec commit ab87b8d

24 files changed

+3134
-4
lines changed

rust/Cargo.lock

Lines changed: 25 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
[workspace]
2-
members = ["daead", "testutil", "tink"]
2+
# members = ["daead", "mac", "prf", "testutil", "tink"]
3+
members = ["daead", "prf", "testutil", "tink"]
34

45
# Patch dependencies on tink crates so that they refer to the versions within this same repository.
56
[patch.crates-io]
67
tink = { path = "tink" }
78
tink-daead = { path = "daead" }
9+
# tink-mac = { path = "mac" }
10+
tink-prf = { path = "prf" }
811
tink-testutil = { path = "testutil" }

rust/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ Go packages and the equivalent Rust crates and modules, when available.
5454
| `tink-daead` | `daead` |
5555
| | `hybrid` |
5656
| | `mac` |
57-
| | `prf` |
57+
| `tink-prf` | `prf` |
5858
| | `signature` |
5959
| | `streamingaead` |
6060

rust/prf/Cargo.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[package]
2+
name = "tink-prf"
3+
version = "0.1.0"
4+
authors = ["David Drysdale <[email protected]>"]
5+
edition = "2018"
6+
7+
[dependencies]
8+
aes = "*"
9+
cmac = "*"
10+
digest = "*"
11+
hkdf = "*"
12+
hmac = "*"
13+
prost = "*"
14+
sha-1 = "*"
15+
sha2 = "*"
16+
tink = "*"
17+
18+
[dev-dependencies]
19+
hex = "*"
20+
maplit = "*"
21+
serde = { version = "*", features = ["derive"] }
22+
serde_json = "*"
23+
tink-testutil = "*"
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// Licensed under the Apache License, Version 2.0 (the "License");
2+
// you may not use this file except in compliance with the License.
3+
// You may obtain a copy of the License at
4+
//
5+
// http://www.apache.org/licenses/LICENSE-2.0
6+
//
7+
// Unless required by applicable law or agreed to in writing, software
8+
// distributed under the License is distributed on an "AS IS" BASIS,
9+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
// See the License for the specific language governing permissions and
11+
// limitations under the License.
12+
//
13+
////////////////////////////////////////////////////////////////////////////////
14+
15+
use crate::subtle;
16+
use prost::Message;
17+
use tink::{utils::wrap_err, TinkError};
18+
19+
/// Maximal version of AES-CMAC PRF keys.
20+
pub const AES_CMAC_PRF_KEY_VERSION: u32 = 0;
21+
/// Type URL of AES-CMAC PRF keys that Tink supports.
22+
pub const AES_CMAC_PRF_TYPE_URL: &str = "type.googleapis.com/google.crypto.tink.AesCmacPrfKey";
23+
24+
/// Generates new AES-CMAC keys and produces new instances of AES-CMAC.
25+
pub(crate) struct AesCmacPrfKeyManager;
26+
27+
impl AesCmacPrfKeyManager {
28+
pub fn new() -> Self {
29+
Self
30+
}
31+
}
32+
33+
impl Default for AesCmacPrfKeyManager {
34+
fn default() -> Self {
35+
Self::new()
36+
}
37+
}
38+
39+
impl tink::registry::KeyManager for AesCmacPrfKeyManager {
40+
/// Create an [`AesCmacPrf`](crate::subtle::AesCmacPrf) instance for the given serialized
41+
/// [`AesCmacPrfKey`](tink:;proto::AesCmacPrfKey) proto.
42+
fn primitive(&self, serialized_key: &[u8]) -> Result<tink::Primitive, TinkError> {
43+
if serialized_key.is_empty() {
44+
return Err("AesCmacPrfKeyManager: invalid key".into());
45+
}
46+
47+
let key = tink::proto::AesCmacPrfKey::decode(serialized_key)
48+
.map_err(|_| TinkError::new("AesCmacPrfKeyManager: invalid key"))?;
49+
validate_key(&key)?;
50+
match subtle::AesCmacPrf::new(&key.key_value) {
51+
Ok(p) => Ok(tink::Primitive::Prf(std::sync::Arc::new(p))),
52+
Err(e) => Err(wrap_err(
53+
"AesCmacPrfManager: cannot create new primitive",
54+
e,
55+
)),
56+
}
57+
}
58+
59+
/// Generate a new serialized [`AesCmacPrfKey`](tink::proto::AesCmacPrfKey) according to
60+
/// specification in the given [`AesCmacPrfKeyFormat`](tink::proto::AesCmacPrfKeyFormat).
61+
fn new_key(&self, serialized_key_format: &[u8]) -> Result<Vec<u8>, TinkError> {
62+
if serialized_key_format.is_empty() {
63+
return Err("AesCmacPrfKeyManager: invalid key format".into());
64+
}
65+
let key_format = tink::proto::AesCmacPrfKeyFormat::decode(serialized_key_format)
66+
.map_err(|_| TinkError::new("AesCmacPrfKeyManager: invalid key format"))?;
67+
validate_key_format(&key_format)
68+
.map_err(|e| wrap_err("AesCmacPrfKeyManager: invalid key format", e))?;
69+
let key_value = tink::subtle::random::get_random_bytes(key_format.key_size as usize);
70+
71+
let mut sk = Vec::new();
72+
tink::proto::AesCmacPrfKey {
73+
version: AES_CMAC_PRF_KEY_VERSION,
74+
key_value,
75+
}
76+
.encode(&mut sk)
77+
.map_err(|e| wrap_err("Failed to encode new key", e))?;
78+
Ok(sk)
79+
}
80+
81+
fn does_support(&self, type_url: &str) -> bool {
82+
type_url == AES_CMAC_PRF_TYPE_URL
83+
}
84+
85+
fn type_url(&self) -> String {
86+
AES_CMAC_PRF_TYPE_URL.to_string()
87+
}
88+
89+
/// Create a new [`KeyData`](tink::proto::KeyData) according to the specification in the given
90+
/// serialized [`AesCmacPrfKeyFormat`](tink::proto::AesCmacPrfKeyFormat). This should be used
91+
/// solely by the key management API.
92+
fn new_key_data(
93+
&self,
94+
serialized_key_format: &[u8],
95+
) -> Result<tink::proto::KeyData, TinkError> {
96+
let serialized_key = self.new_key(serialized_key_format)?;
97+
98+
Ok(tink::proto::KeyData {
99+
type_url: AES_CMAC_PRF_TYPE_URL.to_string(),
100+
value: serialized_key,
101+
key_material_type: tink::proto::key_data::KeyMaterialType::Symmetric as i32,
102+
})
103+
}
104+
}
105+
106+
/// Validate the given [`AesCmacPrfKey`](tink::proto::AesCmacPrfKey). It only validates the version
107+
/// of the key because other parameters will be validated in primitive construction.
108+
fn validate_key(key: &tink::proto::AesCmacPrfKey) -> Result<(), TinkError> {
109+
tink::keyset::validate_key_version(key.version, AES_CMAC_PRF_KEY_VERSION)
110+
.map_err(|e| wrap_err("AesCmacPrfKeyManager: invalid version", e))?;
111+
let key_size = key.key_value.len();
112+
subtle::validate_aes_cmac_prf_params(key_size)
113+
}
114+
115+
/// Validate the given [`AesCmacPrfKeyFormat`](tink::proto::AesCmacPrfKeyFormat).
116+
fn validate_key_format(format: &tink::proto::AesCmacPrfKeyFormat) -> Result<(), TinkError> {
117+
subtle::validate_aes_cmac_prf_params(format.key_size as usize)
118+
}

rust/prf/src/hkdf_prf_key_manager.rs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// Licensed under the Apache License, Version 2.0 (the "License");
2+
// you may not use this file except in compliance with the License.
3+
// You may obtain a copy of the License at
4+
//
5+
// http://www.apache.org/licenses/LICENSE-2.0
6+
//
7+
// Unless required by applicable law or agreed to in writing, software
8+
// distributed under the License is distributed on an "AS IS" BASIS,
9+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
// See the License for the specific language governing permissions and
11+
// limitations under the License.
12+
//
13+
////////////////////////////////////////////////////////////////////////////////
14+
15+
use crate::subtle;
16+
use prost::Message;
17+
use tink::{
18+
utils::{hash_name, wrap_err},
19+
TinkError,
20+
};
21+
22+
/// Maximal version of HKDF PRF keys.
23+
pub const HKDF_PRF_KEY_VERSION: u32 = 0;
24+
/// Type URL of HKDF PRF keys that Tink supports.
25+
pub const HKDF_PRF_TYPE_URL: &str = "type.googleapis.com/google.crypto.tink.HkdfPrfKey";
26+
27+
/// Generates new HKDF PRF keys and produces new instances of HKDF.
28+
pub(crate) struct HkdfPrfKeyManager;
29+
30+
impl HkdfPrfKeyManager {
31+
pub fn new() -> Self {
32+
Self
33+
}
34+
}
35+
36+
impl Default for HkdfPrfKeyManager {
37+
fn default() -> Self {
38+
Self::new()
39+
}
40+
}
41+
42+
impl tink::registry::KeyManager for HkdfPrfKeyManager {
43+
/// Construct an HKDF instance for the given serialized [`HkdfPrfKey`](tink::proto::HkdfPrfKey).
44+
fn primitive(&self, serialized_key: &[u8]) -> Result<tink::Primitive, TinkError> {
45+
if serialized_key.is_empty() {
46+
return Err("HkdfPrfKeyManager: invalid key".into());
47+
}
48+
let key = tink::proto::HkdfPrfKey::decode(serialized_key)
49+
.map_err(|_| TinkError::new("HkdfPrfKeyManager: invalid key"))?;
50+
validate_key(&key)?;
51+
let params = key
52+
.params
53+
.ok_or_else(|| TinkError::new("no key parameters"))?;
54+
let hash = hash_name(params.hash);
55+
56+
match subtle::HkdfPrf::new(hash, &key.key_value, &params.salt) {
57+
Ok(p) => Ok(tink::Primitive::Prf(std::sync::Arc::new(p))),
58+
Err(e) => Err(wrap_err("HkdfPrfManager: cannot create new primitive", e)),
59+
}
60+
}
61+
62+
/// Generate a new [`HkdfPrfKey`](tink::proto::HkdfPrfKey) according to specification in the
63+
/// given [`HkdfPrfKeyFormat`](tink::proto::HkdfPrfKeyFormat).
64+
fn new_key(&self, serialized_key_format: &[u8]) -> Result<Vec<u8>, TinkError> {
65+
if serialized_key_format.is_empty() {
66+
return Err("HkdfPrfKeyManager: invalid key format".into());
67+
}
68+
69+
let key_format = tink::proto::HkdfPrfKeyFormat::decode(serialized_key_format)
70+
.map_err(|_| TinkError::new("HkdfPrfKeyManager: invalid key format"))?;
71+
validate_key_format(&key_format)
72+
.map_err(|e| wrap_err("HkdfPrfKeyManager: invalid key format", e))?;
73+
74+
let key_value = tink::subtle::random::get_random_bytes(key_format.key_size as usize);
75+
let mut sk = Vec::new();
76+
77+
tink::proto::HkdfPrfKey {
78+
version: HKDF_PRF_KEY_VERSION,
79+
params: key_format.params,
80+
key_value,
81+
}
82+
.encode(&mut sk)
83+
.map_err(|e| wrap_err("Failed to encode new key", e))?;
84+
Ok(sk)
85+
}
86+
87+
fn does_support(&self, type_url: &str) -> bool {
88+
type_url == HKDF_PRF_TYPE_URL
89+
}
90+
91+
fn type_url(&self) -> String {
92+
HKDF_PRF_TYPE_URL.to_string()
93+
}
94+
95+
/// Generate a new [`KeyData`](tink::proto::KeyData) according to specification in the given
96+
/// serialized [`HkdfPrfKeyFormat`](tink::proto::HkdfPrfKeyFormat). This should be used solely
97+
/// by the key management API.
98+
fn new_key_data(
99+
&self,
100+
serialized_key_format: &[u8],
101+
) -> Result<tink::proto::KeyData, TinkError> {
102+
let serialized_key = self.new_key(serialized_key_format)?;
103+
104+
Ok(tink::proto::KeyData {
105+
type_url: HKDF_PRF_TYPE_URL.to_string(),
106+
value: serialized_key,
107+
key_material_type: tink::proto::key_data::KeyMaterialType::Symmetric as i32,
108+
})
109+
}
110+
}
111+
112+
/// Validate the given [`HkdfPrfKey`](tink::proto::HkdfPrfKey). It only validates the version of the
113+
/// key because other parameters will be validated in primitive construction.
114+
fn validate_key(key: &tink::proto::HkdfPrfKey) -> Result<(), TinkError> {
115+
tink::keyset::validate_key_version(key.version, HKDF_PRF_KEY_VERSION)
116+
.map_err(|e| wrap_err("HkdfPrfKeyManager: invalid version", e))?;
117+
let key_size = key.key_value.len();
118+
let hash = hash_name(key.params.as_ref().unwrap().hash);
119+
subtle::validate_hkdf_prf_params(hash, key_size, &key.params.as_ref().unwrap().salt)
120+
}
121+
122+
/// Validate the given [`HkdfPrfKeyFormat`](tink::proto::HkdfPrfKeyFormat).
123+
fn validate_key_format(format: &tink::proto::HkdfPrfKeyFormat) -> Result<(), TinkError> {
124+
if format.params.is_none() {
125+
return Err("null HKDF params".into());
126+
}
127+
let hash = hash_name(format.params.as_ref().unwrap().hash);
128+
subtle::validate_hkdf_prf_params(
129+
hash,
130+
format.key_size as usize,
131+
&format.params.as_ref().unwrap().salt,
132+
)
133+
}

0 commit comments

Comments
 (0)