Skip to main content

pubhubs/
phcrypto.rs

1//! Pubhubs specific crypto
2
3use crate::{
4    api, attr,
5    common::{
6        elgamal,
7        secret::{self, DigestibleSecret},
8    },
9    id,
10    misc::{crypto, jwt},
11    servers::constellation,
12};
13
14use curve25519_dalek::Scalar;
15use sha2::digest::Digest;
16
17/// Computes the `x B` from `x_T * B` and `x_PHC`, used by PHC to create the constellation
18pub fn combine_master_enc_key_parts(
19    public_part: &elgamal::PublicKey,
20    private_part: &elgamal::PrivateKey,
21) -> elgamal::PublicKey {
22    private_part.scale(public_part)
23}
24
25/// Computes the **pseudonymisation factor** $g_H$ for the hub identified by `hub_id`,
26/// from the transcryptor's `pseud_factor_secret`.  See [`crate::api::sso`] for the
27/// exact formula.
28pub fn pseud_factor_for_hub(pseud_factor_secret: impl DigestibleSecret, hub_id: id::Id) -> Scalar {
29    pseud_factor_secret.derive_scalar(
30        sha2::Sha512::new().chain_update(hub_id.as_slice()),
31        "pubhubs-pseud-factor",
32    )
33}
34
35/// Turns the given polymorphic pseudonym `pp` (which should be `Id_U` elgamal encrypted for `x`)
36/// into an encrypted hub pseudonym (which should be `g_H Id_U` elgamal encrypted for `x_PHC`).
37pub fn t_encrypted_hub_pseudonym(
38    pp: elgamal::Triple,
39    pseud_factor_secret: impl DigestibleSecret,
40    master_enc_key_part_inv: &Scalar,
41    hub_id: id::Id,
42) -> elgamal::Triple {
43    let g_h = pseud_factor_for_hub(pseud_factor_secret, hub_id);
44    pp.rsk_with_s(&g_h).and_k(master_enc_key_part_inv)
45}
46
47/// Computes the [`jwt::HS256`] key used to sign [`Attr`] from the secret shared between the
48/// authentication server and pubhubs central.
49///
50/// [`Attr`]: crate::attr::Attr
51pub fn attr_signing_key(shared_secret: &elgamal::SharedSecret) -> jwt::HS256 {
52    shared_secret.derive_hs256(sha2::Sha256::new(), "pubhubs-attr-signing")
53}
54
55/// Computes the [`crypto::SealingKey`] used to seal messages between servers shared a secret.
56pub fn sealing_secret(shared_secret: &elgamal::SharedSecret) -> crypto::SealingKey {
57    shared_secret.derive_sealing_key(sha2::Sha256::new(), "pubhubs-sealing-secret")
58}
59
60/// Derives an [`Id`] for an [`Attr`].
61///
62/// [`Attr`]: attr::Attr
63/// [`Id`]: id::Id
64pub fn attr_id(attr: &attr::Attr, secret: impl secret::DigestibleSecret) -> crate::id::Id {
65    secret.derive_id(
66        sha2::Sha256::new()
67            .chain_update(attr.attr_type.as_slice())
68            .chain_update(secret::encode_usize(attr.value.len()))
69            .chain_update(attr.value.as_bytes()),
70        "pubhubs-attr-id",
71    )
72}
73
74/// Derives an [`id::Id`] for a [`constellation::Inner`].
75pub fn constellation_id(c: &constellation::Inner) -> id::Id {
76    b"".as_slice()
77        .derive_id(c.sha256(), "pubhubs-constellation-id")
78}
79
80/// Derives an [`id::Id`] for a [`jwt::JWT`].
81pub fn jwt_id(jwt: &jwt::JWT) -> id::Id {
82    b"".as_slice().derive_id(jwt.sha256(), "pubhubs-jwt-id")
83}
84
85/// Derives an `hmac` for a user object stored at pubhubs central.
86///
87/// See [`crate::api::phc::user::GetObjectEP`].
88pub fn phc_user_object_hmac(
89    object_id: crate::id::Id,
90    secret: impl secret::DigestibleSecret,
91) -> crate::id::Id {
92    secret.derive_id(
93        sha2::Sha256::new().chain_update(object_id.as_slice()),
94        "pubhubs-user-object-hmac",
95    )
96}
97
98/// Derives attribute keys for a given [`attr::Attr`]ibute and a list of timestamps.
99pub fn auths_attr_keys(
100    attr: attr::Attr,
101    secret: impl secret::DigestibleSecret,
102    timestamps: impl IntoIterator<Item = api::NumericDate>,
103) -> Vec<Vec<u8>> {
104    let attr_secret = attr_id(&attr, secret);
105
106    timestamps
107        .into_iter()
108        .map(|ts| {
109            attr_secret.derive_bytes(
110                sha2::Sha256::new().chain_update(ts.timestamp().to_be_bytes()),
111                "pubhubs-attr-key",
112            )
113        })
114        .collect()
115}