SE050 Driver
API reference
Loading...
Searching...
No Matches
Namespaces | Classes | Functions | Variables
se050::scp03 Namespace Reference

Namespaces

namespace  crypto
 

Classes

struct  ChannelState
 Live SCP03 session state after a successful handshake. More...
 
struct  CommandFields
 A C-APDU split into its ISO/IEC 7816-4 section 5.1 fields. More...
 
class  Session
 SCP03 session bound to a T=1 transport. More...
 
struct  StaticKeys
 Runtime static keys (never compiled-in NXP defaults). More...
 

Functions

Error ParseCommand (const std::uint8_t *capdu, std::size_t len, CommandFields *f) noexcept
 Split a serialized C-APDU into data and Le (ISO/IEC 7816-4 section 5.1, cases 1, 2S/E, 3S/E, 4S/E).
 
Error WrapCommand (ChannelState &st, const std::uint8_t *capdu, std::size_t capdu_len, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len) noexcept
 C-MAC + C-ENC wrap of a C-APDU in any ISO/IEC 7816-4 case, short or extended.
 
void WipeChannel (ChannelState &st) noexcept
 End a session: wipe the session keys, MAC chaining value and counter, mark it closed.
 
Error UnwrapResponse (ChannelState &st, const std::uint8_t *rapdu, std::size_t rapdu_len, std::uint8_t *out, std::size_t out_cap, std::size_t *out_len) noexcept
 R-MAC check and R-ENC decryption of one response. Increments the counter on success.
 
bool FillPutKeyBlock (std::uint8_t *block, const std::uint8_t current_dek[crypto::kAes128KeyLen], const std::uint8_t plain[crypto::kAes128KeyLen], std::uint8_t kcv3[kPutKeyKcvLen]) noexcept
 One AES key field inside GP PUT KEY (encrypted with the current DEK).
 
Error BuildPutKey (std::uint8_t key_version, const std::uint8_t current_dek[crypto::kAes128KeyLen], const std::uint8_t new_enc[crypto::kAes128KeyLen], const std::uint8_t new_mac[crypto::kAes128KeyLen], const std::uint8_t new_dek[crypto::kAes128KeyLen], std::uint8_t *capdu, std::size_t capdu_cap, std::size_t *capdu_len, std::uint8_t *expect_rsp, std::size_t expect_cap, std::size_t *expect_len) noexcept
 Build GP PUT KEY (CLA 0x80, INS 0xD8, P1 = key version, P2 0x81).
 

Variables

constexpr std::uint8_t kClaGp = 0x80U
 
constexpr std::uint8_t kClaGpSecure = 0x84U
 
constexpr std::uint8_t kInsInitializeUpdate = 0x50U
 
constexpr std::uint8_t kInsExternalAuthenticate = 0x82U
 
constexpr std::uint8_t kDefaultKeyVersion = 0x0BU
 
constexpr std::uint8_t kSecLevelCmacCencRmacRenc = 0x33U
 
constexpr std::size_t kInitUpdateRspMin = 10U + 3U + 8U + 8U + 2U
 
constexpr std::uint8_t kClaSmBit = 0x04U
 
constexpr std::size_t kMacFieldLen = 8U
 
constexpr std::size_t kWrapScratchBytes = 320U
 Minimum wrap workspace, enough for short APDUs (CM4: D2 .se_apdu_scratch, not task stack).
 
constexpr std::size_t kWrapScratchBytesExtended = kMaxApduCommandBytes + 7U + 16U + kMacFieldLen + 2U
 Wrap workspace for any command up to kMaxApduCommandBytes (extended header, padding, MAC, Le).
 
constexpr std::uint8_t kInsPutKey = 0xD8U
 
constexpr std::uint8_t kPutKeyTypeAes = 0x88U
 
constexpr std::uint8_t kPutKeyP2Multiple = 0x81U
 
constexpr std::uint8_t kPutKeyKcvLen = 0x03U
 
constexpr std::size_t kPutKeyBlockBytes = 23U
 type + lens + enc key + KCV
 
constexpr std::size_t kPutKeyDataBytes = 1U + 3U * kPutKeyBlockBytes
 version + ENC/MAC/DEK
 
constexpr std::size_t kPutKeyExpectRspBytes = 1U + 3U * kPutKeyKcvLen
 version + 3 KCVs
 

Function Documentation

◆ BuildPutKey()

Error se050::scp03::BuildPutKey ( std::uint8_t  key_version,
const std::uint8_t  current_dek[crypto::kAes128KeyLen],
const std::uint8_t  new_enc[crypto::kAes128KeyLen],
const std::uint8_t  new_mac[crypto::kAes128KeyLen],
const std::uint8_t  new_dek[crypto::kAes128KeyLen],
std::uint8_t *  capdu,
std::size_t  capdu_cap,
std::size_t *  capdu_len,
std::uint8_t *  expect_rsp,
std::size_t  expect_cap,
std::size_t *  expect_len 
)
inlinenoexcept

Build GP PUT KEY (CLA 0x80, INS 0xD8, P1 = key version, P2 0x81).

Replaces ISD key set key_version (product: 0x0B) with new_enc, new_mac, new_dek. The current DEK encrypts the new key values. Caller must have an open SCP03 session with the current set. Never embeds NXP default key bytes.

Parameters
expect_rspVersion byte + three 3-byte KCVs the card must echo.

◆ FillPutKeyBlock()

bool se050::scp03::FillPutKeyBlock ( std::uint8_t *  block,
const std::uint8_t  current_dek[crypto::kAes128KeyLen],
const std::uint8_t  plain[crypto::kAes128KeyLen],
std::uint8_t  kcv3[kPutKeyKcvLen] 
)
inlinenoexcept

One AES key field inside GP PUT KEY (encrypted with the current DEK).

Layout matches NXP ex_se05x_rotate_scp03_keys: type 0x88, KCV = first 3 bytes of AES-ECB(plain, 0x01×16). This is GPCS B.2.1 AES-ECB of a 16-byte key with the current DEK (NXP ex_se05x_rotate_scp03_keys). It is not RFC 3394 AES Key Wrap (that wrap is ADR-0054 sec_rpc / image KEK). Do not substitute.

◆ ParseCommand()

Error se050::scp03::ParseCommand ( const std::uint8_t *  capdu,
std::size_t  len,
CommandFields *  f 
)
inlinenoexcept

Split a serialized C-APDU into data and Le (ISO/IEC 7816-4 section 5.1, cases 1, 2S/E, 3S/E, 4S/E).

Returns
Error::Protocol when the length bytes do not describe the buffer.

◆ UnwrapResponse()

Error se050::scp03::UnwrapResponse ( ChannelState &  st,
const std::uint8_t *  rapdu,
std::size_t  rapdu_len,
std::uint8_t *  out,
std::size_t  out_cap,
std::size_t *  out_len 
)
inlinenoexcept

R-MAC check and R-ENC decryption of one response. Increments the counter on success.

GPC Amendment D 6.2.5 / 6.2.7 (security level 0x33): every response in the session carries an R-MAC over the MAC chaining value, the encrypted data and SW1 SW2. A response that is shorter than R-MAC + SW (for example a bare 90 00 an attacker injects on the bus), whose R-MAC does not match, or whose padding is invalid returns Error::Authentication, and the channel is closed with its keys wiped. Nothing from such a response is written to out. The MAC is compared in constant time and checked before anything is decrypted.

◆ WipeChannel()

void se050::scp03::WipeChannel ( ChannelState &  st)
inlinenoexcept

End a session: wipe the session keys, MAC chaining value and counter, mark it closed.

Uses crypto::SecureZero so the wipe is not optimised away.

◆ WrapCommand()

Error se050::scp03::WrapCommand ( ChannelState &  st,
const std::uint8_t *  capdu,
std::size_t  capdu_len,
std::uint8_t *  out,
std::size_t  out_cap,
std::size_t *  out_len 
)
inlinenoexcept

C-MAC + C-ENC wrap of a C-APDU in any ISO/IEC 7816-4 case, short or extended.

GPC Amendment D 6.2.4 / 6.2.6: the command data is padded (80 00..) and encrypted with the command ICV, then the MAC is computed over the MAC chaining value, the header (CLA with the secure-messaging bit) and the new Lc and data. The wrapped command uses extended length when the input did or when the new Lc exceeds 255. When the input had an Le, the wrapped command keeps one, set to the maximum (00, or 00 00 extended): the protected answer is longer than the plain one by its padding and R-MAC, so the plain Ne cannot be reused. Le is not covered by the C-MAC. A command without data still gets one encrypted padding block (SE050 erratum JOS.2, see the comment in the body). Caller owns out (CM4: D2 .se_apdu_scratch); kWrapScratchBytes covers short commands, kWrapScratchBytesExtended any command. Updates the MCV. The command counter moves on in UnwrapResponse once the card has answered.

Variable Documentation

◆ kClaGp

constexpr std::uint8_t se050::scp03::kClaGp = 0x80U
inlineconstexpr

◆ kClaGpSecure

constexpr std::uint8_t se050::scp03::kClaGpSecure = 0x84U
inlineconstexpr

◆ kClaSmBit

constexpr std::uint8_t se050::scp03::kClaSmBit = 0x04U
inlineconstexpr

◆ kDefaultKeyVersion

constexpr std::uint8_t se050::scp03::kDefaultKeyVersion = 0x0BU
inlineconstexpr

◆ kInitUpdateRspMin

constexpr std::size_t se050::scp03::kInitUpdateRspMin = 10U + 3U + 8U + 8U + 2U
inlineconstexpr

◆ kInsExternalAuthenticate

constexpr std::uint8_t se050::scp03::kInsExternalAuthenticate = 0x82U
inlineconstexpr

◆ kInsInitializeUpdate

constexpr std::uint8_t se050::scp03::kInsInitializeUpdate = 0x50U
inlineconstexpr

◆ kInsPutKey

constexpr std::uint8_t se050::scp03::kInsPutKey = 0xD8U
inlineconstexpr

◆ kMacFieldLen

constexpr std::size_t se050::scp03::kMacFieldLen = 8U
inlineconstexpr

◆ kPutKeyBlockBytes

constexpr std::size_t se050::scp03::kPutKeyBlockBytes = 23U
inlineconstexpr

type + lens + enc key + KCV

◆ kPutKeyDataBytes

constexpr std::size_t se050::scp03::kPutKeyDataBytes = 1U + 3U * kPutKeyBlockBytes
inlineconstexpr

version + ENC/MAC/DEK

◆ kPutKeyExpectRspBytes

constexpr std::size_t se050::scp03::kPutKeyExpectRspBytes = 1U + 3U * kPutKeyKcvLen
inlineconstexpr

version + 3 KCVs

◆ kPutKeyKcvLen

constexpr std::uint8_t se050::scp03::kPutKeyKcvLen = 0x03U
inlineconstexpr

◆ kPutKeyP2Multiple

constexpr std::uint8_t se050::scp03::kPutKeyP2Multiple = 0x81U
inlineconstexpr

◆ kPutKeyTypeAes

constexpr std::uint8_t se050::scp03::kPutKeyTypeAes = 0x88U
inlineconstexpr

◆ kSecLevelCmacCencRmacRenc

constexpr std::uint8_t se050::scp03::kSecLevelCmacCencRmacRenc = 0x33U
inlineconstexpr

◆ kWrapScratchBytes

constexpr std::size_t se050::scp03::kWrapScratchBytes = 320U
inlineconstexpr

Minimum wrap workspace, enough for short APDUs (CM4: D2 .se_apdu_scratch, not task stack).

◆ kWrapScratchBytesExtended

constexpr std::size_t se050::scp03::kWrapScratchBytesExtended = kMaxApduCommandBytes + 7U + 16U + kMacFieldLen + 2U
inlineconstexpr

Wrap workspace for any command up to kMaxApduCommandBytes (extended header, padding, MAC, Le).