tink_core/primitiveset/
mod.rs

1// Copyright 2020 The Tink-Rust Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15////////////////////////////////////////////////////////////////////////////////
16
17//! Provides a container for a set of cryptographic primitives.
18//!
19//! It provides also additional properties for the primitives it holds. In
20//! particular, one of the primitives in the set can be distinguished as "the
21//! primary" one.
22
23use crate::utils::{wrap_err, TinkError};
24use std::{
25    collections::{hash_map, HashMap},
26    convert::TryFrom,
27};
28
29/// `Entry` represents a single entry in the keyset. In addition to the actual
30/// primitive, it holds the identifier and status of the primitive.
31#[derive(Clone)]
32pub struct Entry {
33    pub key_id: crate::KeyId,
34    pub primitive: crate::Primitive,
35    pub prefix: Vec<u8>,
36    pub prefix_type: tink_proto::OutputPrefixType,
37    pub status: tink_proto::KeyStatusType,
38}
39
40impl Entry {
41    fn new(
42        key_id: crate::KeyId,
43        p: crate::Primitive,
44        prefix: &[u8],
45        prefix_type: tink_proto::OutputPrefixType,
46        status: tink_proto::KeyStatusType,
47    ) -> Self {
48        Entry {
49            key_id,
50            primitive: p,
51            prefix: prefix.to_vec(),
52            prefix_type,
53            status,
54        }
55    }
56}
57
58/// `PrimitiveSet` is used for supporting key rotation: primitives in a set correspond to keys in a
59/// keyset.
60///
61/// Users will usually work with primitive instances, which essentially wrap primitive sets. For
62/// example an instance of an AEAD-primitive for a given keyset holds a set of AEAD-primitives
63/// corresponding to the keys in the keyset, and uses the set members to do the actual crypto
64/// operations: to encrypt data the primary AEAD-primitive from the set is used, and upon decryption
65/// the ciphertext's prefix determines the id of the primitive from the set.
66///
67/// `PrimitiveSet` is public to allow its use in implementations of custom primitives.
68#[derive(Clone, Default)]
69pub struct PrimitiveSet {
70    // Copy of the primary entry in `entries`.
71    pub primary: Option<Entry>,
72
73    // The primitives are stored in a map of (ciphertext prefix, list of
74    // primitives sharing the prefix). This allows quickly retrieving the
75    // primitives sharing some particular prefix.
76    pub entries: HashMap<Vec<u8>, Vec<Entry>>,
77}
78
79impl PrimitiveSet {
80    /// Return an empty instance of [`PrimitiveSet`].
81    pub fn new() -> Self {
82        PrimitiveSet {
83            primary: None,
84            entries: HashMap::new(),
85        }
86    }
87
88    /// Return all primitives in the set that have RAW prefix.
89    pub fn raw_entries(&self) -> Vec<Entry> {
90        self.entries_for_prefix(&crate::cryptofmt::RAW_PREFIX)
91    }
92
93    /// Return all primitives in the set that have the given prefix.
94    pub fn entries_for_prefix(&self, prefix: &[u8]) -> Vec<Entry> {
95        match self.entries.get(prefix) {
96            Some(v) => v.clone(),
97            None => Vec::new(),
98        }
99    }
100
101    /// Create a new entry in the primitive set and returns a copy of the added entry.
102    pub fn add(
103        &mut self,
104        p: crate::Primitive,
105        key: &tink_proto::keyset::Key,
106    ) -> Result<Entry, TinkError> {
107        if key.status != tink_proto::KeyStatusType::Enabled as i32 {
108            return Err("The key must be ENABLED".into());
109        }
110        let prefix =
111            crate::cryptofmt::output_prefix(key).map_err(|e| wrap_err("primitiveset", e))?;
112        let entry = Entry::new(
113            key.key_id,
114            p,
115            &prefix,
116            tink_proto::OutputPrefixType::try_from(key.output_prefix_type)
117                .map_err(|_e| TinkError::new("invalid key prefix type"))?,
118            tink_proto::KeyStatusType::try_from(key.status)
119                .map_err(|_e| TinkError::new("invalid key status"))?,
120        );
121        let retval = entry.clone();
122        match self.entries.entry(prefix) {
123            hash_map::Entry::Occupied(mut oe) => oe.get_mut().push(entry),
124            hash_map::Entry::Vacant(ve) => {
125                ve.insert(vec![entry]);
126            }
127        };
128        Ok(retval)
129    }
130}
131
132/// `TypedEntry` represents a single entry in a keyset for primitives of a known type. In addition
133/// to the actual primitive, it holds the identifier and status of the primitive.
134pub struct TypedEntry<P: From<crate::Primitive>> {
135    pub key_id: crate::KeyId,
136    pub primitive: P,
137    pub prefix: Vec<u8>,
138    pub prefix_type: tink_proto::OutputPrefixType,
139    pub status: tink_proto::KeyStatusType,
140}
141
142impl<P: From<crate::Primitive>> From<Entry> for TypedEntry<P> {
143    fn from(entry: Entry) -> Self {
144        Self {
145            key_id: entry.key_id,
146            primitive: entry.primitive.into(),
147            prefix: entry.prefix,
148            prefix_type: entry.prefix_type,
149            status: entry.status,
150        }
151    }
152}
153
154/// `TypedPrimitiveSet` is equivalent to [`PrimitiveSet`] but holds primitives
155/// of a specific known type `P`.
156pub struct TypedPrimitiveSet<P: From<crate::Primitive>> {
157    // Copy of the primary entry in `entries`.
158    pub primary: Option<TypedEntry<P>>,
159
160    // The primitives are stored in a map of (ciphertext prefix, list of
161    // primitives sharing the prefix). This allows quickly retrieving the
162    // primitives sharing some particular prefix.
163    pub entries: HashMap<Vec<u8>, Vec<TypedEntry<P>>>,
164}
165
166impl<P: From<crate::Primitive>> TypedPrimitiveSet<P> {
167    /// Return all primitives in the set that have RAW prefix.
168    pub fn raw_entries(&self) -> Option<&Vec<TypedEntry<P>>> {
169        self.entries_for_prefix(&crate::cryptofmt::RAW_PREFIX)
170    }
171
172    /// Return all primitives in the set that have the given prefix.
173    pub fn entries_for_prefix(&self, prefix: &[u8]) -> Option<&Vec<TypedEntry<P>>> {
174        self.entries.get(prefix)
175    }
176}
177
178/// A `TypedPrimitiveSet` is [`Clone`]able if its constituent [`TypedEntry`] objects
179/// are [`Clone`]able.
180impl<T> Clone for TypedPrimitiveSet<T>
181where
182    TypedEntry<T>: Clone,
183    T: From<crate::Primitive>,
184{
185    fn clone(&self) -> Self {
186        Self {
187            primary: self.primary.as_ref().cloned(),
188            entries: self.entries.clone(),
189        }
190    }
191}
192
193/// Convert an untyped [`PrimitiveSet`] into a [`TypedPrimitiveSet`]. This will
194/// panic if any of the primitives are not of the correct type.
195impl<P: From<crate::Primitive>> From<PrimitiveSet> for TypedPrimitiveSet<P> {
196    fn from(ps: PrimitiveSet) -> Self {
197        Self {
198            primary: ps.primary.map(|e| e.into()),
199            entries: ps
200                .entries
201                .into_iter()
202                .map(|(k, v)| (k, v.into_iter().map(TypedEntry::<P>::from).collect()))
203                .collect(),
204        }
205    }
206}
207
208// When used for a primitive, instances of `TypedPrimitiveSet` need to support `Clone`.
209// This is possible for each primitive type individually using the `box_clone()` method,
210// but needs a specialized implementation of `Clone` for each primitive.
211
212impl Clone for TypedEntry<Box<dyn crate::Aead>> {
213    fn clone(&self) -> Self {
214        Self {
215            key_id: self.key_id,
216            primitive: self.primitive.box_clone(),
217            prefix: self.prefix.clone(),
218            prefix_type: self.prefix_type,
219            status: self.status,
220        }
221    }
222}
223impl Clone for TypedEntry<Box<dyn crate::DeterministicAead>> {
224    fn clone(&self) -> Self {
225        Self {
226            key_id: self.key_id,
227            primitive: self.primitive.box_clone(),
228            prefix: self.prefix.clone(),
229            prefix_type: self.prefix_type,
230            status: self.status,
231        }
232    }
233}
234impl Clone for TypedEntry<Box<dyn crate::HybridDecrypt>> {
235    fn clone(&self) -> Self {
236        Self {
237            key_id: self.key_id,
238            primitive: self.primitive.box_clone(),
239            prefix: self.prefix.clone(),
240            prefix_type: self.prefix_type,
241            status: self.status,
242        }
243    }
244}
245impl Clone for TypedEntry<Box<dyn crate::HybridEncrypt>> {
246    fn clone(&self) -> Self {
247        Self {
248            key_id: self.key_id,
249            primitive: self.primitive.box_clone(),
250            prefix: self.prefix.clone(),
251            prefix_type: self.prefix_type,
252            status: self.status,
253        }
254    }
255}
256impl Clone for TypedEntry<Box<dyn crate::Mac>> {
257    fn clone(&self) -> Self {
258        Self {
259            key_id: self.key_id,
260            primitive: self.primitive.box_clone(),
261            prefix: self.prefix.clone(),
262            prefix_type: self.prefix_type,
263            status: self.status,
264        }
265    }
266}
267impl Clone for TypedEntry<Box<dyn crate::Signer>> {
268    fn clone(&self) -> Self {
269        Self {
270            key_id: self.key_id,
271            primitive: self.primitive.box_clone(),
272            prefix: self.prefix.clone(),
273            prefix_type: self.prefix_type,
274            status: self.status,
275        }
276    }
277}
278impl Clone for TypedEntry<Box<dyn crate::StreamingAead>> {
279    fn clone(&self) -> Self {
280        Self {
281            key_id: self.key_id,
282            primitive: self.primitive.box_clone(),
283            prefix: self.prefix.clone(),
284            prefix_type: self.prefix_type,
285            status: self.status,
286        }
287    }
288}
289impl Clone for TypedEntry<Box<dyn crate::Verifier>> {
290    fn clone(&self) -> Self {
291        Self {
292            key_id: self.key_id,
293            primitive: self.primitive.box_clone(),
294            prefix: self.prefix.clone(),
295            prefix_type: self.prefix_type,
296            status: self.status,
297        }
298    }
299}