Skip to content

Commit

Permalink
Convert CMAC to Rust
Browse files Browse the repository at this point in the history
  • Loading branch information
alex committed Nov 1, 2023
1 parent a712d56 commit 2cdbf9e
Show file tree
Hide file tree
Showing 15 changed files with 423 additions and 163 deletions.
5 changes: 0 additions & 5 deletions src/cryptography/hazmat/backends/openssl/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.backends.openssl import aead
from cryptography.hazmat.backends.openssl.ciphers import _CipherContext
from cryptography.hazmat.backends.openssl.cmac import _CMACContext
from cryptography.hazmat.bindings._rust import openssl as rust_openssl
from cryptography.hazmat.bindings.openssl import binding
from cryptography.hazmat.primitives import hashes, serialization
Expand All @@ -31,7 +30,6 @@
PublicKeyTypes,
)
from cryptography.hazmat.primitives.ciphers import (
BlockCipherAlgorithm,
CipherAlgorithm,
)
from cryptography.hazmat.primitives.ciphers.algorithms import (
Expand Down Expand Up @@ -571,9 +569,6 @@ def cmac_algorithm_supported(self, algorithm) -> bool:
algorithm, CBC(b"\x00" * algorithm.block_size)
)

def create_cmac_ctx(self, algorithm: BlockCipherAlgorithm) -> _CMACContext:
return _CMACContext(self, algorithm)

def load_pem_private_key(
self,
data: bytes,
Expand Down
89 changes: 0 additions & 89 deletions src/cryptography/hazmat/backends/openssl/cmac.py

This file was deleted.

2 changes: 2 additions & 0 deletions src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import typing

from cryptography.hazmat.bindings._rust.openssl import (
aead,
cmac,
dh,
dsa,
ec,
Expand All @@ -24,6 +25,7 @@ __all__ = [
"openssl_version",
"raise_openssl_error",
"aead",
"cmac",
"dh",
"dsa",
"ec",
Expand Down
18 changes: 18 additions & 0 deletions src/cryptography/hazmat/bindings/_rust/openssl/cmac.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.

import typing

from cryptography.hazmat.primitives import ciphers

class CMAC:
def __init__(
self,
algorithm: ciphers.BlockCipherAlgorithm,
backend: typing.Any = None,
) -> None: ...
def update(self, data: bytes) -> None: ...
def finalize(self) -> bytes: ...
def verify(self, signature: bytes) -> None: ...
def copy(self) -> CMAC: ...
61 changes: 3 additions & 58 deletions src/cryptography/hazmat/primitives/cmac.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,62 +4,7 @@

from __future__ import annotations

import typing
from cryptography.hazmat.bindings._rust import openssl as rust_openssl

from cryptography import utils
from cryptography.exceptions import AlreadyFinalized
from cryptography.hazmat.primitives import ciphers

if typing.TYPE_CHECKING:
from cryptography.hazmat.backends.openssl.cmac import _CMACContext


class CMAC:
_ctx: _CMACContext | None
_algorithm: ciphers.BlockCipherAlgorithm

def __init__(
self,
algorithm: ciphers.BlockCipherAlgorithm,
backend: typing.Any = None,
ctx: _CMACContext | None = None,
) -> None:
if not isinstance(algorithm, ciphers.BlockCipherAlgorithm):
raise TypeError("Expected instance of BlockCipherAlgorithm.")
self._algorithm = algorithm

if ctx is None:
from cryptography.hazmat.backends.openssl.backend import (
backend as ossl,
)

self._ctx = ossl.create_cmac_ctx(self._algorithm)
else:
self._ctx = ctx

def update(self, data: bytes) -> None:
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")

utils._check_bytes("data", data)
self._ctx.update(data)

def finalize(self) -> bytes:
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
digest = self._ctx.finalize()
self._ctx = None
return digest

def verify(self, signature: bytes) -> None:
utils._check_bytes("signature", signature)
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")

ctx, self._ctx = self._ctx, None
ctx.verify(signature)

def copy(self) -> CMAC:
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
return CMAC(self._algorithm, ctx=self._ctx.copy())
__all__ = ["CMAC"]
CMAC = rust_openssl.cmac.CMAC
6 changes: 6 additions & 0 deletions src/rust/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,10 @@ fn main() {
if env::var("DEP_OPENSSL_BORINGSSL").is_ok() {
println!("cargo:rustc-cfg=CRYPTOGRAPHY_IS_BORINGSSL");
}

if let Ok(vars) = env::var("DEP_OPENSSL_CONF") {
for var in vars.split(',') {
println!("cargo:rustc-cfg=CRYPTOGRAPHY_OSSLCONF=\"{}\"", var);
}
}
}
71 changes: 71 additions & 0 deletions src/rust/cryptography-openssl/src/cmac.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// This file is dual licensed under the terms of the Apache License, Version
// 2.0, and the BSD License. See the LICENSE file in the root of this repository
// for complete details.

use crate::hmac::DigestBytes;
use crate::{cvt, cvt_p, OpenSSLResult};
use foreign_types_shared::{ForeignType, ForeignTypeRef};
use std::ptr;

foreign_types::foreign_type! {
type CType = ffi::CMAC_CTX;
fn drop = ffi::CMAC_CTX_free;

pub struct Cmac;
pub struct CmacRef;
}

// SAFETY: It's safe to have `&` references from multiple threads.
unsafe impl Sync for Cmac {}
// SAFETY: It's safe to move the `Cmac` from one thread to another.
unsafe impl Send for Cmac {}

impl Cmac {
pub fn new(key: &[u8], cipher: &openssl::symm::Cipher) -> OpenSSLResult<Cmac> {
// SAFETY: All FFI conditions are handled.
unsafe {
let ctx = Cmac::from_ptr(cvt_p(ffi::CMAC_CTX_new())?);
cvt(ffi::CMAC_Init(
ctx.as_ptr(),
key.as_ptr().cast(),
key.len(),
cipher.as_ptr(),
ptr::null_mut(),
))?;
Ok(ctx)
}
}
}

impl CmacRef {
pub fn update(&mut self, data: &[u8]) -> OpenSSLResult<()> {
// SAFETY: All FFI conditions are handled.
unsafe {
cvt(ffi::CMAC_Update(
self.as_ptr(),
data.as_ptr().cast(),
data.len(),
))?;
}
Ok(())
}

pub fn finish(&mut self) -> OpenSSLResult<DigestBytes> {
let mut buf = [0; ffi::EVP_MAX_MD_SIZE as usize];
let mut len = ffi::EVP_MAX_MD_SIZE as usize;
// SAFETY: All FFI conditions are handled.
unsafe {
cvt(ffi::CMAC_Final(self.as_ptr(), buf.as_mut_ptr(), &mut len))?;
}
Ok(DigestBytes { buf, len })
}

pub fn copy(&self) -> OpenSSLResult<Cmac> {
// SAFETY: All FFI conditions are handled.
unsafe {
let h = Cmac::from_ptr(cvt_p(ffi::CMAC_CTX_new())?);
cvt(ffi::CMAC_CTX_copy(h.as_ptr(), self.as_ptr()))?;
Ok(h)
}
}
}
4 changes: 2 additions & 2 deletions src/rust/cryptography-openssl/src/hmac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ impl HmacRef {
}

pub struct DigestBytes {
buf: [u8; ffi::EVP_MAX_MD_SIZE as usize],
len: usize,
pub(crate) buf: [u8; ffi::EVP_MAX_MD_SIZE as usize],
pub(crate) len: usize,
}

impl std::ops::Deref for DigestBytes {
Expand Down
1 change: 1 addition & 0 deletions src/rust/cryptography-openssl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#![deny(rust_2018_idioms, clippy::undocumented_unsafe_blocks)]

pub mod cmac;
pub mod fips;
pub mod hmac;
#[cfg(any(CRYPTOGRAPHY_IS_BORINGSSL, CRYPTOGRAPHY_IS_LIBRESSL))]
Expand Down
Loading

0 comments on commit 2cdbf9e

Please sign in to comment.