1 unstable release
0.1.1 | Jan 17, 2022 |
---|---|
0.1.0 |
|
#1516 in Cryptography
20KB
190 lines
google-cloud-iot-jwt
Rust implementation of the Google Cloud IOT Core JWT for embedded no_std heapless (no alloc) devices.
Features
- ES256 JWT signature - implements Elliptic Curves ES256 signature as it needs less computational resources for generation, and it's shorter than RSA RS256 signature.
no_std
compliant - the library and all its dependencies are no_std compatible and can be freely used for Rust embedded applications.heapless
(withoutalloc
) compliant - the library and all its dependencies do not require heap memory allocation. All calculations are preformed using stack fixed-size variables. Special thanks to heapless and ufmt contributors.- RustCrypto - the library uses high quality cryptographic algorithms written in pure Rust.
- Low flash memory footprint - takes only 49.7 KB. See details below.
Install
https://crates.io/crates/google-cloud-iot-jwt
# Cargo.toml
[dependencies]
google-cloud-iot-jwt = "0.1.1"
Usage
- Get the Google Cloud project name from the console dashboard.
- Generate private key for ES256 signature in PEM sec1 format.
- Get current unix timestamp in seconds (use Real-Time Clock hardware, NTP client, etc). The timestamp is +-10 minutes tolerant.
- Create a JWT ES256 using the project name, the private key and the timestamp.
- Use with Google Cloud IOT Core.
Generate Elliptic Curve keys
Excerpts from the official Google IOT Core documentation.
You can use the following commands to generate a P-256 Elliptic Curve key pair:
openssl ecparam -genkey -name prime256v1 -noout -out ec_private.pem
openssl ec -in ec_private.pem -pubout -out ec_public.pem
These commands create the following public/private key pair:
ec_private.pem
: The private key in sec1 PEM-string format that must be securely stored on the device and used to sign the authentication JWT.ec_public.pem
: The public key that must be stored in Cloud IoT Core and used to verify the signature of the authentication JWT.
Open the ec_private.pem
and use its contents to create a JWT.
Generate ES256 JWT
#[cfg(test)]
mod test {
use google_cloud_iot_jwt::create_google_jwt_es256;
use google_cloud_iot_jwt::JWT_ES256_MAX_LENGTH;
#[test]
fn print_jwt() {
// Project name from the Google Cloud Dashboard
let project = "your_google_cloud_project_name";
// Caution: Do not place the Private Key into your sources.
// Flash it into your device separately and then load in your code from the flash or whatever else.
let private_key = "\
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIDMvJjBfq3YVCHHeJj8pbsGITyhoHjkwg9o+3pLZkAAWoAoGCCqGSM49
AwEHoUQDQgAE5JHMOhIYK0AwPmvWXpRz2tU4OaC9A2+j8wTPDYmDLT1C3hV5ZeWr
iuPXSxsC6gVceKszCX/sJkcgQVXVkE3nOg==
-----END EC PRIVATE KEY-----
";
// Get current Unix timestamp in seconds (e.g. Real Timer Clock, NTP client, etc)
let timestamp = 1642293084;
// Create JWT
let jwt = create_google_jwt_es256(
project,
private_key,
timestamp
).unwrap();
println!("JWT = {}", jwt);
println!("Actual JWT length = {}", jwt.len());
println!("Max possible JWT length = {}", JWT_ES256_MAX_LENGTH);
}
}
The generated JWT is valid
- since the specified
timestamp + 10 minutes
(Google time skew parameter) and - till the specified
timestamp + 24 hours + 10 minutes
,
thus you can store the JWT in the memory and use for 24 hours.
Firmware size optimizations
Reached limits of your MCU flash size? No problem.
Set opt-level = "z"
and reduce firmware size up to ~50% of the original.
# Cargo.toml
# See https://docs.rust-embedded.org/book/unsorted/speed-vs-size.html
[profile.dev.package.google-cloud-iot-jwt]
opt-level = "z"
# or even set z-level for all packages to optimize your debug firmware size
# [profile.dev.package."*"]
# opt-level = "z"
[profile.release]
opt-level = "z"
lto = true
panic = "abort"
debug = true
Flash memory footprint
Tested in a firmware for STM32F3Discovery:
- Build target
thumbv7em-none-eabihf
- Release profile
- opt-level = "z"
- lto = true
- panic = "abort"
- debug = true
Compilation with google_cloud_iot_jwt::create_google_jwt_es256;
section size addr
.text 46132 0x8000194
.rodata 8580 0x800b5c8
Total = 54712 bytes
Compilation without google_cloud_iot_jwt::create_google_jwt_es256;
section size addr
.text 3388 0x8000194
.rodata 432 0x8000ed0
Total = 3820 bytes
Flash memory footprint = 54712 - 3820 = 50892 bytes (49.7 KB)
License
MIT (c) 2022 Viacheslav Dobromyslov <viacheslav@dobromyslov.ru>
Dependencies
~5MB
~105K SLoC