pdk-contracts-lib 1.9.1-alpha.2

PDK Contracts Library
Documentation
// Copyright (c) 2026, Salesforce, Inc.,
// All rights reserved.
// For full license text, see the LICENSE.txt file

use crate::ClientSecret;

pub fn hash(salt: &str, client_secret: &ClientSecret) -> Vec<u8> {
    cfg_if::cfg_if! {
        if #[cfg(not(fips))] {
            hash_native(salt, client_secret)
        } else {
            hash_fips(salt, client_secret)
        }
    }
}

#[cfg(not(fips))]
fn hash_native(salt: &str, client_secret: &ClientSecret) -> Vec<u8> {
    use sha2::{Digest, Sha256};

    let mut hashed_result = [0u8; 32];
    let mut hasher = Sha256::new();
    hasher.update(format!("{}{}", salt, client_secret.as_str()).as_str());
    hashed_result.copy_from_slice(&hasher.finalize());
    let result = hex::encode(hashed_result);
    result.into_bytes()
}

#[cfg(fips)]
fn hash_fips(salt: &str, client_secret: &ClientSecret) -> Vec<u8> {
    use pdk_core::ffi::{GetShaDigestArguments, GetShaDigestResult, Message};

    let data = format!("{}{}", salt, client_secret.as_str());
    let args = GetShaDigestArguments {
        data: data.into_bytes(),
        ..Default::default()
    };
    let args_bytes = args
        .write_to_bytes()
        .unwrap_or_else(|e| panic!("Failed to serialize GetShaDigestArguments: {}", e));

    match pdk_core::classy::proxy_wasm::hostcalls::call_foreign_function(
        "get_sha_digest",
        Some(&args_bytes),
    ) {
        Ok(Some(bytes)) => match GetShaDigestResult::parse_from_bytes(&bytes) {
            Ok(result) if result.result => {
                let hex_result = hex::encode(result.digest);
                hex_result.into_bytes()
            }
            Ok(result) => panic!("get_sha_digest failed: {}", result.error),
            Err(e) => panic!("Failed to parse GetShaDigestResult: {}", e),
        },
        Ok(None) => panic!("get_sha_digest returned no result"),
        Err(e) => panic!("get_sha_digest hostcall failed: {:?}", e),
    }
}

#[cfg(test)]
mod tests {
    use crate::{implementation::hashing::hash, ClientSecret};

    #[test]
    #[cfg(not(fips))]
    fn hash_simple_value() {
        let a_secret = &ClientSecret::new(String::from("gateway"));
        let a_salt = "some_salt";
        let a_hashed_secret = "ada97098baab31248ff4cdd1540e65acfd997fbd05863bd25e67a17d3c30fff3";

        assert_eq!(hash(a_salt, a_secret), a_hashed_secret.as_bytes());
    }
}